Bastien Nocera 78100db
From e11e9e78799a7641fe0dc5289f35f2604a4b71a3 Mon Sep 17 00:00:00 2001
Bastien Nocera 78100db
From: Bastien Nocera <hadess@hadess.net>
Bastien Nocera 78100db
Date: Sun, 17 Jan 2010 00:40:15 +0000
Bastien Nocera 78100db
Subject: [PATCH] Input: add appleir USB driver
Bastien Nocera 78100db
Bastien Nocera 78100db
This driver was originally written by James McKenzie, updated by
Bastien Nocera 78100db
Greg Kroah-Hartman, further updated by myself, with suspend support
Bastien Nocera 78100db
added.
Bastien Nocera 78100db
Bastien Nocera 78100db
More recent versions of the IR receiver are also supported through
Bastien Nocera 78100db
a patch by Alex Karpenko. The patch also adds support for the 2nd
Bastien Nocera 78100db
and 5th generation of the controller, and the menu key on newer
Bastien Nocera 78100db
brushed metal remotes.
Bastien Nocera 78100db
Bastien Nocera 78100db
Tested on a MacbookAir1,1
Bastien Nocera 78100db
Bastien Nocera 78100db
Signed-off-by: Bastien Nocera <hadess@hadess.net>
Kyle McMartin 0ca5626
---
Bastien Nocera 78100db
 Documentation/input/appleir.txt |   46 ++++
Bastien Nocera 78100db
 drivers/hid/hid-apple.c         |    4 -
Bastien Nocera 78100db
 drivers/hid/hid-core.c          |    7 +-
Bastien Nocera 78100db
 drivers/hid/hid-ids.h           |    5 +-
Bastien Nocera 78100db
 drivers/input/misc/Kconfig      |   13 +
Bastien Nocera 78100db
 drivers/input/misc/Makefile     |    1 +
Bastien Nocera 78100db
 drivers/input/misc/appleir.c    |  519 +++++++++++++++++++++++++++++++++++++++
Bastien Nocera 78100db
 7 files changed, 588 insertions(+), 7 deletions(-)
Bastien Nocera 78100db
 create mode 100644 Documentation/input/appleir.txt
Bastien Nocera 78100db
 create mode 100644 drivers/input/misc/appleir.c
Bastien Nocera 78100db
Kyle McMartin 407cbd0
diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
Kyle McMartin 407cbd0
new file mode 100644
Bastien Nocera 78100db
index 0000000..db637fb
Kyle McMartin 407cbd0
--- /dev/null
Kyle McMartin 407cbd0
+++ b/Documentation/input/appleir.txt
Bastien Nocera 78100db
@@ -0,0 +1,46 @@
Kyle McMartin 407cbd0
+Apple IR receiver Driver (appleir)
Kyle McMartin 407cbd0
+----------------------------------
Kyle McMartin 407cbd0
+	Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+The appleir driver is a kernel input driver to handle Apple's IR
Kyle McMartin 407cbd0
+receivers (and associated remotes) in the kernel.
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+The driver is an input driver which only handles "official" remotes
Kyle McMartin 407cbd0
+as built and sold by Apple.
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+Authors
Kyle McMartin 407cbd0
+-------
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+James McKenzie (original driver)
Kyle McMartin 407cbd0
+Alex Karpenko (05ac:8242 support)
Kyle McMartin 407cbd0
+Greg Kroah-Hartman (cleanups and original submission)
Bastien Nocera 78100db
+Bastien Nocera (further cleanups, brushed metal "enter"
Bastien Nocera 78100db
+button support and suspend support)
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+Supported hardware
Kyle McMartin 407cbd0
+------------------
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+- All Apple laptops and desktops from 2005 onwards, except:
Kyle McMartin 407cbd0
+  - the unibody Macbook (2009)
Kyle McMartin 407cbd0
+  - Mac Pro (all versions)
Bastien Nocera 78100db
+- Apple TV (all revisions prior to September 2010)
Kyle McMartin 407cbd0
+
Bastien Nocera 78100db
+The remote will only support the 6 (old white) or 7 (brushed metal) buttons
Bastien Nocera 78100db
+of the remotes as sold by Apple. See the next section if you want to use
Bastien Nocera 78100db
+other remotes or want to use lirc with the device instead of the kernel driver.
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+Using lirc (native) instead of the kernel driver
Kyle McMartin 407cbd0
+------------------------------------------------
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+First, you will need to disable the kernel driver for the receiver.
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+This can be achieved by passing quirks to the usbhid driver.
Kyle McMartin 407cbd0
+The quirk line would be:
Kyle McMartin 407cbd0
+usbhid.quirks=0x05ac:0x8242:0x40000010
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
Kyle McMartin 407cbd0
+With 0x8242 being the product ID (check the output of lsusb for your hardware)
Kyle McMartin 407cbd0
+And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE"
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+This should force the creation of a hiddev device for the receiver, and
Kyle McMartin 407cbd0
+make it usable under lirc.
Kyle McMartin 0ca5626
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
Kyle McMartin 0ca5626
index bba05d0..0059d5a 100644
Kyle McMartin 0ca5626
--- a/drivers/hid/hid-apple.c
Kyle McMartin 0ca5626
+++ b/drivers/hid/hid-apple.c
Kyle McMartin 0ca5626
@@ -361,10 +361,6 @@ static void apple_remove(struct hid_device *hdev)
Kyle McMartin 0ca5626
 }
