diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-05-30 19:39:33 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 23:34:30 (GMT) |
commit | b41a60eca833d76593d4dac8a59f5c38714194ee (patch) | |
tree | a7c5cf721d9978503c3c8c88183747cf954b8733 /drivers/usb/core/sysfs.c | |
parent | 54515fe528d8c6f9bfaf7d0b9fffb908deecad78 (diff) | |
download | linux-b41a60eca833d76593d4dac8a59f5c38714194ee.tar.xz |
USB: add power/persist device attribute
This patch (as920) adds an extra level of protection to the
USB-Persist facility. Now it will apply by default only to hubs; for
all other devices the user must enable it explicitly by setting the
power/persist device attribute.
The disconnect_all_children() routine in hub.c has been removed and
its code placed inline. This is the way it was originally as part of
hub_pre_reset(); the revised usage in hub_reset_resume() is
sufficiently different that the code can no longer be shared.
Likewise, mark_children_for_reset() is now inline as part of
hub_reset_resume(). The end result looks much cleaner than before.
The sysfs interface is updated to add the new attribute file, and
there are corresponding documentation updates.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/sysfs.c')
-rw-r--r-- | drivers/usb/core/sysfs.c | 75 |
1 files changed, 73 insertions, 2 deletions
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index be37c86..5dfe31b 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -169,6 +169,73 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); + +#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND) +static const char power_group[] = "power"; +#endif + +#ifdef CONFIG_USB_PERSIST + +static ssize_t +show_persist(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) +{ + struct usb_device *udev = to_usb_device(dev); + int value; + + /* Hubs are always enabled for USB_PERSIST */ + if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) + return -EPERM; + + if (sscanf(buf, "%d", &value) != 1) + return -EINVAL; + usb_pm_lock(udev); + udev->persist_enabled = !!value; + usb_pm_unlock(udev); + return count; +} + +static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist); + +static int add_persist_attributes(struct device *dev) +{ + int rc = 0; + + if (is_usb_device(dev)) { + struct usb_device *udev = to_usb_device(dev); + + /* Hubs are automatically enabled for USB_PERSIST */ + if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) + udev->persist_enabled = 1; + rc = sysfs_add_file_to_group(&dev->kobj, + &dev_attr_persist.attr, + power_group); + } + return rc; +} + +static void remove_persist_attributes(struct device *dev) +{ + sysfs_remove_file_from_group(&dev->kobj, + &dev_attr_persist.attr, + power_group); +} + +#else + +#define add_persist_attributes(dev) 0 +#define remove_persist_attributes(dev) do {} while (0) + +#endif /* CONFIG_USB_PERSIST */ + #ifdef CONFIG_USB_SUSPEND static ssize_t @@ -276,8 +343,6 @@ set_level(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level); -static char power_group[] = "power"; - static int add_power_attributes(struct device *dev) { int rc = 0; @@ -311,6 +376,7 @@ static void remove_power_attributes(struct device *dev) #endif /* CONFIG_USB_SUSPEND */ + /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ @@ -384,6 +450,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev) if (retval) return retval; + retval = add_persist_attributes(dev); + if (retval) + goto error; + retval = add_power_attributes(dev); if (retval) goto error; @@ -421,6 +491,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev) device_remove_file(dev, &dev_attr_product); device_remove_file(dev, &dev_attr_serial); remove_power_attributes(dev); + remove_persist_attributes(dev); sysfs_remove_group(&dev->kobj, &dev_attr_grp); } |