--- zzzz-none-000/linux-3.10.107/drivers/usb/core/sysfs.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/usb/core/sysfs.c 2021-02-04 17:41:59.000000000 +0000 @@ -18,62 +18,70 @@ /* Active configuration fields */ #define usb_actconfig_show(field, format_string) \ -static ssize_t show_##field(struct device *dev, \ - struct device_attribute *attr, char *buf) \ +static ssize_t field##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ + ssize_t rc = 0; \ \ udev = to_usb_device(dev); \ + usb_lock_device(udev); \ actconfig = udev->actconfig; \ if (actconfig) \ - return sprintf(buf, format_string, \ + rc = sprintf(buf, format_string, \ actconfig->desc.field); \ - else \ - return 0; \ + usb_unlock_device(udev); \ + return rc; \ } \ #define usb_actconfig_attr(field, format_string) \ usb_actconfig_show(field, format_string) \ - static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); + static DEVICE_ATTR_RO(field) -usb_actconfig_attr(bNumInterfaces, "%2d\n") -usb_actconfig_attr(bmAttributes, "%2x\n") +usb_actconfig_attr(bNumInterfaces, "%2d\n"); +usb_actconfig_attr(bmAttributes, "%2x\n"); -static ssize_t show_bMaxPower(struct device *dev, +static ssize_t bMaxPower_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; struct usb_host_config *actconfig; + ssize_t rc = 0; udev = to_usb_device(dev); + usb_lock_device(udev); actconfig = udev->actconfig; - if (!actconfig) - return 0; - return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); + if (actconfig) + rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); + usb_unlock_device(udev); + return rc; } -static DEVICE_ATTR(bMaxPower, S_IRUGO, show_bMaxPower, NULL); +static DEVICE_ATTR_RO(bMaxPower); -static ssize_t show_configuration_string(struct device *dev, +static ssize_t configuration_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; struct usb_host_config *actconfig; + ssize_t rc = 0; udev = to_usb_device(dev); + usb_lock_device(udev); actconfig = udev->actconfig; - if ((!actconfig) || (!actconfig->string)) - return 0; - return sprintf(buf, "%s\n", actconfig->string); + if (actconfig && actconfig->string) + rc = sprintf(buf, "%s\n", actconfig->string); + usb_unlock_device(udev); + return rc; } -static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); +static DEVICE_ATTR_RO(configuration); /* configuration value is always present, and r/w */ usb_actconfig_show(bConfigurationValue, "%u\n"); -static ssize_t -set_bConfigurationValue(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t bConfigurationValue_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); int config, value; @@ -85,13 +93,12 @@ usb_unlock_device(udev); return (value < 0) ? value : count; } - static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR, - show_bConfigurationValue, set_bConfigurationValue); + bConfigurationValue_show, bConfigurationValue_store); /* String fields */ #define usb_string_attr(name) \ -static ssize_t show_##name(struct device *dev, \ +static ssize_t name##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ @@ -103,14 +110,14 @@ usb_unlock_device(udev); \ return retval; \ } \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); +static DEVICE_ATTR_RO(name) usb_string_attr(product); usb_string_attr(manufacturer); usb_string_attr(serial); -static ssize_t -show_speed(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t speed_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; char *speed; @@ -139,40 +146,40 @@ } return sprintf(buf, "%s\n", speed); } -static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); +static DEVICE_ATTR_RO(speed); -static ssize_t -show_busnum(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t busnum_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; udev = to_usb_device(dev); return sprintf(buf, "%d\n", udev->bus->busnum); } -static DEVICE_ATTR(busnum, S_IRUGO, show_busnum, NULL); +static DEVICE_ATTR_RO(busnum); -static ssize_t -show_devnum(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t devnum_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; udev = to_usb_device(dev); return sprintf(buf, "%d\n", udev->devnum); } -static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); +static DEVICE_ATTR_RO(devnum); -static ssize_t -show_devpath(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t devpath_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; udev = to_usb_device(dev); return sprintf(buf, "%s\n", udev->devpath); } -static DEVICE_ATTR(devpath, S_IRUGO, show_devpath, NULL); +static DEVICE_ATTR_RO(devpath); -static ssize_t -show_version(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t version_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; u16 bcdUSB; @@ -181,30 +188,30 @@ bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB); return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff); } -static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); +static DEVICE_ATTR_RO(version); -static ssize_t -show_maxchild(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxchild_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; udev = to_usb_device(dev); return sprintf(buf, "%d\n", udev->maxchild); } -static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); +static DEVICE_ATTR_RO(maxchild); -static ssize_t -show_quirks(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t quirks_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; udev = to_usb_device(dev); return sprintf(buf, "0x%x\n", udev->quirks); } -static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); +static DEVICE_ATTR_RO(quirks); -static ssize_t -show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t avoid_reset_quirk_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_device *udev; @@ -212,9 +219,9 @@ return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET)); } -static ssize_t -set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t avoid_reset_quirk_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); int val; @@ -229,22 +236,20 @@ usb_unlock_device(udev); return count; } +static DEVICE_ATTR_RW(avoid_reset_quirk); -static DEVICE_ATTR(avoid_reset_quirk, S_IRUGO | S_IWUSR, - show_avoid_reset_quirk, set_avoid_reset_quirk); - -static ssize_t -show_urbnum(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; udev = to_usb_device(dev); return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); } -static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); +static DEVICE_ATTR_RO(urbnum); -static ssize_t -show_removable(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t removable_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev; char *state; @@ -264,30 +269,29 @@ return sprintf(buf, "%s\n", state); } -static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL); +static DEVICE_ATTR_RO(removable); -static ssize_t -show_ltm_capable(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t ltm_capable_show(struct device *dev, + struct device_attribute *attr, char *buf) { if (usb_device_supports_ltm(to_usb_device(dev))) return sprintf(buf, "%s\n", "yes"); return sprintf(buf, "%s\n", "no"); } -static DEVICE_ATTR(ltm_capable, S_IRUGO, show_ltm_capable, NULL); +static DEVICE_ATTR_RO(ltm_capable); #ifdef CONFIG_PM -static ssize_t -show_persist(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t persist_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev = to_usb_device(dev); return sprintf(buf, "%d\n", udev->persist_enabled); } -static ssize_t -set_persist(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t persist_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); int value; @@ -304,8 +308,7 @@ usb_unlock_device(udev); return count; } - -static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist); +static DEVICE_ATTR_RW(persist); static int add_persist_attributes(struct device *dev) { @@ -331,26 +334,16 @@ &dev_attr_persist.attr, power_group_name); } -#else - -#define add_persist_attributes(dev) 0 -#define remove_persist_attributes(dev) do {} while (0) - -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME -static ssize_t -show_connected_duration(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t connected_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_device *udev = to_usb_device(dev); return sprintf(buf, "%u\n", jiffies_to_msecs(jiffies - udev->connect_time)); } - -static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL); +static DEVICE_ATTR_RO(connected_duration); /* * If the device is resumed, the last time the device was suspended has @@ -359,9 +352,8 @@ * * If the device is suspended, the active_duration is up-to-date. */ -static ssize_t -show_active_duration(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t active_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_device *udev = to_usb_device(dev); int duration; @@ -372,18 +364,17 @@ duration = jiffies_to_msecs(udev->active_duration); return sprintf(buf, "%u\n", duration); } +static DEVICE_ATTR_RO(active_duration); -static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL); - -static ssize_t -show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t autosuspend_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000); } -static ssize_t -set_autosuspend(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t autosuspend_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { int value; @@ -391,17 +382,23 @@ value <= -INT_MAX/1000) return -EINVAL; +/* == 20171115 AVM/VGJ Prevent suspension of blacklisted devices == */ +#if defined (CONFIG_AVM_USB_PM) + if (avm_usb_pm_is_blacklisted(to_usb_device(dev))) { + value = -1; + } +#endif + pm_runtime_set_autosuspend_delay(dev, value * 1000); return count; } - -static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR, - show_autosuspend, set_autosuspend); +static DEVICE_ATTR_RW(autosuspend); static const char on_string[] = "on"; static const char auto_string[] = "auto"; -static void warn_level(void) { +static void warn_level(void) +{ static int level_warned; if (!level_warned) { @@ -411,8 +408,8 @@ } } -static ssize_t -show_level(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t level_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_device *udev = to_usb_device(dev); const char *p = auto_string; @@ -423,9 +420,8 @@ return sprintf(buf, "%s\n", p); } -static ssize_t -set_level(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t level_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); int len = count; @@ -453,17 +449,15 @@ usb_unlock_device(udev); return rc; } +static DEVICE_ATTR_RW(level); -static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level); - -static ssize_t -show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t usb2_hardware_lpm_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_device *udev = to_usb_device(dev); const char *p; - if (udev->usb2_hw_lpm_enabled == 1) + if (udev->usb2_hw_lpm_allowed == 1) p = "enabled"; else p = "disabled"; @@ -471,9 +465,9 @@ return sprintf(buf, "%s\n", p); } -static ssize_t -set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t usb2_hardware_lpm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); bool value; @@ -483,8 +477,10 @@ ret = strtobool(buf, &value); - if (!ret) + if (!ret) { + udev->usb2_hw_lpm_allowed = value; ret = usb_set_usb2_hardware_lpm(udev, value); + } usb_unlock_device(udev); @@ -493,12 +489,97 @@ return ret; } +static DEVICE_ATTR_RW(usb2_hardware_lpm); + +static ssize_t usb2_lpm_l1_timeout_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->l1_params.timeout); +} + +static ssize_t usb2_lpm_l1_timeout_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_device *udev = to_usb_device(dev); + u16 timeout; + + if (kstrtou16(buf, 0, &timeout)) + return -EINVAL; + + udev->l1_params.timeout = timeout; + + return count; +} +static DEVICE_ATTR_RW(usb2_lpm_l1_timeout); + +static ssize_t usb2_lpm_besl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->l1_params.besl); +} + +static ssize_t usb2_lpm_besl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_device *udev = to_usb_device(dev); + u8 besl; + + if (kstrtou8(buf, 0, &besl) || besl > 15) + return -EINVAL; + + udev->l1_params.besl = besl; -static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm, - set_usb2_hardware_lpm); + return count; +} +static DEVICE_ATTR_RW(usb2_lpm_besl); + +static ssize_t usb3_hardware_lpm_u1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + const char *p; + + usb_lock_device(udev); + + if (udev->usb3_lpm_u1_enabled) + p = "enabled"; + else + p = "disabled"; + + usb_unlock_device(udev); + + return sprintf(buf, "%s\n", p); +} +static DEVICE_ATTR_RO(usb3_hardware_lpm_u1); + +static ssize_t usb3_hardware_lpm_u2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + const char *p; + + usb_lock_device(udev); + + if (udev->usb3_lpm_u2_enabled) + p = "enabled"; + else + p = "disabled"; + + usb_unlock_device(udev); + + return sprintf(buf, "%s\n", p); +} +static DEVICE_ATTR_RO(usb3_hardware_lpm_u2); static struct attribute *usb2_hardware_lpm_attr[] = { &dev_attr_usb2_hardware_lpm.attr, + &dev_attr_usb2_lpm_l1_timeout.attr, + &dev_attr_usb2_lpm_besl.attr, NULL, }; static struct attribute_group usb2_hardware_lpm_attr_group = { @@ -506,6 +587,16 @@ .attrs = usb2_hardware_lpm_attr, }; +static struct attribute *usb3_hardware_lpm_attr[] = { + &dev_attr_usb3_hardware_lpm_u1.attr, + &dev_attr_usb3_hardware_lpm_u2.attr, + NULL, +}; +static struct attribute_group usb3_hardware_lpm_attr_group = { + .name = power_group_name, + .attrs = usb3_hardware_lpm_attr, +}; + static struct attribute *power_attrs[] = { &dev_attr_autosuspend.attr, &dev_attr_level.attr, @@ -528,6 +619,10 @@ if (udev->usb2_hw_lpm_capable == 1) rc = sysfs_merge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); + if (udev->speed == USB_SPEED_SUPER && + udev->lpm_capable == 1) + rc = sysfs_merge_group(&dev->kobj, + &usb3_hardware_lpm_attr_group); } return rc; @@ -541,16 +636,19 @@ #else +#define add_persist_attributes(dev) 0 +#define remove_persist_attributes(dev) do {} while (0) + #define add_power_attributes(dev) 0 #define remove_power_attributes(dev) do {} while (0) -#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ -show_##field(struct device *dev, struct device_attribute *attr, \ +field##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_device *udev; \ @@ -559,15 +657,15 @@ return sprintf(buf, format_string, \ le16_to_cpu(udev->descriptor.field)); \ } \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); +static DEVICE_ATTR_RO(field) -usb_descriptor_attr_le16(idVendor, "%04x\n") -usb_descriptor_attr_le16(idProduct, "%04x\n") -usb_descriptor_attr_le16(bcdDevice, "%04x\n") +usb_descriptor_attr_le16(idVendor, "%04x\n"); +usb_descriptor_attr_le16(idProduct, "%04x\n"); +usb_descriptor_attr_le16(bcdDevice, "%04x\n"); #define usb_descriptor_attr(field, format_string) \ static ssize_t \ -show_##field(struct device *dev, struct device_attribute *attr, \ +field##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_device *udev; \ @@ -575,34 +673,31 @@ udev = to_usb_device(dev); \ return sprintf(buf, format_string, udev->descriptor.field); \ } \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); - -usb_descriptor_attr(bDeviceClass, "%02x\n") -usb_descriptor_attr(bDeviceSubClass, "%02x\n") -usb_descriptor_attr(bDeviceProtocol, "%02x\n") -usb_descriptor_attr(bNumConfigurations, "%d\n") -usb_descriptor_attr(bMaxPacketSize0, "%d\n") +static DEVICE_ATTR_RO(field) +usb_descriptor_attr(bDeviceClass, "%02x\n"); +usb_descriptor_attr(bDeviceSubClass, "%02x\n"); +usb_descriptor_attr(bDeviceProtocol, "%02x\n"); +usb_descriptor_attr(bNumConfigurations, "%d\n"); +usb_descriptor_attr(bMaxPacketSize0, "%d\n"); /* show if the device is authorized (1) or not (0) */ -static ssize_t usb_dev_authorized_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t authorized_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_device *usb_dev = to_usb_device(dev); return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized); } - /* * Authorize a device to be used in the system * * Writing a 0 deauthorizes the device, writing a 1 authorizes it. */ -static ssize_t usb_dev_authorized_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) +static ssize_t authorized_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) { ssize_t result; struct usb_device *usb_dev = to_usb_device(dev); @@ -614,16 +709,14 @@ result = usb_deauthorize_device(usb_dev); else result = usb_authorize_device(usb_dev); - return result < 0? result : size; + return result < 0 ? result : size; } - -static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644, - usb_dev_authorized_show, usb_dev_authorized_store); +static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR, + authorized_show, authorized_store); /* "Safely remove a device" */ -static ssize_t usb_remove_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t remove_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); int rc = 0; @@ -640,8 +733,70 @@ usb_unlock_device(udev); return rc; } -static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store); +static DEVICE_ATTR_IGNORE_LOCKDEP(remove, S_IWUSR, NULL, remove_store); + +#if 1 /* == 20160222 AVM/VGJ - CHANGESET: noprobe Extension for AURA == */ + +/* show if probing is allowed (0) or not allowed (1) for the device */ +static ssize_t usb_dev_noprobe_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *usb_dev = to_usb_device(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->noprobe); +} + +/* + * Prevent probing for a device + * (configures or deconfigures the device as a side effect) + * + * Writing a 0 allows probing and reconfigures the device + * writing a 1 prevents probing and unconfigures the device it + * writing a 2 prevents probing and resets the device + * + */ +static ssize_t usb_dev_noprobe_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + struct usb_device *usb_dev = to_usb_device(dev); + unsigned val; + result = sscanf(buf, "%u\n", &val); + if (result != 1) + result = -EINVAL; + else { + usb_lock_device(usb_dev); + if (val == 0) { + int c,err; + usb_dev->noprobe = 0; + c = usb_choose_configuration(usb_dev); + if (c >= 0) { + err = usb_set_configuration(usb_dev, c); + if (err) { + dev_err(&usb_dev->dev, + "can't set config #%d, error %d\n", c, err); + /* This need not be fatal. The user can try to + * set other configurations. */ + } + } + } else { + usb_dev->noprobe = 1; + usb_set_configuration(usb_dev, -1); + /* == 20160219 AVM/VGJ - CHANGESET: noprobe: extra value 2 resets device */ + if (val == 2) { + usb_reset_device (usb_dev); + } + } + usb_unlock_device(usb_dev); + } + return result < 0? result : size; +} + +static DEVICE_ATTR(noprobe, 0644, + usb_dev_noprobe_show, usb_dev_noprobe_store); +#endif static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -672,6 +827,9 @@ &dev_attr_remove.attr, &dev_attr_removable.attr, &dev_attr_ltm_capable.attr, +#if 1 /* == 20160222 AVM/VGJ - CHANGESET: noprobe Extension == */ + &dev_attr_noprobe.attr, +#endif NULL, }; static struct attribute_group dev_attr_grp = { @@ -736,6 +894,7 @@ * Following that are the raw descriptor entries for all the * configurations (config plus subsidiary descriptors). */ + usb_lock_device(udev); for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && nleft > 0; ++cfgno) { if (cfgno < 0) { @@ -756,6 +915,7 @@ off -= srclen; } } + usb_unlock_device(udev); return count - nleft; } @@ -796,10 +956,10 @@ device_remove_bin_file(dev, &dev_bin_attr_descriptors); } -/* Interface Accociation Descriptor fields */ +/* Interface Association Descriptor fields */ #define usb_intf_assoc_attr(field, format_string) \ static ssize_t \ -show_iad_##field(struct device *dev, struct device_attribute *attr, \ +iad_##field##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ @@ -807,18 +967,18 @@ return sprintf(buf, format_string, \ intf->intf_assoc->field); \ } \ -static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL); +static DEVICE_ATTR_RO(iad_##field) -usb_intf_assoc_attr(bFirstInterface, "%02x\n") -usb_intf_assoc_attr(bInterfaceCount, "%02d\n") -usb_intf_assoc_attr(bFunctionClass, "%02x\n") -usb_intf_assoc_attr(bFunctionSubClass, "%02x\n") -usb_intf_assoc_attr(bFunctionProtocol, "%02x\n") +usb_intf_assoc_attr(bFirstInterface, "%02x\n"); +usb_intf_assoc_attr(bInterfaceCount, "%02d\n"); +usb_intf_assoc_attr(bFunctionClass, "%02x\n"); +usb_intf_assoc_attr(bFunctionSubClass, "%02x\n"); +usb_intf_assoc_attr(bFunctionProtocol, "%02x\n"); /* Interface fields */ #define usb_intf_attr(field, format_string) \ static ssize_t \ -show_##field(struct device *dev, struct device_attribute *attr, \ +field##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ @@ -826,33 +986,31 @@ return sprintf(buf, format_string, \ intf->cur_altsetting->desc.field); \ } \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); +static DEVICE_ATTR_RO(field) -usb_intf_attr(bInterfaceNumber, "%02x\n") -usb_intf_attr(bAlternateSetting, "%2d\n") -usb_intf_attr(bNumEndpoints, "%02x\n") -usb_intf_attr(bInterfaceClass, "%02x\n") -usb_intf_attr(bInterfaceSubClass, "%02x\n") -usb_intf_attr(bInterfaceProtocol, "%02x\n") +usb_intf_attr(bInterfaceNumber, "%02x\n"); +usb_intf_attr(bAlternateSetting, "%2d\n"); +usb_intf_attr(bNumEndpoints, "%02x\n"); +usb_intf_attr(bInterfaceClass, "%02x\n"); +usb_intf_attr(bInterfaceSubClass, "%02x\n"); +usb_intf_attr(bInterfaceProtocol, "%02x\n"); -static ssize_t show_interface_string(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t interface_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_interface *intf; char *string; intf = to_usb_interface(dev); - string = intf->cur_altsetting->string; - barrier(); /* The altsetting might change! */ - + string = ACCESS_ONCE(intf->cur_altsetting->string); if (!string) return 0; return sprintf(buf, "%s\n", string); } -static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); +static DEVICE_ATTR_RO(interface); -static ssize_t show_modalias(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct usb_interface *intf; struct usb_device *udev; @@ -860,7 +1018,7 @@ intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); - alt = intf->cur_altsetting; + alt = ACCESS_ONCE(intf->cur_altsetting); return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" "ic%02Xisc%02Xip%02Xin%02X\n", @@ -875,30 +1033,57 @@ alt->desc.bInterfaceProtocol, alt->desc.bInterfaceNumber); } -static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); +static DEVICE_ATTR_RO(modalias); + +static ssize_t supports_autosuspend_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int s; + + device_lock(dev); + /* Devices will be autosuspended even when an interface isn't claimed */ + s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend); + device_unlock(dev); + + return sprintf(buf, "%u\n", s); +} +static DEVICE_ATTR_RO(supports_autosuspend); -static ssize_t show_supports_autosuspend(struct device *dev, +/* + * interface_authorized_show - show authorization status of an USB interface + * 1 is authorized, 0 is deauthorized + */ +static ssize_t interface_authorized_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct usb_interface *intf; - struct usb_device *udev; - int ret; + struct usb_interface *intf = to_usb_interface(dev); - intf = to_usb_interface(dev); - udev = interface_to_usbdev(intf); + return sprintf(buf, "%u\n", intf->authorized); +} - usb_lock_device(udev); - /* Devices will be autosuspended even when an interface isn't claimed */ - if (!intf->dev.driver || - to_usb_driver(intf->dev.driver)->supports_autosuspend) - ret = sprintf(buf, "%u\n", 1); +/* + * interface_authorized_store - authorize or deauthorize an USB interface + */ +static ssize_t interface_authorized_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + bool val; + + if (strtobool(buf, &val) != 0) + return -EINVAL; + + if (val) + usb_authorize_interface(intf); else - ret = sprintf(buf, "%u\n", 0); - usb_unlock_device(udev); + usb_deauthorize_interface(intf); - return ret; + return count; } -static DEVICE_ATTR(supports_autosuspend, S_IRUGO, show_supports_autosuspend, NULL); +static struct device_attribute dev_attr_interface_authorized = + __ATTR(authorized, S_IRUGO | S_IWUSR, + interface_authorized_show, interface_authorized_store); static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceNumber.attr, @@ -909,6 +1094,7 @@ &dev_attr_bInterfaceProtocol.attr, &dev_attr_modalias.attr, &dev_attr_supports_autosuspend.attr, + &dev_attr_interface_authorized.attr, NULL, }; static struct attribute_group intf_attr_grp = {