summaryrefslogtreecommitdiffstats
path: root/drivers/hid/usbhid/hiddev.c
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2008-12-17 15:38:03 +0100
committerJiri Kosina <jkosina@suse.cz>2009-03-25 17:57:57 +0100
commit0361a28d3f9a4315a100c7b37ba0b55cfe15fe07 (patch)
tree2aa33c5325118e68ce8691a009c5fb30ffdea68c /drivers/hid/usbhid/hiddev.c
parent8e0ee43bc2c3e19db56a4adaa9a9b04ce885cd84 (diff)
downloadlinux-0361a28d3f9a4315a100c7b37ba0b55cfe15fe07.tar.bz2
HID: autosuspend support for USB HID
This uses the USB busy mechanism for aggessive autosuspend of USB HID devices. It autosuspends all opened devices supporting remote wakeup after a timeout unless - output is being done to the device - a key is being held down (remote wakeup isn't triggered upon key release) - LED(s) are lit - hiddev is opened As in the current driver closed devices will be autosuspended even if they don't support remote wakeup. The patch is quite large because output to devices is done in hard interrupt context meaning a lot a queuing and locking had to be touched. The LED stuff has been solved by means of a simple counter. Additions to the generic HID code could be avoided. In addition it now covers hidraw. It contains an embryonic version of an API to let the generic HID code tell the lower levels which capabilities with respect to power management are needed. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/usbhid/hiddev.c')
-rw-r--r--drivers/hid/usbhid/hiddev.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 1f5b5d4c3c34..fd7375627e5d 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -249,10 +249,12 @@ static int hiddev_release(struct inode * inode, struct file * file)
spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
if (!--list->hiddev->open) {
- if (list->hiddev->exist)
+ if (list->hiddev->exist) {
usbhid_close(list->hiddev->hid);
- else
+ usbhid_put_power(list->hiddev->hid);
+ } else {
kfree(list->hiddev);
+ }
}
kfree(list);
@@ -303,6 +305,17 @@ static int hiddev_open(struct inode *inode, struct file *file)
list_add_tail(&list->node, &hiddev_table[i]->list);
spin_unlock_irq(&list->hiddev->list_lock);
+ if (!list->hiddev->open++)
+ if (list->hiddev->exist) {
+ struct hid_device *hid = hiddev_table[i]->hid;
+ res = usbhid_get_power(hid);
+ if (res < 0) {
+ res = -EIO;
+ goto bail;
+ }
+ usbhid_open(hid);
+ }
+
return 0;
bail:
file->private_data = NULL;