[libvirt] [v3 00/14] USB improvements and new redirdev

Hei, Here we go with the third version of this patch series that leads to support for various USB controllers, USB hubs, and USB redirection devices. Major change since v2 is the creation of a new element 'redirdev' instead of reusing the existing 'hostdev'. Marc-André Lureau (14): Add various USB devices QEMU_CAPS Split virDomainControllerModel to virDomainControllerModelSCSI Add USB controller models Add a new controller type 'usb' with optionnal 'model' USB controller can have a PCI address child element USB devices gain a new USB address child element Add USB companion controllers support Add USB hub device Modify USB port to be defined as a port path qemu: don't reserve slot 1 if a PIIX3 USB controller is defined there qemu: Don't append 0 at usb id, so that it is compatible with legacy -usb Add a usb1 & usb2 qemuxml2argv test Add "redirdev" redirection device Learn to use spicevmc as a redirection type for usb-redir docs/formatdomain.html.in | 105 +++++- docs/schemas/domain.rng | 100 ++++- src/conf/domain_audit.c | 65 +++ src/conf/domain_audit.h | 5 + src/conf/domain_conf.c | 443 +++++++++++++++++++- src/conf/domain_conf.h | 104 +++++- src/esx/esx_driver.c | 8 +- src/libvirt_private.syms | 11 +- src/qemu/qemu_capabilities.c | 28 ++ src/qemu/qemu_capabilities.h | 9 + src/qemu/qemu_command.c | 342 ++++++++++++++- src/qemu/qemu_command.h | 14 +- src/qemu/qemu_driver.c | 7 + src/qemu/qemu_hotplug.c | 55 +++- src/qemu/qemu_hotplug.h | 3 + src/vmx/vmx.c | 32 +- tests/qemuhelptest.c | 17 +- .../qemuxml2argv-input-usbmouse-addr.args | 1 + .../qemuxml2argv-input-usbmouse-addr.xml | 27 ++ .../qemuxml2argv-usb-controller.args | 1 + .../qemuxml2argv-usb-controller.xml | 16 + tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args | 1 + tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml | 19 + .../qemuxml2argv-usb-ich9-companion.args | 6 + .../qemuxml2argv-usb-ich9-companion.xml | 30 ++ .../qemuxml2argv-usb-ich9-ehci-addr.args | 1 + .../qemuxml2argv-usb-ich9-ehci-addr.xml | 18 + .../qemuxml2argv-usb-piix3-controller.args | 1 + .../qemuxml2argv-usb-piix3-controller.xml | 16 + tests/qemuxml2argvdata/qemuxml2argv-usb-ports.args | 1 + tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml | 31 ++ tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args | 10 + tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml | 40 ++ tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args | 15 + tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml | 74 ++++ tests/qemuxml2argvtest.c | 30 ++ tests/qemuxml2xmltest.c | 2 + tests/xml2vmxtest.c | 2 +- 38 files changed, 1598 insertions(+), 92 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml 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-hub.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ports.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml -- 1.7.6

Changes since v1: - added pci-ohci - removed extra ich9 companions that came with ich9-ehci --- src/qemu/qemu_capabilities.c | 25 +++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 8 ++++++++ tests/qemuhelptest.c | 14 +++++++++++--- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index f665de4..a776a0c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -125,6 +125,15 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "sga", "virtio-blk-pci.event_idx", "virtio-net-pci.event_idx", + + "piix3-usb-uhci", /* 65 */ + "piix4-usb-uhci", + "usb-ehci", + "ich9-usb-ehci1", + "vt82c686b-usb-uhci", + + "pci-ohci", /* 70 */ + "usb-redir", ); struct qemu_feature_flags { @@ -1196,6 +1205,22 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags) qemuCapsSet(flags, QEMU_CAPS_CCID_EMULATED); if (strstr(str, "name \"ccid-card-passthru\"")) qemuCapsSet(flags, QEMU_CAPS_CCID_PASSTHRU); + + if (strstr(str, "name \"piix3-usb-uhci\"")) + qemuCapsSet(flags, QEMU_CAPS_PIIX3_USB_UHCI); + if (strstr(str, "name \"piix4-usb-uhci\"")) + qemuCapsSet(flags, QEMU_CAPS_PIIX4_USB_UHCI); + if (strstr(str, "name \"usb-ehci\"")) + qemuCapsSet(flags, QEMU_CAPS_USB_EHCI); + if (strstr(str, "name \"ich9-usb-ehci1\"")) + qemuCapsSet(flags, QEMU_CAPS_ICH9_USB_EHCI1); + if (strstr(str, "name \"vt82c686b-usb-uhci\"")) + qemuCapsSet(flags, QEMU_CAPS_VT82C686B_USB_UHCI); + if (strstr(str, "name \"pci-ohci\"")) + qemuCapsSet(flags, QEMU_CAPS_PCI_OHCI); + if (strstr(str, "name \"usb-redir\"")) + qemuCapsSet(flags, QEMU_CAPS_USB_REDIR); + /* Prefer -chardev spicevmc (detected earlier) over -device spicevmc */ if (!qemuCapsGet(flags, QEMU_CAPS_CHARDEV_SPICEVMC) && strstr(str, "name \"spicevmc\"")) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 13af0b9..f4bb368 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -101,6 +101,14 @@ enum qemuCapsFlags { QEMU_CAPS_VIRTIO_BLK_EVENT_IDX = 63, /* virtio-blk-pci.event_idx */ QEMU_CAPS_VIRTIO_NET_EVENT_IDX = 64, /* virtio-net-pci.event_idx */ + QEMU_CAPS_PIIX3_USB_UHCI = 65, /* -device piix3-usb-uhci */ + QEMU_CAPS_PIIX4_USB_UHCI = 66, /* -device piix4-usb-uhci */ + QEMU_CAPS_USB_EHCI = 67, /* -device usb-ehci */ + QEMU_CAPS_ICH9_USB_EHCI1 = 68, /* -device ich9-usb-ehci1 and companions */ + QEMU_CAPS_VT82C686B_USB_UHCI = 69, /* -device vt82c686b-usb-uhci */ + QEMU_CAPS_PCI_OHCI = 70, /* -device pci-ohci */ + QEMU_CAPS_USB_REDIR = 71, /* -device usb-redir */ + QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index 102dd22..d57e499 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -347,7 +347,9 @@ mymain(void) QEMU_CAPS_VGA_NONE, QEMU_CAPS_MIGRATE_QEMU_FD, QEMU_CAPS_DRIVE_AIO, - QEMU_CAPS_DEVICE_SPICEVMC); + QEMU_CAPS_DEVICE_SPICEVMC, + QEMU_CAPS_PIIX3_USB_UHCI, + QEMU_CAPS_PIIX4_USB_UHCI); DO_TEST("qemu-kvm-0.12.3", 12003, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -431,7 +433,11 @@ mymain(void) QEMU_CAPS_MIGRATE_QEMU_FD, QEMU_CAPS_DRIVE_AIO, QEMU_CAPS_DEVICE_SPICEVMC, - QEMU_CAPS_PCI_MULTIFUNCTION); + QEMU_CAPS_PCI_MULTIFUNCTION, + QEMU_CAPS_PIIX3_USB_UHCI, + QEMU_CAPS_PIIX4_USB_UHCI, + QEMU_CAPS_VT82C686B_USB_UHCI, + QEMU_CAPS_PCI_OHCI); DO_TEST("qemu-kvm-0.12.1.2-rhel61", 12001, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -476,7 +482,9 @@ mymain(void) QEMU_CAPS_CHARDEV_SPICEVMC, QEMU_CAPS_DEVICE_QXL_VGA, QEMU_CAPS_VIRTIO_TX_ALG, - QEMU_CAPS_VIRTIO_IOEVENTFD); + QEMU_CAPS_VIRTIO_IOEVENTFD, + QEMU_CAPS_PIIX3_USB_UHCI, + QEMU_CAPS_PIIX4_USB_UHCI); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.7.6

--- src/conf/domain_conf.c | 26 +++++++++++++++++++++++--- src/conf/domain_conf.h | 18 ++++++++++-------- src/esx/esx_driver.c | 8 ++++---- src/libvirt_private.syms | 4 ++-- src/vmx/vmx.c | 32 ++++++++++++++++---------------- tests/xml2vmxtest.c | 2 +- 6 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index ce1f3c5..5e91d54 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -195,7 +195,7 @@ VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST, "virtio-serial", "ccid") -VIR_ENUM_IMPL(virDomainControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST, +VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, "auto", "buslogic", "lsilogic", @@ -2455,6 +2455,16 @@ no_memory: } +static int +virDomainControllerModelTypeFromString(const virDomainControllerDefPtr def, + const char *model) +{ + if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) + return virDomainControllerModelSCSITypeFromString(model); + + return -1; +} + /* Parse the XML definition for a controller * @param node XML nodeset to parse for controller definition */ @@ -2492,7 +2502,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, model = virXMLPropString(node, "model"); if (model) { - if ((def->model = virDomainControllerModelTypeFromString(model)) < 0) { + if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown model type '%s'"), model); goto error; @@ -8733,6 +8743,16 @@ virDomainDiskDefFormat(virBufferPtr buf, return 0; } +static const char * +virDomainControllerModelTypeToString(virDomainControllerDefPtr def, + int model) +{ + if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) + return virDomainControllerModelSCSITypeToString(model); + + return NULL; +} + static int virDomainControllerDefFormat(virBufferPtr buf, virDomainControllerDefPtr def, @@ -8748,7 +8768,7 @@ virDomainControllerDefFormat(virBufferPtr buf, } if (def->model != -1) { - model = virDomainControllerModelTypeToString(def->model); + model = virDomainControllerModelTypeToString(def, def->model); if (!model) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 2cc9b06..8a4cd11 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -257,14 +257,16 @@ enum virDomainControllerType { }; -enum virDomainControllerModel { - VIR_DOMAIN_CONTROLLER_MODEL_AUTO, - VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC, - VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC, - VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068, - VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI, +enum virDomainControllerModelSCSI { + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI, + + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST +}; - VIR_DOMAIN_CONTROLLER_MODEL_LAST }; typedef struct _virDomainVirtioSerialOpts virDomainVirtioSerialOpts; @@ -1673,7 +1675,7 @@ VIR_ENUM_DECL(virDomainDiskIo) VIR_ENUM_DECL(virDomainIoEventFd) VIR_ENUM_DECL(virDomainVirtioEventIdx) VIR_ENUM_DECL(virDomainController) -VIR_ENUM_DECL(virDomainControllerModel) +VIR_ENUM_DECL(virDomainControllerModelSCSI) VIR_ENUM_DECL(virDomainFS) VIR_ENUM_DECL(virDomainFSAccessMode) VIR_ENUM_DECL(virDomainNet) diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index c097651..e603399 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -412,16 +412,16 @@ esxAutodetectSCSIControllerModel(virDomainDiskDefPtr def, int *model, if (STRCASEEQ(vmDiskFileInfo->controllerType, "VirtualBusLogicController")) { - *model = VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC; + *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC; } else if (STRCASEEQ(vmDiskFileInfo->controllerType, "VirtualLsiLogicController")) { - *model = VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC; + *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC; } else if (STRCASEEQ(vmDiskFileInfo->controllerType, "VirtualLsiLogicSASController")) { - *model = VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068; + *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068; } else if (STRCASEEQ(vmDiskFileInfo->controllerType, "ParaVirtualSCSIController")) { - *model = VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI; + *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI; } else { ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Found unexpected controller model '%s' for disk '%s'"), diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index acae122..91ecd7b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -248,8 +248,8 @@ virDomainConfigFile; virDomainControllerDefFree; virDomainControllerInsert; virDomainControllerInsertPreAlloced; -virDomainControllerModelTypeFromString; -virDomainControllerModelTypeToString; +virDomainControllerModelSCSITypeFromString; +virDomainControllerModelSCSITypeToString; virDomainControllerTypeToString; virDomainCpuSetFormat; virDomainCpuSetParse; diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index 08c2716..dff3599 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -483,8 +483,8 @@ def->parallels[0]... /* directly map the virDomainControllerModel to virVMXSCSIControllerModel, * this is good enough for now because all virDomainControllerModel values * are actually SCSI controller models in the ESX case */ -VIR_ENUM_DECL(virVMXSCSIControllerModel) -VIR_ENUM_IMPL(virVMXSCSIControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST, +VIR_ENUM_DECL(virVMXControllerModelSCSI) +VIR_ENUM_IMPL(virVMXControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, "auto", /* just to match virDomainControllerModel, will never be used */ "buslogic", "lsilogic", @@ -1040,7 +1040,7 @@ virVMXHandleLegacySCSIDiskDriverName(virDomainDefPtr def, *tmp = c_tolower(*tmp); } - model = virDomainControllerModelTypeFromString(disk->driverName); + model = virDomainControllerModelSCSITypeFromString(disk->driverName); if (model < 0) { VMX_ERROR(VIR_ERR_INTERNAL_ERROR, @@ -1068,7 +1068,7 @@ virVMXHandleLegacySCSIDiskDriverName(virDomainDefPtr def, VMX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Inconsistent SCSI controller model ('%s' is not '%s') " "for SCSI controller index %d"), disk->driverName, - virDomainControllerModelTypeToString(controller->model), + virDomainControllerModelSCSITypeToString(controller->model), controller->idx); return -1; } @@ -1120,7 +1120,7 @@ virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def, continue; } - if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_AUTO && + if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO && ctx->autodetectSCSIControllerModel != NULL) { count = 0; @@ -1157,15 +1157,15 @@ virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def, } if (controller->model != -1 && - controller->model != VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC && - controller->model != VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC && - controller->model != VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068 && - controller->model != VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI) { + controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC && + controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC && + controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068 && + controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI) { VMX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Expecting domain XML attribute 'model' of entry " "'controller' to be 'buslogic' or 'lsilogic' or " "'lsisas1068' or 'vmpvscsi' but found '%s'"), - virDomainControllerModelTypeToString(controller->model)); + virDomainControllerModelSCSITypeToString(controller->model)); goto cleanup; } @@ -1869,13 +1869,13 @@ virVMXParseSCSIController(virConfPtr conf, int controller, bool *present, *tmp = c_tolower(*tmp); } - *virtualDev = virVMXSCSIControllerModelTypeFromString(virtualDev_string); + *virtualDev = virVMXControllerModelSCSITypeFromString(virtualDev_string); if (*virtualDev == -1 || - (*virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC && - *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC && - *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068 && - *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI)) { + (*virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC && + *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC && + *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068 && + *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI)) { VMX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Expecting VMX entry '%s' to be 'buslogic' or 'lsilogic' " "or 'lsisas1068' or 'pvscsi' but found '%s'"), @@ -3088,7 +3088,7 @@ virVMXFormatConfig(virVMXContext *ctx, virCapsPtr caps, virDomainDefPtr def, if (scsi_virtualDev[i] != -1) { virBufferAsprintf(&buffer, "scsi%d.virtualDev = \"%s\"\n", i, - virVMXSCSIControllerModelTypeToString + virVMXControllerModelSCSITypeToString (scsi_virtualDev[i])); } } diff --git a/tests/xml2vmxtest.c b/tests/xml2vmxtest.c index 439ddc8..77b1611 100644 --- a/tests/xml2vmxtest.c +++ b/tests/xml2vmxtest.c @@ -143,7 +143,7 @@ static int testAutodetectSCSIControllerModel(virDomainDiskDefPtr def ATTRIBUTE_UNUSED, int *model, void *opaque ATTRIBUTE_UNUSED) { - *model = VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC; + *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC; return 0; } -- 1.7.6

