aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/usbhid/hiddev.c
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2008-12-17 09:38:03 -0500
committerJiri Kosina <jkosina@suse.cz>2009-03-25 12:57:57 -0400
commit0361a28d3f9a4315a100c7b37ba0b55cfe15fe07 (patch)
tree2aa33c5325118e68ce8691a009c5fb30ffdea68c /drivers/hid/usbhid/hiddev.c
parent8e0ee43bc2c3e19db56a4adaa9a9b04ce885cd84 (diff)
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)
249 spin_unlock_irqrestore(&list->hiddev->list_lock, flags); 249 spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
250 250
251 if (!--list->hiddev->open) { 251 if (!--list->hiddev->open) {
252 if (list->hiddev->exist) 252 if (list->hiddev->exist) {
253 usbhid_close(list->hiddev->hid); 253 usbhid_close(list->hiddev->hid);
254 else 254 usbhid_put_power(list->hiddev->hid);
255 } else {
255 kfree(list->hiddev); 256 kfree(list->hiddev);
257 }
256 } 258 }
257 259
258 kfree(list); 260 kfree(list);
@@ -303,6 +305,17 @@ static int hiddev_open(struct inode *inode, struct file *file)
303 list_add_tail(&list->node, &hiddev_table[i]->list); 305 list_add_tail(&list->node, &hiddev_table[i]->list);
304 spin_unlock_irq(&list->hiddev->list_lock); 306 spin_unlock_irq(&list->hiddev->list_lock);
305 307
308 if (!list->hiddev->open++)
309 if (list->hiddev->exist) {
310 struct hid_device *hid = hiddev_table[i]->hid;
311 res = usbhid_get_power(hid);
312 if (res < 0) {
313 res = -EIO;
314 goto bail;
315 }
316 usbhid_open(hid);
317 }
318
306 return 0; 319 return 0;
307bail: 320bail:
308 file->private_data = NULL; 321 file->private_data = NULL;