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 --- src/libvirt_private.syms | 2 + src/util/hostusb.c | 209 +++++++++++++++++++++++++++++++++------------- src/util/hostusb.h | 22 ++++-- 3 files changed, 170 insertions(+), 63 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 025816a..b9f9015 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1084,6 +1084,8 @@ usbDeviceListGet; usbDeviceListNew; usbDeviceListSteal; usbDeviceSetUsedBy; +usbFindDeviceByBus; +usbFindDeviceByVendor; usbFindDevice; usbFreeDevice; usbGetDevice; diff --git a/src/util/hostusb.c b/src/util/hostusb.c index 92f52a2..cad0a6c 100644 --- a/src/util/hostusb.c +++ b/src/util/hostusb.c @@ -42,9 +42,16 @@ #define USB_ID_LEN 10 /* "1234 5678" */ #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 { - unsigned bus; - unsigned dev; + unsigned int bus; + unsigned int dev; char name[USB_ADDR_LEN]; /* domain:bus:slot.function */ char id[USB_ID_LEN]; /* product vendor */ @@ -57,15 +64,14 @@ struct _usbDeviceList { usbDevice **devs; }; -/* For virReportOOMError() and virReportSystemError() */ -#define VIR_FROM_THIS VIR_FROM_NONE - -#define usbReportError(code, ...) \ - virReportErrorHelper(VIR_FROM_NONE, code, __FILE__, \ - __FUNCTION__, __LINE__, __VA_ARGS__) +typedef enum { + USB_DEVICE_ALL = 0, + USB_DEVICE_FIND_BY_VENDOR = 1, + USB_DEVICE_FIND_BY_BUS = 2, +} usbDeviceFindFlags; static int usbSysReadFile(const char *f_name, const char *d_name, - int base, unsigned *value) + int base, unsigned int *value) { int ret = -1, tmp; char *buf = NULL; @@ -94,13 +100,22 @@ cleanup: return ret; } -static int usbFindBusByVendor(unsigned vendor, unsigned product, - unsigned *bus, unsigned *devno) +static usbDeviceList * +usbDeviceSearch(unsigned int vendor, + unsigned int product, + unsigned int bus, + unsigned int devno, + unsigned int flags) { DIR *dir = NULL; - int ret = -1, found = 0; + 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) { @@ -111,48 +126,71 @@ static int usbFindBusByVendor(unsigned vendor, unsigned product, } 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, ':')) 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 (found_prod == product && found_vend == vendor) { - /* Lookup bus.addr info */ - char *tmpstr = de->d_name; - unsigned found_bus, found_addr; + if (STRPREFIX(de->d_name, "usb")) + tmpstr += 3; + + if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { + usbReportError(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; + + /* + * Don't set found to true in order to continue the loop + * to find multiple USB devices with same idVendor and idProduct + */ + if (flags && !(flags & ~USB_DEVICE_FIND_BY_VENDOR)) + if (found_prod != product || found_vend != vendor) + continue; + + if (flags && !(flags & ~USB_DEVICE_FIND_BY_BUS)) { + if (found_bus != bus || found_devno != devno) + continue; + found = true; + } - if (STRPREFIX(de->d_name, "usb")) - tmpstr += 3; + if ((flags & USB_DEVICE_FIND_BY_BUS) + && (flags & USB_DEVICE_FIND_BY_VENDOR)) { + if (found_prod != product || + found_vend != vendor || + found_bus != bus || + found_devno != devno) + continue; + found = true; + } - if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { - usbReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to parse dir name '%s'"), - de->d_name); - goto cleanup; - } + usb = usbGetDevice(found_bus, found_devno); + if (!usb) + goto cleanup; - if (usbSysReadFile("devnum", de->d_name, - 10, &found_addr) < 0) - goto cleanup; + if (usbDeviceListAdd(list, usb) < 0) { + usbFreeDevice(usb); + goto cleanup; + } - *bus = found_bus; - *devno = found_addr; - found = 1; + if (found) break; - } } - - if (!found) - usbReportError(VIR_ERR_INTERNAL_ERROR, - _("Did not find USB device %x:%x"), vendor, product); - else - ret = 0; + ret = list; cleanup: if (dir) { @@ -160,12 +198,84 @@ cleanup: closedir (dir); errno = saved_errno; } + + if (!ret) + usbDeviceListFree(list); 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 * -usbGetDevice(unsigned bus, - unsigned devno) +usbFindDeviceByBus(unsigned int bus, 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; @@ -207,21 +317,6 @@ usbGetDevice(unsigned bus, 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 usbFreeDevice(usbDevice *dev) { @@ -247,13 +342,13 @@ const char *usbDeviceGetName(usbDevice *dev) return dev->name; } -unsigned usbDeviceGetBus(usbDevice *dev) +unsigned int usbDeviceGetBus(usbDevice *dev) { return dev->bus; } -unsigned usbDeviceGetDevno(usbDevice *dev) +unsigned int usbDeviceGetDevno(usbDevice *dev) { return dev->dev; } diff --git a/src/util/hostusb.h b/src/util/hostusb.h index afaa32f..0c43e3f 100644 --- a/src/util/hostusb.h +++ b/src/util/hostusb.h @@ -28,17 +28,27 @@ typedef struct _usbDevice usbDevice; typedef struct _usbDeviceList usbDeviceList; -usbDevice *usbGetDevice(unsigned bus, - unsigned devno); -usbDevice *usbFindDevice(unsigned vendor, - unsigned product); +usbDevice *usbGetDevice(unsigned int bus, + unsigned int devno); + +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 usbDeviceSetUsedBy(usbDevice *dev, const char *name); const char *usbDeviceGetUsedBy(usbDevice *dev); const char *usbDeviceGetName(usbDevice *dev); -unsigned usbDeviceGetBus(usbDevice *dev); -unsigned usbDeviceGetDevno(usbDevice *dev); +unsigned int usbDeviceGetBus(usbDevice *dev); +unsigned int usbDeviceGetDevno(usbDevice *dev); /* * Callback that will be invoked once for each file -- 1.7.7.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list