Commit 2fc82c2d authored by Wolfram Sang's avatar Wolfram Sang Committed by Greg Kroah-Hartman

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: default avatarWolfram Sang <wsa@the-dreams.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c63fe8f6
......@@ -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:
......
......@@ -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);
......
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment