diff options
Diffstat (limited to 'drivers/usb/core/driver.c')
| -rw-r--r-- | drivers/usb/core/driver.c | 43 | 
1 files changed, 37 insertions, 6 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 47aade2a5e74..ab90a0156828 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -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; @@ -60,11 +62,36 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,  	dynid->id.idVendor = idVendor;  	dynid->id.idProduct = idProduct;  	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; -	if (fields == 3) { +	if (fields > 2 && bInterfaceClass) { +		if (bInterfaceClass > 255) { +			retval = -EINVAL; +			goto fail; +		} +  		dynid->id.bInterfaceClass = (u8)bInterfaceClass;  		dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;  	} +	if (fields > 4) { +		const struct usb_device_id *id = id_table; + +		if (!id) { +			retval = -ENODEV; +			goto fail; +		} + +		for (; id->match_flags; id++) +			if (id->idVendor == refVendor && id->idProduct == refProduct) +				break; + +		if (id->match_flags) { +			dynid->id.driver_info = id->driver_info; +		} else { +			retval = -ENODEV; +			goto fail; +		} +	} +  	spin_lock(&dynids->lock);  	list_add_tail(&dynid->node, &dynids->list);  	spin_unlock(&dynids->lock); @@ -74,6 +101,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,  	if (retval)  		return retval;  	return count; + +fail: +	kfree(dynid); +	return retval;  }  EXPORT_SYMBOL_GPL(usb_store_new_id); @@ -106,7 +137,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); @@ -839,7 +870,7 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,  		return -ENODEV;  	new_udriver->drvwrap.for_devices = 1; -	new_udriver->drvwrap.driver.name = (char *) new_udriver->name; +	new_udriver->drvwrap.driver.name = new_udriver->name;  	new_udriver->drvwrap.driver.bus = &usb_bus_type;  	new_udriver->drvwrap.driver.probe = usb_probe_device;  	new_udriver->drvwrap.driver.remove = usb_unbind_device; @@ -900,7 +931,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,  		return -ENODEV;  	new_driver->drvwrap.for_devices = 0; -	new_driver->drvwrap.driver.name = (char *) new_driver->name; +	new_driver->drvwrap.driver.name = new_driver->name;  	new_driver->drvwrap.driver.bus = &usb_bus_type;  	new_driver->drvwrap.driver.probe = usb_probe_interface;  	new_driver->drvwrap.driver.remove = usb_unbind_interface;  | 
