--- docs/schemas/domain.rng | 14 +++++ src/conf/domain_conf.c | 62 +++++++++++++++++++- src/conf/domain_conf.h | 10 +++ src/qemu/qemu_command.c | 40 ++++++++++--- src/qemu/qemu_command.h | 6 +- src/qemu/qemu_hotplug.c | 2 +- .../qemuxml2argv-input-usbmouse-addr.args | 1 + .../qemuxml2argv-input-usbmouse-addr.xml | 27 +++++++++ tests/qemuxml2argvtest.c | 2 + 9 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index a059ce0..cc0bbca 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -2028,6 +2028,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"> @@ -2359,6 +2367,12 @@ </attribute> <ref name="ccidaddress"/> </group> + <group> + <attribute name="type"> + <value>usb</value> + </attribute> + <ref name="usbportaddress"/> + </group> </choice> </element> </define> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7fe7f4c..00345a3 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", @@ -1395,6 +1396,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; @@ -1416,6 +1420,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) @@ -1784,6 +1795,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 */ @@ -1857,6 +1902,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, @@ -3791,7 +3841,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, @@ -3869,6 +3919,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 c859e51..f231725 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; }; @@ -1431,6 +1440,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 4168504..280b7ae 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1321,7 +1321,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; } @@ -2084,7 +2088,8 @@ error: char * -qemuBuildUSBInputDevStr(virDomainInputDefPtr dev) +qemuBuildUSBInputDevStr(virDomainInputDefPtr dev, + virBitmapPtr qemuCaps) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -2092,6 +2097,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; @@ -2280,9 +2288,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) { @@ -2291,13 +2300,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) + 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); + + if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) + goto error; + + if (virBufferError(&buf)) { virReportOOMError(); + goto error; + } - return ret; + return virBufferContentAndReset(&buf); + +error: + virBufferFreeAndReset(&buf); + return NULL; } @@ -4218,7 +4238,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); @@ -4736,7 +4756,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 099d683..de09577 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 b2da6d0..60cd241 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 0000000..b6dc0d3 --- /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=usb.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 0000000..a2fa8e3 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml @@ -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> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index f3abc24..b573380 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -493,6 +493,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); -- 1.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list