Companion controllers take an extra 'master' attribute to associate
them.
---
docs/formatdomain.html.in | 20 +++++++++
docs/schemas/domain.rng | 15 +++++++
src/conf/domain_conf.c | 44 ++++++++++++++++++++
src/conf/domain_conf.h | 18 ++++++++
src/qemu/qemu_command.c | 7 +++
.../qemuxml2argv-usb-ich9-companion.args | 6 +++
.../qemuxml2argv-usb-ich9-companion.xml | 30 +++++++++++++
tests/qemuxml2argvtest.c | 5 ++
8 files changed, 145 insertions(+), 0 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 0a383f6..5c232fa 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1243,6 +1243,26 @@
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.
+ </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='1'
model='ich9-uhci1'>
+ <master bus='0' 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 cc0bbca..6a2e71a 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -922,6 +922,9 @@
</attribute>
</optional>
<optional>
+ <ref name="usbmaster"/>
+ </optional>
+ <optional>
<ref name="address"/>
</optional>
</element>
@@ -2377,6 +2380,18 @@
</element>
</define>
+ <define name="usbmaster">
+ <element name="master">
+ <attribute name="bus">
+ <ref name="usbAddr"/>
+ </attribute>
+ <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 00345a3..837e657 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1829,6 +1829,40 @@ cleanup:
return ret;
}
+static int
+virDomainDeviceUSBMasterParseXML(xmlNodePtr node,
+ virDomainDeviceUSBMasterPtr master)
+{
+ char *bus, *startport;
+ int ret = -1;
+
+ memset(master, 0, sizeof(*master));
+
+ bus = virXMLPropString(node, "bus");
+ startport = virXMLPropString(node, "startport");
+
+ if (bus &&
+ virStrToLong_ui(bus, NULL, 10, &master->bus) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot parse <master> 'bus'
attribute"));
+ goto cleanup;
+ }
+
+ 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(bus);
+ VIR_FREE(startport);
+ return ret;
+}
+
/* Parse the XML definition for a device address
* @param node XML nodeset to parse for device address definition
*/
@@ -1839,6 +1873,7 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
{
xmlNodePtr cur;
xmlNodePtr address = NULL;
+ xmlNodePtr master = NULL;
xmlNodePtr alias = NULL;
char *type = NULL;
int ret = -1;
@@ -1855,6 +1890,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;
@@ -1863,6 +1901,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 f231725..0f51d47 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 280b7ae..8deae23 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1754,6 +1754,13 @@ qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def,
}
virBufferAsprintf(buf, "%s,id=usb%d", smodel, def->idx);
+
+ if (def->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) {
+ virBufferAsprintf(buf, ",masterbus=usb%d.0,firstport=%d",
+ def->info.master.usb.bus,
def->info.master.usb.startport);
+ }
+
+
return 0;
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args
b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args
new file mode 100644
index 0000000..d5a2e08
--- /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,id=usb1,masterbus=usb0.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0
\
+-device
ich9-usb-uhci2,id=usb2,masterbus=usb0.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1
\
+-device
ich9-usb-uhci3,id=usb3,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..fe02514
--- /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='1' model='ich9-uhci1'>
+ <master bus='0' startport='0'/>
+ <address type='pci' domain='0' bus='0' slot='4'
function='0'/>
+ </controller>
+ <controller type='usb' index='2' model='ich9-uhci2'>
+ <master bus='0' startport='2'/>
+ <address type='pci' domain='0' bus='0' slot='4'
function='1'/>
+ </controller>
+ <controller type='usb' index='3' model='ich9-uhci3'>
+ <master bus='0' 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..c938034 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -495,6 +495,11 @@ 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,
+ QEMU_CAPS_ICH9_USB_UHCI1, QEMU_CAPS_ICH9_USB_UHCI2,
+ QEMU_CAPS_ICH9_USB_UHCI3);
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);
--
1.7.6