On Fri, Sep 02, 2011 at 03:18:12AM +0200, Marc-André Lureau wrote:
--- src/conf/domain_conf.c | 26 +++++++++++++++++++++++--- src/conf/domain_conf.h | 18 ++++++++++-------- src/esx/esx_driver.c | 8 ++++---- src/libvirt_private.syms | 4 ++-- src/vmx/vmx.c | 32 ++++++++++++++++---------------- tests/xml2vmxtest.c | 2 +- 6 files changed, 56 insertions(+), 34 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index ce1f3c5..5e91d54 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -195,7 +195,7 @@ VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST, "virtio-serial", "ccid")
-VIR_ENUM_IMPL(virDomainControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST, +VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, "auto", "buslogic", "lsilogic", @@ -2455,6 +2455,16 @@ no_memory: }
+static int +virDomainControllerModelTypeFromString(const virDomainControllerDefPtr def, + const char *model) +{ + if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) + return virDomainControllerModelSCSITypeFromString(model); + + return -1; +} + /* Parse the XML definition for a controller * @param node XML nodeset to parse for controller definition */ @@ -2492,7 +2502,7 @@ virDomainControllerDefParseXML(xmlNodePtr node,
model = virXMLPropString(node, "model"); if (model) { - if ((def->model = virDomainControllerModelTypeFromString(model)) < 0) { + if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown model type '%s'"), model); goto error; @@ -8733,6 +8743,16 @@ virDomainDiskDefFormat(virBufferPtr buf, return 0; }
+static const char * +virDomainControllerModelTypeToString(virDomainControllerDefPtr def, + int model) +{ + if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) + return virDomainControllerModelSCSITypeToString(model); + + return NULL; +} + static int virDomainControllerDefFormat(virBufferPtr buf, virDomainControllerDefPtr def, @@ -8748,7 +8768,7 @@ virDomainControllerDefFormat(virBufferPtr buf, }
if (def->model != -1) { - model = virDomainControllerModelTypeToString(def->model); + model = virDomainControllerModelTypeToString(def, def->model);
if (!model) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 2cc9b06..8a4cd11 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -257,14 +257,16 @@ enum virDomainControllerType { };
-enum virDomainControllerModel { - VIR_DOMAIN_CONTROLLER_MODEL_AUTO, - VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC, - VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC, - VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068, - VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI, +enum virDomainControllerModelSCSI { + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI, + + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST +};
- VIR_DOMAIN_CONTROLLER_MODEL_LAST };
Hum, I had to remove that extra }; there :-)
typedef struct _virDomainVirtioSerialOpts virDomainVirtioSerialOpts;
fine otherwise ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Changes since v1: - Added pci-ohci --- docs/schemas/domain.rng | 9 +++++++++ src/conf/domain_conf.c | 11 +++++++++++ src/conf/domain_conf.h | 13 +++++++++++++ src/libvirt_private.syms | 2 ++ 4 files changed, 35 insertions(+), 0 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index dd8c41a..04c9b61 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -909,6 +909,15 @@ <value>lsilogic</value> <value>lsisas1068</value> <value>vmpvscsi</value> + <value>piix3-uhci</value> + <value>piix4-uhci</value> + <value>ehci</value> + <value>ich9-ehci1</value> + <value>ich9-uhci1</value> + <value>ich9-uhci2</value> + <value>ich9-uhci3</value> + <value>vt82c686b-uhci</value> + <value>pci-ohci</value> </choice> </attribute> </optional> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 5e91d54..0361065 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -202,6 +202,17 @@ VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAS "lsisas1068", "vmpvscsi") +VIR_ENUM_IMPL(virDomainControllerModelUSB, VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST, + "piix3-uhci", + "piix4-uhci", + "ehci", + "ich9-ehci1", + "ich9-uhci1", + "ich9-uhci2", + "ich9-uhci3", + "vt82c686b-uhci", + "pci-ohci") + VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST, "mount", "block", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8a4cd11..e378a9c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -267,6 +267,18 @@ enum virDomainControllerModelSCSI { VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST }; +enum virDomainControllerModelUSB { + VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI, + VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI, + VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI, + VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1, + VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1, + VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2, + VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3, + VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI, + VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI, + + VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST }; typedef struct _virDomainVirtioSerialOpts virDomainVirtioSerialOpts; @@ -1676,6 +1688,7 @@ VIR_ENUM_DECL(virDomainIoEventFd) VIR_ENUM_DECL(virDomainVirtioEventIdx) VIR_ENUM_DECL(virDomainController) VIR_ENUM_DECL(virDomainControllerModelSCSI) +VIR_ENUM_DECL(virDomainControllerModelUSB) VIR_ENUM_DECL(virDomainFS) VIR_ENUM_DECL(virDomainFSAccessMode) VIR_ENUM_DECL(virDomainNet) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 91ecd7b..74948b8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -248,6 +248,8 @@ virDomainConfigFile; virDomainControllerDefFree; virDomainControllerInsert; virDomainControllerInsertPreAlloced; +virDomainControllerModelUSBTypeFromString; +virDomainControllerModelUSBTypeToString; virDomainControllerModelSCSITypeFromString; virDomainControllerModelSCSITypeToString; virDomainControllerTypeToString; -- 1.7.6

On Fri, Sep 02, 2011 at 03:18:13AM +0200, Marc-André Lureau wrote:
Changes since v1: - Added pci-ohci --- docs/schemas/domain.rng | 9 +++++++++ src/conf/domain_conf.c | 11 +++++++++++ src/conf/domain_conf.h | 13 +++++++++++++ src/libvirt_private.syms | 2 ++ 4 files changed, 35 insertions(+), 0 deletions(-)
[..]
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8a4cd11..e378a9c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -267,6 +267,18 @@ enum virDomainControllerModelSCSI { VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST };
+enum virDomainControllerModelUSB { + VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI, + VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI, + VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI, + VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1, + VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1, + VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2, + VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3, + VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI, + VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI, + + VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST };
The extra }; went missing here but that's just normal :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

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

--- .../qemuxml2argv-usb-ich9-ehci-addr.args | 1 + .../qemuxml2argv-usb-ich9-ehci-addr.xml | 18 ++++++++++++++++++ tests/qemuxml2argvtest.c | 3 +++ 3 files changed, 22 insertions(+), 0 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args new file mode 100644 index 0000000..502244d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.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 ich9-usb-ehci1,id=usb0,bus=pci.0,multifunction=on,addr=0x4.0x7 -device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml new file mode 100644 index 0000000..49a57e2 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml @@ -0,0 +1,18 @@ +<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> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 692a02b..f3abc24 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -490,6 +490,9 @@ mymain(void) DO_TEST("usb-piix3-controller", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_NODEFCONFIG); + DO_TEST("usb-ich9-ehci-addr", 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

--- docs/schemas/domain.rng | 14 +++++ src/conf/domain_conf.c | 62 +++++++++++++++++++- src/conf/domain_conf.h | 10 +++ src/qemu/qemu_command.c | 40 ++++++++++--- src/qemu/qemu_command.h | 6 +- src/qemu/qemu_hotplug.c | 2 +- .../qemuxml2argv-input-usbmouse-addr.args | 1 + .../qemuxml2argv-input-usbmouse-addr.xml | 27 +++++++++ tests/qemuxml2argvtest.c | 2 + 9 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 82a4339..632e029 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -2029,6 +2029,14 @@ </attribute> </element> </define> + <define name="usbportaddress"> + <attribute name="bus"> + <ref name="usbAddr"/> + </attribute> + <attribute name="port"> + <ref name="usbAddr"/> + </attribute> + </define> <define name="pciaddress"> <optional> <attribute name="domain"> @@ -2360,6 +2368,12 @@ </attribute> <ref name="ccidaddress"/> </group> + <group> + <attribute name="type"> + <value>usb</value> + </attribute> + <ref name="usbportaddress"/> + </group> </choice> </element> </define> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 10bc130..5487e0e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -133,7 +133,8 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "pci", "drive", "virtio-serial", - "ccid") + "ccid", + "usb") VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST, "block", @@ -1398,6 +1399,9 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE: return virDomainDeviceDriveAddressIsValid(&info->addr.drive); + + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB: + return virDomainDeviceUSBAddressIsValid(&info->addr.usb); } return 0; @@ -1419,6 +1423,13 @@ int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr ATTRI return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */ } +int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr) +{ + if (addr->port >= 128) /* FIXME: is this correct */ + return 0; + + return 1; +} int virDomainDeviceVirtioSerialAddressIsValid( virDomainDeviceVirtioSerialAddressPtr addr ATTRIBUTE_UNUSED) @@ -1787,6 +1798,40 @@ cleanup: return ret; } +static int +virDomainDeviceUSBAddressParseXML(xmlNodePtr node, + virDomainDeviceUSBAddressPtr addr) +{ + char *port, *bus; + int ret = -1; + + memset(addr, 0, sizeof(*addr)); + + port = virXMLPropString(node, "port"); + bus = virXMLPropString(node, "bus"); + + if (port && + virStrToLong_ui(port, NULL, 10, &addr->port) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'port' attribute")); + goto cleanup; + } + + if (bus && + virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'bus' attribute")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(bus); + VIR_FREE(port); + return ret; +} + /* Parse the XML definition for a device address * @param node XML nodeset to parse for device address definition */ @@ -1860,6 +1905,11 @@ virDomainDeviceInfoParseXML(xmlNodePtr node, goto cleanup; break; + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB: + if (virDomainDeviceUSBAddressParseXML(address, &info->addr.usb) < 0) + goto cleanup; + break; + default: /* Should not happen */ virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -3806,7 +3856,7 @@ error: goto cleanup; } -/* Parse the XML definition for a network interface */ +/* Parse the XML definition for an input device */ static virDomainInputDefPtr virDomainInputDefParseXML(const char *ostype, xmlNodePtr node, @@ -3884,6 +3934,14 @@ virDomainInputDefParseXML(const char *ostype, if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0) goto error; + if (def->bus == VIR_DOMAIN_INPUT_BUS_USB && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("Invalid address for a USB device")); + goto error; + } + cleanup: VIR_FREE(type); VIR_FREE(bus); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 0f5e974..1ad8071 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -69,6 +69,7 @@ enum virDomainDeviceAddressType { VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID, + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST }; @@ -105,6 +106,13 @@ struct _virDomainDeviceCcidAddress { unsigned int slot; }; +typedef struct _virDomainDeviceUSBAddress virDomainDeviceUSBAddress; +typedef virDomainDeviceUSBAddress *virDomainDeviceUSBAddressPtr; +struct _virDomainDeviceUSBAddress { + unsigned int bus; + unsigned int port; +}; + typedef struct _virDomainDeviceInfo virDomainDeviceInfo; typedef virDomainDeviceInfo *virDomainDeviceInfoPtr; struct _virDomainDeviceInfo { @@ -115,6 +123,7 @@ struct _virDomainDeviceInfo { virDomainDeviceDriveAddress drive; virDomainDeviceVirtioSerialAddress vioserial; virDomainDeviceCcidAddress ccid; + virDomainDeviceUSBAddress usb; } addr; }; @@ -1437,6 +1446,7 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr); int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr); int virDomainDeviceVirtioSerialAddressIsValid(virDomainDeviceVirtioSerialAddressPtr addr); +int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr); void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); void virDomainDefClearPCIAddresses(virDomainDefPtr def); void virDomainDefClearDeviceAliases(virDomainDefPtr def); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index c64fe65..716f3fe 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1317,7 +1317,11 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, info->addr.pci.slot, info->addr.pci.function); else virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot); + } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { + virBufferAsprintf(buf, ",bus=usb%d.0", info->addr.usb.bus); + virBufferAsprintf(buf, ",port=%d", info->addr.usb.port); } + return 0; } @@ -2079,7 +2083,8 @@ error: char * -qemuBuildUSBInputDevStr(virDomainInputDefPtr dev) +qemuBuildUSBInputDevStr(virDomainInputDefPtr dev, + virBitmapPtr qemuCaps) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -2087,6 +2092,9 @@ qemuBuildUSBInputDevStr(virDomainInputDefPtr dev) dev->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "usb-mouse" : "usb-tablet", dev->info.alias); + if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) + goto error; + if (virBufferError(&buf)) { virReportOOMError(); goto error; @@ -2275,9 +2283,10 @@ qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev) char * -qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev) +qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, + virBitmapPtr qemuCaps) { - char *ret = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; if (!dev->source.subsys.u.usb.bus && !dev->source.subsys.u.usb.device) { @@ -2286,13 +2295,24 @@ qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev) return NULL; } - if (virAsprintf(&ret, "usb-host,hostbus=%d,hostaddr=%d,id=%s", - dev->source.subsys.u.usb.bus, - dev->source.subsys.u.usb.device, - dev->info.alias) < 0) + virBufferAsprintf(&buf, "usb-host,hostbus=%d,hostaddr=%d,id=%s", + dev->source.subsys.u.usb.bus, + dev->source.subsys.u.usb.device, + dev->info.alias); + + if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) + goto error; + + if (virBufferError(&buf)) { virReportOOMError(); + goto error; + } - return ret; + return virBufferContentAndReset(&buf); + +error: + virBufferFreeAndReset(&buf); + return NULL; } @@ -4213,7 +4233,7 @@ qemuBuildCommandLine(virConnectPtr conn, if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { char *optstr; virCommandAddArg(cmd, "-device"); - if (!(optstr = qemuBuildUSBInputDevStr(input))) + if (!(optstr = qemuBuildUSBInputDevStr(input, qemuCaps))) goto error; virCommandAddArg(cmd, optstr); VIR_FREE(optstr); @@ -4731,7 +4751,7 @@ qemuBuildCommandLine(virConnectPtr conn, if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { virCommandAddArg(cmd, "-device"); - if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev))) + if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, qemuCaps))) goto error; virCommandAddArg(cmd, devstr); VIR_FREE(devstr); diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 099d683..de09577 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -98,7 +98,8 @@ char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev, char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev, virBitmapPtr qemuCaps); -char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev); +char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev, + virBitmapPtr qemuCaps); char * qemuBuildSoundDevStr(virDomainSoundDefPtr sound, virBitmapPtr qemuCaps); @@ -115,7 +116,8 @@ int qemuOpenPCIConfig(virDomainHostdevDefPtr dev); /* Legacy, pre device support */ char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev); /* Current, best practice */ -char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev); +char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, + virBitmapPtr qemuCaps); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index b2da6d0..60cd241 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -922,7 +922,7 @@ int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver, if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0) goto error; - if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev))) + if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, priv->qemuCaps))) goto error; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args new file mode 100644 index 0000000..b6dc0d3 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.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 -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 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml new file mode 100644 index 0000000..a2fa8e3 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml @@ -0,0 +1,27 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219136</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </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> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + <input type='mouse' bus='usb'> + <address type='usb' bus='0' port='4'/> + </input> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index f3abc24..b573380 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -493,6 +493,8 @@ mymain(void) DO_TEST("usb-ich9-ehci-addr", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1); + DO_TEST("input-usbmouse-addr", false, + QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE); -- 1.7.6

