[libvirt] [v2 00/13] various USB support improvements

Hola, This is the second version of the patch set which should address most of the comments I recieved. It should be good enough to let virt-manager & co support USB2 & usb-redirection. Some of the auto-assign of USB addresses etc.. are leftover for future improvements. It should not introduce regressions. Marc-André Lureau (13): 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 usb-redir device docs/formatdomain.html.in | 81 ++++- docs/schemas/domain.rng | 122 +++++-- src/conf/domain_conf.c | 369 +++++++++++++++++++- src/conf/domain_conf.h | 82 ++++- src/esx/esx_driver.c | 8 +- src/libvirt_private.syms | 8 +- src/qemu/qemu_capabilities.c | 28 ++ src/qemu/qemu_capabilities.h | 9 + src/qemu/qemu_cgroup.c | 3 +- src/qemu/qemu_command.c | 284 ++++++++++++++-- src/qemu/qemu_command.h | 10 +- src/qemu/qemu_hostdev.c | 2 + src/qemu/qemu_hotplug.c | 66 ++++- src/qemu/qemu_hotplug.h | 3 + src/security/security_dac.c | 6 + src/security/security_selinux.c | 6 + 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 | 8 + tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml | 33 ++ tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args | 15 + tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml | 74 ++++ tests/qemuxml2argvtest.c | 29 ++ tests/xml2vmxtest.c | 2 +- 38 files changed, 1350 insertions(+), 116 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

On Fri, Aug 26, 2011 at 01:44:17AM +0300, Marc-André Lureau wrote:
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(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- 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, Aug 26, 2011 at 01:44:18AM +0300, 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 };
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; }
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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, Aug 26, 2011 at 01:44:19AM +0300, 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/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;
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

The model by default is piix3-uchi. Example: <controller type='usb' index='0' model='ich9-ehci'/> --- 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 | 117 ++++++++++++++++++-- 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, 179 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..2f32e37 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -83,6 +83,30 @@ VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST, "", /* don't support vbox */ "qxl"); +VIR_ENUM_DECL(qemuControllerModelSCSI) + +VIR_ENUM_IMPL(qemuControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, + "", /* auto */ + "", /* buslogic don't support */ + "", /* lsilogic don't support */ + "", /* lsisas don't support */ + "", /* vmpvscsi don't support */ + ); + +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 +1708,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 +1793,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 +2969,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 +3489,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 +4213,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

On Fri, Aug 26, 2011 at 01:44:20AM +0300, Marc-André Lureau wrote:
The model by default is piix3-uchi.
Example: <controller type='usb' index='0' model='ich9-ehci'/>
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index dbfc7d9..2f32e37 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -83,6 +83,30 @@ VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST, "", /* don't support vbox */ "qxl");
+VIR_ENUM_DECL(qemuControllerModelSCSI) + +VIR_ENUM_IMPL(qemuControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, + "", /* auto */ + "", /* buslogic don't support */ + "", /* lsilogic don't support */ + "", /* lsisas don't support */ + "", /* vmpvscsi don't support */ + );
I don't see this enum used anywhere, so I think you can just leave it out entirely. ACK aside from that bit Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- .../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

