diff mbox

[PATCHes] Apple IR receiver driver

Message ID 1263824065.20565.2730.camel@localhost.localdomain (mailing list archive)
State New, archived
Headers show

Commit Message

Bastien Nocera Jan. 18, 2010, 2:14 p.m. UTC
None
diff mbox

Patch

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(-)

diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
index 54a9647..f03db3e 100644
--- a/drivers/input/misc/appleir.c
+++ b/drivers/input/misc/appleir.c
@@ -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