Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+8 −2
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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);


+3 −1
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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);