diff options
author | Oliver Neukum <oneukum@suse.de> | 2010-07-15 16:19:51 (GMT) |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-07-15 16:30:52 (GMT) |
commit | 5d9efc59e689445f1f8c4eceb125c1a12898e65c (patch) | |
tree | 21b21794e49de25f728aa0d974722f875fac95cf | |
parent | ed4299e1b173f111ac0c40d6617e47fbff02b52f (diff) | |
download | linux-fsl-qoriq-5d9efc59e689445f1f8c4eceb125c1a12898e65c.tar.xz |
Input: usbtouchscreen - implement runtime power management
This implement USB autosuspend while the device is opened for
devices that do remote wakeup with a fallback to open/close for
those devices that don't. Devices that require the host to
constantly poll them are never autosuspended.
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Tested-by: Petr Štetiar <ynezz@true.cz>
Tested-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/touchscreen/usbtouchscreen.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 9cda660..77e671f 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -1268,6 +1268,7 @@ static void usbtouch_irq(struct urb *urb) usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length); exit: + usb_mark_last_busy(interface_to_usbdev(usbtouch->interface)); retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) err("%s - usb_submit_urb failed with result: %d", @@ -1277,23 +1278,39 @@ exit: static int usbtouch_open(struct input_dev *input) { struct usbtouch_usb *usbtouch = input_get_drvdata(input); + int r; usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface); + r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0; + if (r < 0) + goto out; + if (!usbtouch->type->irq_always) { - if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) - return -EIO; + if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) { + r = -EIO; + goto out_put; + } } - return 0; + usbtouch->interface->needs_remote_wakeup = 1; +out_put: + usb_autopm_put_interface(usbtouch->interface); +out: + return r; } static void usbtouch_close(struct input_dev *input) { struct usbtouch_usb *usbtouch = input_get_drvdata(input); + int r; if (!usbtouch->type->irq_always) usb_kill_urb(usbtouch->irq); + r = usb_autopm_get_interface(usbtouch->interface); + usbtouch->interface->needs_remote_wakeup = 0; + if (!r) + usb_autopm_put_interface(usbtouch->interface); } static int usbtouch_suspend @@ -1457,8 +1474,11 @@ static int usbtouch_probe(struct usb_interface *intf, usb_set_intfdata(intf, usbtouch); if (usbtouch->type->irq_always) { + /* this can't fail */ + usb_autopm_get_interface(intf); err = usb_submit_urb(usbtouch->irq, GFP_KERNEL); if (err) { + usb_autopm_put_interface(intf); err("%s - usb_submit_urb failed with result: %d", __func__, err); goto out_unregister_input; @@ -1512,6 +1532,7 @@ static struct usb_driver usbtouch_driver = { .suspend = usbtouch_suspend, .resume = usbtouch_resume, .id_table = usbtouch_devices, + .supports_autosuspend = 1, }; static int __init usbtouch_init(void) |