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);