Browse Source

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>
Wolfram Sang 11 years ago
parent
commit
2fc82c2de6

+ 8 - 2
Documentation/ABI/testing/sysfs-bus-usb

@@ -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:

+ 15 - 3
drivers/usb/core/driver.c

@@ -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,
-					&bInterfaceClass);
+	fields = sscanf(buf, "%x %x %x %x %x", &idVendor, &idProduct,
+			&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);
 
 

+ 3 - 1
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)
 			    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;

+ 1 - 0
include/linux/usb.h

@@ -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);