mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-06 21:15:22 +00:00
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:
parent
05aa969fc9
commit
18c1491697
@ -1084,6 +1084,8 @@ usbDeviceListNew;
|
|||||||
usbDeviceListSteal;
|
usbDeviceListSteal;
|
||||||
usbDeviceSetUsedBy;
|
usbDeviceSetUsedBy;
|
||||||
usbFindDevice;
|
usbFindDevice;
|
||||||
|
usbFindDeviceByBus;
|
||||||
|
usbFindDeviceByVendor;
|
||||||
usbFreeDevice;
|
usbFreeDevice;
|
||||||
usbGetDevice;
|
usbGetDevice;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user