summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorWolfram Sang2014-01-10 19:36:42 +0100
committerGreg Kroah-Hartman2014-01-11 01:54:35 +0100
commit2fc82c2de604deabb86b0558be0a301bb2209a19 (patch)
tree968d174a545222b71a3e43d44ab10b21fb0c5ac4 /drivers/usb/core
parentusb: core: add sanity checks when using bInterfaceClass with new_id (diff)
downloadkernel-qcow2-linux-2fc82c2de604deabb86b0558be0a301bb2209a19.tar.gz
kernel-qcow2-linux-2fc82c2de604deabb86b0558be0a301bb2209a19.tar.xz
kernel-qcow2-linux-2fc82c2de604deabb86b0558be0a301bb2209a19.zip
usb: core: allow a reference device for new_id
Often, usb drivers need some driver_info to get a device to work. To have access to driver_info when using new_id, allow to pass a reference vendor:product tuple from which new_id will inherit driver_info. Signed-off-by: Wolfram Sang <wsa@the-dreams.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/driver.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 574f5a04c92d..9b29e5c94be7 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -37,6 +37,7 @@
* and cause the driver to probe for all devices again.
*/
ssize_t usb_store_new_id(struct usb_dynids *dynids,
+ const struct usb_device_id *id_table,
struct device_driver *driver,
const char *buf, size_t count)
{
@@ -44,11 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
u32 idVendor = 0;
u32 idProduct = 0;
unsigned int bInterfaceClass = 0;
+ u32 refVendor, refProduct;
int fields = 0;
int retval = 0;
- fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct,
- &bInterfaceClass);
+ fields = sscanf(buf, "%x %x %x %x %x", &idVendor, &idProduct,
+ &bInterfaceClass, &refVendor, &refProduct);
if (fields < 2)
return -EINVAL;
@@ -68,6 +70,16 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
}
+ if (fields > 4) {
+ const struct usb_device_id *id = id_table;
+
+ for (; id->match_flags; id++)
+ if (id->idVendor == refVendor && id->idProduct == refProduct) {
+ dynid->id.driver_info = id->driver_info;
+ break;
+ }
+ }
+
spin_lock(&dynids->lock);
list_add_tail(&dynid->node, &dynids->list);
spin_unlock(&dynids->lock);
@@ -109,7 +121,7 @@ static ssize_t new_id_store(struct device_driver *driver,
{
struct usb_driver *usb_drv = to_usb_driver(driver);
- return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+ return usb_store_new_id(&usb_drv->dynids, usb_drv->id_table, driver, buf, count);
}
static DRIVER_ATTR_RW(new_id);