On Fri, Sep 02, 2011 at 03:18:16AM +0200, Marc-André Lureau wrote:
--- docs/schemas/domain.rng | 14 +++++ src/conf/domain_conf.c | 62 +++++++++++++++++++- src/conf/domain_conf.h | 10 +++ src/qemu/qemu_command.c | 40 ++++++++++--- src/qemu/qemu_command.h | 6 +- src/qemu/qemu_hotplug.c | 2 +- .../qemuxml2argv-input-usbmouse-addr.args | 1 + .../qemuxml2argv-input-usbmouse-addr.xml | 27 +++++++++ tests/qemuxml2argvtest.c | 2 + 9 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml [...] +++ b/src/qemu/qemu_command.c @@ -1317,7 +1317,11 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, info->addr.pci.slot, info->addr.pci.function); else virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot); + } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { + virBufferAsprintf(buf, ",bus=usb%d.0", info->addr.usb.bus);
Assuming bus 0 we should see "bus=usb0.0" in the output
+ virBufferAsprintf(buf, ",port=%d", info->addr.usb.port); } + return 0; [...] +++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.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 -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
But apparently the test data was using bus=usb.0, so I had to fix it Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

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 Changes since v2: - removed unused bus field in _virDomainDeviceUSBMaster --- docs/formatdomain.html.in | 22 +++++++++++ docs/schemas/domain.rng | 12 ++++++ src/conf/domain_conf.c | 40 ++++++++++++++++++++ src/conf/domain_conf.h | 17 ++++++++ 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, 141 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..7d03bcd 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1555,6 +1555,11 @@ virDomainDeviceInfoFormat(virBufferPtr buf, virBufferAsprintf(buf, " <alias name='%s'/>\n", info->alias); } + if (info->mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) { + virBufferAsprintf(buf, " <master startport='%d'/>\n", + info->master.usb.startport); + } + if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) return 0; @@ -1832,6 +1837,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 +1872,7 @@ virDomainDeviceInfoParseXML(xmlNodePtr node, { xmlNodePtr cur; xmlNodePtr address = NULL; + xmlNodePtr master = NULL; xmlNodePtr alias = NULL; char *type = NULL; int ret = -1; @@ -1858,6 +1889,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 +1900,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..7d5193a 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -113,6 +113,19 @@ 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 startport; +}; + typedef struct _virDomainDeviceInfo virDomainDeviceInfo; typedef virDomainDeviceInfo *virDomainDeviceInfoPtr; struct _virDomainDeviceInfo { @@ -125,6 +138,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 716f3fe..ba87b04 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1748,7 +1748,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

--- docs/formatdomain.html.in | 27 ++++ docs/schemas/domain.rng | 13 ++ src/conf/domain_conf.c | 157 +++++++++++++++++++++- src/conf/domain_conf.h | 20 +++ src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 3 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 56 ++++++++- src/qemu/qemu_command.h | 1 + tests/qemuhelptest.c | 9 +- tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args | 1 + tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml | 19 +++ tests/qemuxml2argvtest.c | 3 + 13 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 633cea1..e35b76b 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2084,6 +2084,33 @@ qemu-kvm -net nic,model=? /dev/null device to a particular PCI slot. </p> + <h4><a name="elementsHub">Hub devices</a></h4> + + <p> + A hub is a device that expands a single port into several so + that there are more ports available to connect devices to a host + system. + </p> + +<pre> + ... + <devices> + <hub type='usb'/> + </devices> + ...</pre> + + <dl> + <dt><code>hub</code></dt> + <dd>The <code>hub</code> element has one mandatory attribute, + the <code>type</code> whose value can only be 'usb'.</dd> + </dl> + + <p> + The <code>hub</code> element has an optional + sub-element <code><address></code> which can tie the + device to a particular controller. + </p> + <h4><a name="elementsGraphics">Graphical framebuffers</a></h4> <p> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 455f57d..16e9687 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -1962,6 +1962,18 @@ </optional> </element> </define> + <define name="hub"> + <element name="hub"> + <attribute name="type"> + <choice> + <value>usb</value> + </choice> + </attribute> + <optional> + <ref name="address"/> + </optional> + </element> + </define> <define name="hostdev"> <element name="hostdev"> <optional> @@ -2125,6 +2137,7 @@ <ref name="serial"/> <ref name="channel"/> <ref name="smartcard"/> + <ref name="hub"/> </choice> </zeroOrMore> <optional> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7d03bcd..af08a03 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -126,7 +126,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, "hostdev", "watchdog", "controller", - "graphics") + "graphics", + "hub") VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "none", @@ -436,6 +437,9 @@ VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1, "shutoff", "crashed") +VIR_ENUM_IMPL(virDomainHub, VIR_DOMAIN_HUB_TYPE_LAST, + "usb") + #define VIR_DOMAIN_NOSTATE_LAST (VIR_DOMAIN_NOSTATE_UNKNOWN + 1) VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST, "unknown") @@ -999,6 +1003,15 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def) VIR_FREE(def); } +void virDomainHubDefFree(virDomainHubDefPtr def) +{ + if (!def) + return; + + virDomainDeviceInfoClear(&def->info); + VIR_FREE(def); +} + void virDomainDeviceDefFree(virDomainDeviceDefPtr def) { if (!def) @@ -1035,6 +1048,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_GRAPHICS: virDomainGraphicsDefFree(def->data.graphics); break; + case VIR_DOMAIN_DEVICE_HUB: + virDomainHubDefFree(def->data.hub); + break; } VIR_FREE(def); @@ -1144,6 +1160,10 @@ void virDomainDefFree(virDomainDefPtr def) virDomainHostdevDefFree(def->hostdevs[i]); VIR_FREE(def->hostdevs); + for (i = 0 ; i < def->nhubs ; i++) + virDomainHubDefFree(def->hubs[i]); + VIR_FREE(def->hubs); + VIR_FREE(def->os.type); VIR_FREE(def->os.arch); VIR_FREE(def->os.machine); @@ -1527,6 +1547,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def, if (def->console) if (cb(def, &def->console->info, opaque) < 0) return -1; + for (i = 0; i < def->nhubs ; i++) + if (cb(def, &def->hubs[i]->info, opaque) < 0) + return -1; return 0; } @@ -1596,6 +1619,12 @@ virDomainDeviceInfoFormat(virBufferPtr buf, info->addr.ccid.slot); break; + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB: + virBufferAsprintf(buf, " bus='%d' port='%d'", + info->addr.usb.bus, + info->addr.usb.port); + break; + default: virDomainReportError(VIR_ERR_INTERNAL_ERROR, _("unknown address type '%d'"), info->type); @@ -3995,6 +4024,47 @@ error: } +/* Parse the XML definition for an hub device */ +static virDomainHubDefPtr +virDomainHubDefParseXML(xmlNodePtr node, unsigned int flags) +{ + virDomainHubDefPtr def; + char *type = NULL; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + type = virXMLPropString(node, "type"); + + if (!type) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing hub device type")); + goto error; + } + + if ((def->type = virDomainHubTypeFromString(type)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown hub device type '%s'"), type); + goto error; + } + + if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0) + goto error; + +cleanup: + VIR_FREE(type); + + return def; + +error: + virDomainHubDefFree(def); + def = NULL; + goto cleanup; +} + + /* Parse the XML definition for a clock timer */ static virDomainTimerDefPtr virDomainTimerDefParseXML(const xmlNodePtr node, @@ -5572,6 +5642,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, dev->type = VIR_DOMAIN_DEVICE_GRAPHICS; if (!(dev->data.graphics = virDomainGraphicsDefParseXML(node, ctxt, flags))) goto error; + } else if (xmlStrEqual(node->name, BAD_CAST "hub")) { + dev->type = VIR_DOMAIN_DEVICE_HUB; + if (!(dev->data.hub = virDomainHubDefParseXML(node, flags))) + goto error; } else { virDomainReportError(VIR_ERR_XML_ERROR, "%s", _("unknown device type")); @@ -6976,6 +7050,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, } } + /* analysis of the hub devices */ + if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) { + goto error; + } + if (n && VIR_ALLOC_N(def->hubs, n) < 0) + goto no_memory; + for (i = 0 ; i < n ; i++) { + virDomainHubDefPtr hub = virDomainHubDefParseXML(nodes[i], flags); + if (!hub) + goto error; + + def->hubs[def->nhubs++] = hub; + } + VIR_FREE(nodes); + /* analysis of security label */ if (virSecurityLabelDefParseXML(def, ctxt, flags) == -1) goto error; @@ -7886,6 +7975,29 @@ cleanup: } +static bool virDomainHubDefCheckABIStability(virDomainHubDefPtr src, + virDomainHubDefPtr dst) +{ + bool identical = false; + + if (src->type != dst->type) { + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target hub device type %s does not match source %s"), + virDomainHubTypeToString(dst->type), + virDomainHubTypeToString(src->type)); + goto cleanup; + } + + if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info)) + goto cleanup; + + identical = true; + +cleanup: + return identical; +} + + /* This compares two configurations and looks for any differences * which will affect the guest ABI. This is primarily to allow * validation of custom XML config passed in during migration @@ -8119,6 +8231,17 @@ bool virDomainDefCheckABIStability(virDomainDefPtr src, goto cleanup; } + if (src->nhubs != dst->nhubs) { + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target domain hub device count %d does not match source %d"), + dst->nhubs, src->nhubs); + goto cleanup; + } + + for (i = 0 ; i < src->nhubs ; i++) + if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i])) + goto cleanup; + if (src->console && !virDomainConsoleDefCheckABIStability(src->console, dst->console)) goto cleanup; @@ -10032,6 +10155,34 @@ virDomainHostdevDefFormat(virBufferPtr buf, } +static int +virDomainHubDefFormat(virBufferPtr buf, + virDomainHubDefPtr def, + unsigned int flags) +{ + const char *type = virDomainHubTypeToString(def->type); + + if (!type) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected hub type %d"), def->type); + return -1; + } + + virBufferAsprintf(buf, " <hub type='%s'", type); + + if (virDomainDeviceInfoIsSet(&def->info, flags)) { + virBufferAddLit(buf, ">\n"); + if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0) + return -1; + virBufferAddLit(buf, " </hub>\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } + + return 0; +} + + #define DUMPXML_FLAGS \ (VIR_DOMAIN_XML_SECURE | \ VIR_DOMAIN_XML_INACTIVE | \ @@ -10437,6 +10588,10 @@ virDomainDefFormatInternal(virDomainDefPtr def, if (virDomainHostdevDefFormat(&buf, def->hostdevs[n], flags) < 0) goto cleanup; + for (n = 0 ; n < def->nhubs ; n++) + if (virDomainHubDefFormat(&buf, def->hubs[n], flags) < 0) + goto cleanup; + if (def->watchdog) virDomainWatchdogDefFormat (&buf, def->watchdog, flags); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7d5193a..569e840 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -615,6 +615,13 @@ struct _virDomainSmartcardDef { virDomainDeviceInfo info; }; +typedef struct _virDomainHubDef virDomainHubDef; +typedef virDomainHubDef *virDomainHubDefPtr; +struct _virDomainHubDef { + int type; + virDomainDeviceInfo info; +}; + enum virDomainInputType { VIR_DOMAIN_INPUT_TYPE_MOUSE, VIR_DOMAIN_INPUT_TYPE_TABLET, @@ -824,6 +831,12 @@ enum virDomainGraphicsListenType { VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST, }; +enum virDomainHubType { + VIR_DOMAIN_HUB_TYPE_USB, + + VIR_DOMAIN_HUB_TYPE_LAST, +}; + typedef struct _virDomainGraphicsListenDef virDomainGraphicsListenDef; typedef virDomainGraphicsListenDef *virDomainGraphicsListenDefPtr; struct _virDomainGraphicsListenDef { @@ -964,6 +977,7 @@ enum virDomainDeviceType { VIR_DOMAIN_DEVICE_WATCHDOG, VIR_DOMAIN_DEVICE_CONTROLLER, VIR_DOMAIN_DEVICE_GRAPHICS, + VIR_DOMAIN_DEVICE_HUB, VIR_DOMAIN_DEVICE_LAST, }; @@ -984,6 +998,7 @@ struct _virDomainDeviceDef { virDomainHostdevDefPtr hostdev; virDomainWatchdogDefPtr watchdog; virDomainGraphicsDefPtr graphics; + virDomainHubDefPtr hub; } data; }; @@ -1311,6 +1326,9 @@ struct _virDomainDef { size_t nleases; virDomainLeaseDefPtr *leases; + int nhubs; + virDomainHubDefPtr *hubs; + /* Only 1 */ virDomainChrDefPtr console; virSecurityLabelDef seclabel; @@ -1457,6 +1475,7 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def); void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def); void virDomainVideoDefFree(virDomainVideoDefPtr def); void virDomainHostdevDefFree(virDomainHostdevDefPtr def); +void virDomainHubDefFree(virDomainHubDefPtr def); void virDomainDeviceDefFree(virDomainDeviceDefPtr def); int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, int type); @@ -1737,6 +1756,7 @@ VIR_ENUM_DECL(virDomainWatchdogAction) VIR_ENUM_DECL(virDomainVideo) VIR_ENUM_DECL(virDomainHostdevMode) VIR_ENUM_DECL(virDomainHostdevSubsys) +VIR_ENUM_DECL(virDomainHub) VIR_ENUM_DECL(virDomainInput) VIR_ENUM_DECL(virDomainInputBus) VIR_ENUM_DECL(virDomainGraphics) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 74948b8..6642ba9 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -327,6 +327,8 @@ virDomainGraphicsTypeToString; virDomainHostdevDefFree; virDomainHostdevModeTypeToString; virDomainHostdevSubsysTypeToString; +virDomainHubTypeFromString; +virDomainHubTypeToString; virDomainInputDefFree; virDomainIoEventFdTypeFromString; virDomainIoEventFdTypeToString; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index a776a0c..5b72a60 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -134,6 +134,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "pci-ohci", /* 70 */ "usb-redir", + "usb-hub", ); struct qemu_feature_flags { @@ -1220,6 +1221,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags) qemuCapsSet(flags, QEMU_CAPS_PCI_OHCI); if (strstr(str, "name \"usb-redir\"")) qemuCapsSet(flags, QEMU_CAPS_USB_REDIR); + if (strstr(str, "name \"usb-hub\"")) + qemuCapsSet(flags, QEMU_CAPS_USB_HUB); /* Prefer -chardev spicevmc (detected earlier) over -device spicevmc */ if (!qemuCapsGet(flags, QEMU_CAPS_CHARDEV_SPICEVMC) && diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index f4bb368..c9b9b45 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -108,6 +108,7 @@ enum qemuCapsFlags { QEMU_CAPS_VT82C686B_USB_UHCI = 69, /* -device vt82c686b-usb-uhci */ QEMU_CAPS_PCI_OHCI = 70, /* -device pci-ohci */ QEMU_CAPS_USB_REDIR = 71, /* -device usb-redir */ + QEMU_CAPS_USB_HUB = 72, /* -device usb-hub */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index ba87b04..6962862 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -679,6 +679,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virBitmapPtr qemuCaps) if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0) goto no_memory; } + for (i = 0; i < def->nhubs ; i++) { + if (virAsprintf(&def->hubs[i]->info.alias, "hub%d", i) < 0) + goto no_memory; + } if (def->console) { if (virAsprintf(&def->console->info.alias, "console%d", i) < 0) goto no_memory; @@ -1262,6 +1266,9 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) for (i = 0; i < def->nchannels ; i++) { /* Nada - none are PCI based (yet) */ } + for (i = 0; i < def->nhubs ; i++) { + /* Nada - none are PCI based (yet) */ + } return 0; @@ -1757,7 +1764,6 @@ qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def, virBufferAsprintf(buf, ",id=usb%d", def->idx); } - return 0; } @@ -2326,6 +2332,43 @@ error: char * +qemuBuildHubDevStr(virDomainHubDefPtr dev, + virBitmapPtr qemuCaps) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (dev->type != VIR_DOMAIN_HUB_TYPE_USB) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hub type %s not supported"), + virDomainHubTypeToString(dev->type)); + goto error; + } + + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_USB_HUB)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("usb-hub not supported by QEMU binary")); + goto error; + } + + virBufferAddLit(&buf, "usb-hub"); + virBufferAsprintf(&buf, ",id=%s", dev->info.alias); + if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) + goto error; + + if (virBufferError(&buf)) { + virReportOOMError(); + goto error; + } + + return virBufferContentAndReset(&buf); + +error: + virBufferFreeAndReset(&buf); + return NULL; +} + + +char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev) { char *ret = NULL; @@ -4235,6 +4278,17 @@ qemuBuildCommandLine(virConnectPtr conn, if (usbcontroller == 0) virCommandAddArg(cmd, "-usb"); + for (i = 0 ; i < def->nhubs ; i++) { + virDomainHubDefPtr hub = def->hubs[i]; + char *optstr; + + virCommandAddArg(cmd, "-device"); + if (!(optstr = qemuBuildHubDevStr(hub, qemuCaps))) + goto error; + virCommandAddArg(cmd, optstr); + VIR_FREE(optstr); + } + 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 de09577..22bc15d 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -119,6 +119,7 @@ char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev); char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, virBitmapPtr qemuCaps); +char * qemuBuildHubDevStr(virDomainHubDefPtr dev, virBitmapPtr qemuCaps); int qemuNetworkIfaceConnect(virDomainDefPtr def, diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index d57e499..ffd30e2 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -349,7 +349,8 @@ mymain(void) QEMU_CAPS_DRIVE_AIO, QEMU_CAPS_DEVICE_SPICEVMC, QEMU_CAPS_PIIX3_USB_UHCI, - QEMU_CAPS_PIIX4_USB_UHCI); + QEMU_CAPS_PIIX4_USB_UHCI, + QEMU_CAPS_USB_HUB); DO_TEST("qemu-kvm-0.12.3", 12003, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -437,7 +438,8 @@ mymain(void) QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_PIIX4_USB_UHCI, QEMU_CAPS_VT82C686B_USB_UHCI, - QEMU_CAPS_PCI_OHCI); + QEMU_CAPS_PCI_OHCI, + QEMU_CAPS_USB_HUB); DO_TEST("qemu-kvm-0.12.1.2-rhel61", 12001, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -484,7 +486,8 @@ mymain(void) QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_VIRTIO_IOEVENTFD, QEMU_CAPS_PIIX3_USB_UHCI, - QEMU_CAPS_PIIX4_USB_UHCI); + QEMU_CAPS_PIIX4_USB_UHCI, + QEMU_CAPS_USB_HUB); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args new file mode 100644 index 0000000..4911dd4 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.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 usb-hub,id=hub0,bus=usb.0,port=1 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml new file mode 100644 index 0000000..5e0b256 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml @@ -0,0 +1,19 @@ +<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'/> + <hub type='usb'> + <address type='usb' bus='0' port='1'/> + </hub> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 33588d0..a053693 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -498,6 +498,9 @@ mymain(void) 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("usb-hub", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB, + QEMU_CAPS_NODEFCONFIG); DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE); -- 1.7.6

