diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-05-30 15:39:33 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 19:34:30 -0400 |
commit | b41a60eca833d76593d4dac8a59f5c38714194ee (patch) | |
tree | a7c5cf721d9978503c3c8c88183747cf954b8733 /drivers/usb/core/sysfs.c | |
parent | 54515fe528d8c6f9bfaf7d0b9fffb908deecad78 (diff) |
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 be37c863fdfb..5dfe31bc32ba 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) | |||
169 | } | 169 | } |
170 | static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); | 170 | static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); |
171 | 171 | ||
172 | |||
173 | #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND) | ||
174 | static const char power_group[] = "power"; | ||
175 | #endif | ||
176 | |||
177 | #ifdef CONFIG_USB_PERSIST | ||
178 | |||
179 | static ssize_t | ||
180 | show_persist(struct device *dev, struct device_attribute *attr, char *buf) | ||
181 | { | ||
182 | struct usb_device *udev = to_usb_device(dev); | ||
183 | |||
184 | return sprintf(buf, "%d\n", udev->persist_enabled); | ||
185 | } | ||
186 | |||
187 | static ssize_t | ||
188 | set_persist(struct device *dev, struct device_attribute *attr, | ||
189 | const char *buf, size_t count) | ||
190 | { | ||
191 | struct usb_device *udev = to_usb_device(dev); | ||
192 | int value; | ||
193 | |||
194 | /* Hubs are always enabled for USB_PERSIST */ | ||
195 | if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) | ||
196 | return -EPERM; | ||
197 | |||
198 | if (sscanf(buf, "%d", &value) != 1) | ||
199 | return -EINVAL; | ||
200 | usb_pm_lock(udev); | ||
201 | udev->persist_enabled = !!value; | ||
202 | usb_pm_unlock(udev); | ||
203 | return count; | ||
204 | } | ||
205 | |||
206 | static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist); | ||
207 | |||
208 | static int add_persist_attributes(struct device *dev) | ||
209 | { | ||
210 | int rc = 0; | ||
211 | |||
212 | if (is_usb_device(dev)) { | ||
213 | struct usb_device *udev = to_usb_device(dev); | ||
214 | |||
215 | /* Hubs are automatically enabled for USB_PERSIST */ | ||
216 | if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) | ||
217 | udev->persist_enabled = 1; | ||
218 | rc = sysfs_add_file_to_group(&dev->kobj, | ||
219 | &dev_attr_persist.attr, | ||
220 | power_group); | ||
221 | } | ||
222 | return rc; | ||
223 | } | ||
224 | |||
225 | static void remove_persist_attributes(struct device *dev) | ||
226 | { | ||
227 | sysfs_remove_file_from_group(&dev->kobj, | ||
228 | &dev_attr_persist.attr, | ||
229 | power_group); | ||
230 | } | ||
231 | |||
232 | #else | ||
233 | |||
234 | #define add_persist_attributes(dev) 0 | ||
235 | #define remove_persist_attributes(dev) do {} while (0) | ||
236 | |||
237 | #endif /* CONFIG_USB_PERSIST */ | ||
238 | |||
172 | #ifdef CONFIG_USB_SUSPEND | 239 | #ifdef CONFIG_USB_SUSPEND |
173 | 240 | ||
174 | static ssize_t | 241 | static ssize_t |
@@ -276,8 +343,6 @@ set_level(struct device *dev, struct device_attribute *attr, | |||
276 | 343 | ||
277 | static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level); | 344 | static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level); |
278 | 345 | ||
279 | static char power_group[] = "power"; | ||
280 | |||
281 | static int add_power_attributes(struct device *dev) | 346 | static int add_power_attributes(struct device *dev) |
282 | { | 347 | { |
283 | int rc = 0; | 348 | int rc = 0; |
@@ -311,6 +376,7 @@ static void remove_power_attributes(struct device *dev) | |||
311 | 376 | ||
312 | #endif /* CONFIG_USB_SUSPEND */ | 377 | #endif /* CONFIG_USB_SUSPEND */ |
313 | 378 | ||
379 | |||
314 | /* Descriptor fields */ | 380 | /* Descriptor fields */ |
315 | #define usb_descriptor_attr_le16(field, format_string) \ | 381 | #define usb_descriptor_attr_le16(field, format_string) \ |
316 | static ssize_t \ | 382 | static ssize_t \ |
@@ -384,6 +450,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev) | |||
384 | if (retval) | 450 | if (retval) |
385 | return retval; | 451 | return retval; |
386 | 452 | ||
453 | retval = add_persist_attributes(dev); | ||
454 | if (retval) | ||
455 | goto error; | ||
456 | |||
387 | retval = add_power_attributes(dev); | 457 | retval = add_power_attributes(dev); |
388 | if (retval) | 458 | if (retval) |
389 | goto error; | 459 | goto error; |
@@ -421,6 +491,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev) | |||
421 | device_remove_file(dev, &dev_attr_product); | 491 | device_remove_file(dev, &dev_attr_product); |
422 | device_remove_file(dev, &dev_attr_serial); | 492 | device_remove_file(dev, &dev_attr_serial); |
423 | remove_power_attributes(dev); | 493 | remove_power_attributes(dev); |
494 | remove_persist_attributes(dev); | ||
424 | sysfs_remove_group(&dev->kobj, &dev_attr_grp); | 495 | sysfs_remove_group(&dev->kobj, &dev_attr_grp); |
425 | } | 496 | } |
426 | 497 | ||