usb: core: allow a reference device for new_id
authorWolfram Sang <wsa@the-dreams.de>
Fri, 10 Jan 2014 18:36:42 +0000 (19:36 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 11 Jan 2014 00:54:35 +0000 (16:54 -0800)
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>
Documentation/ABI/testing/sysfs-bus-usb
drivers/usb/core/driver.c
drivers/usb/serial/bus.c
include/linux/usb.h

index 1430f584b266415296ba4b9f0b71428106b441d1..614d451cee41978dc8eabec3fc4ad0956dc11fbc 100644 (file)
@@ -50,13 +50,19 @@ Description:
                This may allow the driver to support more hardware than
                was included in the driver's static device ID support
                table at compile time. The format for the device ID is:
-               idVendor idProduct bInterfaceClass.
+               idVendor idProduct bInterfaceClass RefIdVendor RefIdProduct
                The vendor ID and device ID fields are required, the
-               interface class is optional.
+               rest is optional. The Ref* tuple can be used to tell the
+               driver to use the same driver_data for the new device as
+               it is used for the reference device.
                Upon successfully adding an ID, the driver will probe
                for the device and attempt to bind to it.  For example:
                # echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id
 
+               Here add a new device (0458:7045) using driver_data from
+               an already supported device (0458:704c):
+               # echo "0458 7045 0 0458 704c" > /sys/bus/usb/drivers/foo/new_id
+
                Reading from this file will list all dynamically added
                device IDs in the same format, with one entry per
                line. For example:
index 574f5a04c92de71f18e01227b70782c91638129c..9b29e5c94be7d36e68cfe19f6a5154a539b180af 100644 (file)
@@ -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);
 
index 6335490d57607ca043dba6306082fefaa8d29a0f..35a2373cde67bbbe01ce7c7afc8fc23a27b4eea5 100644 (file)
@@ -125,10 +125,12 @@ static ssize_t new_id_store(struct device_driver *driver,
                            const char *buf, size_t count)
 {
        struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
-       ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+       ssize_t retval = usb_store_new_id(&usb_drv->dynids, usb_drv->id_table,
+                                        driver, buf, count);
 
        if (retval >= 0 && usb_drv->usb_driver != NULL)
                retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+                                         usb_drv->usb_driver->id_table,
                                          &usb_drv->usb_driver->drvwrap.driver,
                                          buf, count);
        return retval;
index 512ab162832ccc0bb4b30f6210d083d762573b78..c716da18c668fe37c4fe91dde3c6385cc81e2d21 100644 (file)
@@ -965,6 +965,7 @@ struct usb_dynid {
 };
 
 extern 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);