Kyle McMartin 0ca5626
 
Kyle McMartin 0ca5626
 static const struct hid_device_id apple_devices[] = {
Kyle McMartin 0ca5626
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
Kyle McMartin 0ca5626
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
Kyle McMartin 0ca5626
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
Kyle McMartin 0ca5626
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
Kyle McMartin 0ca5626
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
Kyle McMartin 0ca5626
 		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
Kyle McMartin 0ca5626
 
Kyle McMartin 0ca5626
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
Bastien Nocera 78100db
index baa25ad..abc5bd7 100644
Kyle McMartin 0ca5626
--- a/drivers/hid/hid-core.c
Kyle McMartin 0ca5626
+++ b/drivers/hid/hid-core.c
Kyle McMartin 0ca5626
@@ -1244,8 +1244,6 @@ static const struct hid_device_id hid_blacklist[] = {
Kyle McMartin 0ca5626
 #if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
Kyle McMartin 0ca5626
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
Kyle McMartin 0ca5626
 #endif
Kyle McMartin 0ca5626
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
Kyle McMartin 0ca5626
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
Kyle McMartin 0ca5626
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
Kyle McMartin 0ca5626
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
Kyle McMartin 0ca5626
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
Bastien Nocera 78100db
@@ -1577,6 +1575,11 @@ static const struct hid_device_id hid_ignore_list[] = {
Bastien Nocera 78100db
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
Bastien Nocera 78100db
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
Bastien Nocera 78100db
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
Bastien Nocera 78100db
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
Bastien Nocera 78100db
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
Bastien Nocera 78100db
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
Bastien Nocera 78100db
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
Bastien Nocera 78100db
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
Kyle McMartin 0ca5626
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
Kyle McMartin 0ca5626
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
Chuck Ebbert 6d1d3d6
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
Kyle McMartin 0ca5626
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
Bastien Nocera 78100db
index 11af537..360a5ca 100644
Kyle McMartin 0ca5626
--- a/drivers/hid/hid-ids.h
Kyle McMartin 0ca5626
+++ b/drivers/hid/hid-ids.h
Bastien Nocera 78100db
@@ -100,8 +100,11 @@
Kyle McMartin 0ca5626
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
Kyle McMartin 0ca5626
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
Kyle McMartin 0ca5626
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
Bastien Nocera 78100db
-#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
Kyle McMartin 0ca5626
+#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
Bastien Nocera 78100db
+#define USB_DEVICE_ID_APPLE_IRCONTROL2	0x1440
Bastien Nocera 78100db
+#define USB_DEVICE_ID_APPLE_IRCONTROL3	0x8241
Kyle McMartin 0ca5626
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
Bastien Nocera 78100db
+#define USB_DEVICE_ID_APPLE_IRCONTROL5	0x8243
Kyle McMartin 0ca5626
 
Bastien Nocera 78100db
 #define USB_VENDOR_ID_ASUS		0x0486
Bastien Nocera 78100db
 #define USB_DEVICE_ID_ASUS_T91MT	0x0185
Kyle McMartin 0ca5626
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
Bastien Nocera 78100db
index 60de906..2f2f2e7 100644
Kyle McMartin 0ca5626
--- a/drivers/input/misc/Kconfig
Kyle McMartin 0ca5626
+++ b/drivers/input/misc/Kconfig
Bastien Nocera 78100db
@@ -209,6 +209,19 @@ config INPUT_KEYSPAN_REMOTE
Kyle McMartin 0ca5626
 	  To compile this driver as a module, choose M here: the module will
Kyle McMartin 0ca5626
 	  be called keyspan_remote.
Kyle McMartin 0ca5626
 
Kyle McMartin 0ca5626
+config INPUT_APPLEIR
Kyle McMartin 0ca5626
+	tristate "Apple infrared receiver (built in)"
Kyle McMartin 0ca5626
+	depends on USB_ARCH_HAS_HCD
Kyle McMartin 0ca5626
+	select USB
Kyle McMartin 0ca5626
+	help
Kyle McMartin 0ca5626
+	  Say Y here if you want to use a Apple infrared remote control. All
Kyle McMartin 0ca5626
+	  the Apple computers from 2005 onwards include such a port, except
Kyle McMartin 0ca5626
+	  the unibody Macbook (2009), and Mac Pros. This receiver is also
Bastien Nocera 78100db
+	  used in the Apple TV set-top box prior to the 2010 model.
Kyle McMartin 0ca5626
+
Kyle McMartin 0ca5626
+	  To compile this driver as a module, choose M here: the module will
Kyle McMartin 0ca5626
+	  be called appleir.
Kyle McMartin 0ca5626
+
Kyle McMartin 0ca5626
 config INPUT_POWERMATE
Kyle McMartin 0ca5626
 	tristate "Griffin PowerMate and Contour Jog support"
Kyle McMartin 0ca5626
 	depends on USB_ARCH_HAS_HCD
Kyle McMartin 0ca5626
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
Bastien Nocera 78100db
index 1fe1f6c..d5ef2b9 100644
Kyle McMartin 0ca5626
--- a/drivers/input/misc/Makefile
Kyle McMartin 0ca5626
+++ b/drivers/input/misc/Makefile
Bastien Nocera 78100db
@@ -13,6 +13,7 @@ obj-$(CONFIG_INPUT_ADXL34X)		+= adxl34x.o
Kyle McMartin 0ca5626
 obj-$(CONFIG_INPUT_ADXL34X_I2C)		+= adxl34x-i2c.o
Kyle McMartin 0ca5626
 obj-$(CONFIG_INPUT_ADXL34X_SPI)		+= adxl34x-spi.o
Kyle McMartin 0ca5626
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
Kyle McMartin 0ca5626
+obj-$(CONFIG_INPUT_APPLEIR)		+= appleir.o
Kyle McMartin 0ca5626
 obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
Kyle McMartin 0ca5626
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
Kyle McMartin 0ca5626
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
Kyle McMartin 407cbd0
diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
Kyle McMartin 407cbd0
new file mode 100644
Bastien Nocera 78100db
index 0000000..3817a3c
Kyle McMartin 407cbd0
--- /dev/null
Kyle McMartin 407cbd0
+++ b/drivers/input/misc/appleir.c
Bastien Nocera 78100db
@@ -0,0 +1,519 @@
Kyle McMartin 407cbd0
+/*
Kyle McMartin 407cbd0
+ * appleir: USB driver for the apple ir device
Kyle McMartin 407cbd0
+ *
Kyle McMartin 407cbd0
+ * Original driver written by James McKenzie
Kyle McMartin 407cbd0
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
Kyle McMartin 407cbd0
+ *
Kyle McMartin 407cbd0
+ * Copyright (C) 2006 James McKenzie
Kyle McMartin 407cbd0
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
Kyle McMartin 407cbd0
+ * Copyright (C) 2008 Novell Inc.
Kyle McMartin 407cbd0
+ *
Kyle McMartin 407cbd0
+ * This program is free software; you can redistribute it and/or modify it
Kyle McMartin 407cbd0
+ * under the terms of the GNU General Public License as published by the Free
Kyle McMartin 407cbd0
+ * Software Foundation, version 2.
Kyle McMartin 407cbd0
+ *
Kyle McMartin 407cbd0
+ */
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+#include <linux/kernel.h>
Kyle McMartin 407cbd0
+#include <linux/slab.h>
Kyle McMartin 407cbd0
+#include <linux/input.h>
Kyle McMartin 407cbd0
+#include <linux/usb/input.h>
Kyle McMartin 407cbd0
+#include <linux/module.h>
Kyle McMartin 407cbd0
+#include <linux/init.h>
Kyle McMartin 407cbd0
+#include <linux/usb.h>
Kyle McMartin 407cbd0
+#include <linux/usb/input.h>
Kyle McMartin 407cbd0
+#include <asm/unaligned.h>
Kyle McMartin 407cbd0
+#include <asm/byteorder.h>
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+#define DRIVER_VERSION "v1.2"
Kyle McMartin 407cbd0
+#define DRIVER_AUTHOR "James McKenzie"
Kyle McMartin 407cbd0
+#define DRIVER_DESC "Apple infrared receiver driver"
Kyle McMartin 407cbd0
+#define DRIVER_LICENSE "GPL"
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+MODULE_AUTHOR(DRIVER_AUTHOR);
Kyle McMartin 407cbd0
+MODULE_DESCRIPTION(DRIVER_DESC);
Kyle McMartin 407cbd0
+MODULE_LICENSE(DRIVER_LICENSE);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+#define USB_VENDOR_ID_APPLE			0x05ac
Kyle McMartin 407cbd0
+#define USB_DEVICE_ID_APPLE_IRCONTROL		0x8240
Bastien Nocera 78100db
+#define USB_DEVICE_ID_APPLE_IRCONTROL2		0x1440
Bastien Nocera 78100db
+#define USB_DEVICE_ID_APPLE_IRCONTROL3		0x8241
Kyle McMartin 407cbd0
+#define USB_DEVICE_ID_APPLE_IRCONTROL4		0x8242
Bastien Nocera 78100db
+#define USB_DEVICE_ID_APPLE_IRCONTROL5		0x8243
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+#define URB_SIZE	32
Kyle McMartin 407cbd0
+
Bastien Nocera 78100db
+#define MAX_KEYS	9
Kyle McMartin 407cbd0
+#define MAX_KEYS_MASK	(MAX_KEYS - 1)
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static int debug;
Kyle McMartin 407cbd0
+module_param(debug, int, 0644);
Kyle McMartin 407cbd0
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+/* I have two devices both of which report the following */
Kyle McMartin 407cbd0
+/* 25 87 ee 83 0a  	+  */
Kyle McMartin 407cbd0
+/* 25 87 ee 83 0c  	-  */
Kyle McMartin 407cbd0
+/* 25 87 ee 83 09	<< */
Kyle McMartin 407cbd0
+/* 25 87 ee 83 06	>> */
Kyle McMartin 407cbd0
+/* 25 87 ee 83 05	>" */
Kyle McMartin 407cbd0
+/* 25 87 ee 83 03	menu */
Kyle McMartin 407cbd0
+/* 26 00 00 00 00	for key repeat*/
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+/* Thomas Glanzmann reports the following responses */
Kyle McMartin 407cbd0
+/* 25 87 ee ca 0b	+  */
Kyle McMartin 407cbd0
+/* 25 87 ee ca 0d	-  */
Kyle McMartin 407cbd0
+/* 25 87 ee ca 08	<< */
Kyle McMartin 407cbd0
+/* 25 87 ee ca 07	>> */
Kyle McMartin 407cbd0
+/* 25 87 ee ca 04	>" */
Kyle McMartin 407cbd0
+/* 25 87 ee ca 02 	menu */
Kyle McMartin 407cbd0
+/* 26 00 00 00 00       for key repeat*/
Kyle McMartin 407cbd0
+/* He also observes the following event sometimes */
Kyle McMartin 407cbd0
+/* sent after a key is release, which I interpret */
Kyle McMartin 407cbd0
+/* as a flat battery message */
Kyle McMartin 407cbd0
+/* 25 87 e0 ca 06	flat battery */
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
Kyle McMartin 407cbd0
+/* 25 87 ee 47 0b	+  */
Kyle McMartin 407cbd0
+/* 25 87 ee 47 0d	-  */
Kyle McMartin 407cbd0
+/* 25 87 ee 47 08	<< */
Kyle McMartin 407cbd0
+/* 25 87 ee 47 07	>> */
Kyle McMartin 407cbd0
+/* 25 87 ee 47 04	>" */
Kyle McMartin 407cbd0
+/* 25 87 ee 47 02 	menu */
Kyle McMartin 407cbd0
+/* 26 87 ee 47 ** 	for key repeat (** is the code of the key being held) */
Kyle McMartin 407cbd0
+
Bastien Nocera 78100db
+/* Bastien Nocera's "new" remote */
Bastien Nocera 78100db
+/* 25 87 ee 91 5f	followed by
Bastien Nocera 78100db
+ * 25 87 ee 91 05	gives you >"
Bastien Nocera 78100db
+ *
Bastien Nocera 78100db
+ * 25 87 ee 91 5c	followed by
Bastien Nocera 78100db
+ * 25 87 ee 91 05	gives you the middle button */
Bastien Nocera 78100db
+
Kyle McMartin 407cbd0
+static const unsigned short appleir_key_table[] = {
Kyle McMartin 407cbd0
+	KEY_RESERVED,
Kyle McMartin 407cbd0
+	KEY_MENU,
Kyle McMartin 407cbd0
+	KEY_PLAYPAUSE,
Kyle McMartin 407cbd0
+	KEY_FORWARD,
Kyle McMartin 407cbd0
+	KEY_BACK,
Kyle McMartin 407cbd0
+	KEY_VOLUMEUP,
Kyle McMartin 407cbd0
+	KEY_VOLUMEDOWN,
Bastien Nocera 78100db
+	KEY_ENTER,
Kyle McMartin 407cbd0
+	KEY_RESERVED,
Kyle McMartin 407cbd0
+};
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+struct appleir {
Kyle McMartin 407cbd0
+	struct input_dev *input_dev;
Kyle McMartin 407cbd0
+	unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
Kyle McMartin 407cbd0
+	u8 *data;
Kyle McMartin 407cbd0
+	dma_addr_t dma_buf;
Kyle McMartin 407cbd0
+	struct usb_device *usbdev;
Kyle McMartin 407cbd0
+	unsigned int flags;
Kyle McMartin 407cbd0
+	struct urb *urb;
Kyle McMartin 407cbd0
+	struct timer_list key_up_timer;
Kyle McMartin 407cbd0
+	int current_key;
Bastien Nocera 78100db
+	int prev_key_idx;
Kyle McMartin 407cbd0
+	char phys[32];
Kyle McMartin 407cbd0
+};
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static DEFINE_MUTEX(appleir_mutex);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+enum {
Kyle McMartin 407cbd0
+	APPLEIR_OPENED = 0x1,
Kyle McMartin 407cbd0
+	APPLEIR_SUSPENDED = 0x2,
Kyle McMartin 407cbd0
+};
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static struct usb_device_id appleir_ids[] = {
Kyle McMartin 407cbd0
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
Bastien Nocera 78100db
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
Bastien Nocera 78100db
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
Kyle McMartin 407cbd0
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
Bastien Nocera 78100db
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
Kyle McMartin 407cbd0
+	{}
Kyle McMartin 407cbd0
+};
Kyle McMartin 407cbd0
+MODULE_DEVICE_TABLE(usb, appleir_ids);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	int i;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	for (i = 0; i < len; ++i)
Kyle McMartin 407cbd0
+		printk(" %02x", data[i]);
Bastien Nocera 78100db
+	printk(" (should be command %d)\n", (data[4] >> 1) & MAX_KEYS_MASK);
Bastien Nocera 78100db
+}
Bastien Nocera 78100db
+
Bastien Nocera 78100db
+static int get_key(int data)
Bastien Nocera 78100db
+{
Bastien Nocera 78100db
+	switch (data) {
Bastien Nocera 78100db
+	case 0x02:
Bastien Nocera 78100db
+	case 0x03:
Bastien Nocera 78100db
+		/* menu */
Bastien Nocera 78100db
+		return 1;
Bastien Nocera 78100db
+	case 0x04:
Bastien Nocera 78100db
+	case 0x05:
Bastien Nocera 78100db
+		/* >" */
Bastien Nocera 78100db
+		return 2;
Bastien Nocera 78100db
+	case 0x06:
Bastien Nocera 78100db
+	case 0x07:
Bastien Nocera 78100db
+		/* >> */
Bastien Nocera 78100db
+		return 3;
Bastien Nocera 78100db
+	case 0x08:
Bastien Nocera 78100db
+	case 0x09:
Bastien Nocera 78100db
+		/* << */
Bastien Nocera 78100db
+		return 4;
Bastien Nocera 78100db
+	case 0x0a:
Bastien Nocera 78100db
+	case 0x0b:
Bastien Nocera 78100db
+		/* + */
Bastien Nocera 78100db
+		return 5;
Bastien Nocera 78100db
+	case 0x0c:
Bastien Nocera 78100db
+	case 0x0d:
Bastien Nocera 78100db
+		/* - */
Bastien Nocera 78100db
+		return 6;
Bastien Nocera 78100db
+	case 0x5c:
Bastien Nocera 78100db
+		/* Middle button, on newer remotes,
Bastien Nocera 78100db
+		 * part of a 2 packet-command */
Bastien Nocera 78100db
+		return -7;
Bastien Nocera 78100db
+	default:
Bastien Nocera 78100db
+		return -1;
Bastien Nocera 78100db
+	}
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void key_up(struct appleir *appleir, int key)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	dbginfo(&appleir->input_dev->dev, "key %d up\n", key);
Kyle McMartin 407cbd0
+	input_report_key(appleir->input_dev, key, 0);
Kyle McMartin 407cbd0
+	input_sync(appleir->input_dev);
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void key_down(struct appleir *appleir, int key)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	dbginfo(&appleir->input_dev->dev, "key %d down\n", key);
Kyle McMartin 407cbd0
+	input_report_key(appleir->input_dev, key, 1);
Kyle McMartin 407cbd0
+	input_sync(appleir->input_dev);
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void battery_flat(struct appleir *appleir)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void key_up_tick(unsigned long data)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	struct appleir *appleir = (struct appleir *)data;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	if (appleir->current_key) {
Kyle McMartin 407cbd0
+		key_up(appleir, appleir->current_key);
Kyle McMartin 407cbd0
+		appleir->current_key = 0;
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void new_data(struct appleir *appleir, u8 *data, int len)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	static const u8 keydown[] = { 0x25, 0x87, 0xee };
Kyle McMartin 407cbd0
+	static const u8 keyrepeat[] = { 0x26, };
Kyle McMartin 407cbd0
+	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	if (debug)
Kyle McMartin 407cbd0
+		dump_packet(appleir, "received", data, len);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	if (len != 5)
Kyle McMartin 407cbd0
+		return;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	if (!memcmp(data, keydown, sizeof(keydown))) {
Bastien Nocera 78100db
+		int index;
Bastien Nocera 78100db
+
Kyle McMartin 407cbd0
+		/* If we already have a key down, take it up before marking
Kyle McMartin 407cbd0
+		   this one down */
Kyle McMartin 407cbd0
+		if (appleir->current_key)
Kyle McMartin 407cbd0
+			key_up(appleir, appleir->current_key);
Kyle McMartin 407cbd0
+
Bastien Nocera 78100db
+		/* Handle dual packet commands */
Bastien Nocera 78100db
+		if (appleir->prev_key_idx > 0)
Bastien Nocera 78100db
+			index = appleir->prev_key_idx;
Bastien Nocera 78100db
+		else
Bastien Nocera 78100db
+			index = get_key(data[4]);
Bastien Nocera 78100db
+
Bastien Nocera 78100db
+		if (index > 0) {
Bastien Nocera 78100db
+			appleir->current_key = appleir->keymap[index];
Bastien Nocera 78100db
+
Bastien Nocera 78100db
+			key_down(appleir, appleir->current_key);
Bastien Nocera 78100db
+			/* Remote doesn't do key up, either pull them up, in the test
Bastien Nocera 78100db
+			   above, or here set a timer which pulls them up after 1/8 s */
Bastien Nocera 78100db
+			mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
Bastien Nocera 78100db
+			appleir->prev_key_idx = 0;
Bastien Nocera 78100db
+			return;
Bastien Nocera 78100db
+		} else if (index == -7) {
Bastien Nocera 78100db
+			/* Remember key for next packet */
Bastien Nocera 78100db
+			appleir->prev_key_idx = 0 - index;
Bastien Nocera 78100db
+			return;
Bastien Nocera 78100db
+		}
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+
Bastien Nocera 78100db
+	appleir->prev_key_idx = 0;
Bastien Nocera 78100db
+
Kyle McMartin 407cbd0
+	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
Kyle McMartin 407cbd0
+		key_down(appleir, appleir->current_key);
Kyle McMartin 407cbd0
+		/* Remote doesn't do key up, either pull them up, in the test
Kyle McMartin 407cbd0
+		   above, or here set a timer which pulls them up after 1/8 s */
Kyle McMartin 407cbd0
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
Kyle McMartin 407cbd0
+		return;
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
Kyle McMartin 407cbd0
+		battery_flat(appleir);
Kyle McMartin 407cbd0
+		/* Fall through */
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	dump_packet(appleir, "unknown packet", data, len);
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void appleir_urb(struct urb *urb)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	struct appleir *appleir = urb->context;
Kyle McMartin 407cbd0
+	int status = urb->status;
Kyle McMartin 407cbd0
+	int retval;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	switch (status) {
Kyle McMartin 407cbd0
+	case 0:
Kyle McMartin 407cbd0
+		new_data(appleir, urb->transfer_buffer, urb->actual_length);
Kyle McMartin 407cbd0
+		break;
Kyle McMartin 407cbd0
+	case -ECONNRESET:
Kyle McMartin 407cbd0
+	case -ENOENT:
Kyle McMartin 407cbd0
+	case -ESHUTDOWN:
Kyle McMartin 407cbd0
+		/* This urb is terminated, clean up */
Kyle McMartin 407cbd0
+		dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__,
Kyle McMartin 407cbd0
+			urb->status);
Kyle McMartin 407cbd0
+		return;
Kyle McMartin 407cbd0
+	default:
Kyle McMartin 407cbd0
+		dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__,
Kyle McMartin 407cbd0
+			urb->status);
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
Kyle McMartin 407cbd0
+	if (retval)
Kyle McMartin 407cbd0
+		err("%s - usb_submit_urb failed with result %d", __func__,
Kyle McMartin 407cbd0
+		    retval);
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static int appleir_open(struct input_dev *dev)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	struct appleir *appleir = input_get_drvdata(dev);
Kyle McMartin 407cbd0
+	struct usb_interface *intf = usb_ifnum_to_if(appleir->usbdev, 0);
Kyle McMartin 407cbd0
+	int r;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	r = usb_autopm_get_interface(intf);
Kyle McMartin 407cbd0
+	if (r) {
Kyle McMartin 407cbd0
+		dev_err(&intf->dev,
Kyle McMartin 407cbd0
+			"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
Kyle McMartin 407cbd0
+		return r;
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	mutex_lock(&appleir_mutex);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	if (usb_submit_urb(appleir->urb, GFP_ATOMIC)) {
Kyle McMartin 407cbd0
+		r = -EIO;
Kyle McMartin 407cbd0
+		goto fail;
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir->flags |= APPLEIR_OPENED;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	mutex_unlock(&appleir_mutex);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	usb_autopm_put_interface(intf);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	return 0;
Kyle McMartin 407cbd0
+fail:
Kyle McMartin 407cbd0
+	mutex_unlock(&appleir_mutex);
Kyle McMartin 407cbd0
+	usb_autopm_put_interface(intf);
Kyle McMartin 407cbd0
+	return r;
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void appleir_close(struct input_dev *dev)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	struct appleir *appleir = input_get_drvdata(dev);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	mutex_lock(&appleir_mutex);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	if (!(appleir->flags & APPLEIR_SUSPENDED)) {
Kyle McMartin 407cbd0
+		usb_kill_urb(appleir->urb);
Kyle McMartin 407cbd0
+		del_timer_sync(&appleir->key_up_timer);
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir->flags &= ~APPLEIR_OPENED;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	mutex_unlock(&appleir_mutex);
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static int appleir_probe(struct usb_interface *intf,
Kyle McMartin 407cbd0
+			 const struct usb_device_id *id)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	struct usb_device *dev = interface_to_usbdev(intf);
Kyle McMartin 407cbd0
+	struct usb_endpoint_descriptor *endpoint;
Kyle McMartin 407cbd0
+	struct appleir *appleir = NULL;
Kyle McMartin 407cbd0
+	struct input_dev *input_dev;
Kyle McMartin 407cbd0
+	int retval = -ENOMEM;
Kyle McMartin 407cbd0
+	int i;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
Kyle McMartin 407cbd0
+	if (!appleir)
Kyle McMartin 407cbd0
+		goto allocfail;
Kyle McMartin 407cbd0
+
Kyle McMartin 818f303
+	appleir->data = usb_alloc_coherent(dev, URB_SIZE, GFP_KERNEL,
Kyle McMartin 407cbd0
+					 &appleir->dma_buf);
Kyle McMartin 407cbd0
+	if (!appleir->data)
Kyle McMartin 407cbd0
+		goto usbfail;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
Kyle McMartin 407cbd0
+	if (!appleir->urb)
Kyle McMartin 407cbd0
+		goto urbfail;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir->usbdev = dev;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	input_dev = input_allocate_device();
Kyle McMartin 407cbd0
+	if (!input_dev)
Kyle McMartin 407cbd0
+		goto inputfail;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir->input_dev = input_dev;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
Kyle McMartin 407cbd0
+	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	input_dev->name = "Apple Infrared Remote Controller";
Kyle McMartin 407cbd0
+	input_dev->phys = appleir->phys;
Kyle McMartin 407cbd0
+	usb_to_input_id(dev, &input_dev->id);
Kyle McMartin 407cbd0
+	input_dev->dev.parent = &intf->dev;
Kyle McMartin 407cbd0
+	input_dev->keycode = appleir->keymap;
Kyle McMartin 407cbd0
+	input_dev->keycodesize = sizeof(unsigned short);
Kyle McMartin 407cbd0
+	input_dev->keycodemax = ARRAY_SIZE(appleir->keymap);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
Kyle McMartin 407cbd0
+	for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
Kyle McMartin 407cbd0
+		set_bit(appleir->keymap[i], input_dev->keybit);
Kyle McMartin 407cbd0
+	clear_bit(KEY_RESERVED, input_dev->keybit);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	input_set_drvdata(input_dev, appleir);
Kyle McMartin 407cbd0
+	input_dev->open = appleir_open;
Kyle McMartin 407cbd0
+	input_dev->close = appleir_close;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	usb_fill_int_urb(appleir->urb, dev,
Kyle McMartin 407cbd0
+			 usb_rcvintpipe(dev, endpoint->bEndpointAddress),
Kyle McMartin 407cbd0
+			 appleir->data, 8,
Kyle McMartin 407cbd0
+			 appleir_urb, appleir, endpoint->bInterval);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir->urb->transfer_dma = appleir->dma_buf;
Kyle McMartin 407cbd0
+	appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	setup_timer(&appleir->key_up_timer,
Kyle McMartin 407cbd0
+		    key_up_tick, (unsigned long) appleir);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	retval = input_register_device(appleir->input_dev);
Kyle McMartin 407cbd0
+	if (retval)
Kyle McMartin 407cbd0
+		goto inputfail;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	usb_set_intfdata(intf, appleir);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	return 0;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+inputfail:
Kyle McMartin 407cbd0
+	input_free_device(appleir->input_dev);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+urbfail:
Kyle McMartin 407cbd0
+	usb_free_urb(appleir->urb);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+usbfail:
Kyle McMartin 818f303
+	usb_free_coherent(dev, URB_SIZE, appleir->data,
Kyle McMartin 407cbd0
+			appleir->dma_buf);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+allocfail:
Kyle McMartin 407cbd0
+	kfree(appleir);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	return retval;
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void appleir_disconnect(struct usb_interface *intf)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	struct appleir *appleir = usb_get_intfdata(intf);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	usb_set_intfdata(intf, NULL);
Kyle McMartin 407cbd0
+	input_unregister_device(appleir->input_dev);
Kyle McMartin 407cbd0
+	usb_free_urb(appleir->urb);
Kyle McMartin 818f303
+	usb_free_coherent(interface_to_usbdev(intf), URB_SIZE,
Kyle McMartin 407cbd0
+			appleir->data, appleir->dma_buf);
Kyle McMartin 407cbd0
+	kfree(appleir);
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static int appleir_suspend(struct usb_interface *interface,
Kyle McMartin 407cbd0
+			   pm_message_t message)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	struct appleir *appleir = usb_get_intfdata(interface);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	mutex_lock(&appleir_mutex);
Kyle McMartin 407cbd0
+	if (appleir->flags & APPLEIR_OPENED)
Kyle McMartin 407cbd0
+		usb_kill_urb(appleir->urb);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir->flags |= APPLEIR_SUSPENDED;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	mutex_unlock(&appleir_mutex);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	return 0;
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static int appleir_resume(struct usb_interface *interface)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	struct appleir *appleir;
Kyle McMartin 407cbd0
+	int r = 0;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir = usb_get_intfdata(interface);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	mutex_lock(&appleir_mutex);
Kyle McMartin 407cbd0
+	if (appleir->flags & APPLEIR_OPENED) {
Kyle McMartin 407cbd0
+		struct usb_endpoint_descriptor *endpoint;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+		endpoint = &interface->cur_altsetting->endpoint[0].desc;
Kyle McMartin 407cbd0
+		usb_fill_int_urb(appleir->urb, appleir->usbdev,
Kyle McMartin 407cbd0
+				 usb_rcvintpipe(appleir->usbdev, endpoint->bEndpointAddress),
Kyle McMartin 407cbd0
+				 appleir->data, 8,
Kyle McMartin 407cbd0
+				 appleir_urb, appleir, endpoint->bInterval);
Kyle McMartin 407cbd0
+		appleir->urb->transfer_dma = appleir->dma_buf;
Kyle McMartin 407cbd0
+		appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+		/* And reset the USB device */
Kyle McMartin 407cbd0
+		if (usb_submit_urb(appleir->urb, GFP_ATOMIC))
Kyle McMartin 407cbd0
+			r = -EIO;
Kyle McMartin 407cbd0
+	}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	appleir->flags &= ~APPLEIR_SUSPENDED;
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	mutex_unlock(&appleir_mutex);
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+	return r;
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static struct usb_driver appleir_driver = {
Kyle McMartin 407cbd0
+	.name                 = "appleir",
Kyle McMartin 407cbd0
+	.probe                = appleir_probe,
Kyle McMartin 407cbd0
+	.disconnect           = appleir_disconnect,
Kyle McMartin 407cbd0
+	.suspend              = appleir_suspend,
Kyle McMartin 407cbd0
+	.resume               = appleir_resume,
Kyle McMartin 407cbd0
+	.reset_resume         = appleir_resume,
Kyle McMartin 407cbd0
+	.id_table             = appleir_ids,
Kyle McMartin 407cbd0
+};
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static int __init appleir_init(void)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	return usb_register(&appleir_driver);
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+static void __exit appleir_exit(void)
Kyle McMartin 407cbd0
+{
Kyle McMartin 407cbd0
+	usb_deregister(&appleir_driver);
Kyle McMartin 407cbd0
+}
Kyle McMartin 407cbd0
+
Kyle McMartin 407cbd0
+module_init(appleir_init);
Kyle McMartin 407cbd0
+module_exit(appleir_exit);
Bastien Nocera 78100db
-- 
Bastien Nocera 78100db
1.7.2.2
Bastien Nocera 78100db