static void
qemuDomainReAttachHostUsbDevices(struct qemud_driver *driver,
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
    int i;

    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
        usbDevice *usb, *tmp;
        const char *used_by = NULL;

        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;
        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;
        if (hostdev->missing)
            continue;

        usb = usbGetDevice(hostdev->source.subsys.u.usb.bus,
                           hostdev->source.subsys.u.usb.device);

        if (!usb) {
            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
                     hostdev->source.subsys.u.usb.bus,
                     hostdev->source.subsys.u.usb.device,
                     name);
            continue;
        }

        /* Delete only those USB devices which belongs
         * to domain @name because qemuProcessStart() might
         * have failed because USB device is already taken.
         * Therefore we want to steal only those devices from
         * the list which were taken by @name */

        tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb);
        usbFreeDevice(usb);

        if (!tmp) {
            VIR_WARN("Unable to find device %03d.%03d "
                     "in list of active USB devices",
                     hostdev->source.subsys.u.usb.bus,
                     hostdev->source.subsys.u.usb.device);
            continue;
        }

        used_by = usbDeviceGetUsedBy(tmp);
        if (STREQ_NULLABLE(used_by, name)) {
            VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
                      hostdev->source.subsys.u.usb.bus,
                      hostdev->source.subsys.u.usb.device,
                      name);

            usbDeviceListDel(driver->activeUsbHostdevs, tmp);
        }
    }
}
Beispiel #2
0
void
usbDeviceListDel(usbDeviceList *list,
                 usbDevice *dev)
{
    usbDevice *ret = usbDeviceListSteal(list, dev);
    if (ret)
        usbFreeDevice(ret);
}
Beispiel #3
0
usbDevice *
usbGetDevice(unsigned int bus,
             unsigned int devno,
             const char *vroot)
{
    usbDevice *dev;

    if (VIR_ALLOC(dev) < 0) {
        virReportOOMError();
        return NULL;
    }

    dev->bus     = bus;
    dev->dev     = devno;

    if (snprintf(dev->name, sizeof(dev->name), "%.3o:%.3o",
                 dev->bus, dev->dev) >= sizeof(dev->name)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("dev->name buffer overflow: %.3o:%.3o"),
                       dev->bus, dev->dev);
        usbFreeDevice(dev);
        return NULL;
    }
    if (virAsprintf(&dev->path, "%s" USB_DEVFS "%03d/%03d",
                    vroot ? vroot : "",
                    dev->bus, dev->dev) < 0) {
        virReportOOMError();
        usbFreeDevice(dev);
        return NULL;
    }

    /* XXX fixme. this should be product/vendor */
    if (snprintf(dev->id, sizeof(dev->id), "%d %d", dev->bus,
                 dev->dev) >= sizeof(dev->id)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("dev->id buffer overflow: %d %d"),
                       dev->bus, dev->dev);
        usbFreeDevice(dev);
        return NULL;
    }

    VIR_DEBUG("%s %s: initialized", dev->id, dev->name);

    return dev;
}
Beispiel #4
0
void
usbDeviceListFree(usbDeviceList *list)
{
    int i;

    if (!list)
        return;

    for (i = 0; i < list->count; i++)
        usbFreeDevice(list->devs[i]);

    VIR_FREE(list->devs);
    VIR_FREE(list);
}
int
qemuUpdateActiveUsbHostdevs(struct qemud_driver *driver,
                            virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
    int i;

    if (!def->nhostdevs)
        return 0;

    for (i = 0; i < def->nhostdevs; i++) {
        usbDevice *usb = NULL;
        hostdev = def->hostdevs[i];

        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;
        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;

        usb = usbGetDevice(hostdev->source.subsys.u.usb.bus,
                           hostdev->source.subsys.u.usb.device);
        if (!usb) {
            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
                     hostdev->source.subsys.u.usb.bus,
                     hostdev->source.subsys.u.usb.device,
                     def->name);
            continue;
        }

        usbDeviceSetUsedBy(usb, def->name);

        if (usbDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
            usbFreeDevice(usb);
            return -1;
        }
    }

    return 0;
}
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;
}
Beispiel #7
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}