Skip to content

Commit

Permalink
HID: autosuspend support for USB HID
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Oliver Neukum authored and Jiri Kosina committed Mar 25, 2009
1 parent 8e0ee43 commit 0361a28
Show file tree
Hide file tree
Showing 6 changed files with 402 additions and 103 deletions.
16 changes: 16 additions & 0 deletions drivers/hid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,22 @@ static DECLARE_WORK(hid_compat_work, hid_compat_load);
static struct workqueue_struct *hid_compat_wq;
#endif

int hid_check_keys_pressed(struct hid_device *hid)
{
struct hid_input *hidinput;
int i;

list_for_each_entry(hidinput, &hid->inputs, list) {
for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++)
if (hidinput->input->key[i])
return 1;
}

return 0;
}

EXPORT_SYMBOL_GPL(hid_check_keys_pressed);

static int __init hid_init(void)
{
int ret;
Expand Down
17 changes: 14 additions & 3 deletions drivers/hid/hidraw.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,17 @@ static int hidraw_open(struct inode *inode, struct file *file)

dev = hidraw_table[minor];
if (!dev->open++) {
if (dev->hid->ll_driver->power) {
err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON);
if (err < 0)
goto out_unlock;
}
err = dev->hid->ll_driver->open(dev->hid);
if (err < 0)
if (err < 0) {
if (dev->hid->ll_driver->power)
dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
dev->open--;
}
}

out_unlock:
Expand All @@ -209,10 +217,13 @@ static int hidraw_release(struct inode * inode, struct file * file)
list_del(&list->node);
dev = hidraw_table[minor];
if (!--dev->open) {
if (list->hidraw->exist)
if (list->hidraw->exist) {
if (dev->hid->ll_driver->power)
dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
dev->hid->ll_driver->close(dev->hid);
else
} else {
kfree(list->hidraw);
}
}

kfree(list);
Expand Down
Loading

0 comments on commit 0361a28

Please sign in to comment.