From 39309f376a988b7a5c37e9ef82e9cd6c87af2e97 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 18 Jan 2010 13:57:03 +0000
Subject: [PATCH 2/2] [appleir] Add suspend support
Close the connection to the device and kill the timer when suspending,
and undo those changes on resume.
Signed-off-by: Bastien Nocera <hadess@hadess.net>
---
drivers/input/misc/appleir.c | 120 +++++++++++++++++++++++++++++++++++++++---
1 files changed, 112 insertions(+), 8 deletions(-)
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
+#include <linux/usb/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
@@ -53,6 +54,7 @@ struct appleir {
u8 *data;
dma_addr_t dma_buf;
struct usb_device *usbdev;
+ unsigned int flags;
struct urb *urb;
int timer_initted;
struct timer_list key_up_timer;
@@ -60,6 +62,13 @@ struct appleir {
char phys[32];
};
+static DEFINE_MUTEX(appleir_mutex);
+
+enum {
+ APPLEIR_OPENED = 0x1,
+ APPLEIR_SUSPENDED = 0x2,
+};
+
static struct usb_device_id appleir_ids[] = {
{USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL)},
{USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4)},
@@ -223,19 +232,50 @@ static void appleir_urb(struct urb *urb)
static int appleir_open(struct input_dev *dev)
{
struct appleir *appleir = input_get_drvdata(dev);
+ struct usb_interface *intf = usb_ifnum_to_if(appleir->usbdev, 0);
+ int r;
+
+ r = usb_autopm_get_interface(intf);
+ if (r) {
+ dev_err(&intf->dev,
+ "%s(): usb_autopm_get_interface() = %d\n", __func__, r);
+ return r;
+ }
+
+ mutex_lock(&appleir_mutex);
- if (usb_submit_urb(appleir->urb, GFP_KERNEL))
- return -EIO;
+ if (usb_submit_urb(appleir->urb, GFP_KERNEL)) {
+ r = -EIO;
+ goto fail;
+ }
+
+ appleir->flags |= APPLEIR_OPENED;
+
+ mutex_unlock(&appleir_mutex);
+
+ usb_autopm_put_interface(intf);
return 0;
+fail:
+ mutex_unlock(&appleir_mutex);
+ usb_autopm_put_interface(intf);
+ return r;
}
static void appleir_close(struct input_dev *dev)
{
struct appleir *appleir = input_get_drvdata(dev);
- usb_kill_urb(appleir->urb);
- del_timer_sync(&appleir->key_up_timer);
+ mutex_lock(&appleir_mutex);
+
+ if (!(appleir->flags & APPLEIR_SUSPENDED)) {
+ usb_kill_urb(appleir->urb);
+ del_timer_sync(&appleir->key_up_timer);
+ }
+
+ appleir->flags &= ~APPLEIR_OPENED;
+
+ mutex_unlock(&appleir_mutex);
}
static int appleir_probe(struct usb_interface *intf,
@@ -350,11 +390,75 @@ static void appleir_disconnect(struct usb_interface *intf)
}
}
+static int appleir_suspend(struct usb_interface *interface,
+ pm_message_t message)
+{
+ struct appleir *appleir;
+/* struct usb_host_interface *alt = interface->cur_altsetting;
+
+ if (alt->desc.bInterfaceNumber)
+ return 0; */
+
+ appleir = usb_get_intfdata(interface);
+
+ mutex_lock(&appleir_mutex);
+
+ if (appleir->flags & APPLEIR_OPENED) {
+ usb_kill_urb(appleir->urb);
+ del_timer_sync(&appleir->key_up_timer);
+ }
+
+ appleir->flags |= APPLEIR_SUSPENDED;
+
+ mutex_unlock(&appleir_mutex);
+
+ return 0;
+}
+
+static int appleir_resume(struct usb_interface *interface)
+{
+ struct appleir *appleir;
+ /* struct usb_host_interface *alt = interface->cur_altsetting;
+
+ if (alt->desc.bInterfaceNumber)
+ return 0; */
+
+ appleir = usb_get_intfdata(interface);
+
+ mutex_lock(&appleir_mutex);
+
+ if (appleir->flags & APPLEIR_OPENED) {
+ struct usb_endpoint_descriptor *endpoint;
+
+ endpoint = &interface->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(appleir->urb, appleir->usbdev,
+ usb_rcvintpipe(appleir->usbdev, endpoint->bEndpointAddress),
+ appleir->data, 8,
+ appleir_urb, appleir, endpoint->bInterval);
+ appleir->urb->transfer_dma = appleir->dma_buf;
+ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ init_timer(&appleir->key_up_timer);
+
+ appleir->key_up_timer.function = key_up_tick;
+ appleir->key_up_timer.data = (unsigned long)appleir;
+ }
+
+ appleir->flags &= ~APPLEIR_SUSPENDED;
+
+ mutex_unlock(&appleir_mutex);
+
+ return 0;
+}
+
static struct usb_driver appleir_driver = {
- .name = "appleir",
- .probe = appleir_probe,
- .disconnect = appleir_disconnect,
- .id_table = appleir_ids,
+ .name = "appleir",
+ .probe = appleir_probe,
+ .disconnect = appleir_disconnect,
+ .suspend = appleir_suspend,
+ .resume = appleir_resume,
+ .reset_resume = appleir_resume,
+ .id_table = appleir_ids,
};
static int __init appleir_init(void)
--
1.6.5.2