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 <w...@the-dreams.de>
---
 Documentation/ABI/testing/sysfs-bus-usb | 10 ++++++++--
 drivers/usb/core/driver.c               | 18 +++++++++++++++---
 drivers/usb/serial/bus.c                |  4 +++-
 include/linux/usb.h                     |  1 +
 4 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-usb 
b/Documentation/ABI/testing/sysfs-bus-usb
index 1430f584b..614d451 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -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:
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 4fca61d..6dbed5e 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);
 
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 6335490..35a2373 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -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;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 512ab16..c716da1 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -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);
 
-- 
1.8.5.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to