]> xenbits.xensource.com Git - libvirt.git/commitdiff
Auto-add one hub if there are too many USB devices
authorJán Tomko <jtomko@redhat.com>
Fri, 17 Jun 2016 07:49:54 +0000 (09:49 +0200)
committerJán Tomko <jtomko@redhat.com>
Thu, 21 Jul 2016 06:30:26 +0000 (08:30 +0200)
When parsing a command line with USB devices that have
no address specified, QEMU automatically adds a USB hub
if the device would fill up all the available USB ports.

To help most of the users, add one hub if there are more
USB devices than available ports. For wilder configurations,
expect the user to provide us with more hubs and/or controllers.

src/conf/domain_addr.c
src/conf/domain_addr.h
src/libvirt_private.syms
src/qemu/qemu_domain_address.c
tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.args [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.xml [new file with mode: 0644]
tests/qemuxml2argvtest.c

index 365ee40ab68d743a75fe00155c9f015ed0cda6db..c3469eec9f23821a1ddd30374e65a60fe88b3a45 100644 (file)
@@ -1604,6 +1604,26 @@ virDomainUSBAddressFindFreePort(virDomainUSBAddressHubPtr hub,
 }
 
 
+size_t
+virDomainUSBAddressCountAllPorts(virDomainDefPtr def)
+{
+    size_t i, ret = 0;
+
+    for (i = 0; i < def->ncontrollers; i++) {
+        virDomainControllerDefPtr cont = def->controllers[i];
+        if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
+            ret += virDomainUSBAddressControllerModelToPorts(cont);
+    }
+
+    for (i = 0; i < def->nhubs; i++) {
+        virDomainHubDefPtr hub = def->hubs[i];
+        if (hub->type == VIR_DOMAIN_HUB_TYPE_USB)
+            ret += VIR_DOMAIN_USB_HUB_PORTS;
+    }
+    return ret;
+}
+
+
 /* Try to find a free port on bus @bus.
  *
  * Returns  0 on success
index cc36aedd529a0ea7b499c9722cb18b32dbb538e0..ce949812dd45c90e4a102fd4bc5084d3fda5903c 100644 (file)
@@ -277,6 +277,8 @@ int
 virDomainUSBAddressSetAddHub(virDomainUSBAddressSetPtr addrs,
                              virDomainHubDefPtr hub)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+size_t
+virDomainUSBAddressCountAllPorts(virDomainDefPtr def);
 void virDomainUSBAddressSetFree(virDomainUSBAddressSetPtr addrs);
 
 int
index be753333acac2696d30baefbebaefd1ca37ce06a..9396c4eb1be655d0f062afede78f0f54b68ad877 100644 (file)
@@ -108,6 +108,7 @@ virDomainPCIAddressSlotInUse;
 virDomainPCIAddressValidate;
 virDomainPCIControllerModelToConnectType;
 virDomainUSBAddressAssign;
+virDomainUSBAddressCountAllPorts;
 virDomainUSBAddressEnsure;
 virDomainUSBAddressPortFormat;
 virDomainUSBAddressPortFormatBuf;
index 7499026f16d30f38ad0fe0545b551392320686b1..787b357d8268183161e2c6cdfe55b5c455d4756e 100644 (file)
@@ -1679,6 +1679,51 @@ qemuDomainAssignUSBPorts(virDomainUSBAddressSetPtr addrs,
 }
 
 
+static int
+qemuDomainAssignUSBPortsCounter(virDomainDeviceInfoPtr info ATTRIBUTE_UNUSED,
+                                void *opaque)
+{
+    struct qemuAssignUSBIteratorInfo *data = opaque;
+
+    data->count++;
+    return 0;
+}
+
+
+static int
+qemuDomainUSBAddressAddHubs(virDomainDefPtr def)
+{
+    struct qemuAssignUSBIteratorInfo data = { .count = 0 };
+    virDomainHubDefPtr hub = NULL;
+    size_t available_ports;
+    int ret = -1;
+
+    available_ports = virDomainUSBAddressCountAllPorts(def);
+    ignore_value(virDomainUSBDeviceDefForeach(def,
+                                              qemuDomainAssignUSBPortsCounter,
+                                              &data,
+                                              false));
+    VIR_DEBUG("Found %zu USB devices and %zu provided USB ports",
+              data.count, available_ports);
+
+    /* Add one hub if there are more devices than ports
+     * otherwise it's up to the user to specify more hubs/controllers */
+    if (data.count > available_ports) {
+        if (VIR_ALLOC(hub) < 0)
+            return -1;
+        hub->type = VIR_DOMAIN_HUB_TYPE_USB;
+
+        if (VIR_APPEND_ELEMENT(def->hubs, def->nhubs, hub) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(hub);
+    return ret;
+}
+
+
 static int
 qemuDomainAssignUSBAddresses(virDomainDefPtr def,
                              virDomainObjPtr obj)
@@ -1690,6 +1735,9 @@ qemuDomainAssignUSBAddresses(virDomainDefPtr def,
     if (!(addrs = virDomainUSBAddressSetCreate()))
         goto cleanup;
 
+    if (qemuDomainUSBAddressAddHubs(def) < 0)
+        goto cleanup;
+
     if (virDomainUSBAddressSetAddControllers(addrs, def) < 0)
         goto cleanup;
 
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.args
new file mode 100644 (file)
index 0000000..7467893
--- /dev/null
@@ -0,0 +1,28 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest1 \
+-S \
+-M pc \
+-m 214 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefconfig \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
+server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=readline \
+-no-acpi \
+-boot c \
+-usb \
+-device usb-hub,id=hub0,bus=usb.0,port=1 \
+-device usb-mouse,id=input0,bus=usb.0,port=2 \
+-device usb-mouse,id=input1,bus=usb.0,port=1.1 \
+-device usb-mouse,id=input2,bus=usb.0,port=1.2 \
+-device usb-tablet,id=input3,bus=usb.0,port=1.3 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.xml
new file mode 100644 (file)
index 0000000..43e0f1f
--- /dev/null
@@ -0,0 +1,23 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <controller type='usb' index='0'/>
+    <memballoon model='virtio'/>
+    <input type='mouse' bus='usb'>
+    </input>
+    <input type='mouse' bus='usb'>
+    </input>
+    <input type='mouse' bus='usb'>
+    </input>
+    <input type='tablet' bus='usb'/>
+  </devices>
+</domain>
index c99568b8f672fa64614b367b52d26365ef0a6de5..356f8435f561c8f85fdb73e4e8bd5acc3da48ca8 100644 (file)
@@ -1184,6 +1184,9 @@ mymain(void)
     DO_TEST("usb-hub",
             QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
             QEMU_CAPS_NODEFCONFIG);
+    DO_TEST("usb-hub-autoadd",
+            QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
+            QEMU_CAPS_NODEFCONFIG);
     DO_TEST_PARSE_ERROR("usb-hub-conflict",
             QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
             QEMU_CAPS_NODEFCONFIG);