From d1710d35ea9d2074b95c2a7de06fd67de955c5ec Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 8 Aug 2008 14:27:05 +0000 Subject: [PATCH] =?UTF-8?q?Extend=20parser=20and=20add=20support=20for=20U?= =?UTF-8?q?SB=20devices=20in=20QEmu/KVM=20*=20src/domain=5Fconf.c=20src/do?= =?UTF-8?q?main=5Fconf.h=20src/qemu=5Fconf.c=20=20=20src/qemu=5Fdriver.c:?= =?UTF-8?q?=20Patch=20from=20Guido=20G=C3=BCnther=20allowing=20to=20pass?= =?UTF-8?q?=20=20=20usb=20devices=20to=20qemu/kvm=20*=20docs/libvirt.rng:?= =?UTF-8?q?=20add=20the=20new=20functionality=20to=20the=20grammar=20*=20t?= =?UTF-8?q?ests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args=20?= =?UTF-8?q?=20=20tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.x?= =?UTF-8?q?ml=20=20=20tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-prod?= =?UTF-8?q?uct.args=20=20=20tests/qemuxml2argvdata/qemuxml2argv-hostdev-us?= =?UTF-8?q?b-product.xml=20=20=20tests/qemuxml2argvtest.c=20tests/qemuxml2?= =?UTF-8?q?xmltest.c:=20adding=20examples=20=20=20to=20the=20regression=20?= =?UTF-8?q?tests=20*=20libvirt.spec.in:=20fix=20the=20licence=20tag=20Dani?= =?UTF-8?q?el?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog | 14 + docs/libvirt.rng | 62 ++++ libvirt.spec.in | 2 +- src/domain_conf.c | 268 +++++++++++++++++- src/domain_conf.h | 51 ++++ src/qemu_conf.c | 29 ++ src/qemu_driver.c | 122 ++++++-- .../qemuxml2argv-hostdev-usb-address.args | 1 + .../qemuxml2argv-hostdev-usb-address.xml | 27 ++ .../qemuxml2argv-hostdev-usb-product.args | 1 + .../qemuxml2argv-hostdev-usb-product.xml | 28 ++ tests/qemuxml2argvtest.c | 3 + tests/qemuxml2xmltest.c | 3 + 13 files changed, 582 insertions(+), 29 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml diff --git a/ChangeLog b/ChangeLog index e392765a65..bed00cd7e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +Fri Aug 8 16:15:55 CEST 2008 Daniel Veillard + + * src/domain_conf.c src/domain_conf.h src/qemu_conf.c + src/qemu_driver.c: Patch from Guido Günther allowing to pass + usb devices to qemu/kvm + * docs/libvirt.rng: add the new functionality to the grammar + * tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args + tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml + tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args + tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml + tests/qemuxml2argvtest.c tests/qemuxml2xmltest.c: adding examples + to the regression tests + * libvirt.spec.in: fix the licence tag + Fri Aug 8 19:18:43 JST 2008 Atsushi SAKAI * docs/formatdomain.html docs/formatdomain.html.in diff --git a/docs/libvirt.rng b/docs/libvirt.rng index cd5d79866e..60e181f41e 100644 --- a/docs/libvirt.rng +++ b/docs/libvirt.rng @@ -848,6 +848,57 @@ + + + + + + subsystem + capabilities + + + + + usb + pci + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -868,6 +919,7 @@ + @@ -986,4 +1038,14 @@ ([0-2]?[0-9]?[0-9]\.){3}[0-2]?[0-9]?[0-9] + + + (0x)?[0-9a-fA-F]{1,4} + + + + + (0x)?[0-9a-fA-F]{1,3} + + diff --git a/libvirt.spec.in b/libvirt.spec.in index 1b572ba385..479592d096 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -29,7 +29,7 @@ Summary: Library providing a simple API virtualization Name: libvirt Version: @VERSION@ Release: 1%{?dist}%{?extra_release} -License: LGPL +License: LGPLv2+ Group: Development/Libraries Source: libvirt-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root diff --git a/src/domain_conf.c b/src/domain_conf.c index 4998a7d3bb..922cf76d4c 100644 --- a/src/domain_conf.c +++ b/src/domain_conf.c @@ -131,6 +131,13 @@ VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST, "sdl", "vnc") +VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST, + "subsystem", + "capabilities") + +VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST, + "usb", + "pci") static void virDomainReportError(virConnectPtr conn, int code, const char *fmt, ...) @@ -332,6 +339,16 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def) VIR_FREE(def); } +void virDomainHostdevDefFree(virDomainHostdevDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->target); + virDomainHostdevDefFree(def->next); + VIR_FREE(def); +} + void virDomainDeviceDefFree(virDomainDeviceDefPtr def) { if (!def) @@ -350,6 +367,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_SOUND: virDomainSoundDefFree(def->data.sound); break; + case VIR_DOMAIN_DEVICE_HOSTDEV: + virDomainHostdevDefFree(def->data.hostdev); + break; } VIR_FREE(def); @@ -369,7 +389,7 @@ void virDomainDefFree(virDomainDefPtr def) virDomainChrDefFree(def->parallels); virDomainChrDefFree(def->console); virDomainSoundDefFree(def->sounds); - + virDomainHostdevDefFree(def->hostdevs); VIR_FREE(def->os.type); VIR_FREE(def->os.arch); @@ -1400,6 +1420,180 @@ error: goto cleanup; } +static int +virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn, + const xmlNodePtr node, + virDomainHostdevDefPtr def) { + + int ret = -1; + xmlNodePtr cur; + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if (xmlStrEqual(cur->name, BAD_CAST "vendor")) { + char *vendor = virXMLPropString(cur, "id"); + + if (vendor) { + if (virStrToLong_ui(vendor, NULL, 0, + &def->source.subsys.usb.vendor) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse vendor id %s"), vendor); + VIR_FREE(vendor); + goto out; + } + VIR_FREE(vendor); + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("usb vendor needs id")); + goto out; + } + } else if (xmlStrEqual(cur->name, BAD_CAST "product")) { + char* product = virXMLPropString(cur, "id"); + + if (product) { + if (virStrToLong_ui(product, NULL, 0, + &def->source.subsys.usb.product) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse product %s"), product); + VIR_FREE(product); + goto out; + } + VIR_FREE(product); + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("usb product needs id")); + goto out; + } + } else if (xmlStrEqual(cur->name, BAD_CAST "address")) { + char *bus, *device; + + bus = virXMLPropString(cur, "bus"); + if (bus) { + if (virStrToLong_ui(bus, NULL, 0, + &def->source.subsys.usb.bus) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse bus %s"), bus); + VIR_FREE(bus); + goto out; + } + VIR_FREE(bus); + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("usb address needs bus id")); + goto out; + } + + device = virXMLPropString(cur, "device"); + if (device) { + if (virStrToLong_ui(device, NULL, 0, + &def->source.subsys.usb.device) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse device %s"), + device); + VIR_FREE(device); + goto out; + } + VIR_FREE(device); + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("usb address needs device id")); + goto out; + } + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown usb source type '%s'"), cur->name); + goto out; + } + } + cur = cur->next; + } + + if (def->source.subsys.usb.vendor == 0 && + def->source.subsys.usb.product != 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("missing vendor")); + goto out; + } + if (def->source.subsys.usb.vendor != 0 && + def->source.subsys.usb.product == 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("missing product")); + goto out; + } + + ret = 0; +out: + return ret; +} + + +static virDomainHostdevDefPtr +virDomainHostdevDefParseXML(virConnectPtr conn, + const xmlNodePtr node) { + + xmlNodePtr cur; + virDomainHostdevDefPtr def; + char *mode, *type = NULL; + + if (VIR_ALLOC(def) < 0) { + virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL); + return NULL; + } + def->target = NULL; + + mode = virXMLPropString(node, "mode"); + if (mode) { + if ((def->mode=virDomainHostdevModeTypeFromString(mode)) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown hostdev mode '%s'"), mode); + goto error; + } + } else { + def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + } + + type = virXMLPropString(node, "type"); + if (type) { + if ((def->source.subsys.type = virDomainHostdevSubsysTypeFromString(type)) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown host device type '%s'"), type); + goto error; + } + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("missing type in hostdev")); + 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(conn, cur, def) < 0) + goto error; + } + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("uknown node %s"), cur->name); + } + } + cur = cur->next; + } + +cleanup: + VIR_FREE(type); + VIR_FREE(mode); + return def; + +error: + virDomainHostdevDefFree(def); + def = NULL; + goto cleanup; +} + static int virDomainLifecycleParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt, @@ -1471,6 +1665,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn, dev->type = VIR_DOMAIN_DEVICE_SOUND; if (!(dev->data.sound = virDomainSoundDefParseXML(conn, node))) goto error; + } else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) { + dev->type = VIR_DOMAIN_DEVICE_HOSTDEV; + if (!(dev->data.hostdev = virDomainHostdevDefParseXML(conn, node))) + goto error; } else { virDomainReportError(conn, VIR_ERR_XML_ERROR, "%s", _("unknown device type")); @@ -1965,6 +2163,22 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn, } VIR_FREE(nodes); + /* analysis of the host devices */ + if ((n = virXPathNodeSet(conn, "./devices/hostdev", ctxt, &nodes)) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot extract host devices")); + goto error; + } + for (i = 0 ; i < n ; i++) { + virDomainHostdevDefPtr hostdev = virDomainHostdevDefParseXML(conn, nodes[i]); + if (!hostdev) + goto error; + + hostdev->next = def->hostdevs; + def->hostdevs = hostdev; + } + VIR_FREE(nodes); + return def; error: @@ -2706,6 +2920,50 @@ virDomainGraphicsDefFormat(virConnectPtr conn, return 0; } + +static int +virDomainHostdevDefFormat(virConnectPtr conn, + virBufferPtr buf, + virDomainHostdevDefPtr def) +{ + const char *mode = virDomainHostdevModeTypeToString(def->mode); + const char *type; + + if (!mode || def->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unexpected hostdev mode %d"), def->mode); + return -1; + } + + type = virDomainHostdevSubsysTypeToString(def->source.subsys.type); + if (!type || def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unexpected hostdev type %d"), + def->source.subsys.type); + return -1; + } + + virBufferVSprintf(buf, " \n", mode, type); + virBufferAddLit(buf, " \n"); + + if (def->source.subsys.usb.vendor) { + virBufferVSprintf(buf, " \n", + def->source.subsys.usb.vendor); + virBufferVSprintf(buf, " \n", + def->source.subsys.usb.product); + } else { + virBufferVSprintf(buf, "
\n", + def->source.subsys.usb.bus, + def->source.subsys.usb.device); + } + + virBufferAddLit(buf, " \n"); + virBufferAddLit(buf, " \n"); + + return 0; +} + + char *virDomainDefFormat(virConnectPtr conn, virDomainDefPtr def, int flags) @@ -2719,6 +2977,7 @@ char *virDomainDefFormat(virConnectPtr conn, virDomainSoundDefPtr sound; virDomainInputDefPtr input; virDomainChrDefPtr chr; + virDomainHostdevDefPtr hostdev; const char *type = NULL, *tmp; int n, allones = 1; @@ -2931,6 +3190,13 @@ char *virDomainDefFormat(virConnectPtr conn, sound = sound->next; } + hostdev = def->hostdevs; + while (hostdev) { + if (virDomainHostdevDefFormat(conn, &buf, hostdev) < 0) + goto cleanup; + hostdev = hostdev->next; + } + virBufferAddLit(&buf, " \n"); virBufferAddLit(&buf, "\n"); diff --git a/src/domain_conf.h b/src/domain_conf.h index 527dc712f2..8a9d1db0f7 100644 --- a/src/domain_conf.h +++ b/src/domain_conf.h @@ -279,7 +279,52 @@ struct _virDomainGraphicsDef { } data; }; +enum virDomainHostdevMode { + VIR_DOMAIN_HOSTDEV_MODE_SUBSYS, + VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES, + VIR_DOMAIN_HOSTDEV_MODE_LAST, +}; + +enum virDomainHostdevSubsysType { + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB, + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI, + + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST +}; + +typedef struct _virDomainHostdevDef virDomainHostdevDef; +typedef virDomainHostdevDef *virDomainHostdevDefPtr; +struct _virDomainHostdevDef { + int mode; /* enum virDomainHostdevMode */ + union { + struct { + int type; /* enum virDomainHostdevBusType */ + union { + struct { + unsigned bus; + unsigned device; + + unsigned vendor; + unsigned product; + } usb; + struct { + unsigned domain; + unsigned bus; + unsigned slot; + unsigned function; + } pci; + }; + } subsys; + struct { + /* TBD: struct capabilities see: + * https://www.redhat.com/archives/libvir-list/2008-July/msg00429.html + */ + } caps; + } source; + char* target; + virDomainHostdevDefPtr next; +}; /* Flags for the 'type' field in next struct */ enum virDomainDeviceType { @@ -288,6 +333,7 @@ enum virDomainDeviceType { VIR_DOMAIN_DEVICE_NET, VIR_DOMAIN_DEVICE_INPUT, VIR_DOMAIN_DEVICE_SOUND, + VIR_DOMAIN_DEVICE_HOSTDEV, }; typedef struct _virDomainDeviceDef virDomainDeviceDef; @@ -300,6 +346,7 @@ struct _virDomainDeviceDef { virDomainNetDefPtr net; virDomainInputDefPtr input; virDomainSoundDefPtr sound; + virDomainHostdevDefPtr hostdev; } data; }; @@ -386,6 +433,7 @@ struct _virDomainDef { virDomainNetDefPtr nets; virDomainInputDefPtr inputs; virDomainSoundDefPtr sounds; + virDomainHostdevDefPtr hostdevs; virDomainChrDefPtr serials; virDomainChrDefPtr parallels; virDomainChrDefPtr console; @@ -441,6 +489,7 @@ void virDomainFSDefFree(virDomainFSDefPtr def); void virDomainNetDefFree(virDomainNetDefPtr def); void virDomainChrDefFree(virDomainChrDefPtr def); void virDomainSoundDefFree(virDomainSoundDefPtr def); +void virDomainHostdevDefFree(virDomainHostdevDefPtr def); void virDomainDeviceDefFree(virDomainDeviceDefPtr def); void virDomainDefFree(virDomainDefPtr vm); void virDomainObjFree(virDomainObjPtr vm); @@ -515,6 +564,8 @@ VIR_ENUM_DECL(virDomainFS) VIR_ENUM_DECL(virDomainNet) VIR_ENUM_DECL(virDomainChr) VIR_ENUM_DECL(virDomainSoundModel) +VIR_ENUM_DECL(virDomainHostdevMode) +VIR_ENUM_DECL(virDomainHostdevSubsys) VIR_ENUM_DECL(virDomainInput) VIR_ENUM_DECL(virDomainInputBus) VIR_ENUM_DECL(virDomainGraphics) diff --git a/src/qemu_conf.c b/src/qemu_conf.c index f5d12c7ddf..46bb9f4c86 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -723,6 +723,7 @@ int qemudBuildCommandLine(virConnectPtr conn, virDomainNetDefPtr net = vm->def->nets; virDomainInputDefPtr input = vm->def->inputs; virDomainSoundDefPtr sound = vm->def->sounds; + virDomainHostdevDefPtr hostdev = vm->def->hostdevs; virDomainChrDefPtr serial = vm->def->serials; virDomainChrDefPtr parallel = vm->def->parallels; struct utsname ut; @@ -1152,6 +1153,34 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG(modstr); } + /* Add host passthrough hardware */ + while (hostdev) { + int ret; + char* usbdev; + + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + if(hostdev->source.subsys.usb.vendor) { + ret = asprintf(&usbdev, "host:%.4x:%.4x", + hostdev->source.subsys.usb.vendor, + hostdev->source.subsys.usb.product); + + } else { + ret = asprintf(&usbdev, "host:%.3d.%.3d", + hostdev->source.subsys.usb.bus, + hostdev->source.subsys.usb.device); + } + if (ret < 0) { + usbdev = NULL; + goto error; + } + ADD_ARG_LIT("-usbdevice"); + ADD_ARG_LIT(usbdev); + VIR_FREE(usbdev); + } + hostdev = hostdev->next; + } + if (migrateFrom) { ADD_ARG_LIT("-incoming"); ADD_ARG_LIT(migrateFrom); diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 7fe3903b46..3c6d7c0346 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2951,12 +2951,95 @@ static int qemudDomainChangeCDROM(virDomainPtr dom, return 0; } +static int qemudDomainAttachCdromDevice(virDomainPtr dom, + virDomainDeviceDefPtr dev) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid); + virDomainDiskDefPtr disk; + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "%s", _("no domain with matching uuid")); + return -1; + } + + disk = vm->def->disks; + while (disk) { + if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM && + STREQ(disk->dst, dev->data.disk->dst)) + break; + disk = disk->next; + } + + if (!disk) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, + "%s", _("CDROM not attached, cannot change media")); + return -1; + } + + if (qemudDomainChangeCDROM(dom, vm, disk, dev->data.disk) < 0) { + return -1; + } + return 0; +} + +static int qemudDomainAttachHostDevice(virDomainPtr dom, virDomainDeviceDefPtr dev) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid); + int ret; + char *cmd, *reply; + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "%s", _("no domain with matching uuid")); + return -1; + } + + if (dev->data.hostdev->source.subsys.usb.vendor) { + ret = asprintf(&cmd, "usb_add host:%.4x:%.4x", + dev->data.hostdev->source.subsys.usb.vendor, + dev->data.hostdev->source.subsys.usb.product); + } else { + ret = asprintf(&cmd, "usb_add host:%.3d.%.3d", + dev->data.hostdev->source.subsys.usb.bus, + dev->data.hostdev->source.subsys.usb.device); + } + if (ret == -1) { + qemudReportError(dom->conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL); + return -1; + } + + if (qemudMonitorCommand(driver, vm, cmd, &reply) < 0) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("cannot attach usb device")); + VIR_FREE(cmd); + return -1; + } + + DEBUG ("attach_usb reply: %s", reply); + /* If the command failed qemu prints: + * Could not add ... */ + if (strstr(reply, "Could not add ")) { + qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + "%s", + _("adding usb device failed")); + VIR_FREE(reply); + VIR_FREE(cmd); + return -1; + } + VIR_FREE(reply); + VIR_FREE(cmd); + return 0; +} + static int qemudDomainAttachDevice(virDomainPtr dom, const char *xml) { struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid); virDomainDeviceDefPtr dev; - virDomainDiskDefPtr disk; + int ret = 0; if (!vm) { qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, @@ -2975,36 +3058,21 @@ static int qemudDomainAttachDevice(virDomainPtr dom, return -1; } - if (dev->type != VIR_DOMAIN_DEVICE_DISK || - dev->data.disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) { + if (dev->type == VIR_DOMAIN_DEVICE_DISK && + dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { + ret = qemudDomainAttachCdromDevice(dom, dev); + } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV && + dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + ret = qemudDomainAttachHostDevice(dom, dev); + } else { qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", _("only CDROM disk devices can be attached")); - VIR_FREE(dev); - return -1; - } - - disk = vm->def->disks; - while (disk) { - if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM && - STREQ(disk->dst, dev->data.disk->dst)) - break; - disk = disk->next; - } - - if (!disk) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", _("CDROM not attached, cannot change media")); - VIR_FREE(dev); - return -1; - } - - if (qemudDomainChangeCDROM(dom, vm, disk, dev->data.disk) < 0) { - VIR_FREE(dev); - return -1; + "%s", _("this devicetype cannnot be attached")); + ret = -1; } VIR_FREE(dev); - return 0; + return ret; } static int qemudDomainGetAutostart(virDomainPtr dom, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args new file mode 100644 index 0000000000..0b89999eca --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args @@ -0,0 +1 @@ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -usbdevice host:014.006 \ No newline at end of file diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml new file mode 100644 index 0000000000..0c044e1787 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml @@ -0,0 +1,27 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219200 + 219200 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + + + + +
+ + + + diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args new file mode 100644 index 0000000000..b993ae56fe --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args @@ -0,0 +1 @@ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -usbdevice host:0204:6025 \ No newline at end of file diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml new file mode 100644 index 0000000000..aecad4ca25 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml @@ -0,0 +1,28 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219200 + 219200 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + + + + + + + + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index d136a1346d..458201b9cd 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -179,6 +179,9 @@ mymain(int argc, char **argv) DO_TEST("console-compat", 0); DO_TEST("sound", 0); + DO_TEST("hostdev-usb-product", 0); + DO_TEST("hostdev-usb-address", 0); + virCapabilitiesFree(driver.caps); return(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 9e380e4262..536c9bd876 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -118,6 +118,9 @@ mymain(int argc, char **argv) DO_TEST("parallel-tcp"); DO_TEST("console-compat"); + DO_TEST("hostdev-usb-product"); + DO_TEST("hostdev-usb-address"); + virCapabilitiesFree(driver.caps); return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);