diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 086d2718dc..0c72a9f28a 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -2030,6 +2030,14 @@ + + + + + + + + @@ -2361,6 +2369,12 @@ + + + usb + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 82338d64c2..ef9fb53401 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -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
'port' attribute")); + goto cleanup; + } + + if (bus && + virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse
'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); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 68cfa213a7..60a296a42d 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -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); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 5e2fad0754..c8e76ada8e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -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); diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 099d683f35..de09577024 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -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); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index b2da6d06df..60cd241c00 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -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; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args new file mode 100644 index 0000000000..d7849609d5 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args @@ -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 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml new file mode 100644 index 0000000000..a2fa8e3041 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml @@ -0,0 +1,27 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + +
+ + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index e0f8523105..9d3409e58f 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -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);