--- zzzz-none-000/linux-4.19.183/drivers/usb/core/sysfs.c 2021-03-24 10:07:39.000000000 +0000 +++ bcm63-7530ax-756/linux-4.19.183/drivers/usb/core/sysfs.c 2023-06-28 08:54:20.000000000 +0000 @@ -329,6 +329,92 @@ } static DEVICE_ATTR_RO(ltm_capable); +/* == 20210723 AVM/WKR - AVM USB Suspend Feature (reworked) == */ +#if defined(CONFIG_AVM_USB_SUSPEND) + +static ssize_t +avm_usb_suspend_status_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret; + struct usb_device *udev = to_usb_device(dev); + + ret = sprintf(buf, "%s\n", udev->port_is_suspended ? "suspended" : "active"); + return ret; +} + +static DEVICE_ATTR_RO(avm_usb_suspend_status); + +static ssize_t +avm_usb_suspend_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + + return sprintf(buf, "%u\n", udev->avm_usb_suspend_enable); +} + +static ssize_t +avm_usb_suspend_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_device *udev = to_usb_device(dev); + unsigned int value; + + if (sscanf(buf, "%u", &value) != 1) + return -EINVAL; + + usb_lock_device(udev); + if (value) { + if (avm_usb_suspend_is_blacklisted(udev)) { + pr_err("USB device %04x:%04x:%04x is blacklisted for suspension\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + le16_to_cpu(udev->descriptor.bcdDevice)); + } else { + udev->avm_usb_suspend_enable = 1; + __avm_usb_suspend_start_timer(udev); + } + } else { + avm_usb_suspend_stop(udev); + __avm_usb_suspend_do_resume(udev); + } + usb_unlock_device(udev); + + return count; +} + +static DEVICE_ATTR_RW(avm_usb_suspend_enable); + +static ssize_t +avm_usb_suspend_delay_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(udev->avm_usb_suspend_delay)/1000); +} + +static ssize_t +avm_usb_suspend_delay_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_device *udev = to_usb_device(dev); + unsigned int seconds; + + if (sscanf(buf, "%u", &seconds) != 1) { + return -EINVAL; + } + + usb_lock_device(udev); + // Zero is accepted but it will prevent the device to suspend + udev->avm_usb_suspend_delay = (seconds == 0) ? 0 : msecs_to_jiffies(seconds*1000); + __avm_usb_suspend_start_timer(udev); + usb_unlock_device(udev); + + return count; +} + +static DEVICE_ATTR_RW(avm_usb_suspend_delay); +#endif //CONFIG_AVM_USB_SUSPEND + #ifdef CONFIG_PM static ssize_t persist_show(struct device *dev, struct device_attribute *attr, @@ -794,6 +880,72 @@ } static DEVICE_ATTR_IGNORE_LOCKDEP(remove, S_IWUSR, NULL, remove_store); +#ifdef CONFIG_AVM_KERNEL +/* == 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 int 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 is not always 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 */ @@ -826,6 +978,15 @@ &dev_attr_remove.attr, &dev_attr_removable.attr, &dev_attr_ltm_capable.attr, +#ifdef CONFIG_AVM_KERNEL + /* == 20160222 AVM/VGJ - CHANGESET: noprobe Extension == */ + &dev_attr_noprobe.attr, +#endif +#ifdef CONFIG_AVM_USB_SUSPEND + &dev_attr_avm_usb_suspend_status.attr, + &dev_attr_avm_usb_suspend_enable.attr, + &dev_attr_avm_usb_suspend_delay.attr, +#endif #ifdef CONFIG_OF &dev_attr_devspec.attr, #endif