diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2007-02-20 15:03:32 -0500 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-23 15:03:47 -0800 | 
| commit | 19c262391c4741b012a5031fc438fb694e77c385 (patch) | |
| tree | 1ce81bf30086104f8102b83617d31d998338fbd6 /drivers/usb/core | |
| parent | dfa87c824a9a5430008acd1ed2e8111ed164fcbe (diff) | |
| download | olio-linux-3.10-19c262391c4741b012a5031fc438fb694e77c385.tar.xz olio-linux-3.10-19c262391c4741b012a5031fc438fb694e77c385.zip  | |
USB: export autosuspend delay in sysfs
This patch (as861) adds sysfs attributes to expose the autosuspend
delay value for each USB device.  If the user changes the delay from 0
(no autosuspend) to a positive value, an autosuspend is attempted.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/driver.c | 20 | ||||
| -rw-r--r-- | drivers/usb/core/sysfs.c | 64 | ||||
| -rw-r--r-- | drivers/usb/core/usb.h | 4 | 
3 files changed, 87 insertions, 1 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index a420d72a025..9e3e943f313 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1225,6 +1225,26 @@ void usb_autosuspend_device(struct usb_device *udev)  }  /** + * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces + * @udev: the usb_device to autosuspend + * + * This routine should be called when a core subsystem thinks @udev may + * be ready to autosuspend. + * + * @udev's usage counter left unchanged.  If it or any of the usage counters + * for an active interface is greater than 0, or autosuspend is not allowed + * for any other reason, no autosuspend request will be queued. + * + * This routine can run only in process context. + */ +void usb_try_autosuspend_device(struct usb_device *udev) +{ +	usb_autopm_do_device(udev, 0); +	// dev_dbg(&udev->dev, "%s: cnt %d\n", +	// 		__FUNCTION__, udev->pm_usage_cnt); +} + +/**   * usb_autoresume_device - immediately autoresume a USB device and its interfaces   * @udev: the usb_device to autoresume   * diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index cad4fb323f6..311d5df8038 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -158,6 +158,65 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)  }  static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); +#ifdef	CONFIG_USB_SUSPEND + +static ssize_t +show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct usb_device *udev = to_usb_device(dev); + +	return sprintf(buf, "%u\n", udev->autosuspend_delay / HZ); +} + +static ssize_t +set_autosuspend(struct device *dev, struct device_attribute *attr, +		const char *buf, size_t count) +{ +	struct usb_device *udev = to_usb_device(dev); +	unsigned value, old; + +	if (sscanf(buf, "%u", &value) != 1 || value >= INT_MAX/HZ) +		return -EINVAL; +	value *= HZ; + +	old = udev->autosuspend_delay; +	udev->autosuspend_delay = value; +	if (value > 0 && old == 0) +		usb_try_autosuspend_device(udev); + +	return count; +} + +static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR, +		show_autosuspend, set_autosuspend); + +static char power_group[] = "power"; + +static int add_power_attributes(struct device *dev) +{ +	int rc = 0; + +	if (is_usb_device(dev)) +		rc = sysfs_add_file_to_group(&dev->kobj, +				&dev_attr_autosuspend.attr, +				power_group); +	return rc; +} + +static void remove_power_attributes(struct device *dev) +{ +	sysfs_remove_file_from_group(&dev->kobj, +			&dev_attr_autosuspend.attr, +			power_group); +} + +#else + +#define add_power_attributes(dev)	0 +#define remove_power_attributes(dev)	do {} while (0) + +#endif	/* CONFIG_USB_SUSPEND */ +  /* Descriptor fields */  #define usb_descriptor_attr_le16(field, format_string)			\  static ssize_t								\ @@ -230,6 +289,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)  	if (retval)  		return retval; +	retval = add_power_attributes(dev); +	if (retval) +		goto error; +  	if (udev->manufacturer) {  		retval = device_create_file(dev, &dev_attr_manufacturer);  		if (retval) @@ -262,6 +325,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)  	device_remove_file(dev, &dev_attr_manufacturer);  	device_remove_file(dev, &dev_attr_product);  	device_remove_file(dev, &dev_attr_serial); +	remove_power_attributes(dev);  	sysfs_remove_group(&dev->kobj, &dev_attr_grp);  } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index b0a35f45b09..08b5a04e375 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -66,11 +66,13 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}  #ifdef CONFIG_USB_SUSPEND  extern void usb_autosuspend_device(struct usb_device *udev); +extern void usb_try_autosuspend_device(struct usb_device *udev);  extern int usb_autoresume_device(struct usb_device *udev);  #else -#define usb_autosuspend_device(udev)	do {} while (0) +#define usb_autosuspend_device(udev)		do {} while (0) +#define usb_try_autosuspend_device(udev)	do {} while (0)  static inline int usb_autoresume_device(struct usb_device *udev)  {  	return 0;  |