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/qemu/qemu_hostdev.c | 14 +++-
src/qemu/qemu_hotplug.c | 14 +++-
src/util/hostusb.c | 202 ++++++++++++++++++++++++++++++++-------------
src/util/hostusb.h | 22 ++++--
5 files changed, 181 insertions(+), 73 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 88f8a21..a4670d3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1088,6 +1088,8 @@ usbDeviceListNew;
usbDeviceListSteal;
usbDeviceSetUsedBy;
usbFindDevice;
+usbFindDeviceByBus;
+usbFindDeviceByVendor;
usbFreeDevice;
usbGetDevice;
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
index 8594fb2..b98fd8f 100644
--- a/src/qemu/qemu_hostdev.c
+++ b/src/qemu/qemu_hostdev.c
@@ -594,13 +594,19 @@ qemuPrepareHostdevUSBDevices(struct qemud_driver *driver,
/* 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);
+ usbDevice *usb;
+ usbDeviceList *devs;
- if (!usb)
+ devs = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor,
+ hostdev->source.subsys.u.usb.product);
+
+ if (!devs)
goto cleanup;
+ usb = usbDeviceListGet(devs, 0);
+ usbDeviceListSteal(devs, usb);
+ usbDeviceListFree(devs);
+
if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) {
const char *other_name = usbDeviceGetUsedBy(tmp);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 7cf7b90..0f5fed1 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1131,16 +1131,22 @@ int qemuDomainAttachHostDevice(struct qemud_driver *driver,
/* Resolve USB product/vendor to bus/device */
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
hostdev->source.subsys.u.usb.vendor) {
+ usbDevice *usb;
+ usbDeviceList *list;
+
if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, &hostdev, 1)
< 0)
goto error;
- usbDevice *usb
- = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
- hostdev->source.subsys.u.usb.product);
+ list = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor,
+ hostdev->source.subsys.u.usb.product);
- if (!usb)
+ if (!list)
return -1;
+ usb = usbDeviceListGet(list, 0);
+ usbDeviceListSteal(list, usb);
+ usbDeviceListFree(list);
+
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
diff --git a/src/util/hostusb.c b/src/util/hostusb.c
index 92f52a2..63b10ef 100644
--- a/src/util/hostusb.c
+++ b/src/util/hostusb.c
@@ -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
* modify it under the terms of the GNU Lesser General Public
@@ -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 << 0,
+ USB_DEVICE_FIND_BY_BUS = 1 << 1,
+} 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,61 +126,145 @@ 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;
+
+ if ((flags & USB_DEVICE_FIND_BY_VENDOR) &&
+ (found_prod != product || found_vend != vendor))
+ continue;
- if (STRPREFIX(de->d_name, "usb"))
- tmpstr += 3;
+ if (flags & USB_DEVICE_FIND_BY_BUS) {
+ if (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) {
int saved_errno = errno;
- closedir (dir);
+ 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 +306,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 +331,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..27e07dc 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