int usbFindDevice(unsigned int vendor, unsigned int product, unsigned int bus, unsigned int devno, const char *vroot, bool mandatory, usbDevice **usb) { usbDeviceList *list; unsigned int flags = USB_DEVICE_FIND_BY_VENDOR|USB_DEVICE_FIND_BY_BUS; if (!(list = usbDeviceSearch(vendor, product, bus, devno, vroot, flags))) return -1; if (list->count == 0) { usbDeviceListFree(list); if (!mandatory) { VIR_DEBUG("Did not find USB device %x:%x bus:%u device:%u", vendor, product, bus, devno); if (usb) *usb = NULL; return 0; } virReportError(VIR_ERR_INTERNAL_ERROR, _("Did not find USB device %x:%x bus:%u device:%u"), vendor, product, bus, devno); return -1; } if (usb) { *usb = usbDeviceListGet(list, 0); usbDeviceListSteal(list, *usb); } usbDeviceListFree(list); return 0; }
int usbFindDeviceByBus(unsigned int bus, unsigned devno, const char *vroot, bool mandatory, usbDevice **usb) { usbDeviceList *list; if (!(list = usbDeviceSearch(0, 0, bus, devno, vroot, USB_DEVICE_FIND_BY_BUS))) return -1; if (list->count == 0) { usbDeviceListFree(list); if (!mandatory) { VIR_DEBUG("Did not find USB device bus:%u device:%u", bus, devno); if (usb) *usb = NULL; return 0; } virReportError(VIR_ERR_INTERNAL_ERROR, _("Did not find USB device bus:%u device:%u"), bus, devno); return -1; } if (usb) { *usb = usbDeviceListGet(list, 0); usbDeviceListSteal(list, *usb); } usbDeviceListFree(list); return 0; }
int usbFindDeviceByVendor(unsigned int vendor, unsigned product, const char *vroot, bool mandatory, usbDeviceList **devices) { usbDeviceList *list; int count; if (!(list = usbDeviceSearch(vendor, product, 0 , 0, vroot, USB_DEVICE_FIND_BY_VENDOR))) return -1; if (list->count == 0) { usbDeviceListFree(list); if (!mandatory) { VIR_DEBUG("Did not find USB device %x:%x", vendor, product); if (devices) *devices = NULL; return 0; } virReportError(VIR_ERR_INTERNAL_ERROR, _("Did not find USB device %x:%x"), vendor, product); return -1; } count = list->count; if (devices) *devices = list; else usbDeviceListFree(list); return count; }
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; }
int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev, bool mandatory, usbDevice **usb) { 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; bool autoAddress = hostdev->source.subsys.u.usb.autoAddress; int rc; *usb = NULL; if (vendor && bus) { rc = usbFindDevice(vendor, product, bus, device, autoAddress ? false : mandatory, usb); if (rc < 0) { return -1; } else if (!autoAddress) { goto out; } else { VIR_INFO("USB device %x:%x could not be found at previous" " address (bus:%u device:%u)", vendor, product, bus, device); } } /* When vendor is specified, its USB address is either unspecified or the * device could not be found at the USB device where it had been * automatically found before. */ if (vendor) { usbDeviceList *devs; rc = usbFindDeviceByVendor(vendor, product, mandatory, &devs); if (rc < 0) return -1; if (rc == 1) { *usb = usbDeviceListGet(devs, 0); usbDeviceListSteal(devs, *usb); } usbDeviceListFree(devs); if (rc == 0) { goto out; } else if (rc > 1) { if (autoAddress) { virReportError(VIR_ERR_OPERATION_FAILED, _("Multiple USB devices for %x:%x were found," " but none of them is at bus:%u device:%u"), vendor, product, bus, device); } else { virReportError(VIR_ERR_OPERATION_FAILED, _("Multiple USB devices for %x:%x, " "use <address> to specify one"), vendor, product); } return -1; } hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(*usb); hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(*usb); hostdev->source.subsys.u.usb.autoAddress = true; if (autoAddress) { VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved" " from bus:%u device:%u)", vendor, product, hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device, bus, device); } } else if (!vendor && bus) { if (usbFindDeviceByBus(bus, device, mandatory, usb) < 0) return -1; } out: if (!*usb) hostdev->missing = 1; return 0; }
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; }
int qemuPrepareHostdevUSBDevices(struct qemud_driver *driver, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { int ret = -1; int i; usbDeviceList *list; usbDevice *tmp; /* 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 and validate no usb device * is already taken */ for (i = 0 ; i < nhostdevs ; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) continue; /* Resolve a vendor/product to bus/device */ if (hostdev->source.subsys.u.usb.vendor) { usbDevice *usb = usbFindDevice(hostdev->source.subsys.u.usb.vendor, hostdev->source.subsys.u.usb.product); if (!usb) return -1; hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) { const char *other_name = usbDeviceGetUsedBy(tmp); if (other_name) qemuReportError(VIR_ERR_OPERATION_INVALID, _("USB device %s is in use by domain %s"), usbDeviceGetName(tmp), other_name); else qemuReportError(VIR_ERR_OPERATION_INVALID, _("USB device %s is already in use"), usbDeviceGetName(tmp)); usbFreeDevice(usb); goto cleanup; } if (usbDeviceListAdd(list, usb) < 0) { usbFreeDevice(usb); goto cleanup; } } } /* Loop 2: Mark devices in temporary list as used by @name * and add them do driver list. However, if something goes * wrong, perform rollback. */ for (i = 0; i < usbDeviceListCount(list); i++) { tmp = usbDeviceListGet(list, i); usbDeviceSetUsedBy(tmp, name); if (usbDeviceListAdd(driver->activeUsbHostdevs, tmp) < 0) { usbFreeDevice(tmp); goto inactivedevs; } } /* Loop 3: 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; goto cleanup; inactivedevs: /* Steal devices from driver->activeUsbHostdevs. * We will free them later. */ for (i = 0; i < usbDeviceListCount(list); i++) { tmp = usbDeviceListGet(list, i); usbDeviceListSteal(driver->activeUsbHostdevs, tmp); } cleanup: usbDeviceListFree(list); return ret; }
static usbDeviceList * usbDeviceSearch(unsigned int vendor, unsigned int product, unsigned int bus, unsigned int devno, const char *vroot, unsigned int flags) { DIR *dir = NULL; bool found = false; char *ignore = NULL; struct dirent *de; usbDeviceList *list = NULL, *ret = NULL; usbDevice *usb; if (!(list = usbDeviceListNew())) goto cleanup; dir = opendir(USB_SYSFS "/devices"); if (!dir) { virReportSystemError(errno, _("Could not open directory %s"), USB_SYSFS "/devices"); goto cleanup; } while ((de = readdir(dir))) { unsigned int found_prod, found_vend, found_bus, found_devno; char *tmpstr = de->d_name; if (de->d_name[0] == '.' || strchr(de->d_name, ':')) continue; if (usbSysReadFile("idVendor", de->d_name, 16, &found_vend) < 0) goto cleanup; if (usbSysReadFile("idProduct", de->d_name, 16, &found_prod) < 0) goto cleanup; if (STRPREFIX(de->d_name, "usb")) tmpstr += 3; if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to parse dir name '%s'"), de->d_name); goto cleanup; } if (usbSysReadFile("devnum", de->d_name, 10, &found_devno) < 0) goto cleanup; if ((flags & USB_DEVICE_FIND_BY_VENDOR) && (found_prod != product || found_vend != vendor)) continue; if (flags & USB_DEVICE_FIND_BY_BUS) { if (found_bus != bus || found_devno != devno) continue; found = true; } usb = usbGetDevice(found_bus, found_devno, vroot); if (!usb) goto cleanup; if (usbDeviceListAdd(list, usb) < 0) { usbFreeDevice(usb); goto cleanup; } if (found) break; } ret = list; cleanup: if (dir) { int saved_errno = errno; closedir(dir); errno = saved_errno; } if (!ret) usbDeviceListFree(list); return ret; }