On Fri, Aug 26, 2011 at 01:44:21AM +0300, Marc-André Lureau wrote:
--- .../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);
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- 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 2f32e37..91d8124 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1327,7 +1327,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; } @@ -2089,7 +2093,8 @@ error: char * -qemuBuildUSBInputDevStr(virDomainInputDefPtr dev) +qemuBuildUSBInputDevStr(virDomainInputDefPtr dev, + virBitmapPtr qemuCaps) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -2097,6 +2102,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; @@ -2285,9 +2293,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) { @@ -2296,13 +2305,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; } @@ -4223,7 +4243,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); @@ -4741,7 +4761,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, Aug 26, 2011 at 01:44:22AM +0300, 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
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 2f32e37..91d8124 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1327,7 +1327,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; }
@@ -2089,7 +2093,8 @@ error:
char * -qemuBuildUSBInputDevStr(virDomainInputDefPtr dev) +qemuBuildUSBInputDevStr(virDomainInputDefPtr dev, + virBitmapPtr qemuCaps) { virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -2097,6 +2102,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; @@ -2285,9 +2293,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) { @@ -2296,13 +2305,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; }
@@ -4223,7 +4243,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); @@ -4741,7 +4761,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);
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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 --- docs/formatdomain.html.in | 22 ++++++++++++ docs/schemas/domain.rng | 12 +++++++ src/conf/domain_conf.c | 35 ++++++++++++++++++++ src/conf/domain_conf.h | 18 ++++++++++ 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, 137 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..5ef062a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1832,6 +1832,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 +1867,7 @@ virDomainDeviceInfoParseXML(xmlNodePtr node, { xmlNodePtr cur; xmlNodePtr address = NULL; + xmlNodePtr master = NULL; xmlNodePtr alias = NULL; char *type = NULL; int ret = -1; @@ -1858,6 +1884,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 +1895,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..07d60a4 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -113,6 +113,20 @@ struct _virDomainDeviceUSBAddress { unsigned int port; }; +enum virDomainControllerMaster { + VIR_DOMAIN_CONTROLLER_MASTER_NONE, + VIR_DOMAIN_CONTROLLER_MASTER_USB, + + VIR_DOMAIN_CONTROLLER_MASTER_LAST +}; + +typedef struct _virDomainDeviceUSBMaster virDomainDeviceUSBMaster; +typedef virDomainDeviceUSBMaster *virDomainDeviceUSBMasterPtr; +struct _virDomainDeviceUSBMaster { + unsigned int bus; + unsigned int startport; +}; + typedef struct _virDomainDeviceInfo virDomainDeviceInfo; typedef virDomainDeviceInfo *virDomainDeviceInfoPtr; struct _virDomainDeviceInfo { @@ -125,6 +139,10 @@ struct _virDomainDeviceInfo { virDomainDeviceCcidAddress ccid; virDomainDeviceUSBAddress usb; } addr; + int mastertype; + union { + virDomainDeviceUSBMaster usb; + } master; }; typedef struct _virDomainLeaseDef virDomainLeaseDef; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 91d8124..835d06f 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1758,7 +1758,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

On Fri, Aug 26, 2011 at 01:44:23AM +0300, Marc-André Lureau wrote:
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 --- docs/formatdomain.html.in | 22 ++++++++++++ docs/schemas/domain.rng | 12 +++++++ src/conf/domain_conf.c | 35 ++++++++++++++++++++ src/conf/domain_conf.h | 18 ++++++++++ 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, 137 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..5ef062a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1832,6 +1832,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 +1867,7 @@ virDomainDeviceInfoParseXML(xmlNodePtr node, { xmlNodePtr cur; xmlNodePtr address = NULL; + xmlNodePtr master = NULL; xmlNodePtr alias = NULL; char *type = NULL; int ret = -1; @@ -1858,6 +1884,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 +1895,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..07d60a4 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -113,6 +113,20 @@ struct _virDomainDeviceUSBAddress { unsigned int port; };
+enum virDomainControllerMaster { + VIR_DOMAIN_CONTROLLER_MASTER_NONE, + VIR_DOMAIN_CONTROLLER_MASTER_USB, + + VIR_DOMAIN_CONTROLLER_MASTER_LAST +}; + +typedef struct _virDomainDeviceUSBMaster virDomainDeviceUSBMaster; +typedef virDomainDeviceUSBMaster *virDomainDeviceUSBMasterPtr; +struct _virDomainDeviceUSBMaster { + unsigned int bus; + unsigned int startport; +};
The 'bus' field is now unused, so can be removed here I believe. ACK aside from that Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- 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 5ef062a..bd05c2a 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", + "usb") 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; } @@ -1591,6 +1614,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); @@ -3990,6 +4019,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, @@ -5567,6 +5637,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")); @@ -6971,6 +7045,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; @@ -7881,6 +7970,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 @@ -8114,6 +8226,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; @@ -10027,6 +10150,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 | \ @@ -10432,6 +10583,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 07d60a4..f880264 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -616,6 +616,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, @@ -825,6 +832,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 { @@ -965,6 +978,7 @@ enum virDomainDeviceType { VIR_DOMAIN_DEVICE_WATCHDOG, VIR_DOMAIN_DEVICE_CONTROLLER, VIR_DOMAIN_DEVICE_GRAPHICS, + VIR_DOMAIN_DEVICE_HUB, VIR_DOMAIN_DEVICE_LAST, }; @@ -985,6 +999,7 @@ struct _virDomainDeviceDef { virDomainHostdevDefPtr hostdev; virDomainWatchdogDefPtr watchdog; virDomainGraphicsDefPtr graphics; + virDomainHubDefPtr hub; } data; }; @@ -1312,6 +1327,9 @@ struct _virDomainDef { size_t nleases; virDomainLeaseDefPtr *leases; + int nhubs; + virDomainHubDefPtr *hubs; + /* Only 1 */ virDomainChrDefPtr console; virSecurityLabelDef seclabel; @@ -1458,6 +1476,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); @@ -1738,6 +1757,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 835d06f..9b09daa 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -689,6 +689,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; @@ -1272,6 +1276,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; @@ -1767,7 +1774,6 @@ qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def, virBufferAsprintf(buf, ",id=usb%d", def->idx); } - return 0; } @@ -2336,6 +2342,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; @@ -4245,6 +4288,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, Aug 26, 2011 at 01:44:24AM +0300, 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
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 5ef062a..bd05c2a 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", + "usb")
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; }
@@ -1591,6 +1614,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); @@ -3990,6 +4019,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, @@ -5567,6 +5637,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")); @@ -6971,6 +7045,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; @@ -7881,6 +7970,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 @@ -8114,6 +8226,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; @@ -10027,6 +10150,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 | \ @@ -10432,6 +10583,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 07d60a4..f880264 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -616,6 +616,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, @@ -825,6 +832,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 { @@ -965,6 +978,7 @@ enum virDomainDeviceType { VIR_DOMAIN_DEVICE_WATCHDOG, VIR_DOMAIN_DEVICE_CONTROLLER, VIR_DOMAIN_DEVICE_GRAPHICS, + VIR_DOMAIN_DEVICE_HUB,
VIR_DOMAIN_DEVICE_LAST, }; @@ -985,6 +999,7 @@ struct _virDomainDeviceDef { virDomainHostdevDefPtr hostdev; virDomainWatchdogDefPtr watchdog; virDomainGraphicsDefPtr graphics; + virDomainHubDefPtr hub; } data; };
@@ -1312,6 +1327,9 @@ struct _virDomainDef { size_t nleases; virDomainLeaseDefPtr *leases;
+ int nhubs; + virDomainHubDefPtr *hubs; + /* Only 1 */ virDomainChrDefPtr console; virSecurityLabelDef seclabel; @@ -1458,6 +1476,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); @@ -1738,6 +1757,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 835d06f..9b09daa 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -689,6 +689,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; @@ -1272,6 +1276,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;
@@ -1767,7 +1774,6 @@ qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def, virBufferAsprintf(buf, ",id=usb%d", def->idx); }
- return 0; }
@@ -2336,6 +2342,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; @@ -4245,6 +4288,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);
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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 bd05c2a..80fe2a0 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; } @@ -1615,7 +1616,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; @@ -1831,7 +1832,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)); @@ -1840,12 +1842,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 f880264..4b48efc 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 9b09daa..aea5bcc 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1336,7 +1336,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

