Skip to content

Commit

Permalink
usb: core: allow a reference device for new_id
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Wolfram Sang authored and Greg Kroah-Hartman committed Jan 11, 2014
1 parent c63fe8f commit 2fc82c2
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 6 deletions.
10 changes: 8 additions & 2 deletions Documentation/ABI/testing/sysfs-bus-usb
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
18 changes: 15 additions & 3 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,20 @@
* 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)
{
struct usb_dynid *dynid;
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;

Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
4 changes: 3 additions & 1 deletion drivers/usb/serial/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 2fc82c2

Please sign in to comment.