diff options
Diffstat (limited to 'drivers/usb/core/sysfs.c')
-rw-r--r-- | drivers/usb/core/sysfs.c | 156 |
1 files changed, 110 insertions, 46 deletions
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 7ec3041ae79e..43c002e3a9aa 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -82,9 +82,13 @@ static ssize_t show_##name(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ + int retval; \ \ udev = to_usb_device(dev); \ - return sprintf(buf, "%s\n", udev->name); \ + usb_lock_device(udev); \ + retval = sprintf(buf, "%s\n", udev->name); \ + usb_unlock_device(udev); \ + return retval; \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); @@ -111,6 +115,12 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf) case USB_SPEED_HIGH: speed = "480"; break; + case USB_SPEED_WIRELESS: + speed = "480"; + break; + case USB_SPEED_SUPER: + speed = "5000"; + break; default: speed = "unknown"; } @@ -139,6 +149,16 @@ show_devnum(struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); static ssize_t +show_devpath(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 ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; @@ -171,6 +191,36 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); static ssize_t +show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET_MORPHS)); +} + +static ssize_t +set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_device *udev = to_usb_device(dev); + int config; + + if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1) + return -EINVAL; + usb_lock_device(udev); + if (config) + udev->quirks |= USB_QUIRK_RESET_MORPHS; + else + udev->quirks &= ~USB_QUIRK_RESET_MORPHS; + usb_unlock_device(udev); + return count; +} + +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) { struct usb_device *udev; @@ -206,9 +256,10 @@ set_persist(struct device *dev, struct device_attribute *attr, if (sscanf(buf, "%d", &value) != 1) return -EINVAL; - usb_pm_lock(udev); + + usb_lock_device(udev); udev->persist_enabled = !!value; - usb_pm_unlock(udev); + usb_unlock_device(udev); return count; } @@ -295,20 +346,34 @@ set_autosuspend(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); - int value; + int value, old_delay; + int rc; if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ || value <= - INT_MAX/HZ) return -EINVAL; value *= HZ; + usb_lock_device(udev); + old_delay = udev->autosuspend_delay; udev->autosuspend_delay = value; - if (value >= 0) - usb_try_autosuspend_device(udev); - else { - if (usb_autoresume_device(udev) == 0) + + if (old_delay < 0) { /* Autosuspend wasn't allowed */ + if (value >= 0) usb_autosuspend_device(udev); + } else { /* Autosuspend was allowed */ + if (value < 0) { + rc = usb_autoresume_device(udev); + if (rc < 0) { + count = rc; + udev->autosuspend_delay = old_delay; + } + } else { + usb_try_autosuspend_device(udev); + } } + + usb_unlock_device(udev); return count; } @@ -317,7 +382,6 @@ static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR, static const char on_string[] = "on"; static const char auto_string[] = "auto"; -static const char suspend_string[] = "suspend"; static ssize_t show_level(struct device *dev, struct device_attribute *attr, char *buf) @@ -325,13 +389,8 @@ show_level(struct device *dev, struct device_attribute *attr, char *buf) struct usb_device *udev = to_usb_device(dev); const char *p = auto_string; - if (udev->state == USB_STATE_SUSPENDED) { - if (udev->autoresume_disabled) - p = suspend_string; - } else { - if (udev->autosuspend_disabled) - p = on_string; - } + if (udev->state != USB_STATE_SUSPENDED && udev->autosuspend_disabled) + p = on_string; return sprintf(buf, "%s\n", p); } @@ -342,45 +401,25 @@ set_level(struct device *dev, struct device_attribute *attr, struct usb_device *udev = to_usb_device(dev); int len = count; char *cp; - int rc = 0; - int old_autosuspend_disabled, old_autoresume_disabled; + int rc; cp = memchr(buf, '\n', count); if (cp) len = cp - buf; usb_lock_device(udev); - old_autosuspend_disabled = udev->autosuspend_disabled; - old_autoresume_disabled = udev->autoresume_disabled; - /* Setting the flags without calling usb_pm_lock is a subject to - * races, but who cares... - */ if (len == sizeof on_string - 1 && - strncmp(buf, on_string, len) == 0) { - udev->autosuspend_disabled = 1; - udev->autoresume_disabled = 0; - rc = usb_external_resume_device(udev, PMSG_USER_RESUME); - - } else if (len == sizeof auto_string - 1 && - strncmp(buf, auto_string, len) == 0) { - udev->autosuspend_disabled = 0; - udev->autoresume_disabled = 0; - rc = usb_external_resume_device(udev, PMSG_USER_RESUME); - - } else if (len == sizeof suspend_string - 1 && - strncmp(buf, suspend_string, len) == 0) { - udev->autosuspend_disabled = 0; - udev->autoresume_disabled = 1; - rc = usb_external_suspend_device(udev, PMSG_USER_SUSPEND); - - } else + strncmp(buf, on_string, len) == 0) + rc = usb_disable_autosuspend(udev); + + else if (len == sizeof auto_string - 1 && + strncmp(buf, auto_string, len) == 0) + rc = usb_enable_autosuspend(udev); + + else rc = -EINVAL; - if (rc) { - udev->autosuspend_disabled = old_autosuspend_disabled; - udev->autoresume_disabled = old_autoresume_disabled; - } usb_unlock_device(udev); return (rc < 0 ? rc : count); } @@ -508,6 +547,28 @@ static ssize_t usb_dev_authorized_store(struct device *dev, static DEVICE_ATTR(authorized, 0644, usb_dev_authorized_show, usb_dev_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) +{ + struct usb_device *udev = to_usb_device(dev); + int rc = 0; + + usb_lock_device(udev); + if (udev->state != USB_STATE_NOTATTACHED) { + + /* To avoid races, first unconfigure and then remove */ + usb_set_configuration(udev, -1); + rc = usb_remove_device(udev); + } + if (rc == 0) + rc = count; + usb_unlock_device(udev); + return rc; +} +static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store); + static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -516,8 +577,8 @@ static struct attribute *dev_attrs[] = { &dev_attr_bConfigurationValue.attr, &dev_attr_bmAttributes.attr, &dev_attr_bMaxPower.attr, - &dev_attr_urbnum.attr, /* device attributes */ + &dev_attr_urbnum.attr, &dev_attr_idVendor.attr, &dev_attr_idProduct.attr, &dev_attr_bcdDevice.attr, @@ -529,10 +590,13 @@ static struct attribute *dev_attrs[] = { &dev_attr_speed.attr, &dev_attr_busnum.attr, &dev_attr_devnum.attr, + &dev_attr_devpath.attr, &dev_attr_version.attr, &dev_attr_maxchild.attr, &dev_attr_quirks.attr, + &dev_attr_avoid_reset_quirk.attr, &dev_attr_authorized.attr, + &dev_attr_remove.attr, NULL, }; static struct attribute_group dev_attr_grp = { |