On Fri, Aug 26, 2011 at 01:44:25AM +0300, Marc-André Lureau wrote:
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 bd05c2a..80fe2a0 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; } @@ -1615,7 +1616,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; @@ -1831,7 +1832,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)); @@ -1840,12 +1842,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 f880264..4b48efc 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 9b09daa..aea5bcc 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1336,7 +1336,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);
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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 aea5bcc..a9dc541 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1099,6 +1099,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) { int i; bool reservedIDE = false; + bool reservedUSB = false; bool reservedVGA = false; /* Host bridge */ @@ -1129,13 +1130,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

On Fri, Aug 26, 2011 at 01:44:26AM +0300, 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 aea5bcc..a9dc541 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1099,6 +1099,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) { int i; bool reservedIDE = false; + bool reservedUSB = false; bool reservedVGA = false;
/* Host bridge */ @@ -1129,13 +1130,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;
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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 a9dc541..f50d927 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1106,7 +1106,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 && @@ -1132,11 +1132,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; + } } } @@ -1294,6 +1307,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, @@ -1343,8 +1364,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; @@ -1776,10 +1798,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, Aug 26, 2011 at 01:44:27AM +0300, 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(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index a9dc541..f50d927 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1106,7 +1106,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 && @@ -1132,11 +1132,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; + } } }
@@ -1294,6 +1307,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, @@ -1343,8 +1364,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; @@ -1776,10 +1798,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); --
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- 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, Aug 26, 2011 at 01:44:28AM +0300, 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);
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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 --- docs/formatdomain.html.in | 15 ++++- docs/schemas/domain.rng | 66 ++++++++++++-------- src/conf/domain_conf.c | 63 ++++++++++++++++--- src/conf/domain_conf.h | 2 + src/qemu/qemu_cgroup.c | 3 +- src/qemu/qemu_command.c | 36 +++++++++-- src/qemu/qemu_hostdev.c | 2 + src/qemu/qemu_hotplug.c | 54 +++++++++++++++- src/qemu/qemu_hotplug.h | 3 + src/security/security_dac.c | 6 ++ src/security/security_selinux.c | 6 ++ tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args | 8 +++ tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml | 33 ++++++++++ tests/qemuxml2argvtest.c | 4 + 14 files changed, 255 insertions(+), 46 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..0ab08de 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1314,6 +1314,12 @@ 0.4.4 for USB and 0.6.0 for PCI (KVM only)</span>: </p> + <p> + Device redirection through a character device is + supported <span class="since">since after 0.9.5 for USB (KVM + only)</span>: + </p> + <pre> ... <devices> @@ -1348,14 +1354,19 @@ "subsystem" and <code>type</code> is "usb" for a USB device and "pci" for a PCI device. When <code>managed</code> is "yes" for a PCI device, it is detached from the host before being passed on to - the guest.</dd> + the guest. Redirection through a character device is enable by + specifying the <code>redirection</code> character device + type.</dd> <dt><code>source</code></dt> <dd>The source element describes the device as seen from the host. The USB device can either be addressed by vendor / product id using the <code>vendor</code> and <code>product</code> elements or by the device's address on the hosts using the <code>address</code> element. PCI devices on the other hand can only be described by their - <code>address</code></dd> + <code>address</code> + In case of device redirection, the source element describes the + character device to redirect from. + </dd> <dt><code>vendor</code>, <code>product</code></dt> <dd>The <code>vendor</code> and <code>product</code> elements each have an <code>id</code> attribute that specifies the USB vendor and product id. diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index b496a32..9b790f6 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"> @@ -1998,21 +2002,29 @@ </choice> </attribute> </optional> + <optional> + <attribute name="redirection"> + <ref name="qemucdevSrcTypeChoice"/> + </attribute> + </optional> <group> - <element name="source"> - <choice> - <group> - <ref name="usbproduct"/> - <optional> - <ref name="usbaddress"/> - </optional> - </group> - <ref name="usbaddress"/> - <element name="address"> - <ref name="pciaddress"/> - </element> - </choice> - </element> + <choice> + <ref name="qemucdevSrcDef"/> + <element name="source"> + <choice> + <group> + <ref name="usbproduct"/> + <optional> + <ref name="usbaddress"/> + </optional> + </group> + <ref name="usbaddress"/> + <element name="address"> + <ref name="pciaddress"/> + </element> + </choice> + </element> + </choice> </group> <optional> <ref name="deviceBoot"/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 80fe2a0..31330a5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -5165,18 +5165,26 @@ error: static int virDomainHostdevSubsysUsbDefParseXML(const xmlNodePtr node, - virDomainHostdevDefPtr def) + virDomainHostdevDefPtr def, + unsigned int flags) { int ret = -1; int got_product, got_vendor; xmlNodePtr cur; + int remaining; /* Product can validly be 0, so we need some extra help to determine * if it is uninitialized*/ got_product = 0; got_vendor = 0; + if (def->redirection) { + remaining = virDomainChrSourceDefParseXML(&def->source.subsys.u.chr, node, flags); + if (remaining < 0) + goto out; + } + cur = node->children; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { @@ -5341,7 +5349,7 @@ virDomainHostdevDefParseXML(const xmlNodePtr node, xmlNodePtr cur; virDomainHostdevDefPtr def; - char *mode, *type = NULL, *managed = NULL; + char *mode, *type = NULL, *managed = NULL, *redirection = NULL; if (VIR_ALLOC(def) < 0) { virReportOOMError(); @@ -5379,14 +5387,30 @@ virDomainHostdevDefParseXML(const xmlNodePtr node, VIR_FREE(managed); } + redirection = virXMLPropString(node, "redirection"); + if (redirection != NULL) { + def->redirection = 1; + if ((def->source.subsys.u.chr.type = virDomainChrTypeFromString(redirection)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown redirection character device type '%s'"), + redirection); + goto error; + } + if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("only usb redirection is supported")); + goto error; + } + } + cur = node->children; while (cur != NULL) { if (cur->type == XML_ELEMENT_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, flags) < 0) + goto error; } if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { @@ -10105,6 +10129,7 @@ virDomainHostdevDefFormat(virBufferPtr buf, { const char *mode = virDomainHostdevModeTypeToString(def->mode); const char *type; + const char *redirection = NULL; if (!mode || def->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -10120,11 +10145,32 @@ virDomainHostdevDefFormat(virBufferPtr buf, return -1; } - virBufferAsprintf(buf, " <hostdev mode='%s' type='%s' managed='%s'>\n", + if (def->redirection) { + redirection = virDomainChrTypeToString(def->source.subsys.u.chr.type); + if (!redirection) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected redirection type %d"), + def->source.subsys.u.chr.type); + return -1; + } + } + + virBufferAsprintf(buf, " <hostdev mode='%s' type='%s' managed='%s'", mode, type, def->managed ? "yes" : "no"); - virBufferAddLit(buf, " <source>\n"); + if (redirection != NULL) { + virBufferAsprintf(buf, " redirection='%s'", redirection); + } + virBufferAddLit(buf, ">\n"); + virBufferAddLit(buf, " <source"); + if (def->redirection) { + virBufferAsprintf(buf, " mode='connect' host='%s' service='%s'/", + def->source.subsys.u.chr.data.tcp.host, + def->source.subsys.u.chr.data.tcp.service); + } + virBufferAddLit(buf, ">\n"); - if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && + redirection == NULL) { if (def->source.subsys.u.usb.vendor) { virBufferAsprintf(buf, " <vendor id='0x%.4x'/>\n", def->source.subsys.u.usb.vendor); @@ -10144,7 +10190,8 @@ virDomainHostdevDefFormat(virBufferPtr buf, def->source.subsys.u.pci.function); } - virBufferAddLit(buf, " </source>\n"); + if (!def->redirection) + virBufferAddLit(buf, " </source>\n"); if (def->bootIndex) virBufferAsprintf(buf, " <boot order='%d'/>\n", def->bootIndex); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4b48efc..ff25743 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -914,6 +914,7 @@ typedef virDomainHostdevDef *virDomainHostdevDefPtr; struct _virDomainHostdevDef { int mode; /* enum virDomainHostdevMode */ unsigned int managed : 1; + unsigned int redirection : 1; union { struct { int type; /* enum virDomainHostdevBusType */ @@ -926,6 +927,7 @@ struct _virDomainHostdevDef { unsigned product; } usb; virDomainDevicePCIAddress pci; /* host address */ + virDomainChrSourceDef chr; } u; } subsys; struct { diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 2a10bd2..ca9c86f 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -284,9 +284,10 @@ int qemuSetupCgroup(struct qemud_driver *driver, if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; + if (hostdev->redirection) + continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) continue; - if ((usb = usbGetDevice(hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device)) == NULL) goto cleanup; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index f50d927..aaaad87 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -590,12 +590,14 @@ qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx) int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx) { + const char *prefix = hostdev->redirection ? "usbredir" : "hostdev"; + if (idx == -1) { int i; idx = 0; for (i = 0 ; i < def->nhostdevs ; i++) { int thisidx; - if ((thisidx = qemuDomainDeviceAliasIndex(&def->hostdevs[i]->info, "hostdev")) < 0) { + if ((thisidx = qemuDomainDeviceAliasIndex(&def->hostdevs[i]->info, prefix)) < 0) { qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to determine device index for hostdev device")); return -1; @@ -605,7 +607,7 @@ qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev } } - if (virAsprintf(&hostdev->info.alias, "hostdev%d", idx) < 0) { + if (virAsprintf(&hostdev->info.alias, "%s%d", prefix, idx) < 0) { virReportOOMError(); return -1; } @@ -2352,10 +2354,16 @@ qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, return NULL; } - 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 (dev->redirection) { + virBufferAsprintf(&buf, "usb-redir,chardev=char%s,id=%s", + dev->info.alias, + dev->info.alias); + } else { + 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; @@ -4854,6 +4862,22 @@ qemuBuildCommandLine(virConnectPtr conn, if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + if (hostdev->redirection) { + 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; + } + virCommandAddArg(cmd, "-chardev"); + if (!(devstr = qemuBuildChrChardevStr(&hostdev->source.subsys.u.chr, + hostdev->info.alias, + qemuCaps))) { + goto error; + } + virCommandAddArg(cmd, devstr); + } + if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { virCommandAddArg(cmd, "-device"); if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, qemuCaps))) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 7f5ad51..357fc94 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -200,6 +200,8 @@ qemuPrepareHostUSBDevices(struct qemud_driver *driver ATTRIBUTE_UNUSED, continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) continue; + if (hostdev->redirection) + continue; /* Resolve a vendor/product to bus/device */ if (hostdev->source.subsys.u.usb.vendor) { diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 60cd241..42bffa8 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -911,6 +911,49 @@ error: } +int qemuDomainAttachUsbRedirDevice(struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + int ret; + qemuDomainObjPrivatePtr priv = vm->privateData; + char *devstr = NULL; + + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { + if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0) + goto error; + if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, priv->qemuCaps))) + goto error; + } + + if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+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); + virDomainAuditHostdev(vm, hostdev, "attach", ret == 0); + if (ret < 0) + goto error; + + vm->def->hostdevs[vm->def->nhostdevs++] = hostdev; + + VIR_FREE(devstr); + + return 0; + +error: + VIR_FREE(devstr); + return -1; + +} + int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev) @@ -960,6 +1003,7 @@ int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver, ret = qemuMonitorAddUSBDeviceExact(priv->mon, hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device); + qemuDomainObjExitMonitorWithDriver(driver, vm); virDomainAuditHostdev(vm, hostdev, "attach", ret == 0); if (ret < 0) @@ -990,6 +1034,7 @@ int qemuDomainAttachHostDevice(struct qemud_driver *driver, /* Resolve USB product/vendor to bus/device */ if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && + !hostdev->redirection && hostdev->source.subsys.u.usb.vendor) { usbDevice *usb = usbFindDevice(hostdev->source.subsys.u.usb.vendor, @@ -1017,9 +1062,14 @@ int qemuDomainAttachHostDevice(struct qemud_driver *driver, break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: - if (qemuDomainAttachHostUsbDevice(driver, vm, - hostdev) < 0) + if (hostdev->redirection) { + if (qemuDomainAttachUsbRedirDevice(driver, vm, + hostdev) < 0) + goto error; + } else if (qemuDomainAttachHostUsbDevice(driver, vm, + hostdev) < 0) goto error; + break; default: diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 009f1f6..85c5d31 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 qemuDomainAttachUsbRedirDevice(struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev); int qemuDomainAttachHostDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev); diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 58d57ec..3f50052 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -280,6 +280,9 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr, if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) return 0; + if (dev->redirection) + return 0; + switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus, @@ -351,6 +354,9 @@ virSecurityDACRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr, if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) return 0; + if (dev->redirection) + return 0; + switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus, diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 5e6145f..fd39e33 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -667,6 +667,9 @@ SELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) return 0; + if (dev->redirection) + return 0; + switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus, @@ -736,6 +739,9 @@ SELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) return 0; + if (dev->redirection) + return 0; + switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args new file mode 100644 index 0000000..0949585 --- /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=charusbredir0,host=localhost,port=4000 \ +-device usb-redir,chardev=charusbredir0,id=usbredir0 \ +-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..bb50b81 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml @@ -0,0 +1,33 @@ +<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> + <hostdev mode='subsystem' type='usb' redirection='tcp'> + <source mode='connect' host='localhost' service='4000'/> + </hostdev> + <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); -- 1.7.6