On Fri, Sep 02, 2011 at 03:18:18AM +0200, Marc-André Lureau wrote:
--- docs/formatdomain.html.in | 27 ++++ docs/schemas/domain.rng | 13 ++ src/conf/domain_conf.c | 157 +++++++++++++++++++++- src/conf/domain_conf.h | 20 +++ src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 3 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 56 ++++++++- src/qemu/qemu_command.h | 1 + tests/qemuhelptest.c | 9 +- tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args | 1 + tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml | 19 +++ tests/qemuxml2argvtest.c | 3 + 13 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml [...] +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.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 usb-hub,id=hub0,bus=usb.0,port=1 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4
Same small problem with bus=usb.0 instead of bus=usb0.0 but easy to fix Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

So that devices can be attached to hubs. Example, to attach to first port of a usb-hub on port 1. <hub type='usb'> <address type='usb' bus='0' port='1'/> </hub> <input type='mouse' type='usb'> <address type='usb' bus='0' port='1.1'/> </hub> --- docs/schemas/domain.rng | 11 +++++-- src/conf/domain_conf.c | 24 ++++++++++----- src/conf/domain_conf.h | 2 +- src/qemu/qemu_command.c | 2 +- tests/qemuxml2argvdata/qemuxml2argv-usb-ports.args | 1 + tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml | 31 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 3 ++ 7 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ports.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 16e9687..b496a32 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -2040,7 +2040,7 @@ <ref name="usbAddr"/> </attribute> <attribute name="device"> - <ref name="usbAddr"/> + <ref name="usbPort"/> </attribute> </element> </define> @@ -2049,7 +2049,7 @@ <ref name="usbAddr"/> </attribute> <attribute name="port"> - <ref name="usbAddr"/> + <ref name="usbPort"/> </attribute> </define> <define name="pciaddress"> @@ -2397,7 +2397,7 @@ <define name="usbmaster"> <element name="master"> <attribute name="startport"> - <ref name="usbAddr"/> + <ref name="usbPort"/> </attribute> <empty/> </element> @@ -2548,6 +2548,11 @@ <param name="pattern">(0x)?[0-9a-fA-F]{1,3}</param> </data> </define> + <define name="usbPort"> + <data type="string"> + <param name="pattern">((0x)?[0-9a-fA-F]{1,3}\.){0,3}(0x)?[0-9a-fA-F]{1,3}</param> + </data> + </define> <define name="pciDomain"> <data type="string"> <param name="pattern">(0x)?[0-9a-fA-F]{1,4}</param> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index af08a03..4fe92d7 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1443,12 +1443,9 @@ int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr ATTRI return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */ } -int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr) +int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr ATTRIBUTE_UNUSED) { - if (addr->port >= 128) /* FIXME: is this correct */ - return 0; - - return 1; + return 1; /* FIXME.. any successfully parsed addr is valid */ } int virDomainDeviceVirtioSerialAddressIsValid( @@ -1472,6 +1469,10 @@ virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info, unsigned int flags) void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info) { VIR_FREE(info->alias); + if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { + VIR_FREE(info->addr.usb.port); + } + VIR_FREE(info->alias); memset(&info->addr, 0, sizeof(info->addr)); info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE; } @@ -1620,7 +1621,7 @@ virDomainDeviceInfoFormat(virBufferPtr buf, break; case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB: - virBufferAsprintf(buf, " bus='%d' port='%d'", + virBufferAsprintf(buf, " bus='%d' port='%s'", info->addr.usb.bus, info->addr.usb.port); break; @@ -1836,7 +1837,8 @@ static int virDomainDeviceUSBAddressParseXML(xmlNodePtr node, virDomainDeviceUSBAddressPtr addr) { - char *port, *bus; + char *port, *bus, *tmp; + unsigned int p; int ret = -1; memset(addr, 0, sizeof(*addr)); @@ -1845,12 +1847,18 @@ virDomainDeviceUSBAddressParseXML(xmlNodePtr node, bus = virXMLPropString(node, "bus"); if (port && - virStrToLong_ui(port, NULL, 10, &addr->port) < 0) { + ((virStrToLong_ui(port, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.')) || + (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.'))) || + (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.'))) || + (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0'))))) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot parse <address> 'port' attribute")); goto cleanup; } + addr->port = port; + port = NULL; + if (bus && virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 569e840..48bfd0f 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -110,7 +110,7 @@ typedef struct _virDomainDeviceUSBAddress virDomainDeviceUSBAddress; typedef virDomainDeviceUSBAddress *virDomainDeviceUSBAddressPtr; struct _virDomainDeviceUSBAddress { unsigned int bus; - unsigned int port; + char *port; }; enum virDomainControllerMaster { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6962862..2b8f548 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1326,7 +1326,7 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot); } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { virBufferAsprintf(buf, ",bus=usb%d.0", info->addr.usb.bus); - virBufferAsprintf(buf, ",port=%d", info->addr.usb.port); + virBufferAsprintf(buf, ",port=%s", info->addr.usb.port); } return 0; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-ports.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-ports.args new file mode 100644 index 0000000..556eb4c --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ports.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 usb-hub,id=hub0,bus=usb.0,port=1 -device usb-hub,id=hub1,bus=usb.0,port=1.2 -device usb-mouse,id=input0,bus=usb.0,port=1.1 -device usb-mouse,id=input1,bus=usb.0,port=1.2.1 -device usb-mouse,id=input2,bus=usb.0,port=1.2.2 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml new file mode 100644 index 0000000..e31e5bc --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml @@ -0,0 +1,31 @@ +<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'/> + <hub type='usb'> + <address type='usb' bus='0' port='1'/> + </hub> + <input type='mouse' bus='usb'> + <address type='usb' bus='0' port='1.1'/> + </input> + <hub type='usb'> + <address type='usb' bus='0' port='1.2'/> + </hub> + <input type='mouse' bus='usb'> + <address type='usb' bus='0' port='1.2.1'/> + </input> + <input type='mouse' bus='usb'> + <address type='usb' bus='0' port='1.2.2'/> + </input> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a053693..4c6c486 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -501,6 +501,9 @@ mymain(void) DO_TEST("usb-hub", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB, QEMU_CAPS_NODEFCONFIG); + DO_TEST("usb-ports", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB, + QEMU_CAPS_NODEFCONFIG); DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE); -- 1.7.6

Changes sinces v1: - apply only to piix3 - check if piix3 controller is on correct address, or report error --- src/qemu/qemu_command.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2b8f548..3b1b4e5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1089,6 +1089,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) { int i; bool reservedIDE = false; + bool reservedUSB = false; bool reservedVGA = false; /* Host bridge */ @@ -1119,13 +1120,20 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) def->controllers[i]->info.addr.pci.slot = 1; def->controllers[i]->info.addr.pci.function = 1; } + } else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + def->controllers[i]->idx == 0 && + def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI && + def->controllers[i]->info.addr.pci.domain == 0 && + def->controllers[i]->info.addr.pci.bus == 0 && + def->controllers[i]->info.addr.pci.slot == 1) { + reservedUSB = true; } } /* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller) * hardcoded slot=1, multifunction device */ - if (!reservedIDE && + if (!reservedIDE && !reservedUSB && qemuDomainPCIAddressReserveSlot(addrs, 1) < 0) goto error; -- 1.7.6

At 09/02/2011 09:18 AM, Marc-André Lureau Write:
Changes sinces v1: - apply only to piix3 - check if piix3 controller is on correct address, or report error
I add usb controller: <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x3'/> </controller> The address 0x01.0x3 is used by piix3-usb-uhci. Your patch does not detect this error
--- src/qemu/qemu_command.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2b8f548..3b1b4e5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1089,6 +1089,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) { int i; bool reservedIDE = false; + bool reservedUSB = false; bool reservedVGA = false;
/* Host bridge */ @@ -1119,13 +1120,20 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) def->controllers[i]->info.addr.pci.slot = 1; def->controllers[i]->info.addr.pci.function = 1; } + } else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + def->controllers[i]->idx == 0 && + def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI && + def->controllers[i]->info.addr.pci.domain == 0 && + def->controllers[i]->info.addr.pci.bus == 0 && + def->controllers[i]->info.addr.pci.slot == 1) { + reservedUSB = true;
You must check the function. The slot 1 is reserved by qemu, we should only allow the user to use function 1 for usb controller. Thanks Wen Congyang
} }
/* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller) * hardcoded slot=1, multifunction device */ - if (!reservedIDE && + if (!reservedIDE && !reservedUSB && qemuDomainPCIAddressReserveSlot(addrs, 1) < 0) goto error;

Hi ----- Original Message -----
At 09/02/2011 09:18 AM, Marc-André Lureau Write:
Changes sinces v1: - apply only to piix3 - check if piix3 controller is on correct address, or report error
I add usb controller: <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x3'/> </controller> The address 0x01.0x3 is used by piix3-usb-uhci. Your patch does not detect this error
I see, we need to handle default mode too. - def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI) { + (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI || + def->controllers[i]->model == -1)) { Would that solve the problem?
--- src/qemu/qemu_command.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2b8f548..3b1b4e5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1089,6 +1089,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) { int i; bool reservedIDE = false; + bool reservedUSB = false; bool reservedVGA = false;
/* Host bridge */ @@ -1119,13 +1120,20 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) def->controllers[i]->info.addr.pci.slot = 1; def->controllers[i]->info.addr.pci.function = 1; } + } else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + def->controllers[i]->idx == 0 && + def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI && + def->controllers[i]->info.addr.pci.domain == 0 && + def->controllers[i]->info.addr.pci.bus == 0 && + def->controllers[i]->info.addr.pci.slot == 1) { + reservedUSB = true;
You must check the function. The slot 1 is reserved by qemu, we should only allow the user to use function 1 for usb controller.
Do you mean function 2? The v2/v3 check is: if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { if (def->controllers[i]->info.addr.pci.domain != 0 || def->controllers[i]->info.addr.pci.bus != 0 || def->controllers[i]->info.addr.pci.slot != 1 || def->controllers[i]->info.addr.pci.function != 2) { qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("PIIX3 USB controller must have PCI address 0:0:1.2")); goto error; Is that correct? thanks, -- Marc-André Lureau

On Fri, Sep 02, 2011 at 03:18:20AM +0200, Marc-André Lureau wrote:
Changes sinces v1: - apply only to piix3 - check if piix3 controller is on correct address, or report error --- src/qemu/qemu_command.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2b8f548..3b1b4e5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1089,6 +1089,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) { int i; bool reservedIDE = false; + bool reservedUSB = false; bool reservedVGA = false;
/* Host bridge */ @@ -1119,13 +1120,20 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) def->controllers[i]->info.addr.pci.slot = 1; def->controllers[i]->info.addr.pci.function = 1; } + } else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + def->controllers[i]->idx == 0 && + def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI && + def->controllers[i]->info.addr.pci.domain == 0 && + def->controllers[i]->info.addr.pci.bus == 0 && + def->controllers[i]->info.addr.pci.slot == 1) { + reservedUSB = true; } }
/* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller) * hardcoded slot=1, multifunction device */ - if (!reservedIDE && + if (!reservedIDE && !reservedUSB && qemuDomainPCIAddressReserveSlot(addrs, 1) < 0) goto error;
I had to change this a bit since the context for the patch was modfified, it's now for (function = 0; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) { if (function == 1 && (reservedIDE || reservedUSB)) /* we have reserved this pci address */ continue; if (qemuDomainPCIAddressReserveFunction(addrs, 1, function) < 0) goto error; } please double check :-) I will let you address Wen comments separately ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

QEMU uses USB bus name "usb.0" when using the legacy -usb argument. If we want to allow USB devices to specify their addresses with legacy -usb, we should either in case of legacy bus name drop the 0 from the address bus, or just drop the 0 from device id. This patch does the later. Another solution would be to permit addressing on non-legacy USB controllers only. --- src/qemu/qemu_command.c | 46 +++++++++++++++----- .../qemuxml2argv-input-usbmouse-addr.args | 2 +- .../qemuxml2argv-usb-ich9-companion.args | 8 ++-- .../qemuxml2argv-usb-ich9-ehci-addr.args | 2 +- .../qemuxml2argv-usb-piix3-controller.args | 2 +- tests/qemuxml2argvtest.c | 2 +- 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3b1b4e5..eaab981 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1096,7 +1096,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) if (qemuDomainPCIAddressReserveSlot(addrs, 0) < 0) goto error; - /* Verify that first IDE controller (if any) is on the PIIX3, fn 1 */ + /* Verify that first IDE and USB controllers (if any) is on the PIIX3, fn 1 */ for (i = 0; i < def->ncontrollers ; i++) { /* First IDE controller lives on the PIIX3 at slot=1, function=1 */ if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && @@ -1122,11 +1122,24 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) } } else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && def->controllers[i]->idx == 0 && - def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI && - def->controllers[i]->info.addr.pci.domain == 0 && - def->controllers[i]->info.addr.pci.bus == 0 && - def->controllers[i]->info.addr.pci.slot == 1) { - reservedUSB = true; + def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI) { + if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { + if (def->controllers[i]->info.addr.pci.domain != 0 || + def->controllers[i]->info.addr.pci.bus != 0 || + def->controllers[i]->info.addr.pci.slot != 1 || + def->controllers[i]->info.addr.pci.function != 2) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("PIIX3 USB controller must have PCI address 0:0:1.2")); + goto error; + } + reservedUSB = true; + } else { + def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + def->controllers[i]->info.addr.pci.domain = 0; + def->controllers[i]->info.addr.pci.bus = 0; + def->controllers[i]->info.addr.pci.slot = 1; + def->controllers[i]->info.addr.pci.function = 2; + } } } @@ -1284,6 +1297,14 @@ error: return -1; } +static void +qemuUsbId(virBufferPtr buf, int idx) +{ + if (idx == 0) + virBufferAsprintf(buf, "usb"); + else + virBufferAsprintf(buf, "usb%d", idx); +} static int qemuBuildDeviceAddressStr(virBufferPtr buf, @@ -1333,8 +1354,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, else virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot); } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { - virBufferAsprintf(buf, ",bus=usb%d.0", info->addr.usb.bus); - virBufferAsprintf(buf, ",port=%s", info->addr.usb.port); + virBufferAsprintf(buf, ",bus="); + qemuUsbId(buf, info->addr.usb.bus); + virBufferAsprintf(buf, ".0,port=%s", info->addr.usb.port); } return 0; @@ -1766,10 +1788,12 @@ qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def, 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); + virBufferAsprintf(buf, ",masterbus="); + qemuUsbId(buf, def->idx); + virBufferAsprintf(buf, ".0,firstport=%d", def->info.master.usb.startport); } else { - virBufferAsprintf(buf, ",id=usb%d", def->idx); + virBufferAsprintf(buf, ",id="); + qemuUsbId(buf, def->idx); } return 0; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args index d784960..b6dc0d3 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=usb0.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=usb.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 index b37dbf6..1007544 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args @@ -1,6 +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 ich9-usb-ehci1,id=usb,bus=pci.0,multifunction=on,addr=0x4.0x7 \ +-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0 \ +-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1 \ +-device ich9-usb-uhci3,masterbus=usb.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-ehci-addr.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args index 502244d..0059ab5 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-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 -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 virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 +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=usb,bus=pci.0,multifunction=on,addr=0x4.0x7 -device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.args index 799b75f..06863bb 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.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 -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 +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=usb,bus=pci.0,multifunction=on,addr=0x1.0x2 -device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 4c6c486..a8e7259 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -489,7 +489,7 @@ mymain(void) QEMU_CAPS_NODEFCONFIG); DO_TEST("usb-piix3-controller", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_PIIX3_USB_UHCI, - QEMU_CAPS_NODEFCONFIG); + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_NODEFCONFIG); DO_TEST("usb-ich9-ehci-addr", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1); -- 1.7.6

