USB devices gain a new USB address child element

Expand the domain and the QEmu driver code
Adds a couple of tests
This commit is contained in:
Marc-André Lureau 2011-09-02 21:28:27 +08:00 committed by Daniel Veillard
parent 33d11150b7
commit 22c0d433ab
9 changed files with 150 additions and 16 deletions

View File

@ -2030,6 +2030,14 @@
</attribute>
</element>
</define>
<define name="usbportaddress">
<attribute name="bus">
<ref name="usbAddr"/>
</attribute>
<attribute name="port">
<ref name="usbAddr"/>
</attribute>
</define>
<define name="pciaddress">
<optional>
<attribute name="domain">
@ -2361,6 +2369,12 @@
</attribute>
<ref name="ccidaddress"/>
</group>
<group>
<attribute name="type">
<value>usb</value>
</attribute>
<ref name="usbportaddress"/>
</group>
</choice>
</element>
</define>

View File

@ -133,7 +133,8 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
"pci",
"drive",
"virtio-serial",
"ccid")
"ccid",
"usb")
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
"block",
@ -1399,6 +1400,9 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
return virDomainDeviceDriveAddressIsValid(&info->addr.drive);
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
return virDomainDeviceUSBAddressIsValid(&info->addr.usb);
}
return 0;
@ -1420,6 +1424,13 @@ int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr ATTRI
return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */
}
int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr)
{
if (addr->port >= 128) /* FIXME: is this correct */
return 0;
return 1;
}
int virDomainDeviceVirtioSerialAddressIsValid(
virDomainDeviceVirtioSerialAddressPtr addr ATTRIBUTE_UNUSED)
@ -1788,6 +1799,40 @@ cleanup:
return ret;
}
static int
virDomainDeviceUSBAddressParseXML(xmlNodePtr node,
virDomainDeviceUSBAddressPtr addr)
{
char *port, *bus;
int ret = -1;
memset(addr, 0, sizeof(*addr));
port = virXMLPropString(node, "port");
bus = virXMLPropString(node, "bus");
if (port &&
virStrToLong_ui(port, NULL, 10, &addr->port) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot parse <address> 'port' attribute"));
goto cleanup;
}
if (bus &&
virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot parse <address> 'bus' attribute"));
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(bus);
VIR_FREE(port);
return ret;
}
/* Parse the XML definition for a device address
* @param node XML nodeset to parse for device address definition
*/
@ -1861,6 +1906,11 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
goto cleanup;
break;
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
if (virDomainDeviceUSBAddressParseXML(address, &info->addr.usb) < 0)
goto cleanup;
break;
default:
/* Should not happen */
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@ -3807,7 +3857,7 @@ error:
goto cleanup;
}
/* Parse the XML definition for a network interface */
/* Parse the XML definition for an input device */
static virDomainInputDefPtr
virDomainInputDefParseXML(const char *ostype,
xmlNodePtr node,
@ -3885,6 +3935,14 @@ virDomainInputDefParseXML(const char *ostype,
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
goto error;
if (def->bus == VIR_DOMAIN_INPUT_BUS_USB &&
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
virDomainReportError(VIR_ERR_XML_ERROR, "%s",
_("Invalid address for a USB device"));
goto error;
}
cleanup:
VIR_FREE(type);
VIR_FREE(bus);

View File

@ -69,6 +69,7 @@ enum virDomainDeviceAddressType {
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST
};
@ -105,6 +106,13 @@ struct _virDomainDeviceCcidAddress {
unsigned int slot;
};
typedef struct _virDomainDeviceUSBAddress virDomainDeviceUSBAddress;
typedef virDomainDeviceUSBAddress *virDomainDeviceUSBAddressPtr;
struct _virDomainDeviceUSBAddress {
unsigned int bus;
unsigned int port;
};
typedef struct _virDomainDeviceInfo virDomainDeviceInfo;
typedef virDomainDeviceInfo *virDomainDeviceInfoPtr;
struct _virDomainDeviceInfo {
@ -115,6 +123,7 @@ struct _virDomainDeviceInfo {
virDomainDeviceDriveAddress drive;
virDomainDeviceVirtioSerialAddress vioserial;
virDomainDeviceCcidAddress ccid;
virDomainDeviceUSBAddress usb;
} addr;
};
@ -1440,6 +1449,7 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr);
int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr);
int virDomainDeviceVirtioSerialAddressIsValid(virDomainDeviceVirtioSerialAddressPtr addr);
int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr);
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
void virDomainDefClearPCIAddresses(virDomainDefPtr def);
void virDomainDefClearDeviceAliases(virDomainDefPtr def);

