Companion controllers take an extra 'master' attribute to associate
them.
Changes since v1:
- use the same bus index for companion controllers
- removed the master bus attribute, redundant with controller index
---
docs/formatdomain.html.in | 22 ++++++++++++
docs/schemas/domain.rng | 12 +++++++
src/conf/domain_conf.c | 35 ++++++++++++++++++++
src/conf/domain_conf.h | 18 ++++++++++
src/qemu/qemu_command.c | 11 ++++++-
.../qemuxml2argv-input-usbmouse-addr.args | 2 +-
.../qemuxml2argv-usb-ich9-companion.args | 6 +++
.../qemuxml2argv-usb-ich9-companion.xml | 30 +++++++++++++++++
tests/qemuxml2argvtest.c | 3 ++
9 files changed, 137 insertions(+), 2 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 5552fbc..633cea1 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1243,6 +1243,28 @@
sub-element.
</p>
+ <p>
+ USB companion controllers have an optional
+ sub-element <code><master></code> to specify the exact
+ relationship of the companion to its master controller.
+ A companion controller is on the same bus as its master, so
+ the companion <code>index</code> value should be equal.
+ </p>
+
+<pre>
+ ...
+ <devices>
+ <controller type='usb' index='0'
model='ich9-ehci1'>
+ <address type='pci' domain='0' bus='0'
slot='4' function='7'/>
+ </controller>
+ <controller type='usb' index='0'
model='ich9-uhci1'>
+ <master startport='0'/>
+ <address type='pci' domain='0' bus='0'
slot='4' function='0'/>
+ </controller>
+ ...
+ </devices>
+ ...</pre>
+
<h4><a name="elementsLease">Device leases</a></h4>
<p>
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 632e029..455f57d 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -923,6 +923,9 @@
</attribute>
</optional>
<optional>
+ <ref name="usbmaster"/>
+ </optional>
+ <optional>
<ref name="address"/>
</optional>
</element>
@@ -2378,6 +2381,15 @@
</element>
</define>
+ <define name="usbmaster">
+ <element name="master">
+ <attribute name="startport">
+ <ref name="usbAddr"/>
+ </attribute>
+ <empty/>
+ </element>
+ </define>
+
<define name="filterref-node-attributes">
<attribute name="filter">
<data type="NCName"/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5487e0e..5ef062a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1832,6 +1832,31 @@ cleanup:
return ret;
}
+static int
+virDomainDeviceUSBMasterParseXML(xmlNodePtr node,
+ virDomainDeviceUSBMasterPtr master)
+{
+ char *startport;
+ int ret = -1;
+
+ memset(master, 0, sizeof(*master));
+
+ startport = virXMLPropString(node, "startport");
+
+ if (startport &&
+ virStrToLong_ui(startport, NULL, 10, &master->startport) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot parse <master> 'startport'
attribute"));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(startport);
+ return ret;
+}
+
/* Parse the XML definition for a device address
* @param node XML nodeset to parse for device address definition
*/
@@ -1842,6 +1867,7 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
{
xmlNodePtr cur;
xmlNodePtr address = NULL;
+ xmlNodePtr master = NULL;
xmlNodePtr alias = NULL;
char *type = NULL;
int ret = -1;
@@ -1858,6 +1884,9 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
} else if (address == NULL &&
xmlStrEqual(cur->name, BAD_CAST "address")) {
address = cur;
+ } else if (master == NULL &&
+ xmlStrEqual(cur->name, BAD_CAST "master")) {
+ master = cur;
}
}
cur = cur->next;
@@ -1866,6 +1895,12 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
if (alias)
info->alias = virXMLPropString(alias, "name");
+ if (master) {
+ info->mastertype = VIR_DOMAIN_CONTROLLER_MASTER_USB;
+ if (virDomainDeviceUSBMasterParseXML(master, &info->master.usb) < 0)
+ goto cleanup;
+ }
+
if (!address)
return 0;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 1ad8071..07d60a4 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -113,6 +113,20 @@ struct _virDomainDeviceUSBAddress {
unsigned int port;
};
+enum virDomainControllerMaster {
+ VIR_DOMAIN_CONTROLLER_MASTER_NONE,
+ VIR_DOMAIN_CONTROLLER_MASTER_USB,
+
+ VIR_DOMAIN_CONTROLLER_MASTER_LAST
+};
+
+typedef struct _virDomainDeviceUSBMaster virDomainDeviceUSBMaster;
+typedef virDomainDeviceUSBMaster *virDomainDeviceUSBMasterPtr;
+struct _virDomainDeviceUSBMaster {
+ unsigned int bus;
+ unsigned int startport;
+};
+
typedef struct _virDomainDeviceInfo virDomainDeviceInfo;
typedef virDomainDeviceInfo *virDomainDeviceInfoPtr;
struct _virDomainDeviceInfo {
@@ -125,6 +139,10 @@ struct _virDomainDeviceInfo {
virDomainDeviceCcidAddress ccid;
virDomainDeviceUSBAddress usb;
} addr;
+ int mastertype;
+ union {
+ virDomainDeviceUSBMaster usb;
+ } master;
};
typedef struct _virDomainLeaseDef virDomainLeaseDef;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 91d8124..835d06f 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1758,7 +1758,16 @@ qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def,
return -1;
}
- virBufferAsprintf(buf, "%s,id=usb%d", smodel, def->idx);
+ virBufferAsprintf(buf, "%s", smodel);
+
+ if (def->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) {
+ virBufferAsprintf(buf, ",masterbus=usb%d.0", def->idx);
+ virBufferAsprintf(buf, ",firstport=%d",
def->info.master.usb.startport);
+ } else {
+ virBufferAsprintf(buf, ",id=usb%d", def->idx);
+ }
+
+
return 0;
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args
b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args
index b6dc0d3..d784960 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args
@@ -1 +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
+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-usb-ich9-companion.args
b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args
new file mode 100644
index 0000000..b37dbf6
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args
@@ -0,0 +1,6 @@
+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 -chardev
socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon
chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c \
+-device ich9-usb-ehci1,id=usb0,bus=pci.0,multifunction=on,addr=0x4.0x7 \
+-device
ich9-usb-uhci1,masterbus=usb0.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0 \
+-device
ich9-usb-uhci2,masterbus=usb0.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1 \
+-device
ich9-usb-uhci3,masterbus=usb0.0,firstport=4,bus=pci.0,multifunction=on,addr=0x4.0x2 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.xml
b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.xml
new file mode 100644
index 0000000..05a6adf
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.xml
@@ -0,0 +1,30 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219136</memory>
+ <currentMemory>219200</currentMemory>
+ <vcpu>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' model='ich9-ehci1'>
+ <address type='pci' domain='0' bus='0' slot='4'
function='7'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci1'>
+ <master startport='0'/>
+ <address type='pci' domain='0' bus='0' slot='4'
function='0'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci2'>
+ <master startport='2'/>
+ <address type='pci' domain='0' bus='0' slot='4'
function='1'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci3'>
+ <master startport='4'/>
+ <address type='pci' domain='0' bus='0' slot='4'
function='2'/>
+ </controller>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index b573380..33588d0 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -495,6 +495,9 @@ mymain(void)
QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1);
DO_TEST("input-usbmouse-addr", false,
QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
+ DO_TEST("usb-ich9-companion", false,
+ QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
+ QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1);
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);
--
1.7.6