static int qemuPrepareHostUSBDevices(struct qemud_driver *driver, virDomainDefPtr def) { int i, ret = -1; usbDeviceList *list; usbDevice *tmp; virDomainHostdevDefPtr *hostdevs = def->hostdevs; int nhostdevs = def->nhostdevs; /* To prevent situation where USB device is assigned to two domains * we need to keep a list of currently assigned USB devices. * This is done in several loops which cannot be joined into one big * loop. See qemuPrepareHostdevPCIDevices() */ if (!(list = usbDeviceListNew())) goto cleanup; /* Loop 1: build temporary list */ for (i = 0 ; i < nhostdevs ; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; usbDevice *usb = NULL; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) continue; unsigned vendor = hostdev->source.subsys.u.usb.vendor; unsigned product = hostdev->source.subsys.u.usb.product; unsigned bus = hostdev->source.subsys.u.usb.bus; unsigned device = hostdev->source.subsys.u.usb.device; if (vendor && bus) { usb = usbFindDevice(vendor, product, bus, device); } else if (vendor && !bus) { usbDeviceList *devs = usbFindDeviceByVendor(vendor, product); if (!devs) goto cleanup; if (usbDeviceListCount(devs) > 1) { virReportError(VIR_ERR_OPERATION_FAILED, _("multiple USB devices for %x:%x, " "use <address> to specify one"), vendor, product); usbDeviceListFree(devs); goto cleanup; } usb = usbDeviceListGet(devs, 0); usbDeviceListSteal(devs, usb); usbDeviceListFree(devs); hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); } else if (!vendor && bus) { usb = usbFindDeviceByBus(bus, device); } if (!usb) goto cleanup; if (usbDeviceListAdd(list, usb) < 0) { usbFreeDevice(usb); goto cleanup; } } /* Mark devices in temporary list as used by @name * and add them do driver list. However, if something goes * wrong, perform rollback. */ if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0) goto cleanup; /* Loop 2: Temporary list was successfully merged with * driver list, so steal all items to avoid freeing them * in cleanup label. */ while (usbDeviceListCount(list) > 0) { tmp = usbDeviceListGet(list, 0); usbDeviceListSteal(list, tmp); } ret = 0; cleanup: usbDeviceListFree(list); return ret; }
static int qemuPrepareHostUSBDevices(struct qemud_driver *driver, virDomainDefPtr def, bool coldBoot) { int i, ret = -1; usbDeviceList *list; usbDevice *tmp; virDomainHostdevDefPtr *hostdevs = def->hostdevs; int nhostdevs = def->nhostdevs; /* To prevent situation where USB device is assigned to two domains * we need to keep a list of currently assigned USB devices. * This is done in several loops which cannot be joined into one big * loop. See qemuPrepareHostdevPCIDevices() */ if (!(list = usbDeviceListNew())) goto cleanup; /* Loop 1: build temporary list */ for (i = 0 ; i < nhostdevs ; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; bool required = true; usbDevice *usb; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) continue; if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL || (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE && !coldBoot)) required = false; if (qemuFindHostdevUSBDevice(hostdev, required, &usb) < 0) goto cleanup; if (usb && usbDeviceListAdd(list, usb) < 0) { usbFreeDevice(usb); goto cleanup; } } /* Mark devices in temporary list as used by @name * and add them do driver list. However, if something goes * wrong, perform rollback. */ if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0) goto cleanup; /* Loop 2: Temporary list was successfully merged with * driver list, so steal all items to avoid freeing them * in cleanup label. */ while (usbDeviceListCount(list) > 0) { tmp = usbDeviceListGet(list, 0); usbDeviceListSteal(list, tmp); } ret = 0; cleanup: usbDeviceListFree(list); return ret; }
static int qemuPrepareHostUSBDevices(struct qemud_driver *driver, virDomainDefPtr def) { return qemuPrepareHostdevUSBDevices(driver, def->name, def->hostdevs, def->nhostdevs); }