On Fri, Sep 02, 2011 at 03:18:21AM +0200, Marc-André Lureau wrote:
QEMU uses USB bus name "usb.0" when using the legacy -usb argument. If we want to allow USB devices to specify their addresses with legacy -usb, we should either in case of legacy bus name drop the 0 from the address bus, or just drop the 0 from device id. This patch does the later.
Another solution would be to permit addressing on non-legacy USB controllers only. --- src/qemu/qemu_command.c | 46 +++++++++++++++----- .../qemuxml2argv-input-usbmouse-addr.args | 2 +- .../qemuxml2argv-usb-ich9-companion.args | 8 ++-- .../qemuxml2argv-usb-ich9-ehci-addr.args | 2 +- .../qemuxml2argv-usb-piix3-controller.args | 2 +- tests/qemuxml2argvtest.c | 2 +- 6 files changed, 43 insertions(+), 19 deletions(-)
Of course I had to fix in the other way the 2 files qemuxml2argvdata/qemuxml2argv-usb-hub.args and qemuxml2argvdata/qemuxml2argv-usb-ports.args I had modified previous to pass make check, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

--- tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args | 15 ++++ tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml | 74 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 4 + 3 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args new file mode 100644 index 0000000..be4a78e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args @@ -0,0 +1,15 @@ +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=usb,bus=pci.0,multifunction=on,addr=0x1.0x2 \ +-device ich9-usb-ehci1,id=usb1,bus=pci.0,multifunction=on,addr=0x4.0x7 \ +-device ich9-usb-uhci1,masterbus=usb1.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0 \ +-device ich9-usb-uhci2,masterbus=usb1.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1 \ +-device ich9-usb-uhci3,masterbus=usb1.0,firstport=4,bus=pci.0,multifunction=on,addr=0x4.0x2 \ +-device ich9-usb-ehci1,id=usb2,bus=pci.0,multifunction=on,addr=0x5.0x7 \ +-device ich9-usb-uhci1,masterbus=usb2.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5.0x0 \ +-device ich9-usb-uhci2,masterbus=usb2.0,firstport=2,bus=pci.0,multifunction=on,addr=0x5.0x1 \ +-device ich9-usb-uhci3,masterbus=usb2.0,firstport=4,bus=pci.0,multifunction=on,addr=0x5.0x2 \ +-device usb-hub,id=hub0,bus=usb1.0,port=1 \ +-device usb-tablet,id=input0,bus=usb.0,port=2 \ +-device usb-host,hostbus=14,hostaddr=6,id=hostdev0,bus=usb2.0,port=1 \ +-device usb-host,hostbus=14,hostaddr=7,id=hostdev1,bus=usb2.0,port=2 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml new file mode 100644 index 0000000..e8ada4d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml @@ -0,0 +1,74 @@ +<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> + <memballoon model='virtio'/> + + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0' bus='0' slot='1' function='2'/> + </controller> + + <controller type='usb' index='1' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='4' function='7'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='4' function='0'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='4' function='1'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='4' function='2'/> + </controller> + + <controller type='usb' index='2' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='5' function='7'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='5' function='0'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='5' function='1'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='5' function='2'/> + </controller> + + <input type='tablet' bus='usb'> + <address type='usb' bus='0' port='2'/> + </input> + + <hub type='usb'> + <address type='usb' bus='1' port='1'/> + </hub> + + <hostdev mode='subsystem' type='usb'> + <source> + <address bus='14' device='6'/> + </source> + <address type='usb' bus='2' port='1'/> + </hostdev> + + <hostdev mode='subsystem' type='usb'> + <source> + <address bus='14' device='7'/> + </source> + <address type='usb' bus='2' port='2'/> + </hostdev> + + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a8e7259..9a8ecca 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -504,6 +504,10 @@ mymain(void) DO_TEST("usb-ports", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB, QEMU_CAPS_NODEFCONFIG); + DO_TEST("usb1-usb2", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_PIIX3_USB_UHCI, + QEMU_CAPS_USB_HUB, QEMU_CAPS_ICH9_USB_EHCI1); DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE); -- 1.7.6