View File

@ -1325,7 +1325,11 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
info->addr.pci.slot, info->addr.pci.function);
else
virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot);
} else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
virBufferAsprintf(buf, ",bus=usb%d.0", info->addr.usb.bus);
virBufferAsprintf(buf, ",port=%d", info->addr.usb.port);
}
return 0;
}
@ -2098,7 +2102,8 @@ error:
char *
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
virBitmapPtr qemuCaps)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
@ -2106,6 +2111,9 @@ qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
dev->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
"usb-mouse" : "usb-tablet", dev->info.alias);
if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0)
goto error;
if (virBufferError(&buf)) {
virReportOOMError();
goto error;
@ -2294,9 +2302,10 @@ qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev)
char *
qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev)
qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev,
virBitmapPtr qemuCaps)
{
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (!dev->source.subsys.u.usb.bus &&
!dev->source.subsys.u.usb.device) {
@ -2305,13 +2314,24 @@ qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev)
return NULL;
}
if (virAsprintf(&ret, "usb-host,hostbus=%d,hostaddr=%d,id=%s",
dev->source.subsys.u.usb.bus,
dev->source.subsys.u.usb.device,
dev->info.alias) < 0)
virReportOOMError();
virBufferAsprintf(&buf, "usb-host,hostbus=%d,hostaddr=%d,id=%s",
dev->source.subsys.u.usb.bus,
dev->source.subsys.u.usb.device,
dev->info.alias);
return ret;
if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0)
goto error;
if (virBufferError(&buf)) {
virReportOOMError();
goto error;
}
return virBufferContentAndReset(&buf);
error:
virBufferFreeAndReset(&buf);
return NULL;
}
@ -4232,7 +4252,7 @@ qemuBuildCommandLine(virConnectPtr conn,
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
char *optstr;
virCommandAddArg(cmd, "-device");
if (!(optstr = qemuBuildUSBInputDevStr(input)))
if (!(optstr = qemuBuildUSBInputDevStr(input, qemuCaps)))
goto error;
virCommandAddArg(cmd, optstr);
VIR_FREE(optstr);
@ -4750,7 +4770,7 @@ qemuBuildCommandLine(virConnectPtr conn,
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
virCommandAddArg(cmd, "-device");
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, qemuCaps)))
goto error;
virCommandAddArg(cmd, devstr);
VIR_FREE(devstr);

View File

@ -98,7 +98,8 @@ char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev,
char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev,
virBitmapPtr qemuCaps);
char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev);
char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
virBitmapPtr qemuCaps);
char * qemuBuildSoundDevStr(virDomainSoundDefPtr sound,
virBitmapPtr qemuCaps);
@ -115,7 +116,8 @@ int qemuOpenPCIConfig(virDomainHostdevDefPtr dev);
/* Legacy, pre device support */
char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev);
/* Current, best practice */
char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev);
char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev,
virBitmapPtr qemuCaps);

View File

@ -922,7 +922,7 @@ int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
goto error;
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, priv->qemuCaps)))
goto error;
}

View File

@ -0,0 +1 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -usb -device usb-mouse,id=input0,bus=usb0.0,port=4 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3

View File

@ -0,0 +1,27 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory>219136</memory>
<currentMemory>219136</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu</emulator>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' unit='0'/>
</disk>
<controller type='ide' index='0'/>
<input type='mouse' bus='usb'>
<address type='usb' bus='0' port='4'/>
</input>
</devices>
</domain>

View File

@ -496,6 +496,8 @@ mymain(void)
DO_TEST("usb-ich9-ehci-addr", false,
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1);
DO_TEST("input-usbmouse-addr", false,
QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);