--- zzzz-none-000/linux-3.10.107/drivers/usb/core/driver.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/usb/core/driver.c 2021-02-04 17:41:59.000000000 +0000 @@ -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 @@ 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 @@ 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 @@ if (retval) return retval; return count; + +fail: + kfree(dynid); + return retval; } EXPORT_SYMBOL_GPL(usb_store_new_id); @@ -94,32 +125,27 @@ } EXPORT_SYMBOL_GPL(usb_show_dynids); -static ssize_t show_dynids(struct device_driver *driver, char *buf) +static ssize_t new_id_show(struct device_driver *driver, char *buf) { struct usb_driver *usb_drv = to_usb_driver(driver); return usb_show_dynids(&usb_drv->dynids, buf); } -static ssize_t store_new_id(struct device_driver *driver, +static ssize_t new_id_store(struct device_driver *driver, const char *buf, size_t count) { 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(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id); +static DRIVER_ATTR_RW(new_id); -/** - * store_remove_id - remove a USB device ID from this driver - * @driver: target device driver - * @buf: buffer for scanning device ID data - * @count: input size - * - * Removes a dynamic usb device ID from this driver. +/* + * Remove a USB device ID from this driver */ -static ssize_t -store_remove_id(struct device_driver *driver, const char *buf, size_t count) +static ssize_t remove_id_store(struct device_driver *driver, const char *buf, + size_t count) { struct usb_dynid *dynid, *n; struct usb_driver *usb_driver = to_usb_driver(driver); @@ -134,6 +160,7 @@ spin_lock(&usb_driver->dynids.lock); list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) { struct usb_device_id *id = &dynid->id; + if ((id->idVendor == idVendor) && (id->idProduct == idProduct)) { list_del(&dynid->node); @@ -144,7 +171,12 @@ spin_unlock(&usb_driver->dynids.lock); return count; } -static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id); + +static ssize_t remove_id_show(struct device_driver *driver, char *buf) +{ + return new_id_show(driver, buf); +} +static DRIVER_ATTR_RW(remove_id); static int usb_create_newid_files(struct usb_driver *usb_drv) { @@ -244,21 +276,6 @@ return 0; } -/* - * Cancel any pending scheduled resets - * - * [see usb_queue_reset_device()] - * - * Called after unconfiguring / when releasing interfaces. See - * comments in __usb_queue_reset_device() regarding - * udev->reset_running. - */ -static void usb_cancel_queued_reset(struct usb_interface *iface) -{ - if (iface->reset_running == 0) - cancel_work_sync(&iface->reset_ws); -} - /* called from driver core with dev locked */ static int usb_probe_interface(struct device *dev) { @@ -267,7 +284,7 @@ struct usb_device *udev = interface_to_usbdev(intf); const struct usb_device_id *id; int error = -ENODEV; - int lpm_disable_error; + int lpm_disable_error = -ENODEV; dev_dbg(dev, "%s\n", __func__); @@ -279,11 +296,22 @@ if (udev->authorized == 0) { dev_err(&intf->dev, "Device is not authorized for usage\n"); return error; + } else if (intf->authorized == 0) { + dev_err(&intf->dev, "Interface %d is not authorized for usage\n", + intf->altsetting->desc.bInterfaceNumber); + return error; + } + +#if 1 /* == 20170908 AVM/VGJ - CHANGESET: noprobe Extension for AURA == */ + if (udev->noprobe) { + dev_err(&intf->dev, "Probing is disabled for this device\n"); + return error; } +#endif - id = usb_match_id(intf, driver->id_table); + id = usb_match_dynamic_id(intf, driver); if (!id) - id = usb_match_dynamic_id(intf, driver); + id = usb_match_id(intf, driver->id_table); if (!id) return error; @@ -315,12 +343,14 @@ * setting during probe, that should also be fine. usb_set_interface() * will attempt to disable LPM, and fail if it can't disable it. */ - lpm_disable_error = usb_unlocked_disable_lpm(udev); - if (lpm_disable_error && driver->disable_hub_initiated_lpm) { - dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", - __func__, driver->name); - error = lpm_disable_error; - goto err; + if (driver->disable_hub_initiated_lpm) { + lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (lpm_disable_error) { + dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", + __func__, driver->name); + error = lpm_disable_error; + goto err; + } } /* Carry out a deferred switch to altsetting 0 */ @@ -349,7 +379,6 @@ usb_set_intfdata(intf, NULL); intf->needs_remote_wakeup = 0; intf->condition = USB_INTERFACE_UNBOUND; - usb_cancel_queued_reset(intf); /* If the LPM disable succeeded, balance the ref counts. */ if (!lpm_disable_error) @@ -369,8 +398,10 @@ { struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); + struct usb_host_endpoint *ep, **eps = NULL; struct usb_device *udev; - int error, r, lpm_disable_error; + int i, j, error, r; + int lpm_disable_error = -ENODEV; intf->condition = USB_INTERFACE_UNBINDING; @@ -378,21 +409,40 @@ udev = interface_to_usbdev(intf); error = usb_autoresume_device(udev); - /* Hub-initiated LPM policy may change, so attempt to disable LPM until + /* If hub-initiated LPM policy may change, attempt to disable LPM until * the driver is unbound. If LPM isn't disabled, that's fine because it * wouldn't be enabled unless all the bound interfaces supported * hub-initiated LPM. */ - lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (driver->disable_hub_initiated_lpm) + lpm_disable_error = usb_unlocked_disable_lpm(udev); - /* Terminate all URBs for this interface unless the driver - * supports "soft" unbinding. + /* + * Terminate all URBs for this interface unless the driver + * supports "soft" unbinding and the device is still present. */ - if (!driver->soft_unbind) + if (!driver->soft_unbind || udev->state == USB_STATE_NOTATTACHED) usb_disable_interface(udev, intf, false); driver->disconnect(intf); - usb_cancel_queued_reset(intf); + + /* Free streams */ + for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { + ep = &intf->cur_altsetting->endpoint[i]; + if (ep->streams == 0) + continue; + if (j == 0) { + eps = kmalloc_array(USB_MAXENDPOINTS, sizeof(void *), + GFP_KERNEL); + if (!eps) + break; + } + eps[j++] = ep; + } + if (j) { + usb_free_streams(intf, eps, j, GFP_KERNEL); + kfree(eps); + } /* Reset other interface state. * We cannot do a Set-Interface if the device is suspended or @@ -457,6 +507,8 @@ * Callers must own the device lock, so driver probe() entries don't need * extra locking, but other call contexts may need to explicitly claim that * lock. + * + * Return: 0 on success. */ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) @@ -464,7 +516,7 @@ struct device *dev; struct usb_device *udev; int retval = 0; - int lpm_disable_error; + int lpm_disable_error = -ENODEV; if (!iface) return -ENODEV; @@ -473,6 +525,10 @@ if (dev->driver) return -EBUSY; + /* reject claim if interface is not authorized */ + if (!iface->authorized) + return -ENODEV; + udev = interface_to_usbdev(iface); dev->driver = &driver->drvwrap.driver; @@ -481,12 +537,14 @@ iface->condition = USB_INTERFACE_BOUND; - /* Disable LPM until this driver is bound. */ - lpm_disable_error = usb_unlocked_disable_lpm(udev); - if (lpm_disable_error && driver->disable_hub_initiated_lpm) { - dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", - __func__, driver->name); - return -ENOMEM; + /* See the comment about disabling LPM in usb_probe_interface(). */ + if (driver->disable_hub_initiated_lpm) { + lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (lpm_disable_error) { + dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", + __func__, driver->name); + return -ENOMEM; + } } /* Claimed interfaces are initially inactive (suspended) and @@ -662,6 +720,8 @@ * These device tables are exported with MODULE_DEVICE_TABLE, through * modutils, to support the driver loading functionality of USB hotplugging. * + * Return: The first matching usb_device_id, or %NULL. + * * What Matches: * * The "match_flags" element in a usb_device_id controls which @@ -827,7 +887,8 @@ * Registers a USB device driver with the USB core. The list of * unattached devices will be rescanned whenever a new driver is * added, allowing the new driver to attach to any recognized devices. - * Returns a negative error code on failure and 0 on success. + * + * Return: A negative error code on failure and 0 on success. */ int usb_register_device_driver(struct usb_device_driver *new_udriver, struct module *owner) @@ -838,7 +899,7 @@ 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; @@ -883,7 +944,8 @@ * Registers a USB interface driver with the USB core. The list of * unattached interfaces will be rescanned whenever a new driver is * added, allowing the new driver to attach to any recognized interfaces. - * Returns a negative error code on failure and 0 on success. + * + * Return: A negative error code on failure and 0 on success. * * NOTE: if you want your driver to use the USB major number, you must call * usb_register_dev() to enable that functionality. This function no longer @@ -898,7 +960,7 @@ 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; @@ -1195,8 +1257,8 @@ "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); @@ -1235,6 +1297,8 @@ * unpredictable times. * * This routine can run only in process context. + * + * Return: 0 if the suspend succeeded. */ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) { @@ -1316,6 +1380,8 @@ * unpredictable times. * * This routine can run only in process context. + * + * Return: 0 on success. */ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) { @@ -1434,10 +1500,6 @@ return status; } -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME - /** * usb_enable_autosuspend - allow a USB device to be autosuspended * @udev: the USB device which may be autosuspended @@ -1513,6 +1575,8 @@ * The caller must hold @udev's device lock. * * This routine can run only in process context. + * + * Return: 0 on success. A negative error code otherwise. */ int usb_autoresume_device(struct usb_device *udev) { @@ -1622,6 +1686,8 @@ * However if the autoresume fails then the counter is re-decremented. * * This routine can run only in process context. + * + * Return: 0 on success. */ int usb_autopm_get_interface(struct usb_interface *intf) { @@ -1655,6 +1721,8 @@ * resumed. * * This routine can run in atomic context. + * + * Return: 0 on success. A negative error code otherwise. */ int usb_autopm_get_interface_async(struct usb_interface *intf) { @@ -1736,6 +1804,18 @@ dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n"); return -EOPNOTSUPP; } + + /* + * If the device is a direct child of the root hub and the HCD + * doesn't handle wakeup requests, don't allow autosuspend when + * wakeup is needed. + */ + if (w && udev->parent == udev->bus->root_hub && + bus_to_hcd(udev->bus)->cant_recv_wakeups) { + dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n"); + return -EOPNOTSUPP; + } + udev->do_remote_wakeup = w; return 0; } @@ -1790,7 +1870,8 @@ */ if (autosuspend_check(udev) == 0) pm_runtime_autosuspend(dev); - return 0; + /* Tell the core not to suspend it, though. */ + return -EBUSY; } int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) @@ -1798,6 +1879,9 @@ 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) @@ -1807,7 +1891,7 @@ return ret; } -#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ struct bus_type usb_bus_type = { .name = "usb",