usb: create functions to search usb device accurately

usbFindDevice():get usb device according to
                idVendor, idProduct, bus, device
                it is the exact match of the four parameters

usbFindDeviceByBus():get usb device according to bus, device
                  it returns only one usb device same as usbFindDevice

usbFindDeviceByVendor():get usb device according to idVendor,idProduct
                     it probably returns multiple usb devices.

usbDeviceSearch(): a helper function to do the actual search
(cherry picked from commit 9914477efc)
This commit is contained in:
Guannan Ren 2012-05-04 15:49:58 +08:00 committed by Cole Robinson
parent 05aa969fc9
commit 18c1491697
5 changed files with 184 additions and 76 deletions

View File

@ -1084,6 +1084,8 @@ usbDeviceListNew;
usbDeviceListSteal; usbDeviceListSteal;
usbDeviceSetUsedBy; usbDeviceSetUsedBy;
usbFindDevice; usbFindDevice;
usbFindDeviceByBus;
usbFindDeviceByVendor;
usbFreeDevice; usbFreeDevice;
usbGetDevice; usbGetDevice;

View File

@ -594,13 +594,19 @@ qemuPrepareHostdevUSBDevices(struct qemud_driver *driver,
/* Resolve a vendor/product to bus/device */ /* Resolve a vendor/product to bus/device */
if (hostdev->source.subsys.u.usb.vendor) { if (hostdev->source.subsys.u.usb.vendor) {
usbDevice *usb usbDevice *usb;
= usbFindDevice(hostdev->source.subsys.u.usb.vendor, usbDeviceList *devs;
hostdev->source.subsys.u.usb.product);
if (!usb) devs = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor,
hostdev->source.subsys.u.usb.product);
if (!devs)
goto cleanup; goto cleanup;
usb = usbDeviceListGet(devs, 0);
usbDeviceListSteal(devs, usb);
usbDeviceListFree(devs);
if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) { if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) {
const char *other_name = usbDeviceGetUsedBy(tmp); const char *other_name = usbDeviceGetUsedBy(tmp);

View File

@ -1131,16 +1131,22 @@ int qemuDomainAttachHostDevice(struct qemud_driver *driver,
/* Resolve USB product/vendor to bus/device */ /* Resolve USB product/vendor to bus/device */
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
hostdev->source.subsys.u.usb.vendor) { hostdev->source.subsys.u.usb.vendor) {
usbDevice *usb;
usbDeviceList *list;
if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, &hostdev, 1) < 0) if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, &hostdev, 1) < 0)
goto error; goto error;
usbDevice *usb list = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor,
= usbFindDevice(hostdev->source.subsys.u.usb.vendor, hostdev->source.subsys.u.usb.product);
hostdev->source.subsys.u.usb.product);
if (!usb) if (!list)
return -1; return -1;
usb = usbDeviceListGet(list, 0);
usbDeviceListSteal(list, usb);
usbDeviceListFree(list);
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2011 Red Hat, Inc. * Copyright (C) 2009-2012 Red Hat, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -42,9 +42,16 @@
#define USB_ID_LEN 10 /* "1234 5678" */ #define USB_ID_LEN 10 /* "1234 5678" */
#define USB_ADDR_LEN 8 /* "123:456" */ #define USB_ADDR_LEN 8 /* "123:456" */
/* For virReportOOMError() and virReportSystemError() */
#define VIR_FROM_THIS VIR_FROM_NONE
#define usbReportError(code, ...) \
virReportErrorHelper(VIR_FROM_NONE, code, __FILE__, \
__FUNCTION__, __LINE__, __VA_ARGS__)
struct _usbDevice { struct _usbDevice {
unsigned bus; unsigned int bus;
unsigned dev; unsigned int dev;
char name[USB_ADDR_LEN]; /* domain:bus:slot.function */ char name[USB_ADDR_LEN]; /* domain:bus:slot.function */
char id[USB_ID_LEN]; /* product vendor */ char id[USB_ID_LEN]; /* product vendor */
@ -57,15 +64,14 @@ struct _usbDeviceList {
usbDevice **devs; usbDevice **devs;
}; };
/* For virReportOOMError() and virReportSystemError() */ typedef enum {
#define VIR_FROM_THIS VIR_FROM_NONE USB_DEVICE_ALL = 0,
USB_DEVICE_FIND_BY_VENDOR = 1 << 0,
#define usbReportError(code, ...) \ USB_DEVICE_FIND_BY_BUS = 1 << 1,
virReportErrorHelper(VIR_FROM_NONE, code, __FILE__, \ } usbDeviceFindFlags;
__FUNCTION__, __LINE__, __VA_ARGS__)
static int usbSysReadFile(const char *f_name, const char *d_name, static int usbSysReadFile(const char *f_name, const char *d_name,
int base, unsigned *value) int base, unsigned int *value)
{ {
int ret = -1, tmp; int ret = -1, tmp;
char *buf = NULL; char *buf = NULL;
@ -94,13 +100,22 @@ cleanup:
return ret; return ret;
} }
static int usbFindBusByVendor(unsigned vendor, unsigned product, static usbDeviceList *
unsigned *bus, unsigned *devno) usbDeviceSearch(unsigned int vendor,
unsigned int product,
unsigned int bus,
unsigned int devno,
unsigned int flags)
{ {
DIR *dir = NULL; DIR *dir = NULL;
int ret = -1, found = 0; bool found = false;
char *ignore = NULL; char *ignore = NULL;
struct dirent *de; struct dirent *de;
usbDeviceList *list = NULL, *ret = NULL;
usbDevice *usb;
if (!(list = usbDeviceListNew()))
goto cleanup;
dir = opendir(USB_SYSFS "/devices"); dir = opendir(USB_SYSFS "/devices");
if (!dir) { if (!dir) {
@ -111,61 +126,145 @@ static int usbFindBusByVendor(unsigned vendor, unsigned product,
} }
while ((de = readdir(dir))) { while ((de = readdir(dir))) {
unsigned found_prod, found_vend; unsigned int found_prod, found_vend, found_bus, found_devno;
char *tmpstr = de->d_name;
if (de->d_name[0] == '.' || strchr(de->d_name, ':')) if (de->d_name[0] == '.' || strchr(de->d_name, ':'))
continue; continue;
if (usbSysReadFile("idVendor", de->d_name, if (usbSysReadFile("idVendor", de->d_name,
16, &found_vend) < 0) 16, &found_vend) < 0)
goto cleanup; goto cleanup;
if (usbSysReadFile("idProduct", de->d_name, if (usbSysReadFile("idProduct", de->d_name,
16, &found_prod) < 0) 16, &found_prod) < 0)
goto cleanup; goto cleanup;
if (found_prod == product && found_vend == vendor) { if (STRPREFIX(de->d_name, "usb"))
/* Lookup bus.addr info */ tmpstr += 3;
char *tmpstr = de->d_name;
unsigned found_bus, found_addr;
if (STRPREFIX(de->d_name, "usb")) if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) {
tmpstr += 3; usbReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to parse dir name '%s'"),
if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { de->d_name);
usbReportError(VIR_ERR_INTERNAL_ERROR, goto cleanup;
_("Failed to parse dir name '%s'"),
de->d_name);
goto cleanup;
}
if (usbSysReadFile("devnum", de->d_name,
10, &found_addr) < 0)
goto cleanup;
*bus = found_bus;
*devno = found_addr;
found = 1;
break;
} }
}
if (!found) if (usbSysReadFile("devnum", de->d_name,
usbReportError(VIR_ERR_INTERNAL_ERROR, 10, &found_devno) < 0)
_("Did not find USB device %x:%x"), vendor, product); goto cleanup;
else
ret = 0; 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);
if (!usb)
goto cleanup;
if (usbDeviceListAdd(list, usb) < 0) {
usbFreeDevice(usb);
goto cleanup;
}
if (found)
break;
}
ret = list;
cleanup: cleanup:
if (dir) { if (dir) {
int saved_errno = errno; int saved_errno = errno;
closedir (dir); closedir(dir);
errno = saved_errno; errno = saved_errno;
} }
if (!ret)
usbDeviceListFree(list);
return ret; return ret;
} }
usbDeviceList *
usbFindDeviceByVendor(unsigned int vendor, unsigned product)
{
usbDeviceList *list;
if (!(list = usbDeviceSearch(vendor, product, 0 , 0,
USB_DEVICE_FIND_BY_VENDOR)))
return NULL;
if (list->count == 0) {
usbReportError(VIR_ERR_INTERNAL_ERROR,
_("Did not find USB device %x:%x"), vendor, product);
usbDeviceListFree(list);
return NULL;
}
return list;
}
usbDevice * usbDevice *
usbGetDevice(unsigned bus, usbFindDeviceByBus(unsigned int bus, unsigned devno)
unsigned devno) {
usbDevice *usb;
usbDeviceList *list;
if (!(list = usbDeviceSearch(0, 0, bus, devno,
USB_DEVICE_FIND_BY_BUS)))
return NULL;
if (list->count == 0) {
usbReportError(VIR_ERR_INTERNAL_ERROR,
_("Did not find USB device bus:%u device:%u"),
bus, devno);
usbDeviceListFree(list);
return NULL;
}
usb = usbDeviceListGet(list, 0);
usbDeviceListSteal(list, usb);
usbDeviceListFree(list);
return usb;
}
usbDevice *
usbFindDevice(unsigned int vendor,
unsigned int product,
unsigned int bus,
unsigned int devno)
{
usbDevice *usb;
usbDeviceList *list;
unsigned int flags = USB_DEVICE_FIND_BY_VENDOR|USB_DEVICE_FIND_BY_BUS;
if (!(list = usbDeviceSearch(vendor, product, bus, devno, flags)))
return NULL;
if (list->count == 0) {
usbReportError(VIR_ERR_INTERNAL_ERROR,
_("Did not find USB device %x:%x bus:%u device:%u"),
vendor, product, bus, devno);
usbDeviceListFree(list);
return NULL;
}
usb = usbDeviceListGet(list, 0);
usbDeviceListSteal(list, usb);
usbDeviceListFree(list);
return usb;
}
usbDevice *
usbGetDevice(unsigned int bus,
unsigned int devno)
{ {
usbDevice *dev; usbDevice *dev;
@ -207,21 +306,6 @@ usbGetDevice(unsigned bus,
return dev; return dev;
} }
usbDevice *
usbFindDevice(unsigned vendor,
unsigned product)
{
unsigned bus = 0, devno = 0;
if (usbFindBusByVendor(vendor, product, &bus, &devno) < 0) {
return NULL;
}
return usbGetDevice(bus, devno);
}
void void
usbFreeDevice(usbDevice *dev) usbFreeDevice(usbDevice *dev)
{ {
@ -247,13 +331,13 @@ const char *usbDeviceGetName(usbDevice *dev)
return dev->name; return dev->name;
} }
unsigned usbDeviceGetBus(usbDevice *dev) unsigned int usbDeviceGetBus(usbDevice *dev)
{ {
return dev->bus; return dev->bus;
} }
unsigned usbDeviceGetDevno(usbDevice *dev) unsigned int usbDeviceGetDevno(usbDevice *dev)
{ {
return dev->dev; return dev->dev;
} }

View File

@ -28,17 +28,27 @@
typedef struct _usbDevice usbDevice; typedef struct _usbDevice usbDevice;
typedef struct _usbDeviceList usbDeviceList; typedef struct _usbDeviceList usbDeviceList;
usbDevice *usbGetDevice(unsigned bus, usbDevice *usbGetDevice(unsigned int bus,
unsigned devno); unsigned int devno);
usbDevice *usbFindDevice(unsigned vendor,
unsigned product); usbDevice *usbFindDeviceByBus(unsigned int bus,
unsigned int devno);
usbDeviceList *usbFindDeviceByVendor(unsigned int vendor,
unsigned int product);
usbDevice *usbFindDevice(unsigned int vendor,
unsigned int product,
unsigned int bus,
unsigned int devno);
void usbFreeDevice (usbDevice *dev); void usbFreeDevice (usbDevice *dev);
void usbDeviceSetUsedBy(usbDevice *dev, const char *name); void usbDeviceSetUsedBy(usbDevice *dev, const char *name);
const char *usbDeviceGetUsedBy(usbDevice *dev); const char *usbDeviceGetUsedBy(usbDevice *dev);
const char *usbDeviceGetName(usbDevice *dev); const char *usbDeviceGetName(usbDevice *dev);
unsigned usbDeviceGetBus(usbDevice *dev); unsigned int usbDeviceGetBus(usbDevice *dev);
unsigned usbDeviceGetDevno(usbDevice *dev); unsigned int usbDeviceGetDevno(usbDevice *dev);
/* /*
* Callback that will be invoked once for each file * Callback that will be invoked once for each file