diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 8fd6ca1f8d..ee9709436a 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1219,17 +1219,22 @@

Each controller has a mandatory attribute type, - which must be one of "ide", "fdc", "scsi", "sata", "ccid", or - "virtio-serial", and a mandatory attribute index - which is the decimal integer describing in which order the bus - controller is encountered (for use in controller - attributes of <address> 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 index which is the decimal integer + describing in which order the bus controller is encountered (for + use in controller attributes + of <address> elements). The "virtio-serial" + controller has two additional optional attributes ports and vectors, which control how many devices can be connected through the controller. A "scsi" controller has an optional attribute model, which is one of "auto", "buslogic", "lsilogic", "lsias1068", or "vmpvscsi". + A "usb" controller has an optional attribute model, + which is one of "piix3-uhci", "piix4-uhci", "ehci", + "ich9-ehci1", "ich9-uhci1", "ich9-uhci2", "ich9-uhci3", + "vt82c686b-uhci" or "pci-ohci".

diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 5830421f7d..086d2718dc 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -878,6 +878,7 @@ scsi sata ccid + usb diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 8c04a32fd8..82338d64c2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -194,7 +194,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", @@ -2473,6 +2474,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; } @@ -8756,6 +8759,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 5396f7ae14..68cfa213a7 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -253,6 +253,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 fa52dc0ab9..5e2fad0754 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -85,6 +85,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) { @@ -1703,9 +1717,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; @@ -1737,6 +1802,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: @@ -2904,7 +2978,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) @@ -3423,14 +3498,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); + } } } @@ -4135,7 +4222,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 87660f2f8f..099d683f35 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 b7fdfa04bb..b2da6d06df 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/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index b009bf3cb5..3a317b22c6 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -487,6 +487,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);