The model by default is piix3-uchi.
Example:
<controller type='usb' index='0' model='ich9-ehci'/>
Changes since v2:
- removed unused qemuControllerModelSCSI enum
---
docs/formatdomain.html.in | 17 ++-
docs/schemas/domain.rng | 1 +
src/conf/domain_conf.c | 7 +-
src/conf/domain_conf.h | 1 +
src/qemu/qemu_command.c | 107 ++++++++++++++++++--
src/qemu/qemu_command.h | 3 +-
src/qemu/qemu_hotplug.c | 10 ++-
.../qemuxml2argv-usb-controller.args | 1 +
.../qemuxml2argv-usb-controller.xml | 16 +++
.../qemuxml2argv-usb-piix3-controller.args | 1 +
.../qemuxml2argv-usb-piix3-controller.xml | 16 +++
tests/qemuxml2argvtest.c | 7 ++
12 files changed, 169 insertions(+), 18 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-controller.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-controller.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index f46771d..5552fbc 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1217,17 +1217,22 @@
<p>
Each controller has a mandatory attribute <code>type</code>,
- which must be one of "ide", "fdc", "scsi",
"sata", "ccid", or
- "virtio-serial", and a mandatory attribute
<code>index</code>
- which is the decimal integer describing in which order the bus
- controller is encountered (for use in <code>controller</code>
- attributes of <code><address></code> elements). The
- "virtio-serial" controller has two additional optional
+ which must be one of "ide", "fdc", "scsi",
"sata", "usb",
+ "ccid", or "virtio-serial", and a mandatory
+ attribute <code>index</code> which is the decimal integer
+ describing in which order the bus controller is encountered (for
+ use in <code>controller</code> attributes
+ of <code><address></code> elements). The
"virtio-serial"
+ controller has two additional optional
attributes <code>ports</code> and <code>vectors</code>,
which
control how many devices can be connected through the
controller. A "scsi" controller has an optional
attribute <code>model</code>, which is one of "auto",
"buslogic", "lsilogic", "lsias1068", or
"vmpvscsi".
+ A "usb" controller has an optional attribute
<code>model</code>,
+ which is one of "piix3-uhci", "piix4-uhci", "ehci",
+ "ich9-ehci1", "ich9-uhci1", "ich9-uhci2",
"ich9-uhci3",
+ "vt82c686b-uhci" or "pci-ohci".
</p>
<p>
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 04c9b61..82a4339 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -877,6 +877,7 @@
<value>scsi</value>
<value>sata</value>
<value>ccid</value>
+ <value>usb</value>
</choice>
</attribute>
</optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0361065..10bc130 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -193,7 +193,8 @@ VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
"scsi",
"sata",
"virtio-serial",
- "ccid")
+ "ccid",
+ "usb")
VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
"auto",
@@ -2472,6 +2473,8 @@ virDomainControllerModelTypeFromString(const
virDomainControllerDefPtr def,
{
if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
return virDomainControllerModelSCSITypeFromString(model);
+ else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
+ return virDomainControllerModelUSBTypeFromString(model);
return -1;
}
@@ -8760,6 +8763,8 @@ virDomainControllerModelTypeToString(virDomainControllerDefPtr def,
{
if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
return virDomainControllerModelSCSITypeToString(model);
+ else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
+ return virDomainControllerModelUSBTypeToString(model);
return NULL;
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index e378a9c..0f5e974 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -252,6 +252,7 @@ enum virDomainControllerType {
VIR_DOMAIN_CONTROLLER_TYPE_SATA,
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
VIR_DOMAIN_CONTROLLER_TYPE_CCID,
+ VIR_DOMAIN_CONTROLLER_TYPE_USB,
VIR_DOMAIN_CONTROLLER_TYPE_LAST
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index dbfc7d9..c64fe65 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -83,6 +83,20 @@ VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
"", /* don't support vbox */
"qxl");
+VIR_ENUM_DECL(qemuControllerModelUSB)
+
+VIR_ENUM_IMPL(qemuControllerModelUSB, VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST,
+ "piix3-usb-uhci",
+ "piix4-usb-uhci",
+ "usb-ehci",
+ "ich9-usb-ehci1",
+ "ich9-usb-uhci1",
+ "ich9-usb-uhci2",
+ "ich9-usb-uhci3",
+ "vt82c686b-usb-uhci",
+ "pci-ohci");
+
+
static void
uname_normalize (struct utsname *ut)
{
@@ -1684,9 +1698,60 @@ error:
}
+static int
+qemuControllerModelUSBToCaps(int model)
+{
+ switch (model) {
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI:
+ return QEMU_CAPS_PIIX3_USB_UHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI:
+ return QEMU_CAPS_PIIX4_USB_UHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI:
+ return QEMU_CAPS_USB_EHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
+ return QEMU_CAPS_ICH9_USB_EHCI1;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI:
+ return QEMU_CAPS_VT82C686B_USB_UHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI:
+ return QEMU_CAPS_PCI_OHCI;
+ default:
+ return -1;
+ }
+}
+
+
+static int
+qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def,
+ virBitmapPtr qemuCaps,
+ virBuffer *buf)
+{
+ const char *smodel;
+ int model, caps;
+
+ model = def->model;
+ if (model == -1)
+ model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI;
+
+ smodel = qemuControllerModelUSBTypeToString(model);
+ caps = qemuControllerModelUSBToCaps(model);
+
+ if (caps == -1 || !qemuCapsGet(qemuCaps, caps)) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("%s not supported in this QEMU binary"), smodel);
+ return -1;
+ }
+
+ virBufferAsprintf(buf, "%s,id=usb%d", smodel, def->idx);
+ return 0;
+}
+
char *
qemuBuildControllerDevStr(virDomainControllerDefPtr def,
- virBitmapPtr qemuCaps)
+ virBitmapPtr qemuCaps,
+ int *nusbcontroller)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -1718,6 +1783,15 @@ qemuBuildControllerDevStr(virDomainControllerDefPtr def,
virBufferAsprintf(&buf, "usb-ccid,id=ccid%d", def->idx);
break;
+ case VIR_DOMAIN_CONTROLLER_TYPE_USB:
+ if (qemuBuildUSBControllerDevStr(def, qemuCaps, &buf) == -1)
+ goto error;
+
+ if (nusbcontroller)
+ *nusbcontroller += 1;
+
+ break;
+
/* We always get an IDE controller, whether we want it or not. */
case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
default:
@@ -2885,7 +2959,8 @@ qemuBuildCommandLine(virConnectPtr conn,
bool has_rbd_hosts = false;
virBuffer rbd_hosts = VIR_BUFFER_INITIALIZER;
bool emitBootindex = false;
-
+ int usbcontroller = 0;
+ bool usblegacy = false;
uname_normalize(&ut);
if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
@@ -3404,14 +3479,26 @@ qemuBuildCommandLine(virConnectPtr conn,
goto error;
}
- virCommandAddArg(cmd, "-device");
+ if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB
&&
+ def->controllers[i]->model == -1 &&
+ !qemuCapsGet(qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI)) {
+ if (usblegacy) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Multiple legacy USB controller not
supported"));
+ goto error;
+ }
+ usblegacy = true;
+ } else {
+ virCommandAddArg(cmd, "-device");
- char *devstr;
- if (!(devstr = qemuBuildControllerDevStr(def->controllers[i], qemuCaps)))
- goto error;
+ char *devstr;
+ if (!(devstr = qemuBuildControllerDevStr(def->controllers[i],
qemuCaps,
+ &usbcontroller)))
+ goto error;
- virCommandAddArg(cmd, devstr);
- VIR_FREE(devstr);
+ virCommandAddArg(cmd, devstr);
+ VIR_FREE(devstr);
+ }
}
}
@@ -4116,7 +4203,9 @@ qemuBuildCommandLine(virConnectPtr conn,
}
}
- virCommandAddArg(cmd, "-usb");
+ if (usbcontroller == 0)
+ virCommandAddArg(cmd, "-usb");
+
for (i = 0 ; i < def->ninputs ; i++) {
virDomainInputDefPtr input = def->inputs[i];
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 87660f2..099d683 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -89,7 +89,8 @@ char * qemuBuildFSDevStr(virDomainFSDefPtr fs,
virBitmapPtr qemuCaps);
/* Current, best practice */
char * qemuBuildControllerDevStr(virDomainControllerDefPtr def,
- virBitmapPtr qemuCaps);
+ virBitmapPtr qemuCaps,
+ int *nusbcontroller);
char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev,
virBitmapPtr qemuCaps);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index b7fdfa0..b2da6d0 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -286,7 +286,15 @@ int qemuDomainAttachPciControllerDevice(struct qemud_driver *driver,
if (qemuAssignDeviceControllerAlias(controller) < 0)
goto cleanup;
- if (!(devstr = qemuBuildControllerDevStr(controller, priv->qemuCaps))) {
+ if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
+ controller->model == -1 &&
+ !qemuCapsGet(priv->qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI)) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("USB controller hotplug unsupported in this QEMU
binary"));
+ goto cleanup;
+ }
+
+ if (!(devstr = qemuBuildControllerDevStr(controller, priv->qemuCaps, NULL)))
{
goto cleanup;
}
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-controller.args
b/tests/qemuxml2argvdata/qemuxml2argv-usb-controller.args
new file mode 100644
index 0000000..f21efc7
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-controller.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 -chardev
socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon
chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -usb -device
virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-controller.xml
b/tests/qemuxml2argvdata/qemuxml2argv-usb-controller.xml
new file mode 100644
index 0000000..82b503e
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-controller.xml
@@ -0,0 +1,16 @@
+<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'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.args
b/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.args
new file mode 100644
index 0000000..799b75f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.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 -chardev
socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon
chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device
piix3-usb-uhci,id=usb0,bus=pci.0,addr=0x3 -device
virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.xml
b/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.xml
new file mode 100644
index 0000000..1996d20
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.xml
@@ -0,0 +1,16 @@
+<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='piix3-uhci'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 6e8da5e..692a02b 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -484,6 +484,13 @@ mymain(void)
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE,
QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CCID_EMULATED);
+ DO_TEST("usb-controller", false,
+ QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE,
+ QEMU_CAPS_NODEFCONFIG);
+ DO_TEST("usb-piix3-controller", false,
+ QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_PIIX3_USB_UHCI,
+ QEMU_CAPS_NODEFCONFIG);
+
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);
DO_TEST("watchdog", false, NONE);
--
1.7.6