From: David Waring <davidjw(a)rd.bbc.co.uk>
This patch adds the ability to include a serial element in a
hostdev/source to select a device with a particular serial number.
Signed-off-by: Ján Tomko <jtomko(a)redhat.com>
---
docs/formatdomain.html.in | 22 +++++++-----
docs/schemas/domaincommon.rng | 8 +++++
src/conf/domain_conf.c | 31 +++++++++++++---
src/conf/domain_conf.h | 1 +
.../qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml | 42 ++++++++++++++++++++++
tests/qemuxml2xmltest.c | 2 ++
6 files changed, 92 insertions(+), 14 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 691a451..5bb2531 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2711,6 +2711,7 @@
<source startupPolicy='optional'>
<vendor id='0x1234'/>
<product id='0xbeef'/>
+ <serial>SERIAL123456</serial>
</source>
<boot order='2'/>
</hostdev>
@@ -2773,10 +2774,11 @@
</dd>
<dt><code>source</code></dt>
<dd>The source element describes the device as seen from the host.
- The USB device can either be addressed by vendor / product id using the
- <code>vendor</code> and <code>product</code> elements or by
the device's
- address on the hosts using the <code>address</code> element. PCI
devices
- on the other hand can only be described by their <code>address</code>.
+ The USB device can either be addressed by vendor / product id and optional
+ serial number using the <code>vendor</code>,
<code>product</code> and
+ <code>serial</code> elements or by the device's address on the
hosts using
+ the <code>address</code> element. PCI devices on the other hand can
only
+ be described by their <code>address</code>.
SCSI devices are described by both the <code>adapter</code> and
<code>address</code> elements.
@@ -2800,11 +2802,13 @@
</tr>
</table>
</dd>
- <dt><code>vendor</code>,
<code>product</code></dt>
- <dd>The <code>vendor</code> and <code>product</code>
elements each have an
- <code>id</code> attribute that specifies the USB vendor and product
id.
- The ids can be given in decimal, hexadecimal (starting with 0x) or
- octal (starting with 0) form.</dd>
+ <dt><code>vendor</code>, <code>product</code>,
<code>serial</code></dt>
+ <dd>The <code>vendor</code>, <code>product</code> and
<code>serial</code>
+ elements each have an <code>id</code> attribute that specifies the USB
+ vendor, product and device serial id. The ids can be given in decimal,
+ hexadecimal (starting with 0x) or octal (starting with 0) form for
+ vendor and product. The serial number is a string that matches the serial
+ number of the device.</dd>
<dt><code>boot</code></dt>
<dd>Specifies that the device is bootable. The
<code>order</code>
attribute determines the order in which devices will be tried during
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index af67123..8595771 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3546,6 +3546,14 @@
<ref name="usbId"/>
</attribute>
</element>
+ <optional>
+ <element name="serial">
+ <choice>
+ <text/>
+ <empty/>
+ </choice>
+ </element>
+ </optional>
</define>
<define name="usbaddress">
<element name="address">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index fe06921..4c1d02e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1719,8 +1719,14 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
}
break;
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
- if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
+ switch (def->source.subsys.type) {
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+ VIR_FREE(def->source.subsys.u.usb.serial);
+ break;
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
VIR_FREE(def->source.subsys.u.scsi.adapter);
+ break;
+ }
break;
}
}
@@ -3852,6 +3858,18 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
"%s", _("usb product needs id"));
goto out;
}
+ } else if (xmlStrEqual(cur->name, BAD_CAST "serial")) {
+ char *serial;
+
+ if (VIR_STRDUP(serial, (const char *)xmlNodeGetContent(cur)) < 0)
+ goto out;
+
+ if (!serial) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("usb serial needs id"));
+ goto out;
+ }
+ def->source.subsys.u.usb.serial = serial;
} else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
char *bus, *device;
@@ -3903,12 +3921,12 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
goto out;
}
- if (!got_vendor && got_product) {
+ if (!got_vendor && (got_product || def->source.subsys.u.usb.serial)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("missing vendor"));
goto out;
}
- if (got_vendor && !got_product) {
+ if ((got_vendor || def->source.subsys.u.usb.serial) && !got_product) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("missing product"));
goto out;
@@ -10095,9 +10113,10 @@ virDomainHostdevMatchSubsysUSB(virDomainHostdevDefPtr a,
a->source.subsys.u.usb.device == b->source.subsys.u.usb.device)
return 1;
} else {
- /* specified by product & vendor id */
+ /* specified by product, vendor id and optionally serial number */
if (a->source.subsys.u.usb.product == b->source.subsys.u.usb.product
&&
- a->source.subsys.u.usb.vendor == b->source.subsys.u.usb.vendor)
+ a->source.subsys.u.usb.vendor == b->source.subsys.u.usb.vendor
&&
+ STREQ_NULLABLE(a->source.subsys.u.usb.serial,
b->source.subsys.u.usb.serial))
return 1;
}
return 0;
@@ -15479,6 +15498,8 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf,
def->source.subsys.u.usb.vendor);
virBufferAsprintf(buf, "<product id='0x%.4x'/>\n",
def->source.subsys.u.usb.product);
+ virBufferEscapeString(buf, "<serial>%s</serial>\n",
+ def->source.subsys.u.usb.serial);
}
if (def->source.subsys.u.usb.bus ||
def->source.subsys.u.usb.device) {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 2de807d..cba3733 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -403,6 +403,7 @@ struct _virDomainHostdevSubsys {
unsigned vendor;
unsigned product;
+ char *serial;
} usb;
struct {
virDevicePCIAddress addr; /* host address */
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml
b/tests/qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml
new file mode 100644
index 0000000..10c4bbf
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml
@@ -0,0 +1,42 @@
+<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>
+ </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>
+ <controller type='usb' index='0' model='ich9-ehci1'>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x7'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci1'>
+ <master startport='0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci2'>
+ <master startport='2'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x1'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci3'>
+ <master startport='4'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <hostdev mode='subsystem' type='usb' managed='no'>
+ <source startupPolicy='optional'>
+ <vendor id='0x1234'/>
+ <product id='0xbeef'/>
+ <serial>S123456</serial>
+ </source>
+ <boot order='1'/>
+ </hostdev>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index da528da..a130034 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -364,6 +364,8 @@ mymain(void)
DO_TEST("chardev-label");
+ DO_TEST("usb-hostdev");
+
virObjectUnref(driver.caps);
virObjectUnref(driver.xmlopt);
--
1.8.3.2