On Fri, Aug 26, 2011 at 01:44:29AM +0300, Marc-André Lureau wrote:
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index e35b76b..0ab08de 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1314,6 +1314,12 @@ 0.4.4 for USB and 0.6.0 for PCI (KVM only)</span>: </p>
+ <p> + Device redirection through a character device is + supported <span class="since">since after 0.9.5 for USB (KVM + only)</span>: + </p> + <pre> ... <devices> @@ -1348,14 +1354,19 @@ "subsystem" and <code>type</code> is "usb" for a USB device and "pci" for a PCI device. When <code>managed</code> is "yes" for a PCI device, it is detached from the host before being passed on to - the guest.</dd> + the guest. Redirection through a character device is enable by + specifying the <code>redirection</code> character device + type.</dd> <dt><code>source</code></dt> <dd>The source element describes the device as seen from the host. The USB device can either be addressed by vendor / product id using the <code>vendor</code> and <code>product</code> elements or by the device's address on the hosts using the <code>address</code> element. PCI devices on the other hand can only be described by their - <code>address</code></dd> + <code>address</code> + In case of device redirection, the source element describes the + character device to redirect from. + </dd> <dt><code>vendor</code>, <code>product</code></dt> <dd>The <code>vendor</code> and <code>product</code> elements each have an <code>id</code> attribute that specifies the USB vendor and product id.
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml new file mode 100644 index 0000000..bb50b81 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
[snip]
+ <hostdev mode='subsystem' type='usb' redirection='tcp'> + <source mode='connect' host='localhost' service='4000'/> + </hostdev> + <memballoon model='virtio'/> + </devices> +</domain>
I'm not convinced that this is the right way to be modelling access to remote USB devices. The <hostdev> element is used to refer to devices that are local to the virtualization host, being assigned. Existing applications using libvirt, expect the child elements in <hostdev> to vary based on the mode+type attributes. This change is making the child elements vary based on mode+type+redirection. This means that any existing application using libvirt is going to get confused when it sees one of these redirected hostdevs, because it will not be expecting this new element contents. As seen earlier in the patch, we've also had to special case all the internal libvirt code to look for the new 'redirection' attribute as well. I think we need to take one of a few possible alternative approaches 1. Introduce a new value for the 'type' parameter, eg <hostdev mode='subsystem' type='usbredir'> ... 2. Introduce an entirely new device type <redirdev type='usb'> ... </redirdev> 3. Same as 1, but s/redir/remote/ 4. Same as 2, but s/redir/remote/ I have a slight preference for 2/4 at this point, because I feel that the handling/processing of redirected USB devices has essentially zero code overlap with handling of host device assignment, both for libvirt internally and for client apps. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (2)
-
Daniel P. Berrange
-
Marc-André Lureau