On Fri, Sep 02, 2011 at 03:18:22AM +0200, Marc-André Lureau wrote:
--- tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args | 15 ++++ tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml | 74 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 4 + 3 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args new file mode 100644 index 0000000..be4a78e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args @@ -0,0 +1,15 @@ +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=usb,bus=pci.0,multifunction=on,addr=0x1.0x2 \ +-device ich9-usb-ehci1,id=usb1,bus=pci.0,multifunction=on,addr=0x4.0x7 \ +-device ich9-usb-uhci1,masterbus=usb1.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0 \ +-device ich9-usb-uhci2,masterbus=usb1.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1 \ +-device ich9-usb-uhci3,masterbus=usb1.0,firstport=4,bus=pci.0,multifunction=on,addr=0x4.0x2 \ +-device ich9-usb-ehci1,id=usb2,bus=pci.0,multifunction=on,addr=0x5.0x7 \ +-device ich9-usb-uhci1,masterbus=usb2.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5.0x0 \ +-device ich9-usb-uhci2,masterbus=usb2.0,firstport=2,bus=pci.0,multifunction=on,addr=0x5.0x1 \ +-device ich9-usb-uhci3,masterbus=usb2.0,firstport=4,bus=pci.0,multifunction=on,addr=0x5.0x2 \ +-device usb-hub,id=hub0,bus=usb1.0,port=1 \ +-device usb-tablet,id=input0,bus=usb.0,port=2 \ +-device usb-host,hostbus=14,hostaddr=6,id=hostdev0,bus=usb2.0,port=1 \ +-device usb-host,hostbus=14,hostaddr=7,id=hostdev1,bus=usb2.0,port=2 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml new file mode 100644 index 0000000..e8ada4d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml @@ -0,0 +1,74 @@ +<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> + <memballoon model='virtio'/> + + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0' bus='0' slot='1' function='2'/> + </controller> + + <controller type='usb' index='1' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='4' function='7'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='4' function='0'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='4' function='1'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='4' function='2'/> + </controller> + + <controller type='usb' index='2' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='5' function='7'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='5' function='0'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='5' function='1'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='5' function='2'/> + </controller> + + <input type='tablet' bus='usb'> + <address type='usb' bus='0' port='2'/> + </input> + + <hub type='usb'> + <address type='usb' bus='1' port='1'/> + </hub> + + <hostdev mode='subsystem' type='usb'> + <source> + <address bus='14' device='6'/> + </source> + <address type='usb' bus='2' port='1'/> + </hostdev> + + <hostdev mode='subsystem' type='usb'> + <source> + <address bus='14' device='7'/> + </source> + <address type='usb' bus='2' port='2'/> + </hostdev> + + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a8e7259..9a8ecca 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -504,6 +504,10 @@ mymain(void) DO_TEST("usb-ports", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB, QEMU_CAPS_NODEFCONFIG); + DO_TEST("usb1-usb2", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_PIIX3_USB_UHCI, + QEMU_CAPS_USB_HUB, QEMU_CAPS_ICH9_USB_EHCI1);
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);
I am skipping that patch, I get a make check error: 121) QEMU XML-2-ARGV usb1-usb2 ... libvir: QEMU error : internal error unable to reserve PCI address 0:0:1.2 FAILED since it's test only we can solve this later, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, Sep 02, 2011 at 11:02:07PM +0800, Daniel Veillard wrote:
On Fri, Sep 02, 2011 at 03:18:22AM +0200, Marc-André Lureau wrote:
--- tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args | 15 ++++ tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml | 74 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 4 + 3 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args new file mode 100644 index 0000000..be4a78e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args @@ -0,0 +1,15 @@ +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=usb,bus=pci.0,multifunction=on,addr=0x1.0x2 \ +-device ich9-usb-ehci1,id=usb1,bus=pci.0,multifunction=on,addr=0x4.0x7 \ +-device ich9-usb-uhci1,masterbus=usb1.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0 \ +-device ich9-usb-uhci2,masterbus=usb1.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1 \ +-device ich9-usb-uhci3,masterbus=usb1.0,firstport=4,bus=pci.0,multifunction=on,addr=0x4.0x2 \ +-device ich9-usb-ehci1,id=usb2,bus=pci.0,multifunction=on,addr=0x5.0x7 \ +-device ich9-usb-uhci1,masterbus=usb2.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5.0x0 \ +-device ich9-usb-uhci2,masterbus=usb2.0,firstport=2,bus=pci.0,multifunction=on,addr=0x5.0x1 \ +-device ich9-usb-uhci3,masterbus=usb2.0,firstport=4,bus=pci.0,multifunction=on,addr=0x5.0x2 \ +-device usb-hub,id=hub0,bus=usb1.0,port=1 \ +-device usb-tablet,id=input0,bus=usb.0,port=2 \ +-device usb-host,hostbus=14,hostaddr=6,id=hostdev0,bus=usb2.0,port=1 \ +-device usb-host,hostbus=14,hostaddr=7,id=hostdev1,bus=usb2.0,port=2 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml new file mode 100644 index 0000000..e8ada4d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml @@ -0,0 +1,74 @@ +<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> + <memballoon model='virtio'/> + + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0' bus='0' slot='1' function='2'/> + </controller> + + <controller type='usb' index='1' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='4' function='7'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='4' function='0'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='4' function='1'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='4' function='2'/> + </controller> + + <controller type='usb' index='2' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='5' function='7'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='5' function='0'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='5' function='1'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='5' function='2'/> + </controller> + + <input type='tablet' bus='usb'> + <address type='usb' bus='0' port='2'/> + </input> + + <hub type='usb'> + <address type='usb' bus='1' port='1'/> + </hub> + + <hostdev mode='subsystem' type='usb'> + <source> + <address bus='14' device='6'/> + </source> + <address type='usb' bus='2' port='1'/> + </hostdev> + + <hostdev mode='subsystem' type='usb'> + <source> + <address bus='14' device='7'/> + </source> + <address type='usb' bus='2' port='2'/> + </hostdev> + + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a8e7259..9a8ecca 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -504,6 +504,10 @@ mymain(void) DO_TEST("usb-ports", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB, QEMU_CAPS_NODEFCONFIG); + DO_TEST("usb1-usb2", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_PIIX3_USB_UHCI, + QEMU_CAPS_USB_HUB, QEMU_CAPS_ICH9_USB_EHCI1);
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);
I am skipping that patch, I get a make check error:
121) QEMU XML-2-ARGV usb1-usb2 ... libvir: QEMU error : internal error unable to reserve PCI address 0:0:1.2 FAILED
since it's test only we can solve this later,
Be very wary of postponing this. Historically this kind of failure is a indication that the QEMU driver will also likely break when attempting to start guests, or restore guests from save image. This should be investigated & checked before release Daniel

