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: Wolfram Sang <wsa@the-dreams.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
c63fe8f6ca
commit
2fc82c2de6
@@ -50,13 +50,19 @@ Description:
|
|||||||
This may allow the driver to support more hardware than
|
This may allow the driver to support more hardware than
|
||||||
was included in the driver's static device ID support
|
was included in the driver's static device ID support
|
||||||
table at compile time. The format for the device ID is:
|
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
|
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
|
Upon successfully adding an ID, the driver will probe
|
||||||
for the device and attempt to bind to it. For example:
|
for the device and attempt to bind to it. For example:
|
||||||
# echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id
|
# 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
|
Reading from this file will list all dynamically added
|
||||||
device IDs in the same format, with one entry per
|
device IDs in the same format, with one entry per
|
||||||
line. For example:
|
line. For example:
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
* and cause the driver to probe for all devices again.
|
* and cause the driver to probe for all devices again.
|
||||||
*/
|
*/
|
||||||
ssize_t usb_store_new_id(struct usb_dynids *dynids,
|
ssize_t usb_store_new_id(struct usb_dynids *dynids,
|
||||||
|
const struct usb_device_id *id_table,
|
||||||
struct device_driver *driver,
|
struct device_driver *driver,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
@@ -44,11 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
|
|||||||
u32 idVendor = 0;
|
u32 idVendor = 0;
|
||||||
u32 idProduct = 0;
|
u32 idProduct = 0;
|
||||||
unsigned int bInterfaceClass = 0;
|
unsigned int bInterfaceClass = 0;
|
||||||
|
u32 refVendor, refProduct;
|
||||||
int fields = 0;
|
int fields = 0;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct,
|
fields = sscanf(buf, "%x %x %x %x %x", &idVendor, &idProduct,
|
||||||
&bInterfaceClass);
|
&bInterfaceClass, &refVendor, &refProduct);
|
||||||
if (fields < 2)
|
if (fields < 2)
|
||||||
return -EINVAL;
|
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;
|
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);
|
spin_lock(&dynids->lock);
|
||||||
list_add_tail(&dynid->node, &dynids->list);
|
list_add_tail(&dynid->node, &dynids->list);
|
||||||
spin_unlock(&dynids->lock);
|
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);
|
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);
|
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)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
|
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)
|
if (retval >= 0 && usb_drv->usb_driver != NULL)
|
||||||
retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
|
retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
|
||||||
|
usb_drv->usb_driver->id_table,
|
||||||
&usb_drv->usb_driver->drvwrap.driver,
|
&usb_drv->usb_driver->drvwrap.driver,
|
||||||
buf, count);
|
buf, count);
|
||||||
return retval;
|
return retval;
|
||||||
|
@@ -965,6 +965,7 @@ struct usb_dynid {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
|
extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
|
||||||
|
const struct usb_device_id *id_table,
|
||||||
struct device_driver *driver,
|
struct device_driver *driver,
|
||||||
const char *buf, size_t count);
|
const char *buf, size_t count);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user