[libvirt] [v2 06/13] USB devices gain a new USB address child element

Marc-André Lureau marcandre.lureau at gmail.com
Thu Aug 25 22:44:22 UTC 2011


---
 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 82a4339..632e029 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -2029,6 +2029,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">
@@ -2360,6 +2368,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 10bc130..5487e0e 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",
@@ -1398,6 +1399,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;
@@ -1419,6 +1423,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)
@@ -1787,6 +1798,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
  */
@@ -1860,6 +1905,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,
@@ -3806,7 +3856,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,
@@ -3884,6 +3934,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 0f5e974..1ad8071 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;
 };
 
@@ -1437,6 +1446,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 2f32e37..91d8124 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1327,7 +1327,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;
 }
 
@@ -2089,7 +2093,8 @@ error:
 
 
 char *
-qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
+qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
+                        virBitmapPtr qemuCaps)
 {
     virBuffer buf = VIR_BUFFER_INITIALIZER;
 
@@ -2097,6 +2102,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;
@@ -2285,9 +2293,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) {
@@ -2296,13 +2305,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;
 }
 
 
@@ -4223,7 +4243,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);
@@ -4741,7 +4761,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




More information about the libvir-list mailing list