On Fri, Sep 02, 2011 at 04:09:35PM +0100, Daniel P. Berrange wrote:
On Fri, Sep 02, 2011 at 11:02:07PM +0800, Daniel Veillard wrote:
On Fri, Sep 02, 2011 at 03:18:22AM +0200, Marc-André Lureau wrote:
--- tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args | 15 ++++ tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml | 74 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 4 + 3 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args new file mode 100644 index 0000000..be4a78e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args @@ -0,0 +1,15 @@ +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=usb,bus=pci.0,multifunction=on,addr=0x1.0x2 \ +-device ich9-usb-ehci1,id=usb1,bus=pci.0,multifunction=on,addr=0x4.0x7 \ +-device ich9-usb-uhci1,masterbus=usb1.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0 \ +-device ich9-usb-uhci2,masterbus=usb1.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1 \ +-device ich9-usb-uhci3,masterbus=usb1.0,firstport=4,bus=pci.0,multifunction=on,addr=0x4.0x2 \ +-device ich9-usb-ehci1,id=usb2,bus=pci.0,multifunction=on,addr=0x5.0x7 \ +-device ich9-usb-uhci1,masterbus=usb2.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5.0x0 \ +-device ich9-usb-uhci2,masterbus=usb2.0,firstport=2,bus=pci.0,multifunction=on,addr=0x5.0x1 \ +-device ich9-usb-uhci3,masterbus=usb2.0,firstport=4,bus=pci.0,multifunction=on,addr=0x5.0x2 \ +-device usb-hub,id=hub0,bus=usb1.0,port=1 \ +-device usb-tablet,id=input0,bus=usb.0,port=2 \ +-device usb-host,hostbus=14,hostaddr=6,id=hostdev0,bus=usb2.0,port=1 \ +-device usb-host,hostbus=14,hostaddr=7,id=hostdev1,bus=usb2.0,port=2 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml new file mode 100644 index 0000000..e8ada4d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml @@ -0,0 +1,74 @@ +<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> + <memballoon model='virtio'/> + + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0' bus='0' slot='1' function='2'/> + </controller> + + <controller type='usb' index='1' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='4' function='7'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='4' function='0'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='4' function='1'/> + </controller> + <controller type='usb' index='1' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='4' function='2'/> + </controller> + + <controller type='usb' index='2' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='5' function='7'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='5' function='0'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='5' function='1'/> + </controller> + <controller type='usb' index='2' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='5' function='2'/> + </controller> + + <input type='tablet' bus='usb'> + <address type='usb' bus='0' port='2'/> + </input> + + <hub type='usb'> + <address type='usb' bus='1' port='1'/> + </hub> + + <hostdev mode='subsystem' type='usb'> + <source> + <address bus='14' device='6'/> + </source> + <address type='usb' bus='2' port='1'/> + </hostdev> + + <hostdev mode='subsystem' type='usb'> + <source> + <address bus='14' device='7'/> + </source> + <address type='usb' bus='2' port='2'/> + </hostdev> + + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a8e7259..9a8ecca 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -504,6 +504,10 @@ mymain(void) DO_TEST("usb-ports", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB, QEMU_CAPS_NODEFCONFIG); + DO_TEST("usb1-usb2", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_PIIX3_USB_UHCI, + QEMU_CAPS_USB_HUB, QEMU_CAPS_ICH9_USB_EHCI1);
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);
I am skipping that patch, I get a make check error:
121) QEMU XML-2-ARGV usb1-usb2 ... libvir: QEMU error : internal error unable to reserve PCI address 0:0:1.2 FAILED
since it's test only we can solve this later,
Be very wary of postponing this. Historically this kind of failure is a indication that the QEMU driver will also likely break when attempting to start guests, or restore guests from save image. This should be investigated & checked before release
Well there was an earlier conflict during a rebase just in that area and I think Wen was looking at this too. Anyway we have updated patches now that I will review and push probably over the w.e. thanks, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Fixed since v1: - avoid setup/restore security contexts - some hotplug code improvements, although the lack of dynamic chardev limits the utility of this code for now Fixed since v2: - create a new "redirdev" element instead of extending "hostdev" --- docs/formatdomain.html.in | 39 ++++++ docs/schemas/domain.rng | 44 +++++-- src/conf/domain_audit.c | 65 ++++++++++ src/conf/domain_audit.h | 5 + src/conf/domain_conf.c | 127 +++++++++++++++++++- src/conf/domain_conf.h | 24 ++++ src/libvirt_private.syms | 3 + src/qemu/qemu_command.c | 96 +++++++++++++++ src/qemu/qemu_command.h | 4 +- src/qemu/qemu_driver.c | 7 + src/qemu/qemu_hotplug.c | 43 +++++++ src/qemu/qemu_hotplug.h | 3 + tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args | 8 ++ tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml | 38 ++++++ tests/qemuxml2argvtest.c | 4 + tests/qemuxml2xmltest.c | 2 + 16 files changed, 494 insertions(+), 18 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index e35b76b..e1fd6ed 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1385,6 +1385,45 @@ not used by qemu.</dd> </dl> + <h4><a name="elementsRedir">Redirected devices</a></h4> + + <p> + USB device redirection through a character device is + supported <span class="since">since after 0.9.5 (KVM + only)</span>: + </p> + +<pre> + ... + <devices> + <redirdev bus='usb' type='tcp'> + <source mode='connect' host='localhost' service='4000'/> + </redirdev> + </devices> + ...</pre> + + <dl> + <dt><code>redirdev</code></dt> + <dd>The <code>redirdev</code> element is the main container for + describing redirected devices. <code>bus</code> must be "usb" + for a USB device. + + An additional attribute <code>type</code> is required, + matching one of the + supported <a href="#elementsConsole">serial device</a> types, + to describe the host side of the + tunnel; <code>type='tcp'</code> + or <code>type='spicevmc'</code> (which uses the usbredir + channel of a <a href="#elementsGraphics">SPICE graphics + device</a>) are typical. Further sub-elements, such + as <code><source></code>, may be required according to + the given type, although a <code><target></code> + sub-element is not required (since the consumer of the + character device is the hypervisor itself, rather than a + device visible in the guest).</dd> + + </dl> + <h4><a name="elementsSmartcard">Smartcard devices</a></h4> <p> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index b496a32..b89108c 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -1723,21 +1723,25 @@ </element> </define> + <define name="qemucdevSrcTypeChoice"> + <choice> + <value>dev</value> + <value>file</value> + <value>pipe</value> + <value>unix</value> + <value>tcp</value> + <value>udp</value> + <value>null</value> + <value>stdio</value> + <value>vc</value> + <value>pty</value> + <value>spicevmc</value> + </choice> + </define> + <define name="qemucdevSrcType"> <attribute name="type"> - <choice> - <value>dev</value> - <value>file</value> - <value>pipe</value> - <value>unix</value> - <value>tcp</value> - <value>udp</value> - <value>null</value> - <value>stdio</value> - <value>vc</value> - <value>pty</value> - <value>spicevmc</value> - </choice> + <ref name="qemucdevSrcTypeChoice"/> </attribute> </define> <define name="qemucdevSrcDef"> @@ -1974,6 +1978,19 @@ </optional> </element> </define> + <define name="redirdev"> + <element name="redirdev"> + <attribute name="bus"> + <choice> + <value>usb</value> + </choice> + </attribute> + <attribute name="type"> + <ref name="qemucdevSrcTypeChoice"/> + </attribute> + <ref name="qemucdevSrcDef"/> + </element> + </define> <define name="hostdev"> <element name="hostdev"> <optional> @@ -2138,6 +2155,7 @@ <ref name="channel"/> <ref name="smartcard"/> <ref name="hub"/> + <ref name="redirdev"/> </choice> </zeroOrMore> <optional> diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index 9d89c94..ef0f47a 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -309,6 +309,66 @@ cleanup: /** + * virDomainAuditRedirdev: + * @vm: domain making a change in pass-through host device + * @redirdev: device being attached or removed + * @reason: one of "start", "attach", or "detach" + * @success: true if the device passthrough operation succeeded + * + * Log an audit message about an attempted device passthrough change. + */ +void +virDomainAuditRedirdev(virDomainObjPtr vm, virDomainRedirdevDefPtr redirdev, + const char *reason, bool success) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + char *vmname; + char *address; + char *device; + const char *virt; + + virUUIDFormat(vm->def->uuid, uuidstr); + if (!(vmname = virAuditEncode("vm", vm->def->name))) { + VIR_WARN("OOM while encoding audit message"); + return; + } + + if (!(virt = virDomainVirtTypeToString(vm->def->virtType))) { + VIR_WARN("Unexpected virt type %d while encoding audit message", vm->def->virtType); + virt = "?"; + } + + switch (redirdev->bus) { + case VIR_DOMAIN_REDIRDEV_BUS_USB: + if (virAsprintf(&address, "USB redirdev") < 0) { + VIR_WARN("OOM while encoding audit message"); + goto cleanup; + } + default: + VIR_WARN("Unexpected redirdev bus while encoding audit message: %d", + redirdev->bus); + goto cleanup; + } + + if (!(device = virAuditEncode("device", VIR_AUDIT_STR(address)))) { + VIR_WARN("OOM while encoding audit message"); + goto cleanup; + } + + VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success, + "virt=%s resrc=dev reason=%s %s uuid=%s bus=%s %s", + virt, reason, vmname, uuidstr, + virDomainRedirdevBusTypeToString(redirdev->bus), + device); + +cleanup: + VIR_FREE(vmname); + VIR_FREE(device); + VIR_FREE(address); +} + + +/** * virDomainAuditCgroup: * @vm: domain making the cgroups ACL change * @cgroup: cgroup that manages the devices @@ -538,6 +598,11 @@ virDomainAuditStart(virDomainObjPtr vm, const char *reason, bool success) virDomainAuditHostdev(vm, hostdev, "start", true); } + for (i = 0 ; i < vm->def->nredirdevs ; i++) { + virDomainRedirdevDefPtr redirdev = vm->def->redirdevs[i]; + virDomainAuditRedirdev(vm, redirdev, "start", true); + } + virDomainAuditMemory(vm, 0, vm->def->mem.cur_balloon, "start", true); virDomainAuditVcpu(vm, 0, vm->def->vcpus, "start", true); diff --git a/src/conf/domain_audit.h b/src/conf/domain_audit.h index 0e88fd3..9ea9d6d 100644 --- a/src/conf/domain_audit.h +++ b/src/conf/domain_audit.h @@ -101,5 +101,10 @@ void virDomainAuditVcpu(virDomainObjPtr vm, void virDomainAuditSecurityLabel(virDomainObjPtr vm, bool success) ATTRIBUTE_NONNULL(1); +void virDomainAuditRedirdev(virDomainObjPtr vm, + virDomainRedirdevDefPtr def, + const char *reason, + bool success) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); #endif /* __VIR_DOMAIN_AUDIT_H__ */ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4fe92d7..08d957a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -127,7 +127,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, "watchdog", "controller", "graphics", - "hub") + "hub", + "redirdev") VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "none", @@ -440,6 +441,9 @@ VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1, VIR_ENUM_IMPL(virDomainHub, VIR_DOMAIN_HUB_TYPE_LAST, "usb") +VIR_ENUM_IMPL(virDomainRedirdevBus, VIR_DOMAIN_REDIRDEV_BUS_LAST, + "usb") + #define VIR_DOMAIN_NOSTATE_LAST (VIR_DOMAIN_NOSTATE_UNKNOWN + 1) VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST, "unknown") @@ -1012,6 +1016,17 @@ void virDomainHubDefFree(virDomainHubDefPtr def) VIR_FREE(def); } +void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def) +{ + if (!def) + return; + + virDomainChrSourceDefClear(&def->source.chr); + virDomainDeviceInfoClear(&def->info); + + VIR_FREE(def); +} + void virDomainDeviceDefFree(virDomainDeviceDefPtr def) { if (!def) @@ -1051,6 +1066,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_HUB: virDomainHubDefFree(def->data.hub); break; + case VIR_DOMAIN_DEVICE_REDIRDEV: + virDomainRedirdevDefFree(def->data.redirdev); + break; } VIR_FREE(def); @@ -5343,7 +5361,6 @@ virDomainHostdevDefParseXML(const xmlNodePtr node, virBitmapPtr bootMap, unsigned int flags) { - xmlNodePtr cur; virDomainHostdevDefPtr def; char *mode, *type = NULL, *managed = NULL; @@ -5390,8 +5407,8 @@ virDomainHostdevDefParseXML(const xmlNodePtr node, if (xmlStrEqual(cur->name, BAD_CAST "source")) { if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { - if (virDomainHostdevSubsysUsbDefParseXML(cur, def) < 0) - goto error; + if (virDomainHostdevSubsysUsbDefParseXML(cur, def) < 0) + goto error; } if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { @@ -5444,6 +5461,68 @@ error: } +static virDomainRedirdevDefPtr +virDomainRedirdevDefParseXML(const xmlNodePtr node, + unsigned int flags) +{ + xmlNodePtr cur; + virDomainRedirdevDefPtr def; + char *bus, *type = NULL; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + bus = virXMLPropString(node, "bus"); + if (bus) { + if ((def->bus = virDomainRedirdevBusTypeFromString(bus)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown redirdev bus '%s'"), bus); + goto error; + } + } else { + def->bus = VIR_DOMAIN_REDIRDEV_BUS_USB; + } + + type = virXMLPropString(node, "type"); + if (type) { + if ((def->source.chr.type = virDomainChrTypeFromString(type)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown redirdev character device type '%s'"), type); + goto error; + } + } else { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing type in redirdev")); + goto error; + } + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if (xmlStrEqual(cur->name, BAD_CAST "source")) { + int remaining; + + remaining = virDomainChrSourceDefParseXML(&def->source.chr, cur, flags); + if (remaining != 0) + goto error; + } + } + cur = cur->next; + } + +cleanup: + VIR_FREE(bus); + VIR_FREE(type); + return def; + +error: + virDomainRedirdevDefFree(def); + def = NULL; + goto cleanup; +} + static int virDomainLifecycleParseXML(xmlXPathContextPtr ctxt, const char *xpath, int *val, @@ -5654,6 +5733,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, dev->type = VIR_DOMAIN_DEVICE_HUB; if (!(dev->data.hub = virDomainHubDefParseXML(node, flags))) goto error; + } else if (xmlStrEqual(node->name, BAD_CAST "redirdev")) { + dev->type = VIR_DOMAIN_DEVICE_REDIRDEV; + if (!(dev->data.redirdev = virDomainRedirdevDefParseXML(node, flags))) + goto error; } else { virDomainReportError(VIR_ERR_XML_ERROR, "%s", _("unknown device type")); @@ -7073,6 +7156,22 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, } VIR_FREE(nodes); + /* analysis of the redirected devices */ + if ((n = virXPathNodeSet("./devices/redirdev", ctxt, &nodes)) < 0) { + goto error; + } + if (n && VIR_ALLOC_N(def->redirdevs, n) < 0) + goto no_memory; + for (i = 0 ; i < n ; i++) { + virDomainRedirdevDefPtr redirdev = virDomainRedirdevDefParseXML(nodes[i], + flags); + if (!redirdev) + goto error; + + def->redirdevs[def->nredirdevs++] = redirdev; + } + VIR_FREE(nodes); + /* analysis of security label */ if (virSecurityLabelDefParseXML(def, ctxt, flags) == -1) goto error; @@ -10162,6 +10261,22 @@ virDomainHostdevDefFormat(virBufferPtr buf, return 0; } +static int +virDomainRedirdevDefFormat(virBufferPtr buf, + virDomainRedirdevDefPtr def, + unsigned int flags) +{ + const char *bus; + + bus = virDomainRedirdevBusTypeToString(def->bus); + + virBufferAsprintf(buf, " <redirdev bus='%s'", bus); + if (virDomainChrSourceDefFormat(buf, &def->source.chr, false, flags) < 0) + return -1; + virBufferAddLit(buf, " </redirdev>\n"); + + return 0; +} static int virDomainHubDefFormat(virBufferPtr buf, @@ -10596,6 +10711,10 @@ virDomainDefFormatInternal(virDomainDefPtr def, if (virDomainHostdevDefFormat(&buf, def->hostdevs[n], flags) < 0) goto cleanup; + for (n = 0 ; n < def->nredirdevs ; n++) + if (virDomainRedirdevDefFormat(&buf, def->redirdevs[n], flags) < 0) + goto cleanup; + for (n = 0 ; n < def->nhubs ; n++) if (virDomainHubDefFormat(&buf, def->hubs[n], flags) < 0) goto cleanup; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 48bfd0f..c79610c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -938,6 +938,23 @@ struct _virDomainHostdevDef { virDomainDeviceInfo info; /* Guest address */ }; +enum virDomainRedirdevBus { + VIR_DOMAIN_REDIRDEV_BUS_USB, + + VIR_DOMAIN_REDIRDEV_BUS_LAST +}; + +typedef struct _virDomainRedirdevDef virDomainRedirdevDef; +typedef virDomainRedirdevDef *virDomainRedirdevDefPtr; +struct _virDomainRedirdevDef { + int bus; /* enum virDomainRedirdevBus */ + + union { + virDomainChrSourceDef chr; + } source; + + virDomainDeviceInfo info; /* Guest address */ +}; enum { VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO, @@ -978,6 +995,7 @@ enum virDomainDeviceType { VIR_DOMAIN_DEVICE_CONTROLLER, VIR_DOMAIN_DEVICE_GRAPHICS, VIR_DOMAIN_DEVICE_HUB, + VIR_DOMAIN_DEVICE_REDIRDEV, VIR_DOMAIN_DEVICE_LAST, }; @@ -999,6 +1017,7 @@ struct _virDomainDeviceDef { virDomainWatchdogDefPtr watchdog; virDomainGraphicsDefPtr graphics; virDomainHubDefPtr hub; + virDomainRedirdevDefPtr redirdev; } data; }; @@ -1311,6 +1330,9 @@ struct _virDomainDef { int nhostdevs; virDomainHostdevDefPtr *hostdevs; + int nredirdevs; + virDomainRedirdevDefPtr *redirdevs; + int nsmartcards; virDomainSmartcardDefPtr *smartcards; @@ -1476,6 +1498,7 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def); void virDomainVideoDefFree(virDomainVideoDefPtr def); void virDomainHostdevDefFree(virDomainHostdevDefPtr def); void virDomainHubDefFree(virDomainHubDefPtr def); +void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def); void virDomainDeviceDefFree(virDomainDeviceDefPtr def); int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, int type); @@ -1757,6 +1780,7 @@ VIR_ENUM_DECL(virDomainVideo) VIR_ENUM_DECL(virDomainHostdevMode) VIR_ENUM_DECL(virDomainHostdevSubsys) VIR_ENUM_DECL(virDomainHub) +VIR_ENUM_DECL(virDomainRedirdevBus) VIR_ENUM_DECL(virDomainInput) VIR_ENUM_DECL(virDomainInputBus) VIR_ENUM_DECL(virDomainGraphics) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6642ba9..101f99e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -219,6 +219,7 @@ virDomainAuditHostdev; virDomainAuditMemory; virDomainAuditNet; virDomainAuditNetDevice; +virDomainAuditRedirdev; virDomainAuditSecurityLabel; virDomainAuditStart; virDomainAuditStop; @@ -375,6 +376,8 @@ virDomainObjSetState; virDomainObjTaint; virDomainObjUnlock; virDomainObjUnref; +virDomainRedirdevBusTypeFromString; +virDomainRedirdevBusTypeToString; virDomainRemoveInactive; virDomainSaveConfig; virDomainSaveStatus; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index eaab981..1ea9f20 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -605,6 +605,33 @@ qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev int +qemuAssignDeviceRedirdevAlias(virDomainDefPtr def, virDomainRedirdevDefPtr redirdev, int idx) +{ + if (idx == -1) { + int i; + idx = 0; + for (i = 0 ; i < def->nredirdevs ; i++) { + int thisidx; + if ((thisidx = qemuDomainDeviceAliasIndex(&def->redirdevs[i]->info, "redir")) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine device index for redirected device")); + return -1; + } + if (thisidx >= idx) + idx = thisidx + 1; + } + } + + if (virAsprintf(&redirdev->info.alias, "redir%d", idx) < 0) { + virReportOOMError(); + return -1; + } + + return 0; +} + + +int qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller) { const char *prefix = virDomainControllerTypeToString(controller->type); @@ -651,6 +678,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virBitmapPtr qemuCaps) if (qemuAssignDeviceHostdevAlias(def, def->hostdevs[i], i) < 0) return -1; } + for (i = 0; i < def->nredirdevs ; i++) { + if (qemuAssignDeviceRedirdevAlias(def, def->redirdevs[i], i) < 0) + return -1; + } for (i = 0; i < def->nvideos ; i++) { if (virAsprintf(&def->videos[i]->info.alias, "video%d", i) < 0) goto no_memory; @@ -2330,6 +2361,45 @@ qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev) char * +qemuBuildRedirdevDevStr(virDomainRedirdevDefPtr dev, + virBitmapPtr qemuCaps) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (dev->bus != VIR_DOMAIN_REDIRDEV_BUS_USB) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Redirection bus %s is not supported by QEMU"), + virDomainRedirdevBusTypeToString(dev->bus)); + goto error; + } + + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("USB redirection is not supported " + "by this version of QEMU")); + goto error; + } + + virBufferAsprintf(&buf, "usb-redir,chardev=char%s,id=%s", + dev->info.alias, + dev->info.alias); + + if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) + goto error; + + if (virBufferError(&buf)) { + virReportOOMError(); + goto error; + } + + return virBufferContentAndReset(&buf); + +error: + virBufferFreeAndReset(&buf); + return NULL; +} + +char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, virBitmapPtr qemuCaps) { @@ -4820,6 +4890,32 @@ qemuBuildCommandLine(virConnectPtr conn, virCommandAddArgList(cmd, "-watchdog-action", action, NULL); } + /* Add redirected devices */ + for (i = 0 ; i < def->nredirdevs ; i++) { + virDomainRedirdevDefPtr redirdev = def->redirdevs[i]; + char *devstr; + + virCommandAddArg(cmd, "-chardev"); + if (!(devstr = qemuBuildChrChardevStr(&redirdev->source.chr, + redirdev->info.alias, + qemuCaps))) { + goto error; + } + + virCommandAddArg(cmd, devstr); + VIR_FREE(devstr); + + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) + goto error; + + virCommandAddArg(cmd, "-device"); + if (!(devstr = qemuBuildRedirdevDevStr(redirdev, qemuCaps))) + goto error; + virCommandAddArg(cmd, devstr); + VIR_FREE(devstr); + } + + /* Add host passthrough hardware */ for (i = 0 ; i < def->nhostdevs ; i++) { virDomainHostdevDefPtr hostdev = def->hostdevs[i]; diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 22bc15d..00e58a2 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -120,6 +120,7 @@ char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, virBitmapPtr qemuCaps); char * qemuBuildHubDevStr(virDomainHubDefPtr dev, virBitmapPtr qemuCaps); +char * qemuBuildRedirdevDevStr(virDomainRedirdevDefPtr dev, virBitmapPtr qemuCaps); int qemuNetworkIfaceConnect(virDomainDefPtr def, @@ -189,8 +190,9 @@ int qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr ad int qemuDomainNetVLAN(virDomainNetDefPtr def); int qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx); int qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, virBitmapPtr qemuCaps); -int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr net, int idx); +int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx); int qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller); +int qemuAssignDeviceRedirdevAlias(virDomainDefPtr def, virDomainRedirdevDefPtr redirdev, int idx); int qemuParseKeywords(const char *str, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 421a98e..cbc31e6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4908,6 +4908,13 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm, dev->data.hostdev = NULL; break; + case VIR_DOMAIN_DEVICE_REDIRDEV: + ret = qemuDomainAttachRedirdevDevice(driver, vm, + dev->data.redirdev); + if (!ret) + dev->data.redirdev = NULL; + break; + default: qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%s' cannot be attached"), diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 60cd241..6ae834c 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -911,6 +911,49 @@ error: } +int qemuDomainAttachRedirdevDevice(struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainRedirdevDefPtr redirdev) +{ + int ret; + qemuDomainObjPrivatePtr priv = vm->privateData; + char *devstr = NULL; + + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { + if (qemuAssignDeviceRedirdevAlias(vm->def, redirdev, -1) < 0) + goto error; + if (!(devstr = qemuBuildRedirdevDevStr(redirdev, priv->qemuCaps))) + goto error; + } + + if (VIR_REALLOC_N(vm->def->redirdevs, vm->def->nredirdevs+1) < 0) { + virReportOOMError(); + goto error; + } + + qemuDomainObjEnterMonitorWithDriver(driver, vm); + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) + ret = qemuMonitorAddDevice(priv->mon, devstr); + else + goto error; + + qemuDomainObjExitMonitorWithDriver(driver, vm); + virDomainAuditRedirdev(vm, redirdev, "attach", ret == 0); + if (ret < 0) + goto error; + + vm->def->redirdevs[vm->def->nredirdevs++] = redirdev; + + VIR_FREE(devstr); + + return 0; + +error: + VIR_FREE(devstr); + return -1; + +} + int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev) diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 009f1f6..ea1cca0 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -53,6 +53,9 @@ int qemuDomainAttachHostPciDevice(struct qemud_driver *driver, int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev); +int qemuDomainAttachRedirdevDevice(struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainRedirdevDefPtr hostdev); int qemuDomainAttachHostDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args new file mode 100644 index 0000000..445aa5f --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args @@ -0,0 +1,8 @@ +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=usb,bus=pci.0,multifunction=on,addr=0x4.0x7 \ +-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0 \ +-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1 \ +-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,multifunction=on,addr=0x4.0x2 \ +-chardev socket,id=charredir0,host=localhost,port=4000 \ +-device usb-redir,chardev=charredir0,id=redir0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml new file mode 100644 index 0000000..d644216 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml @@ -0,0 +1,38 @@ +<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> + <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'/> + </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> + <redirdev bus='usb' type='tcp'> + <source mode='connect' host='localhost' service='4000'/> + <protocol type='raw'/> + </redirdev> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 9a8ecca..35e6d27 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -508,6 +508,10 @@ mymain(void) QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_USB_HUB, QEMU_CAPS_ICH9_USB_EHCI1); + DO_TEST("usb-redir", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_USB_HUB, + QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_USB_REDIR); DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE); diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 4e109d5..af635d9 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -189,6 +189,8 @@ mymain(void) DO_TEST("lease"); DO_TEST("event_idx"); + DO_TEST("usb-redir"); + /* These tests generate different XML */ DO_TEST_DIFFERENT("balloon-device-auto"); DO_TEST_DIFFERENT("channel-virtio-auto"); -- 1.7.6

