diff options
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r-- | drivers/usb/core/driver.c | 50 |
1 files changed, 42 insertions, 8 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index f7841d44fed..ab90a015682 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; @@ -1179,8 +1210,8 @@ static int usb_resume_interface(struct usb_device *udev, "reset_resume", status); } else { intf->needs_binding = 1; - dev_warn(&intf->dev, "no %s for driver %s?\n", - "reset_resume", driver->name); + dev_dbg(&intf->dev, "no reset_resume for driver %s?\n", + driver->name); } } else { status = driver->resume(intf); @@ -1790,6 +1821,9 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; + if (enable && !udev->usb2_hw_lpm_allowed) + return 0; + if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) |