aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb10
-rw-r--r--drivers/usb/core/driver.c18
-rw-r--r--drivers/usb/serial/bus.c4
-rw-r--r--include/linux/usb.h1
4 files changed, 27 insertions, 6 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 1430f584b266..614d451cee41 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -50,13 +50,19 @@ Description:
50 This may allow the driver to support more hardware than 50 This may allow the driver to support more hardware than
51 was included in the driver's static device ID support 51 was included in the driver's static device ID support
52 table at compile time. The format for the device ID is: 52 table at compile time. The format for the device ID is:
53 idVendor idProduct bInterfaceClass. 53 idVendor idProduct bInterfaceClass RefIdVendor RefIdProduct
54 The vendor ID and device ID fields are required, the 54 The vendor ID and device ID fields are required, the
55 interface class is optional. 55 rest is optional. The Ref* tuple can be used to tell the
56 driver to use the same driver_data for the new device as
57 it is used for the reference device.
56 Upon successfully adding an ID, the driver will probe 58 Upon successfully adding an ID, the driver will probe
57 for the device and attempt to bind to it. For example: 59 for the device and attempt to bind to it. For example:
58 # echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id 60 # echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id
59 61
62 Here add a new device (0458:7045) using driver_data from
63 an already supported device (0458:704c):
64 # echo "0458 7045 0 0458 704c" > /sys/bus/usb/drivers/foo/new_id
65
60 Reading from this file will list all dynamically added 66 Reading from this file will list all dynamically added
61 device IDs in the same format, with one entry per 67 device IDs in the same format, with one entry per
62 line. For example: 68 line. For example:
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 @@
37 * and cause the driver to probe for all devices again. 37 * and cause the driver to probe for all devices again.
38 */ 38 */
39ssize_t usb_store_new_id(struct usb_dynids *dynids, 39ssize_t usb_store_new_id(struct usb_dynids *dynids,
40 const struct usb_device_id *id_table,
40 struct device_driver *driver, 41 struct device_driver *driver,
41 const char *buf, size_t count) 42 const char *buf, size_t count)
42{ 43{
@@ -44,11 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
44 u32 idVendor = 0; 45 u32 idVendor = 0;
45 u32 idProduct = 0; 46 u32 idProduct = 0;
46 unsigned int bInterfaceClass = 0; 47 unsigned int bInterfaceClass = 0;
48 u32 refVendor, refProduct;
47 int fields = 0; 49 int fields = 0;
48 int retval = 0; 50 int retval = 0;
49 51
50 fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct, 52 fields = sscanf(buf, "%x %x %x %x %x", &idVendor, &idProduct,
51 &bInterfaceClass); 53 &bInterfaceClass, &refVendor, &refProduct);
52 if (fields < 2) 54 if (fields < 2)
53 return -EINVAL; 55 return -EINVAL;
54 56
@@ -68,6 +70,16 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
68 dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS; 70 dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
69 } 71 }
70 72
73 if (fields > 4) {
74 const struct usb_device_id *id = id_table;
75
76 for (; id->match_flags; id++)
77 if (id->idVendor == refVendor && id->idProduct == refProduct) {
78 dynid->id.driver_info = id->driver_info;
79 break;
80 }
81 }
82
71 spin_lock(&dynids->lock); 83 spin_lock(&dynids->lock);
72 list_add_tail(&dynid->node, &dynids->list); 84 list_add_tail(&dynid->node, &dynids->list);
73 spin_unlock(&dynids->lock); 85 spin_unlock(&dynids->lock);
@@ -109,7 +121,7 @@ static ssize_t new_id_store(struct device_driver *driver,
109{ 121{
110 struct usb_driver *usb_drv = to_usb_driver(driver); 122 struct usb_driver *usb_drv = to_usb_driver(driver);
111 123
112 return usb_store_new_id(&usb_drv->dynids, driver, buf, count); 124 return usb_store_new_id(&usb_drv->dynids, usb_drv->id_table, driver, buf, count);
113} 125}
114static DRIVER_ATTR_RW(new_id); 126static DRIVER_ATTR_RW(new_id);
115 127
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 6335490d5760..35a2373cde67 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,
125 const char *buf, size_t count) 125 const char *buf, size_t count)
126{ 126{
127 struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); 127 struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
128 ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); 128 ssize_t retval = usb_store_new_id(&usb_drv->dynids, usb_drv->id_table,
129 driver, buf, count);
129 130
130 if (retval >= 0 && usb_drv->usb_driver != NULL) 131 if (retval >= 0 && usb_drv->usb_driver != NULL)
131 retval = usb_store_new_id(&usb_drv->usb_driver->dynids, 132 retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
133 usb_drv->usb_driver->id_table,
132 &usb_drv->usb_driver->drvwrap.driver, 134 &usb_drv->usb_driver->drvwrap.driver,
133 buf, count); 135 buf, count);
134 return retval; 136 return retval;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 512ab162832c..c716da18c668 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -965,6 +965,7 @@ struct usb_dynid {
965}; 965};
966 966
967extern ssize_t usb_store_new_id(struct usb_dynids *dynids, 967extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
968 const struct usb_device_id *id_table,
968 struct device_driver *driver, 969 struct device_driver *driver,
969 const char *buf, size_t count); 970 const char *buf, size_t count);
970 971