--- src/conf/domain_conf.c | 7 ++++++- src/conf/domain_conf.h | 1 + tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args | 2 ++ tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml | 2 ++ tests/qemuxml2argvtest.c | 3 ++- 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 08d957a..9435abd 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -289,7 +289,8 @@ VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST, VIR_ENUM_IMPL(virDomainChrSpicevmc, VIR_DOMAIN_CHR_SPICEVMC_LAST, "vdagent", - "smartcard") + "smartcard", + "usbredir") VIR_ENUM_IMPL(virDomainSmartcard, VIR_DOMAIN_SMARTCARD_TYPE_LAST, "host", @@ -5512,6 +5513,10 @@ virDomainRedirdevDefParseXML(const xmlNodePtr node, cur = cur->next; } + if (def->source.chr.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) { + def->source.chr.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_USBREDIR; + } + cleanup: VIR_FREE(bus); VIR_FREE(type); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index c79610c..027ac67 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -537,6 +537,7 @@ enum virDomainChrTcpProtocol { enum virDomainChrSpicevmcName { VIR_DOMAIN_CHR_SPICEVMC_VDAGENT, VIR_DOMAIN_CHR_SPICEVMC_SMARTCARD, + VIR_DOMAIN_CHR_SPICEVMC_USBREDIR, VIR_DOMAIN_CHR_SPICEVMC_LAST, }; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args index 445aa5f..4d4f30a 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args @@ -5,4 +5,6 @@ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,multifunction=on,addr=0x4.0x2 \ -chardev socket,id=charredir0,host=localhost,port=4000 \ -device usb-redir,chardev=charredir0,id=redir0 \ +-chardev spicevmc,id=charredir1,name=usbredir \ +-device usb-redir,chardev=charredir1,id=redir1 \ -device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml index d644216..c73e569 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml @@ -33,6 +33,8 @@ <source mode='connect' host='localhost' service='4000'/> <protocol type='raw'/> </redirdev> + <redirdev bus='usb' type='spicevmc'> + </redirdev> <memballoon model='virtio'/> </devices> </domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 35e6d27..090ec7a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -511,7 +511,8 @@ mymain(void) DO_TEST("usb-redir", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_USB_HUB, - QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_USB_REDIR); + QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_USB_REDIR, + QEMU_CAPS_SPICE, QEMU_CAPS_CHARDEV_SPICEVMC); DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE); -- 1.7.6

On Fri, Sep 02, 2011 at 03:18:10AM +0200, Marc-André Lureau wrote:
Hei,
Here we go with the third version of this patch series that leads to support for various USB controllers, USB hubs, and USB redirection devices.
Major change since v2 is the creation of a new element 'redirdev' instead of reusing the existing 'hostdev'.
Marc-André Lureau (14): Add various USB devices QEMU_CAPS Split virDomainControllerModel to virDomainControllerModelSCSI Add USB controller models Add a new controller type 'usb' with optionnal 'model' USB controller can have a PCI address child element USB devices gain a new USB address child element Add USB companion controllers support Add USB hub device Modify USB port to be defined as a port path qemu: don't reserve slot 1 if a PIIX3 USB controller is defined there qemu: Don't append 0 at usb id, so that it is compatible with legacy -usb Add a usb1 & usb2 qemuxml2argv test Add "redirdev" redirection device Learn to use spicevmc as a redirection type for usb-redir
Okay, I pushed the patch set, I had to rebase a bit since it conflicted with directsync support which was pushed in the meantime. Now you just have to update patch 12, check comments from Wen and send the small updates, thanks ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (5)
-
Daniel P. Berrange
-
Daniel Veillard
-
Marc-André Lureau
-
Marc-André Lureau
-
Wen Congyang