linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Input: add appleir USB driver
@ 2010-02-08 16:32 Bastien Nocera
  0 siblings, 0 replies; 57+ messages in thread
From: Bastien Nocera @ 2010-02-08 16:32 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-input, Dmitry Torokhov

This driver was originally written by James McKenzie, updated by
Greg Kroah-Hartman, further updated by myself, with suspend support
added.

More recent versions of the IR receiver are also supported through
a patch by Alex Karpenko.

Tested on a MacbookAir1,1

Signed-off-by: Bastien Nocera <hadess@hadess.net>
---
 Documentation/input/appleir.txt |   45 ++++
 drivers/hid/hid-apple.c         |    4 -
 drivers/hid/hid-core.c          |    5 +-
 drivers/hid/hid-ids.h           |    1 +
 drivers/input/misc/Kconfig      |   13 +
 drivers/input/misc/Makefile     |    1 +
 drivers/input/misc/appleir.c    |  477 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 540 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/input/appleir.txt
 create mode 100644 drivers/input/misc/appleir.c

diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
new file mode 100644
index 0000000..21e0d60
--- /dev/null
+++ b/Documentation/input/appleir.txt
@@ -0,0 +1,45 @@
+Apple IR receiver Driver (appleir)
+----------------------------------
+	Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+
+The appleir driver is a kernel input driver to handle Apple's IR
+receivers (and associated remotes) in the kernel.
+
+The driver is an input driver which only handles "official" remotes
+as built and sold by Apple.
+
+Authors
+-------
+
+James McKenzie (original driver)
+Alex Karpenko (05ac:8242 support)
+Greg Kroah-Hartman (cleanups and original submission)
+Bastien Nocera (further cleanups and suspend support)
+
+Supported hardware
+------------------
+
+- All Apple laptops and desktops from 2005 onwards, except:
+  - the unibody Macbook (2009)
+  - Mac Pro (all versions)
+- Apple TV (all revisions)
+
+The remote will only support the 6 buttons of the original remotes
+as sold by Apple. See the next section if you want to use other remotes
+or want to use lirc with the device instead of the kernel driver.
+
+Using lirc (native) instead of the kernel driver
+------------------------------------------------
+
+First, you will need to disable the kernel driver for the receiver.
+
+This can be achieved by passing quirks to the usbhid driver.
+The quirk line would be:
+usbhid.quirks=0x05ac:0x8242:0x08
+
+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
+With 0x8242 being the product ID (check the output of lsusb for your hardware)
+And 0x08 being "HID_CONNECT_HIDDEV"
+
+This should force the creation of a hiddev device for the receiver, and
+make it usable under lirc.
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 4b96e7a..d1fdcd0 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -353,10 +353,6 @@ static void apple_remove(struct hid_device *hdev)
 }
 
 static const struct hid_device_id apple_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
 		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
 
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 80792d3..61b199e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1250,8 +1250,6 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
 static const struct hid_device_id hid_blacklist[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
@@ -1540,6 +1538,9 @@ static const struct hid_device_id hid_ignore_list[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3839340..8b29a88 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -90,6 +90,7 @@
 #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS	0x0238
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
 #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
 
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 16ec523..4340986 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -149,6 +149,19 @@ config INPUT_KEYSPAN_REMOTE
 	  To compile this driver as a module, choose M here: the module will
 	  be called keyspan_remote.
 
+config INPUT_APPLEIR
+	tristate "Apple infrared receiver (built in)"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use a Apple infrared remote control. All
+	  the Apple computers from 2005 onwards include such a port, except
+	  the unibody Macbook (2009), and Mac Pros. This receiver is also
+	  used in the Apple TV set-top box.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called appleir.
+
 config INPUT_POWERMATE
 	tristate "Griffin PowerMate and Contour Jog support"
 	depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index a8b8485..041e6f5 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -5,6 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
+obj-$(CONFIG_INPUT_APPLEIR)		+= appleir.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
new file mode 100644
index 0000000..138f4c8
--- /dev/null
+++ b/drivers/input/misc/appleir.c
@@ -0,0 +1,477 @@
+/*
+ * appleir: USB driver for the apple ir device
+ *
+ * Original driver written by James McKenzie
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Copyright (C) 2006 James McKenzie
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2008 Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+
+#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>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#define DRIVER_VERSION "v1.2"
+#define DRIVER_AUTHOR "James McKenzie"
+#define DRIVER_DESC "Apple infrared receiver driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_APPLE			0x05ac
+#define USB_DEVICE_ID_APPLE_IRCONTROL		0x8240
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4		0x8242
+
+#define URB_SIZE	32
+
+#define MAX_KEYS	8
+#define MAX_KEYS_MASK	(MAX_KEYS - 1)
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+struct appleir {
+	struct input_dev *input_dev;
+	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;
+	int current_key;
+	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_ATV_IRCONTROL) },
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+	{}
+};
+MODULE_DEVICE_TABLE(usb, appleir_ids);
+
+/* I have two devices both of which report the following */
+/* 25 87 ee 83 0a  	+  */
+/* 25 87 ee 83 0c  	-  */
+/* 25 87 ee 83 09	<< */
+/* 25 87 ee 83 06	>> */
+/* 25 87 ee 83 05	>" */
+/* 25 87 ee 83 03	menu */
+/* 26 00 00 00 00	for key repeat*/
+
+/* Thomas Glanzmann reports the following responses */
+/* 25 87 ee ca 0b	+  */
+/* 25 87 ee ca 0d	-  */
+/* 25 87 ee ca 08	<< */
+/* 25 87 ee ca 07	>> */
+/* 25 87 ee ca 04	>" */
+/* 25 87 ee ca 02 	menu */
+/* 26 00 00 00 00       for key repeat*/
+/* He also observes the following event sometimes */
+/* sent after a key is release, which I interpret */
+/* as a flat battery message */
+/* 25 87 e0 ca 06	flat battery */
+
+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
+/* 25 87 ee 47 0b	+  */
+/* 25 87 ee 47 0d	-  */
+/* 25 87 ee 47 08	<< */
+/* 25 87 ee 47 07	>> */
+/* 25 87 ee 47 04	>" */
+/* 25 87 ee 47 02 	menu */
+/* 26 87 ee 47 ** 	for key repeat (** is the code of the key being held) */
+
+static int keymap[MAX_KEYS] = {
+	KEY_RESERVED,
+	KEY_MENU,
+	KEY_PLAYPAUSE,
+	KEY_FORWARD,
+	KEY_BACK,
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_RESERVED,
+};
+
+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
+{
+	int i;
+
+	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
+
+	for (i = 0; i < len; ++i)
+		printk(" %02x", data[i]);
+	printk("\n");
+}
+
+static void key_up(struct appleir *appleir, int key)
+{
+	dbginfo (&appleir->input_dev->dev, "key %d up\n", key);
+	input_report_key(appleir->input_dev, key, 0);
+	input_sync(appleir->input_dev);
+}
+
+static void key_down(struct appleir *appleir, int key)
+{
+	dbginfo (&appleir->input_dev->dev, "key %d down\n", key);
+	input_report_key(appleir->input_dev, key, 1);
+	input_sync(appleir->input_dev);
+}
+
+static void battery_flat(struct appleir *appleir)
+{
+	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
+}
+
+static void key_up_tick(unsigned long data)
+{
+	struct appleir *appleir = (struct appleir *)data;
+
+	if (appleir->current_key) {
+		key_up(appleir, appleir->current_key);
+		appleir->current_key = 0;
+	}
+}
+
+static void new_data(struct appleir *appleir, u8 *data, int len)
+{
+	static const u8 keydown[] = { 0x25, 0x87, 0xee };
+	static const u8 keyrepeat[] = { 0x26, };
+	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
+
+	if (debug)
+		dump_packet(appleir, "received", data, len);
+
+	if (len != 5)
+		return;
+
+	if (!memcmp(data, keydown, sizeof(keydown))) {
+		/* If we already have a key down, take it up before marking
+		   this one down */
+		if (appleir->current_key)
+			key_up(appleir, appleir->current_key);
+		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
+
+		key_down(appleir, appleir->current_key);
+		/* Remote doesn't do key up, either pull them up, in the test
+		   above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+
+		return;
+	}
+
+	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
+		key_down(appleir, appleir->current_key);
+		/* Remote doesn't do key up, either pull them up, in the test
+		   above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+		return;
+	}
+
+	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
+		battery_flat(appleir);
+		/* Fall through */
+	}
+
+	dump_packet(appleir, "unknown packet", data, len);
+}
+
+static void appleir_urb(struct urb *urb)
+{
+	struct appleir *appleir = urb->context;
+	int status = urb->status;
+	int retval;
+
+	switch (status) {
+	case 0:
+		new_data(appleir, urb->transfer_buffer, urb->actual_length);
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* This urb is terminated, clean up */
+		dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__,
+			urb->status);
+		return;
+	default:
+		dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__,
+			urb->status);
+	}
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result %d", __func__,
+		    retval);
+}
+
+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)) {
+		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);
+
+	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,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct appleir *appleir = NULL;
+	struct input_dev *input_dev;
+	int retval = -ENOMEM;
+	int i;
+
+	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
+	if (!appleir)
+		goto fail;
+
+	appleir->data = usb_buffer_alloc(dev, URB_SIZE, GFP_KERNEL,
+					 &appleir->dma_buf);
+	if (!appleir->data)
+		goto fail;
+
+	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!appleir->urb)
+		goto fail;
+
+	appleir->usbdev = dev;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		goto fail;
+
+	appleir->input_dev = input_dev;
+
+	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
+	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
+
+	input_dev->name = "Apple infrared remote control driver";
+	input_dev->phys = appleir->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+	input_set_drvdata(input_dev, appleir);
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+	input_dev->ledbit[0] = 0;
+
+	for (i = 0; i < MAX_KEYS; i++)
+		set_bit(keymap[i], input_dev->keybit);
+
+	clear_bit(0, input_dev->keybit);
+
+	input_dev->open = appleir_open;
+	input_dev->close = appleir_close;
+
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+	usb_fill_int_urb(appleir->urb, dev,
+			 usb_rcvintpipe(dev, 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;
+
+	usb_set_intfdata(intf, appleir);
+
+	init_timer(&appleir->key_up_timer);
+
+	appleir->key_up_timer.function = key_up_tick;
+	appleir->key_up_timer.data = (unsigned long)appleir;
+
+	appleir->timer_initted++;
+
+	retval = input_register_device(appleir->input_dev);
+	if (retval)
+		goto fail;
+
+	return 0;
+
+fail:
+	printk(KERN_WARNING "Failed to load appleir\n");
+	if (appleir) {
+		if (appleir->data)
+			usb_buffer_free(dev, URB_SIZE, appleir->data,
+					appleir->dma_buf);
+
+		if (appleir->timer_initted)
+			del_timer_sync(&appleir->key_up_timer);
+
+		if (appleir->input_dev)
+			input_free_device(appleir->input_dev);
+
+		kfree(appleir);
+	}
+
+	return retval;
+}
+
+static void appleir_disconnect(struct usb_interface *intf)
+{
+	struct appleir *appleir = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (appleir) {
+		input_unregister_device(appleir->input_dev);
+		if (appleir->timer_initted)
+			del_timer_sync(&appleir->key_up_timer);
+		usb_kill_urb(appleir->urb);
+		usb_free_urb(appleir->urb);
+		usb_buffer_free(interface_to_usbdev(intf), URB_SIZE,
+				appleir->data, appleir->dma_buf);
+		kfree(appleir);
+	}
+}
+
+static int appleir_suspend(struct usb_interface *interface,
+			   pm_message_t message)
+{
+	struct appleir *appleir;
+
+	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;
+
+	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,
+	.suspend              = appleir_suspend,
+	.resume               = appleir_resume,
+	.reset_resume         = NULL,
+	.id_table             = appleir_ids,
+	.supports_autosuspend = 1,
+};
+
+static int __init appleir_init(void)
+{
+	int retval;
+
+	retval = usb_register(&appleir_driver);
+	if (retval)
+		goto out;
+	printk(KERN_INFO DRIVER_VERSION ":" DRIVER_DESC);
+out:
+	return retval;
+}
+
+static void __exit appleir_exit(void)
+{
+	usb_deregister(&appleir_driver);
+}
+
+module_init(appleir_init);
+module_exit(appleir_exit);
-- 
1.6.6



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2012-11-19 15:44   ` Bastien Nocera
@ 2012-11-19 16:01     ` Benjamin Tissoires
  0 siblings, 0 replies; 57+ messages in thread
From: Benjamin Tissoires @ 2012-11-19 16:01 UTC (permalink / raw)
  To: Bastien Nocera
  Cc: Fabien André,
	linux-input, Jarod Wilson, Jiri Kosina, Dmitry Torokhov

On Mon, Nov 19, 2012 at 4:44 PM, Bastien Nocera <hadess@hadess.net> wrote:
> On Mon, 2012-11-19 at 16:32 +0100, Benjamin Tissoires wrote:
>> Hi Bastien,
>>
>> (adding the input and HID maintainers to the recipient list).
>>
>> On Thu, Nov 15, 2012 at 7:13 PM, Bastien Nocera <hadess@hadess.net> wrote:
>> >
>> > This driver was originally written by James McKenzie, updated by
>> > Greg Kroah-Hartman, further updated by myself, with suspend support
>> > added.
>> >
>> > More recent versions of the IR receiver are also supported through
>> > a patch by Alex Karpenko. The patch also adds support for the 2nd
>> > and 5th generation of the controller, and the menu key on newer
>> > brushed metal remotes.
>> >
>> > Tested on a MacbookAir1,1
>> >
>> > Signed-off-by: Bastien Nocera <hadess@hadess.net>
>> > ---
>> >
>> > Resend, as the original patch never made it. I cleaned up the patch a
>> > bit further, and test compiled it, but didn't have a chance to test it
>> > as I don't have a machine with that hardware available anymore.
>>
>> Fabien, in CC, gracefully accepted to test and to try to adapt this
>> patch depending on the reviews. So we can ask for tests and changes!
>
> \o/
>
>> > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
>> > index 9d7a428..a4af9a9 100644
>> > --- a/drivers/hid/hid-ids.h
>> > +++ b/drivers/hid/hid-ids.h
>> > @@ -137,8 +137,11 @@
>> >  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO   0x0256
>> >  #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
>> >  #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
>> > -#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL      0x8241
>>
>> not sure we should change this define to an undocumented one.
>
> I don't understand the comment here. The name is an artifact of where
> the receiver was first seen and the Apple TV receiver is actually just
> another model of this same receiver. So it makes sense to consolidate
> below.

ok, if this id is not specific to Apple TV, that makes sense.

>
>> > +#define USB_DEVICE_ID_APPLE_IRCONTROL  0x8240
>> > +#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440
>> > +#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
>> >  #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
>> > +#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
>
>
>> > +struct appleir {
>> > +       struct input_dev *input_dev;
>> > +       unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
>>
>> why this keymap is embedded in the struct? It's basically just a copy
>> of appleir_key_table and it's not modified anytime.
>
> It would be modified if you change the keymap.

ouch, sorry, I read it too fast. You're perfectly right.
That makes me wondering if this will still be possible with a hid
driver that implements raw_event...

Cheers,
Benjamin

>
> Cheers
>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2012-11-19 15:32 ` Benjamin Tissoires
@ 2012-11-19 15:44   ` Bastien Nocera
  2012-11-19 16:01     ` Benjamin Tissoires
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2012-11-19 15:44 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Fabien André,
	linux-input, Jarod Wilson, Jiri Kosina, Dmitry Torokhov

On Mon, 2012-11-19 at 16:32 +0100, Benjamin Tissoires wrote:
> Hi Bastien,
> 
> (adding the input and HID maintainers to the recipient list).
> 
> On Thu, Nov 15, 2012 at 7:13 PM, Bastien Nocera <hadess@hadess.net> wrote:
> >
> > This driver was originally written by James McKenzie, updated by
> > Greg Kroah-Hartman, further updated by myself, with suspend support
> > added.
> >
> > More recent versions of the IR receiver are also supported through
> > a patch by Alex Karpenko. The patch also adds support for the 2nd
> > and 5th generation of the controller, and the menu key on newer
> > brushed metal remotes.
> >
> > Tested on a MacbookAir1,1
> >
> > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > ---
> >
> > Resend, as the original patch never made it. I cleaned up the patch a
> > bit further, and test compiled it, but didn't have a chance to test it
> > as I don't have a machine with that hardware available anymore.
> 
> Fabien, in CC, gracefully accepted to test and to try to adapt this
> patch depending on the reviews. So we can ask for tests and changes!

\o/

> > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> > index 9d7a428..a4af9a9 100644
> > --- a/drivers/hid/hid-ids.h
> > +++ b/drivers/hid/hid-ids.h
> > @@ -137,8 +137,11 @@
> >  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO   0x0256
> >  #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
> >  #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
> > -#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL      0x8241
> 
> not sure we should change this define to an undocumented one.

I don't understand the comment here. The name is an artifact of where
the receiver was first seen and the Apple TV receiver is actually just
another model of this same receiver. So it makes sense to consolidate
below.

> > +#define USB_DEVICE_ID_APPLE_IRCONTROL  0x8240
> > +#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440
> > +#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
> >  #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
> > +#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243


> > +struct appleir {
> > +       struct input_dev *input_dev;
> > +       unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
> 
> why this keymap is embedded in the struct? It's basically just a copy
> of appleir_key_table and it's not modified anytime.

It would be modified if you change the keymap.

Cheers


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2012-11-15 18:13 Bastien Nocera
@ 2012-11-19 15:32 ` Benjamin Tissoires
  2012-11-19 15:44   ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Benjamin Tissoires @ 2012-11-19 15:32 UTC (permalink / raw)
  To: Bastien Nocera, Fabien André
  Cc: linux-input, Jarod Wilson, Jiri Kosina, Dmitry Torokhov

Hi Bastien,

(adding the input and HID maintainers to the recipient list).

On Thu, Nov 15, 2012 at 7:13 PM, Bastien Nocera <hadess@hadess.net> wrote:
>
> This driver was originally written by James McKenzie, updated by
> Greg Kroah-Hartman, further updated by myself, with suspend support
> added.
>
> More recent versions of the IR receiver are also supported through
> a patch by Alex Karpenko. The patch also adds support for the 2nd
> and 5th generation of the controller, and the menu key on newer
> brushed metal remotes.
>
> Tested on a MacbookAir1,1
>
> Signed-off-by: Bastien Nocera <hadess@hadess.net>
> ---
>
> Resend, as the original patch never made it. I cleaned up the patch a
> bit further, and test compiled it, but didn't have a chance to test it
> as I don't have a machine with that hardware available anymore.

Fabien, in CC, gracefully accepted to test and to try to adapt this
patch depending on the reviews. So we can ask for tests and changes!

>
>  Documentation/input/appleir.txt |  46 ++++
>  drivers/hid/hid-apple.c         |   4 -
>  drivers/hid/hid-core.c          |   7 +-
>  drivers/hid/hid-ids.h           |   5 +-
>  drivers/input/misc/Kconfig      |  13 +
>  drivers/input/misc/Makefile     |   1 +
>  drivers/input/misc/appleir.c    | 527 ++++++++++++++++++++++++++++++++++++++++

If this device presents itself as a hid device, there are much chances
that we can use the hid .raw_event interface. This will help us for
the usb part and remove potential bugs and support and greatly
simplify this driver.

>  7 files changed, 596 insertions(+), 7 deletions(-)
>  create mode 100644 Documentation/input/appleir.txt
>  create mode 100644 drivers/input/misc/appleir.c
>
> diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
> new file mode 100644
> index 0000000..db637fb
> --- /dev/null
> +++ b/Documentation/input/appleir.txt
> @@ -0,0 +1,46 @@
> +Apple IR receiver Driver (appleir)
> +----------------------------------
> +       Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
> +
> +The appleir driver is a kernel input driver to handle Apple's IR
> +receivers (and associated remotes) in the kernel.
> +
> +The driver is an input driver which only handles "official" remotes
> +as built and sold by Apple.
> +
> +Authors
> +-------
> +
> +James McKenzie (original driver)
> +Alex Karpenko (05ac:8242 support)
> +Greg Kroah-Hartman (cleanups and original submission)
> +Bastien Nocera (further cleanups, brushed metal "enter"
> +button support and suspend support)
> +
> +Supported hardware
> +------------------
> +
> +- All Apple laptops and desktops from 2005 onwards, except:
> +  - the unibody Macbook (2009)
> +  - Mac Pro (all versions)
> +- Apple TV (all revisions prior to September 2010)
> +
> +The remote will only support the 6 (old white) or 7 (brushed metal) buttons
> +of the remotes as sold by Apple. See the next section if you want to use
> +other remotes or want to use lirc with the device instead of the kernel driver.
> +
> +Using lirc (native) instead of the kernel driver
> +------------------------------------------------
> +
> +First, you will need to disable the kernel driver for the receiver.
> +
> +This can be achieved by passing quirks to the usbhid driver.
> +The quirk line would be:
> +usbhid.quirks=0x05ac:0x8242:0x40000010
> +
> +With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
> +With 0x8242 being the product ID (check the output of lsusb for your hardware)
> +And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE"
> +
> +This should force the creation of a hiddev device for the receiver, and
> +make it usable under lirc.
> diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
> index fd7722a..30a4824 100644
> --- a/drivers/hid/hid-apple.c
> +++ b/drivers/hid/hid-apple.c
> @@ -390,10 +390,6 @@ static void apple_remove(struct hid_device *hdev)
>  }
>
>  static const struct hid_device_id apple_devices[] = {
> -       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
> -               .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
> -       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
> -               .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
>         { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
>                 .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
>
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index f4109fd..3fd4c10 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -1471,8 +1471,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
>         { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
> -       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
> -       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
>         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
>         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
> @@ -1925,6 +1923,11 @@ static const struct hid_device_id hid_ignore_list[] = {
>         { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
> +       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
> +       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
> +       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
> +       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
> +       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },

Using a hid kernel driver will move these additions to hid_have_special_driver.

>         { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
>         { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
>         { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 9d7a428..a4af9a9 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -137,8 +137,11 @@
>  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO   0x0256
>  #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
>  #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
> -#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL      0x8241

not sure we should change this define to an undocumented one.

> +#define USB_DEVICE_ID_APPLE_IRCONTROL  0x8240
> +#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440
> +#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
>  #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
> +#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
>
>  #define USB_VENDOR_ID_ASUS             0x0486
>  #define USB_DEVICE_ID_ASUS_T91MT       0x0185
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index 2a1647e..c1890c3 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -321,6 +321,19 @@ config INPUT_KXTJ9_POLLED_MODE
>         help
>           Say Y here if you need accelerometer to work in polling mode.
>
> +config INPUT_APPLEIR
> +       tristate "Apple infrared receiver (built in)"
> +       depends on USB_ARCH_HAS_HCD
> +       select USB
> +       help
> +         Say Y here if you want to use a Apple infrared remote control. All
> +         the Apple computers from 2005 onwards include such a port, except
> +         the unibody Macbook (2009), and Mac Pros. This receiver is also
> +         used in the Apple TV set-top box prior to the 2010 model.
> +
> +         To compile this driver as a module, choose M here: the module will
> +         be called appleir.
> +
>  config INPUT_POWERMATE
>         tristate "Griffin PowerMate and Contour Jog support"
>         depends on USB_ARCH_HAS_HCD
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index 1f874af..c00d562 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_INPUT_ADXL34X)           += adxl34x.o
>  obj-$(CONFIG_INPUT_ADXL34X_I2C)                += adxl34x-i2c.o
>  obj-$(CONFIG_INPUT_ADXL34X_SPI)                += adxl34x-spi.o
>  obj-$(CONFIG_INPUT_APANEL)             += apanel.o
> +obj-$(CONFIG_INPUT_APPLEIR)            += appleir.o
>  obj-$(CONFIG_INPUT_ATI_REMOTE2)                += ati_remote2.o
>  obj-$(CONFIG_INPUT_ATLAS_BTNS)         += atlas_btns.o
>  obj-$(CONFIG_INPUT_BFIN_ROTARY)                += bfin_rotary.o
> diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
> new file mode 100644
> index 0000000..c6ca58c
> --- /dev/null
> +++ b/drivers/input/misc/appleir.c
> @@ -0,0 +1,527 @@
> +/*
> + * appleir: USB driver for the apple ir device
> + *
> + * Original driver written by James McKenzie
> + * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
> + *
> + * Copyright (C) 2006 James McKenzie
> + * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
> + * Copyright (C) 2008 Novell Inc.
> + * Copyright (C) 2010, 2012 Bastien Nocera <hadess@hadess.net>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation, version 2.
> + *
> + */
> +
> +#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>
> +#include <linux/usb/input.h>
> +#include <asm/unaligned.h>
> +#include <asm/byteorder.h>
> +
> +#define DRIVER_VERSION "v1.2"
> +#define DRIVER_AUTHOR "James McKenzie"
> +#define DRIVER_DESC "Apple infrared receiver driver"
> +#define DRIVER_LICENSE "GPL"

No need to create these macros.

> +
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE(DRIVER_LICENSE);
> +
> +#define USB_VENDOR_ID_APPLE                    0x05ac
> +#define USB_DEVICE_ID_APPLE_IRCONTROL          0x8240
> +#define USB_DEVICE_ID_APPLE_IRCONTROL2         0x1440
> +#define USB_DEVICE_ID_APPLE_IRCONTROL3         0x8241
> +#define USB_DEVICE_ID_APPLE_IRCONTROL4         0x8242
> +#define USB_DEVICE_ID_APPLE_IRCONTROL5         0x8243

these definitions are already in drivers/hid/hid-ids.h, so they can be
skipped in the hid version.

> +
> +#define URB_SIZE       32
> +
> +#define MAX_KEYS       9
> +#define MAX_KEYS_MASK  (MAX_KEYS - 1)

can be skipped too.

> +
> +#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
> +
> +/* I have two devices both of which report the following */
> +/* 25 87 ee 83 0a      +  */
> +/* 25 87 ee 83 0c      -  */
> +/* 25 87 ee 83 09      << */
> +/* 25 87 ee 83 06      >> */
> +/* 25 87 ee 83 05      >" */
> +/* 25 87 ee 83 03      menu */
> +/* 26 00 00 00 00      for key repeat*/
> +
> +/* Thomas Glanzmann reports the following responses */
> +/* 25 87 ee ca 0b      +  */
> +/* 25 87 ee ca 0d      -  */
> +/* 25 87 ee ca 08      << */
> +/* 25 87 ee ca 07      >> */
> +/* 25 87 ee ca 04      >" */
> +/* 25 87 ee ca 02      menu */
> +/* 26 00 00 00 00       for key repeat*/
> +/* He also observes the following event sometimes */
> +/* sent after a key is release, which I interpret */
> +/* as a flat battery message */
> +/* 25 87 e0 ca 06      flat battery */
> +
> +/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
> +/* 25 87 ee 47 0b      +  */
> +/* 25 87 ee 47 0d      -  */
> +/* 25 87 ee 47 08      << */
> +/* 25 87 ee 47 07      >> */
> +/* 25 87 ee 47 04      >" */
> +/* 25 87 ee 47 02      menu */
> +/* 26 87 ee 47 **      for key repeat (** is the code of the key being held) */
> +
> +/* Bastien Nocera's "new" remote */
> +/* 25 87 ee 91 5f      followed by
> + * 25 87 ee 91 05      gives you >"
> + *
> + * 25 87 ee 91 5c      followed by
> + * 25 87 ee 91 05      gives you the middle button */
> +
> +static const unsigned short appleir_key_table[] = {
> +       KEY_RESERVED,
> +       KEY_MENU,
> +       KEY_PLAYPAUSE,
> +       KEY_FORWARD,
> +       KEY_BACK,
> +       KEY_VOLUMEUP,
> +       KEY_VOLUMEDOWN,
> +       KEY_ENTER,
> +       KEY_RESERVED,
> +};
> +
> +struct appleir {
> +       struct input_dev *input_dev;
> +       unsigned short keymap[ARRAY_SIZE(appleir_key_table)];

why this keymap is embedded in the struct? It's basically just a copy
of appleir_key_table and it's not modified anytime.

> +       u8 *data;
> +       dma_addr_t dma_buf;
> +       struct usb_device *usbdev;
> +       unsigned int flags;
> +       struct urb *urb;
> +       struct timer_list key_up_timer;

all these usb stuff can be skipped with hid.

> +       int current_key;
> +       int prev_key_idx;
> +       char phys[32];

same for phys

> +};
> +
> +static DEFINE_MUTEX(appleir_mutex);

no need to maintain a mutex with hid

> +
> +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_IRCONTROL2) },
> +       { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
> +       { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
> +       { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(usb, appleir_ids);
> +
> +static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
> +{
> +       int i;
> +
> +       printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);

Should be KERN_INFO when used with if (debug)

> +
> +       for (i = 0; i < len; ++i)
> +               printk(" %02x", data[i]);
> +       printk(" (should be command %d)\n", (data[4] >> 1) & MAX_KEYS_MASK);

Since 3.6, you can use syntax like dev_XXX(&dev, "%*ph\n", n, buf);

So this function can be skipped entirely as you can use %*ph with dbginfo.

> +}
> +
> +static int get_key(int data)
> +{
> +       switch (data) {
> +       case 0x02:
> +       case 0x03:
> +               /* menu */
> +               return 1;
> +       case 0x04:
> +       case 0x05:
> +               /* >" */
> +               return 2;
> +       case 0x06:
> +       case 0x07:
> +               /* >> */
> +               return 3;
> +       case 0x08:
> +       case 0x09:
> +               /* << */
> +               return 4;
> +       case 0x0a:
> +       case 0x0b:
> +               /* + */
> +               return 5;
> +       case 0x0c:
> +       case 0x0d:
> +               /* - */
> +               return 6;
> +       case 0x5c:
> +               /* Middle button, on newer remotes,
> +                * part of a 2 packet-command */
> +               return -7;
> +       default:
> +               return -1;
> +       }
> +}
> +
> +static void key_up(struct appleir *appleir, int key)
> +{
> +       dbginfo(&appleir->input_dev->dev, "key %d up\n", key);
> +       input_report_key(appleir->input_dev, key, 0);
> +       input_sync(appleir->input_dev);
> +}
> +
> +static void key_down(struct appleir *appleir, int key)
> +{
> +       dbginfo(&appleir->input_dev->dev, "key %d down\n", key);
> +       input_report_key(appleir->input_dev, key, 1);
> +       input_sync(appleir->input_dev);
> +}
> +
> +static void battery_flat(struct appleir *appleir)
> +{
> +       dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
> +}
> +
> +static void key_up_tick(unsigned long data)
> +{
> +       struct appleir *appleir = (struct appleir *)data;
> +
> +       if (appleir->current_key) {
> +               key_up(appleir, appleir->current_key);
> +               appleir->current_key = 0;
> +       }
> +}
> +
> +static void new_data(struct appleir *appleir, u8 *data, int len)
> +{
> +       static const u8 keydown[] = { 0x25, 0x87, 0xee };
> +       static const u8 keyrepeat[] = { 0x26, };
> +       static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
> +
> +       if (debug)
> +               dump_packet(appleir, "received", data, len);

use dginfo directly

> +
> +       if (len != 5)
> +               return;
> +
> +       if (!memcmp(data, keydown, sizeof(keydown))) {
> +               int index;
> +
> +               /* If we already have a key down, take it up before marking
> +                  this one down */
> +               if (appleir->current_key)
> +                       key_up(appleir, appleir->current_key);
> +
> +               /* Handle dual packet commands */
> +               if (appleir->prev_key_idx > 0)
> +                       index = appleir->prev_key_idx;
> +               else
> +                       index = get_key(data[4]);
> +
> +               if (index > 0) {
> +                       appleir->current_key = appleir->keymap[index];
> +
> +                       key_down(appleir, appleir->current_key);
> +                       /* Remote doesn't do key up, either pull them up, in
> +                        * the test above, or here set a timer which pulls
> +                        * them up after 1/8 s */
> +                       mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
> +                       appleir->prev_key_idx = 0;
> +                       return;
> +               } else if (index == -7) {
> +                       /* Remember key for next packet */
> +                       appleir->prev_key_idx = 0 - index;
> +                       return;
> +               }
> +       }
> +
> +       appleir->prev_key_idx = 0;
> +
> +       if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
> +               key_down(appleir, appleir->current_key);
> +               /* Remote doesn't do key up, either pull them up, in the test
> +                  above, or here set a timer which pulls them up after 1/8 s */
> +               mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
> +               return;
> +       }
> +
> +       if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
> +               battery_flat(appleir);
> +               /* Fall through */
> +       }
> +
> +       dump_packet(appleir, "unknown packet", data, len);
> +}

Then, the usb part of the driver can be skipped.

> +
> +static void appleir_urb(struct urb *urb)
> +{
> +       struct appleir *appleir = urb->context;
> +       int status = urb->status;
> +       int retval;
> +
> +       switch (status) {
> +       case 0:
> +               new_data(appleir, urb->transfer_buffer, urb->actual_length);
> +               break;
> +       case -ECONNRESET:
> +       case -ENOENT:
> +       case -ESHUTDOWN:
> +               /* This urb is terminated, clean up */
> +               dbginfo(&appleir->input_dev->dev,
> +                       "%s - urb shutting down with status: %d",
> +                       __func__, urb->status);
> +               return;
> +       default:
> +               dbginfo(&appleir->input_dev->dev,
> +                       "%s - nonzero urb status received: %d",
> +                       __func__, urb->status);
> +       }
> +
> +       retval = usb_submit_urb(urb, GFP_ATOMIC);
> +       if (retval)
> +               dev_err(&appleir->input_dev->dev,
> +                       "%s - usb_submit_urb failed with result %d", __func__,
> +                       retval);
> +}
> +
> +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_ATOMIC)) {
> +               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);
> +
> +       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,
> +                        const struct usb_device_id *id)
> +{
> +       struct usb_device *dev = interface_to_usbdev(intf);
> +       struct usb_endpoint_descriptor *endpoint;
> +       struct appleir *appleir = NULL;
> +       struct input_dev *input_dev;
> +       int retval = -ENOMEM;
> +       int i;
> +
> +       appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
> +       if (!appleir)
> +               goto allocfail;
> +
> +       appleir->data = usb_alloc_coherent(dev, URB_SIZE, GFP_KERNEL,
> +                                        &appleir->dma_buf);
> +       if (!appleir->data)
> +               goto usbfail;
> +
> +       appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
> +       if (!appleir->urb)
> +               goto urbfail;
> +
> +       appleir->usbdev = dev;
> +
> +       input_dev = input_allocate_device();
> +       if (!input_dev)
> +               goto inputfail;
> +
> +       appleir->input_dev = input_dev;
> +
> +       usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
> +       strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
> +
> +       input_dev->name = "Apple Infrared Remote Controller";
> +       input_dev->phys = appleir->phys;
> +       usb_to_input_id(dev, &input_dev->id);
> +       input_dev->dev.parent = &intf->dev;
> +       input_dev->keycode = appleir->keymap;
> +       input_dev->keycodesize = sizeof(unsigned short);
> +       input_dev->keycodemax = ARRAY_SIZE(appleir->keymap);
> +
> +       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
> +
> +       memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
> +       for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
> +               set_bit(appleir->keymap[i], input_dev->keybit);
> +       clear_bit(KEY_RESERVED, input_dev->keybit);
> +
> +       input_set_drvdata(input_dev, appleir);
> +       input_dev->open = appleir_open;
> +       input_dev->close = appleir_close;
> +
> +       endpoint = &intf->cur_altsetting->endpoint[0].desc;
> +
> +       usb_fill_int_urb(appleir->urb, dev,
> +                        usb_rcvintpipe(dev, 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;
> +
> +       setup_timer(&appleir->key_up_timer,
> +                   key_up_tick, (unsigned long) appleir);
> +
> +       retval = input_register_device(appleir->input_dev);
> +       if (retval)
> +               goto inputfail;
> +
> +       usb_set_intfdata(intf, appleir);
> +
> +       return 0;
> +
> +inputfail:

it seems that inputfail should not call input_free_device.

> +       input_free_device(appleir->input_dev);
> +
> +urbfail:

urbfail should not free the urb, it has failed to allocate

> +       usb_free_urb(appleir->urb);
> +
> +usbfail:

ditto

> +       usb_free_coherent(dev, URB_SIZE, appleir->data,
> +                       appleir->dma_buf);
> +
> +allocfail:

this is called when appleir == NULL, so no need to free it.
Apparently, all these references should be move from 1 line :)

> +       kfree(appleir);
> +
> +       return retval;
> +}
> +
> +static void appleir_disconnect(struct usb_interface *intf)
> +{
> +       struct appleir *appleir = usb_get_intfdata(intf);
> +
> +       usb_set_intfdata(intf, NULL);
> +       input_unregister_device(appleir->input_dev);
> +       usb_free_urb(appleir->urb);
> +       usb_free_coherent(interface_to_usbdev(intf), URB_SIZE,
> +                       appleir->data, appleir->dma_buf);
> +       kfree(appleir);
> +}
> +
> +static int appleir_suspend(struct usb_interface *interface,
> +                          pm_message_t message)

I don't think suspend and resume should be set with the hid driver.

> +{
> +       struct appleir *appleir = usb_get_intfdata(interface);
> +
> +       mutex_lock(&appleir_mutex);
> +       if (appleir->flags & APPLEIR_OPENED)
> +               usb_kill_urb(appleir->urb);
> +
> +       appleir->flags |= APPLEIR_SUSPENDED;
> +
> +       mutex_unlock(&appleir_mutex);
> +
> +       return 0;
> +}
> +
> +static int appleir_resume(struct usb_interface *interface)
> +{
> +       struct appleir *appleir;
> +       int r = 0;
> +
> +       appleir = usb_get_intfdata(interface);
> +
> +       mutex_lock(&appleir_mutex);
> +       if (appleir->flags & APPLEIR_OPENED) {
> +               struct usb_endpoint_descriptor *endpoint;
> +               unsigned int pipe;
> +
> +               endpoint = &interface->cur_altsetting->endpoint[0].desc;
> +               pipe = usb_rcvintpipe(appleir->usbdev,
> +                                     endpoint->bEndpointAddress);
> +               usb_fill_int_urb(appleir->urb, appleir->usbdev,
> +                                pipe,
> +                                appleir->data, 8,
> +                                appleir_urb, appleir, endpoint->bInterval);
> +               appleir->urb->transfer_dma = appleir->dma_buf;
> +               appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> +
> +               /* And reset the USB device */
> +               if (usb_submit_urb(appleir->urb, GFP_ATOMIC))
> +                       r = -EIO;
> +       }
> +
> +       appleir->flags &= ~APPLEIR_SUSPENDED;
> +
> +       mutex_unlock(&appleir_mutex);
> +
> +       return r;
> +}
> +
> +static struct usb_driver appleir_driver = {
> +       .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)
> +{
> +       return usb_register(&appleir_driver);
> +}
> +
> +static void __exit appleir_exit(void)
> +{
> +       usb_deregister(&appleir_driver);
> +}
> +
> +module_init(appleir_init);
> +module_exit(appleir_exit);
> --
> 1.8.0
>
>

Cheers,
Benjamin

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH] Input: add appleir USB driver
@ 2012-11-15 18:13 Bastien Nocera
  2012-11-19 15:32 ` Benjamin Tissoires
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2012-11-15 18:13 UTC (permalink / raw)
  To: linux-input, Jarod Wilson, benjamin.tissoires


This driver was originally written by James McKenzie, updated by
Greg Kroah-Hartman, further updated by myself, with suspend support
added.

More recent versions of the IR receiver are also supported through
a patch by Alex Karpenko. The patch also adds support for the 2nd
and 5th generation of the controller, and the menu key on newer
brushed metal remotes.

Tested on a MacbookAir1,1

Signed-off-by: Bastien Nocera <hadess@hadess.net>
---

Resend, as the original patch never made it. I cleaned up the patch a
bit further, and test compiled it, but didn't have a chance to test it
as I don't have a machine with that hardware available anymore.

 Documentation/input/appleir.txt |  46 ++++
 drivers/hid/hid-apple.c         |   4 -
 drivers/hid/hid-core.c          |   7 +-
 drivers/hid/hid-ids.h           |   5 +-
 drivers/input/misc/Kconfig      |  13 +
 drivers/input/misc/Makefile     |   1 +
 drivers/input/misc/appleir.c    | 527 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 596 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/input/appleir.txt
 create mode 100644 drivers/input/misc/appleir.c

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



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH] Input: add appleir USB driver
@ 2010-09-10 15:19 Bastien Nocera
  0 siblings, 0 replies; 57+ messages in thread
From: Bastien Nocera @ 2010-09-10 15:19 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Jiri Kosina

This driver was originally written by James McKenzie, updated by
Greg Kroah-Hartman, further updated by myself, with suspend support
added.

More recent versions of the IR receiver are also supported through
a patch by Alex Karpenko. The patch also adds support for the 2nd
and 5th generation of the controller, and the menu key on newer
brushed metal remotes.

Tested on a MacbookAir1,1

Signed-off-by: Bastien Nocera <hadess@hadess.net>
---
 Documentation/input/appleir.txt |   46 ++++
 drivers/hid/hid-apple.c         |    4 -
 drivers/hid/hid-core.c          |    7 +-
 drivers/hid/hid-ids.h           |    5 +-
 drivers/input/misc/Kconfig      |   13 +
 drivers/input/misc/Makefile     |    1 +
 drivers/input/misc/appleir.c    |  519 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 588 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/input/appleir.txt
 create mode 100644 drivers/input/misc/appleir.c

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



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-21 20:09             ` Dmitry Torokhov
@ 2010-09-03 16:58               ` Bastien Nocera
  0 siblings, 0 replies; 57+ messages in thread
From: Bastien Nocera @ 2010-09-03 16:58 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Jiri Kosina, linux-input

On Wed, 2010-04-21 at 13:09 -0700, Dmitry Torokhov wrote:
> On Mon, Apr 19, 2010 at 01:08:57PM +0200, Jiri Kosina wrote:
> > On Mon, 19 Apr 2010, Bastien Nocera wrote:
> > 
> > > > > > > > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > > > > > > > ---
> > > > > > > >  Documentation/input/appleir.txt |   45 ++++
> > > > > > > >  drivers/hid/hid-apple.c         |    4 -
> > > > > > > >  drivers/hid/hid-core.c          |    5 +-
> > > > > > > >  drivers/hid/hid-ids.h           |    1 +
> > > > > > > 
> > > > > > > HID pieces need to go through Jiri or he needs to ack them to go through
> > > > > > > my tree...
> > > > > > 
> > > > > > Please feel free to put
> > > > > > 
> > > > > > 	Signed-off-by: Jiri Kosina <jkosina@suse.cz>
> > > > > > 
> > > > > > on the blakclist changes in drivers/hid once you merge the 
> > > > > > standalone appleir driver from Bastien.
> > > > > 
> > > > > Any comments on the additional quirks necessary to get lirc working?
> > > > 
> > > > Ouch, I thought that we have discussed previously that I am basically fine 
> > > > with adding those two quirks, but I haven't seen any patch doing that 
> > > > since then ... ?
> > > > 
> > > > So I'd suggest you either remove that part from the appleir documentation 
> > > > until this is implemented, or send me a patch adding those two flags.
> > > 
> > > I sent it Friday with the subject:
> > > [PATCH] Add HID_QUIRK_HIDDEV_FORCE and HID_QUIRK_NO_IGNORE
> > > 
> > > The patch was also sent to the input list:
> > > http://thread.gmane.org/gmane.linux.kernel.input/12176
> > 
> > Ah, now I see it. It somehow didn't reach my inbox, though your other 
> > mails do, odd.
> > 
> > Thanks, I will take it through my tree and queue it for next merge window 
> > (if Dmitry is not going to push the driver even for current -rcs ... ?).
> > 
> 
> No, even though it is a new driver it is gettign kind of late. I am
> going to put it in my 'next' branch.

Could I please have this patch upstream somewhere?

The blocking patch has been merged for a long while now.

Cheers


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-19 11:08           ` Jiri Kosina
@ 2010-04-21 20:09             ` Dmitry Torokhov
  2010-09-03 16:58               ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Dmitry Torokhov @ 2010-04-21 20:09 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Bastien Nocera, linux-input

On Mon, Apr 19, 2010 at 01:08:57PM +0200, Jiri Kosina wrote:
> On Mon, 19 Apr 2010, Bastien Nocera wrote:
> 
> > > > > > > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > > > > > > ---
> > > > > > >  Documentation/input/appleir.txt |   45 ++++
> > > > > > >  drivers/hid/hid-apple.c         |    4 -
> > > > > > >  drivers/hid/hid-core.c          |    5 +-
> > > > > > >  drivers/hid/hid-ids.h           |    1 +
> > > > > > 
> > > > > > HID pieces need to go through Jiri or he needs to ack them to go through
> > > > > > my tree...
> > > > > 
> > > > > Please feel free to put
> > > > > 
> > > > > 	Signed-off-by: Jiri Kosina <jkosina@suse.cz>
> > > > > 
> > > > > on the blakclist changes in drivers/hid once you merge the 
> > > > > standalone appleir driver from Bastien.
> > > > 
> > > > Any comments on the additional quirks necessary to get lirc working?
> > > 
> > > Ouch, I thought that we have discussed previously that I am basically fine 
> > > with adding those two quirks, but I haven't seen any patch doing that 
> > > since then ... ?
> > > 
> > > So I'd suggest you either remove that part from the appleir documentation 
> > > until this is implemented, or send me a patch adding those two flags.
> > 
> > I sent it Friday with the subject:
> > [PATCH] Add HID_QUIRK_HIDDEV_FORCE and HID_QUIRK_NO_IGNORE
> > 
> > The patch was also sent to the input list:
> > http://thread.gmane.org/gmane.linux.kernel.input/12176
> 
> Ah, now I see it. It somehow didn't reach my inbox, though your other 
> mails do, odd.
> 
> Thanks, I will take it through my tree and queue it for next merge window 
> (if Dmitry is not going to push the driver even for current -rcs ... ?).
> 

No, even though it is a new driver it is gettign kind of late. I am
going to put it in my 'next' branch.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-21  6:31                 ` Dmitry Torokhov
@ 2010-04-21 14:06                   ` Bastien Nocera
  0 siblings, 0 replies; 57+ messages in thread
From: Bastien Nocera @ 2010-04-21 14:06 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Jiri Kosina

On Tue, 2010-04-20 at 23:31 -0700, Dmitry Torokhov wrote:
<snip>
> > I tested udev's keymap, and the keymap isn't being saved across
> > suspend/resume cycles. I re-added the _suspend() and _resume() calls
> > (and their definitions in the usb_driver struct), but the keymap still
> > disappears.
> 
> Do you see another instance of the device appearing in dmesg?

The device was disappearing when a reset_resume wasn't present. I now
use resume for both reset_resume and resume, and force a URB on resume,
which should fix some cases of the device being dead on resume.

That also fixes the keymap disappearing on suspend.

Updated patch is now on the list

Cheers


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH] Input: add appleir USB driver
@ 2010-04-21 13:51 Bastien Nocera
  0 siblings, 0 replies; 57+ messages in thread
From: Bastien Nocera @ 2010-04-21 13:51 UTC (permalink / raw)
  To: linux-input; +Cc: Dmitry Torokhov

This driver was originally written by James McKenzie, updated by
Greg Kroah-Hartman, further updated by myself, with suspend support
added.

More recent versions of the IR receiver are also supported through
a patch by Alex Karpenko.

Tested on a MacbookAir1,1

Signed-off-by: Bastien Nocera <hadess@hadess.net>
---
 Documentation/input/appleir.txt |   45 ++++
 drivers/hid/hid-apple.c         |    4 -
 drivers/hid/hid-core.c          |    5 +-
 drivers/hid/hid-ids.h           |    1 +
 drivers/input/misc/Kconfig      |   13 ++
 drivers/input/misc/Makefile     |    1 +
 drivers/input/misc/appleir.c    |  453 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 516 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/input/appleir.txt
 create mode 100644 drivers/input/misc/appleir.c

diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
new file mode 100644
index 0000000..0267a4b
--- /dev/null
+++ b/Documentation/input/appleir.txt
@@ -0,0 +1,45 @@
+Apple IR receiver Driver (appleir)
+----------------------------------
+	Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+
+The appleir driver is a kernel input driver to handle Apple's IR
+receivers (and associated remotes) in the kernel.
+
+The driver is an input driver which only handles "official" remotes
+as built and sold by Apple.
+
+Authors
+-------
+
+James McKenzie (original driver)
+Alex Karpenko (05ac:8242 support)
+Greg Kroah-Hartman (cleanups and original submission)
+Bastien Nocera (further cleanups and suspend support)
+
+Supported hardware
+------------------
+
+- All Apple laptops and desktops from 2005 onwards, except:
+  - the unibody Macbook (2009)
+  - Mac Pro (all versions)
+- Apple TV (all revisions)
+
+The remote will only support the 6 buttons of the original remotes
+as sold by Apple. See the next section if you want to use other remotes
+or want to use lirc with the device instead of the kernel driver.
+
+Using lirc (native) instead of the kernel driver
+------------------------------------------------
+
+First, you will need to disable the kernel driver for the receiver.
+
+This can be achieved by passing quirks to the usbhid driver.
+The quirk line would be:
+usbhid.quirks=0x05ac:0x8242:0x40000010
+
+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
+With 0x8242 being the product ID (check the output of lsusb for your hardware)
+And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE"
+
+This should force the creation of a hiddev device for the receiver, and
+make it usable under lirc.
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 78286b1..5f2a731 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -360,10 +360,6 @@ static void apple_remove(struct hid_device *hdev)
 }
 
 static const struct hid_device_id apple_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
 		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
 
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 368fbb0..b57e5f7 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1253,8 +1253,6 @@ static const struct hid_device_id hid_blacklist[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
@@ -1553,6 +1551,9 @@ static const struct hid_device_id hid_ignore_list[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 72c05f9..66a2ca8 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -97,6 +97,7 @@
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
 #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
 
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 23140a3..46614b2 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -159,6 +159,19 @@ config INPUT_KEYSPAN_REMOTE
 	  To compile this driver as a module, choose M here: the module will
 	  be called keyspan_remote.
 
+config INPUT_APPLEIR
+	tristate "Apple infrared receiver (built in)"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use a Apple infrared remote control. All
+	  the Apple computers from 2005 onwards include such a port, except
+	  the unibody Macbook (2009), and Mac Pros. This receiver is also
+	  used in the Apple TV set-top box.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called appleir.
+
 config INPUT_POWERMATE
 	tristate "Griffin PowerMate and Contour Jog support"
 	depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 7e95a5d..3fa4404 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_INPUT_88PM860X_ONKEY)	+= 88pm860x_onkey.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
+obj-$(CONFIG_INPUT_APPLEIR)		+= appleir.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
new file mode 100644
index 0000000..cff4df6
--- /dev/null
+++ b/drivers/input/misc/appleir.c
@@ -0,0 +1,453 @@
+/*
+ * appleir: USB driver for the apple ir device
+ *
+ * Original driver written by James McKenzie
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Copyright (C) 2006 James McKenzie
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2008 Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+
+#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>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#define DRIVER_VERSION "v1.2"
+#define DRIVER_AUTHOR "James McKenzie"
+#define DRIVER_DESC "Apple infrared receiver driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_APPLE			0x05ac
+#define USB_DEVICE_ID_APPLE_IRCONTROL		0x8240
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4		0x8242
+
+#define URB_SIZE	32
+
+#define MAX_KEYS	8
+#define MAX_KEYS_MASK	(MAX_KEYS - 1)
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+/* I have two devices both of which report the following */
+/* 25 87 ee 83 0a  	+  */
+/* 25 87 ee 83 0c  	-  */
+/* 25 87 ee 83 09	<< */
+/* 25 87 ee 83 06	>> */
+/* 25 87 ee 83 05	>" */
+/* 25 87 ee 83 03	menu */
+/* 26 00 00 00 00	for key repeat*/
+
+/* Thomas Glanzmann reports the following responses */
+/* 25 87 ee ca 0b	+  */
+/* 25 87 ee ca 0d	-  */
+/* 25 87 ee ca 08	<< */
+/* 25 87 ee ca 07	>> */
+/* 25 87 ee ca 04	>" */
+/* 25 87 ee ca 02 	menu */
+/* 26 00 00 00 00       for key repeat*/
+/* He also observes the following event sometimes */
+/* sent after a key is release, which I interpret */
+/* as a flat battery message */
+/* 25 87 e0 ca 06	flat battery */
+
+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
+/* 25 87 ee 47 0b	+  */
+/* 25 87 ee 47 0d	-  */
+/* 25 87 ee 47 08	<< */
+/* 25 87 ee 47 07	>> */
+/* 25 87 ee 47 04	>" */
+/* 25 87 ee 47 02 	menu */
+/* 26 87 ee 47 ** 	for key repeat (** is the code of the key being held) */
+
+static const unsigned short appleir_key_table[] = {
+	KEY_RESERVED,
+	KEY_MENU,
+	KEY_PLAYPAUSE,
+	KEY_FORWARD,
+	KEY_BACK,
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_RESERVED,
+};
+
+struct appleir {
+	struct input_dev *input_dev;
+	unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
+	u8 *data;
+	dma_addr_t dma_buf;
+	struct usb_device *usbdev;
+	unsigned int flags;
+	struct urb *urb;
+	struct timer_list key_up_timer;
+	int current_key;
+	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_ATV_IRCONTROL) },
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+	{}
+};
+MODULE_DEVICE_TABLE(usb, appleir_ids);
+
+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
+{
+	int i;
+
+	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
+
+	for (i = 0; i < len; ++i)
+		printk(" %02x", data[i]);
+	printk("\n");
+}
+
+static void key_up(struct appleir *appleir, int key)
+{
+	dbginfo(&appleir->input_dev->dev, "key %d up\n", key);
+	input_report_key(appleir->input_dev, key, 0);
+	input_sync(appleir->input_dev);
+}
+
+static void key_down(struct appleir *appleir, int key)
+{
+	dbginfo(&appleir->input_dev->dev, "key %d down\n", key);
+	input_report_key(appleir->input_dev, key, 1);
+	input_sync(appleir->input_dev);
+}
+
+static void battery_flat(struct appleir *appleir)
+{
+	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
+}
+
+static void key_up_tick(unsigned long data)
+{
+	struct appleir *appleir = (struct appleir *)data;
+
+	if (appleir->current_key) {
+		key_up(appleir, appleir->current_key);
+		appleir->current_key = 0;
+	}
+}
+
+static void new_data(struct appleir *appleir, u8 *data, int len)
+{
+	static const u8 keydown[] = { 0x25, 0x87, 0xee };
+	static const u8 keyrepeat[] = { 0x26, };
+	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
+
+	if (debug)
+		dump_packet(appleir, "received", data, len);
+
+	if (len != 5)
+		return;
+
+	if (!memcmp(data, keydown, sizeof(keydown))) {
+		/* If we already have a key down, take it up before marking
+		   this one down */
+		if (appleir->current_key)
+			key_up(appleir, appleir->current_key);
+		appleir->current_key = appleir->keymap[(data[4] >> 1) & MAX_KEYS_MASK];
+
+		key_down(appleir, appleir->current_key);
+		/* Remote doesn't do key up, either pull them up, in the test
+		   above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+
+		return;
+	}
+
+	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
+		key_down(appleir, appleir->current_key);
+		/* Remote doesn't do key up, either pull them up, in the test
+		   above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+		return;
+	}
+
+	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
+		battery_flat(appleir);
+		/* Fall through */
+	}
+
+	dump_packet(appleir, "unknown packet", data, len);
+}
+
+static void appleir_urb(struct urb *urb)
+{
+	struct appleir *appleir = urb->context;
+	int status = urb->status;
+	int retval;
+
+	switch (status) {
+	case 0:
+		new_data(appleir, urb->transfer_buffer, urb->actual_length);
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* This urb is terminated, clean up */
+		dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__,
+			urb->status);
+		return;
+	default:
+		dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__,
+			urb->status);
+	}
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result %d", __func__,
+		    retval);
+}
+
+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_ATOMIC)) {
+		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);
+
+	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,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct appleir *appleir = NULL;
+	struct input_dev *input_dev;
+	int retval = -ENOMEM;
+	int i;
+
+	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
+	if (!appleir)
+		goto allocfail;
+
+	appleir->data = usb_buffer_alloc(dev, URB_SIZE, GFP_KERNEL,
+					 &appleir->dma_buf);
+	if (!appleir->data)
+		goto usbfail;
+
+	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!appleir->urb)
+		goto urbfail;
+
+	appleir->usbdev = dev;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		goto inputfail;
+
+	appleir->input_dev = input_dev;
+
+	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
+	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
+
+	input_dev->name = "Apple Infrared Remote Controller";
+	input_dev->phys = appleir->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+	input_dev->keycode = appleir->keymap;
+	input_dev->keycodesize = sizeof(unsigned short);
+	input_dev->keycodemax = ARRAY_SIZE(appleir->keymap);
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+	memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
+	for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
+		set_bit(appleir->keymap[i], input_dev->keybit);
+	clear_bit(KEY_RESERVED, input_dev->keybit);
+
+	input_set_drvdata(input_dev, appleir);
+	input_dev->open = appleir_open;
+	input_dev->close = appleir_close;
+
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+	usb_fill_int_urb(appleir->urb, dev,
+			 usb_rcvintpipe(dev, 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;
+
+	setup_timer(&appleir->key_up_timer,
+		    key_up_tick, (unsigned long) appleir);
+
+	retval = input_register_device(appleir->input_dev);
+	if (retval)
+		goto inputfail;
+
+	usb_set_intfdata(intf, appleir);
+
+	return 0;
+
+inputfail:
+	input_free_device(appleir->input_dev);
+
+urbfail:
+	usb_free_urb(appleir->urb);
+
+usbfail:
+	usb_buffer_free(dev, URB_SIZE, appleir->data,
+			appleir->dma_buf);
+
+allocfail:
+	kfree(appleir);
+
+	return retval;
+}
+
+static void appleir_disconnect(struct usb_interface *intf)
+{
+	struct appleir *appleir = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	input_unregister_device(appleir->input_dev);
+	usb_free_urb(appleir->urb);
+	usb_buffer_free(interface_to_usbdev(intf), URB_SIZE,
+			appleir->data, appleir->dma_buf);
+	kfree(appleir);
+}
+
+static int appleir_suspend(struct usb_interface *interface,
+			   pm_message_t message)
+{
+	struct appleir *appleir = usb_get_intfdata(interface);
+
+	mutex_lock(&appleir_mutex);
+	if (appleir->flags & APPLEIR_OPENED)
+		usb_kill_urb(appleir->urb);
+
+	appleir->flags |= APPLEIR_SUSPENDED;
+
+	mutex_unlock(&appleir_mutex);
+
+	return 0;
+}
+
+static int appleir_resume(struct usb_interface *interface)
+{
+	struct appleir *appleir;
+	int r = 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;
+
+		/* And reset the USB device */
+		if (usb_submit_urb(appleir->urb, GFP_ATOMIC))
+			r = -EIO;
+	}
+
+	appleir->flags &= ~APPLEIR_SUSPENDED;
+
+	mutex_unlock(&appleir_mutex);
+
+	return r;
+}
+
+static struct usb_driver appleir_driver = {
+	.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)
+{
+	return usb_register(&appleir_driver);
+}
+
+static void __exit appleir_exit(void)
+{
+	usb_deregister(&appleir_driver);
+}
+
+module_init(appleir_init);
+module_exit(appleir_exit);
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-19 10:08               ` Bastien Nocera
@ 2010-04-21  6:31                 ` Dmitry Torokhov
  2010-04-21 14:06                   ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Dmitry Torokhov @ 2010-04-21  6:31 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-input, Jiri Kosina

On Mon, Apr 19, 2010 at 11:08:10AM +0100, Bastien Nocera wrote:
> On Mon, 2010-04-19 at 00:28 -0700, Dmitry Torokhov wrote:
> > On Mon, Apr 19, 2010 at 01:31:49AM +0100, Bastien Nocera wrote:
> > > On Sun, 2010-04-18 at 13:19 -0700, Dmitry Torokhov wrote:
> > > <snip>
> > > > > > Hmm, I am curious why suspend and resume is not necessary for this
> > > > > > device... Are you relying on the USB core to tear down and re-create the
> > > > > > device? Then you may lose user-applied settings (like changed keymap).
> > > > > 
> > > > > How could I test that?
> > > > 
> > > > Change the keymap (with keyfuzz or something similar), suspend. resume and see 
> > > > if the mapping persisted.
> > > 
> > > Tried using udev's keymap tool on it, but the default get function
> > > doesn't give me any output.
> > > 
> > > Am I supposed to implement get/setkeycode myself for this to work, or
> > > should the default input functions work? If the latter, is there
> > > anything missing in the driver for me to call to enable that?
> > > 
> > > Trying to set a keycode says that the "EVIOCSKEYCODE" ioctl returns
> > > EINVAL.
> > > 
> > 
> > As I said in an earlier e-mail:
> > 
> > > ... also set up input_dev->keycode, keycodemax and keycodesize so that
> > > keymap can be adjusted from userspace on per-device basis.
> 
> I missed that bit, sorry.
> 
> I tested udev's keymap, and the keymap isn't being saved across
> suspend/resume cycles. I re-added the _suspend() and _resume() calls
> (and their definitions in the usb_driver struct), but the keymap still
> disappears.

Do you see another instance of the device appearing in dmesg?

> 
> Is there anything else I would need to do in this case to keep the
> device (and its keymap) around during suspend?
> 
> I'm guessing that this problem wouldn't matter too much because udev
> would re-apply any keymaps it had for the device when it reappears, and
> in the lirc case, the keymap is in user-space.

That assumes that user does use udev. Extremely likely, but still not certain.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-19 10:14         ` Bastien Nocera
@ 2010-04-19 11:08           ` Jiri Kosina
  2010-04-21 20:09             ` Dmitry Torokhov
  0 siblings, 1 reply; 57+ messages in thread
From: Jiri Kosina @ 2010-04-19 11:08 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: Dmitry Torokhov, linux-input

On Mon, 19 Apr 2010, Bastien Nocera wrote:

> > > > > > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > > > > > ---
> > > > > >  Documentation/input/appleir.txt |   45 ++++
> > > > > >  drivers/hid/hid-apple.c         |    4 -
> > > > > >  drivers/hid/hid-core.c          |    5 +-
> > > > > >  drivers/hid/hid-ids.h           |    1 +
> > > > > 
> > > > > HID pieces need to go through Jiri or he needs to ack them to go through
> > > > > my tree...
> > > > 
> > > > Please feel free to put
> > > > 
> > > > 	Signed-off-by: Jiri Kosina <jkosina@suse.cz>
> > > > 
> > > > on the blakclist changes in drivers/hid once you merge the 
> > > > standalone appleir driver from Bastien.
> > > 
> > > Any comments on the additional quirks necessary to get lirc working?
> > 
> > Ouch, I thought that we have discussed previously that I am basically fine 
> > with adding those two quirks, but I haven't seen any patch doing that 
> > since then ... ?
> > 
> > So I'd suggest you either remove that part from the appleir documentation 
> > until this is implemented, or send me a patch adding those two flags.
> 
> I sent it Friday with the subject:
> [PATCH] Add HID_QUIRK_HIDDEV_FORCE and HID_QUIRK_NO_IGNORE
> 
> The patch was also sent to the input list:
> http://thread.gmane.org/gmane.linux.kernel.input/12176

Ah, now I see it. It somehow didn't reach my inbox, though your other 
mails do, odd.

Thanks, I will take it through my tree and queue it for next merge window 
(if Dmitry is not going to push the driver even for current -rcs ... ?).

Thanks,

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-19 10:00       ` Jiri Kosina
@ 2010-04-19 10:14         ` Bastien Nocera
  2010-04-19 11:08           ` Jiri Kosina
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-04-19 10:14 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Dmitry Torokhov, linux-input

On Mon, 2010-04-19 at 12:00 +0200, Jiri Kosina wrote:
> On Mon, 19 Apr 2010, Bastien Nocera wrote:
> 
> > > > A few comments...
> > > > 
> > > > > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > > > > ---
> > > > >  Documentation/input/appleir.txt |   45 ++++
> > > > >  drivers/hid/hid-apple.c         |    4 -
> > > > >  drivers/hid/hid-core.c          |    5 +-
> > > > >  drivers/hid/hid-ids.h           |    1 +
> > > > 
> > > > HID pieces need to go through Jiri or he needs to ack them to go through
> > > > my tree...
> > > 
> > > Please feel free to put
> > > 
> > > 	Signed-off-by: Jiri Kosina <jkosina@suse.cz>
> > > 
> > > on the blakclist changes in drivers/hid once you merge the 
> > > standalone appleir driver from Bastien.
> > 
> > Any comments on the additional quirks necessary to get lirc working?
> 
> Ouch, I thought that we have discussed previously that I am basically fine 
> with adding those two quirks, but I haven't seen any patch doing that 
> since then ... ?
> 
> So I'd suggest you either remove that part from the appleir documentation 
> until this is implemented, or send me a patch adding those two flags.

I sent it Friday with the subject:
[PATCH] Add HID_QUIRK_HIDDEV_FORCE and HID_QUIRK_NO_IGNORE

The patch was also sent to the input list:
http://thread.gmane.org/gmane.linux.kernel.input/12176

Cheers


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-19  7:28             ` Dmitry Torokhov
@ 2010-04-19 10:08               ` Bastien Nocera
  2010-04-21  6:31                 ` Dmitry Torokhov
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-04-19 10:08 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Jiri Kosina

On Mon, 2010-04-19 at 00:28 -0700, Dmitry Torokhov wrote:
> On Mon, Apr 19, 2010 at 01:31:49AM +0100, Bastien Nocera wrote:
> > On Sun, 2010-04-18 at 13:19 -0700, Dmitry Torokhov wrote:
> > <snip>
> > > > > Hmm, I am curious why suspend and resume is not necessary for this
> > > > > device... Are you relying on the USB core to tear down and re-create the
> > > > > device? Then you may lose user-applied settings (like changed keymap).
> > > > 
> > > > How could I test that?
> > > 
> > > Change the keymap (with keyfuzz or something similar), suspend. resume and see 
> > > if the mapping persisted.
> > 
> > Tried using udev's keymap tool on it, but the default get function
> > doesn't give me any output.
> > 
> > Am I supposed to implement get/setkeycode myself for this to work, or
> > should the default input functions work? If the latter, is there
> > anything missing in the driver for me to call to enable that?
> > 
> > Trying to set a keycode says that the "EVIOCSKEYCODE" ioctl returns
> > EINVAL.
> > 
> 
> As I said in an earlier e-mail:
> 
> > ... also set up input_dev->keycode, keycodemax and keycodesize so that
> > keymap can be adjusted from userspace on per-device basis.

I missed that bit, sorry.

I tested udev's keymap, and the keymap isn't being saved across
suspend/resume cycles. I re-added the _suspend() and _resume() calls
(and their definitions in the usb_driver struct), but the keymap still
disappears.

Is there anything else I would need to do in this case to keep the
device (and its keymap) around during suspend?

I'm guessing that this problem wouldn't matter too much because udev
would re-apply any keymaps it had for the device when it reappears, and
in the lirc case, the keymap is in user-space.

Cheers


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-19  9:31     ` Bastien Nocera
@ 2010-04-19 10:00       ` Jiri Kosina
  2010-04-19 10:14         ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Jiri Kosina @ 2010-04-19 10:00 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: Dmitry Torokhov, linux-input

On Mon, 19 Apr 2010, Bastien Nocera wrote:

> > > A few comments...
> > > 
> > > > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > > > ---
> > > >  Documentation/input/appleir.txt |   45 ++++
> > > >  drivers/hid/hid-apple.c         |    4 -
> > > >  drivers/hid/hid-core.c          |    5 +-
> > > >  drivers/hid/hid-ids.h           |    1 +
> > > 
> > > HID pieces need to go through Jiri or he needs to ack them to go through
> > > my tree...
> > 
> > Please feel free to put
> > 
> > 	Signed-off-by: Jiri Kosina <jkosina@suse.cz>
> > 
> > on the blakclist changes in drivers/hid once you merge the 
> > standalone appleir driver from Bastien.
> 
> Any comments on the additional quirks necessary to get lirc working?

Ouch, I thought that we have discussed previously that I am basically fine 
with adding those two quirks, but I haven't seen any patch doing that 
since then ... ?

So I'd suggest you either remove that part from the appleir documentation 
until this is implemented, or send me a patch adding those two flags.

Thanks,

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-19  9:22   ` Jiri Kosina
@ 2010-04-19  9:31     ` Bastien Nocera
  2010-04-19 10:00       ` Jiri Kosina
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-04-19  9:31 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Dmitry Torokhov, linux-input

On Mon, 2010-04-19 at 11:22 +0200, Jiri Kosina wrote:
> On Sat, 17 Apr 2010, Dmitry Torokhov wrote:
> 
> > > More recent versions of the IR receiver are also supported through
> > > a patch by Alex Karpenko.
> > > 
> > > Tested on a MacbookAir1,1
> > > 
> > 
> > A few comments...
> > 
> > > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > > ---
> > >  Documentation/input/appleir.txt |   45 ++++
> > >  drivers/hid/hid-apple.c         |    4 -
> > >  drivers/hid/hid-core.c          |    5 +-
> > >  drivers/hid/hid-ids.h           |    1 +
> > 
> > HID pieces need to go through Jiri or he needs to ack them to go through
> > my tree...
> 
> Please feel free to put
> 
> 	Signed-off-by: Jiri Kosina <jkosina@suse.cz>
> 
> on the blakclist changes in drivers/hid once you merge the 
> standalone appleir driver from Bastien.

Any comments on the additional quirks necessary to get lirc working?


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-17  8:12 ` Dmitry Torokhov
  2010-04-17 21:44   ` Bastien Nocera
@ 2010-04-19  9:22   ` Jiri Kosina
  2010-04-19  9:31     ` Bastien Nocera
  1 sibling, 1 reply; 57+ messages in thread
From: Jiri Kosina @ 2010-04-19  9:22 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Bastien Nocera, linux-input

On Sat, 17 Apr 2010, Dmitry Torokhov wrote:

> > More recent versions of the IR receiver are also supported through
> > a patch by Alex Karpenko.
> > 
> > Tested on a MacbookAir1,1
> > 
> 
> A few comments...
> 
> > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > ---
> >  Documentation/input/appleir.txt |   45 ++++
> >  drivers/hid/hid-apple.c         |    4 -
> >  drivers/hid/hid-core.c          |    5 +-
> >  drivers/hid/hid-ids.h           |    1 +
> 
> HID pieces need to go through Jiri or he needs to ack them to go through
> my tree...

Please feel free to put

	Signed-off-by: Jiri Kosina <jkosina@suse.cz>

on the blakclist changes in drivers/hid once you merge the 
standalone appleir driver from Bastien.

Thanks,

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-19  0:31           ` Bastien Nocera
@ 2010-04-19  7:28             ` Dmitry Torokhov
  2010-04-19 10:08               ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Dmitry Torokhov @ 2010-04-19  7:28 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-input, Jiri Kosina

On Mon, Apr 19, 2010 at 01:31:49AM +0100, Bastien Nocera wrote:
> On Sun, 2010-04-18 at 13:19 -0700, Dmitry Torokhov wrote:
> <snip>
> > > > Hmm, I am curious why suspend and resume is not necessary for this
> > > > device... Are you relying on the USB core to tear down and re-create the
> > > > device? Then you may lose user-applied settings (like changed keymap).
> > > 
> > > How could I test that?
> > 
> > Change the keymap (with keyfuzz or something similar), suspend. resume and see 
> > if the mapping persisted.
> 
> Tried using udev's keymap tool on it, but the default get function
> doesn't give me any output.
> 
> Am I supposed to implement get/setkeycode myself for this to work, or
> should the default input functions work? If the latter, is there
> anything missing in the driver for me to call to enable that?
> 
> Trying to set a keycode says that the "EVIOCSKEYCODE" ioctl returns
> EINVAL.
> 

As I said in an earlier e-mail:

> ... also set up input_dev->keycode, keycodemax and keycodesize so that
> keymap can be adjusted from userspace on per-device basis.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-18 20:19         ` Dmitry Torokhov
@ 2010-04-19  0:31           ` Bastien Nocera
  2010-04-19  7:28             ` Dmitry Torokhov
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-04-19  0:31 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Jiri Kosina

On Sun, 2010-04-18 at 13:19 -0700, Dmitry Torokhov wrote:
<snip>
> > > Hmm, I am curious why suspend and resume is not necessary for this
> > > device... Are you relying on the USB core to tear down and re-create the
> > > device? Then you may lose user-applied settings (like changed keymap).
> > 
> > How could I test that?
> 
> Change the keymap (with keyfuzz or something similar), suspend. resume and see 
> if the mapping persisted.

Tried using udev's keymap tool on it, but the default get function
doesn't give me any output.

Am I supposed to implement get/setkeycode myself for this to work, or
should the default input functions work? If the latter, is there
anything missing in the driver for me to call to enable that?

Trying to set a keycode says that the "EVIOCSKEYCODE" ioctl returns
EINVAL.

Cheers


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-18 19:49       ` Bastien Nocera
@ 2010-04-18 20:19         ` Dmitry Torokhov
  2010-04-19  0:31           ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Dmitry Torokhov @ 2010-04-18 20:19 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-input, Jiri Kosina

On Sunday 18 April 2010 12:49:37 pm Bastien Nocera wrote:
> On Sun, 2010-04-18 at 12:43 -0700, Dmitry Torokhov wrote:
> > On Sat, Apr 17, 2010 at 10:44:55PM +0100, Bastien Nocera wrote:
> > > On Sat, 2010-04-17 at 01:12 -0700, Dmitry Torokhov wrote:
> > > > HI Bastien,
> > > > 
> > > > On Fri, Apr 16, 2010 at 05:19:52PM +0100, Bastien Nocera wrote:
> > > > > This driver was originally written by James McKenzie, updated by
> > > > > Greg Kroah-Hartman, further updated by myself, with suspend support
> > > > > added.
> > > > > 
> > > > > More recent versions of the IR receiver are also supported through
> > > > > a patch by Alex Karpenko.
> > > > > 
> > > > > Tested on a MacbookAir1,1
> > > > 
> > > > A few comments...
> > > 
> > > All fixed. I removed the suspend/resume code as it worked fine without
> > > it (I was working of an old patch).
> > > 
> > > Sent the new patch separately.
> > 
> > Hmm, I am curious why suspend and resume is not necessary for this
> > device... Are you relying on the USB core to tear down and re-create the
> > device? Then you may lose user-applied settings (like changed keymap).
> 
> How could I test that?

Change the keymap (with keyfuzz or something similar), suspend. resume and see 
if the mapping persisted.
 
> 
> > But if suspend and resume are really not needed then you need to
> > complete cleanup and get rid of APPLIEIR_OPENED and APPLEIR_SUSPENDED
> > and their handling in applieir_open() and appleir_close().
> 
> My mistake. I'll clean that up now.
> 
> > Right. I was just saying that Jiri needs to either take HID parts
> > through his tree or give OK for me to take through mine.
> 
> OK.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-18 19:43     ` Dmitry Torokhov
@ 2010-04-18 19:49       ` Bastien Nocera
  2010-04-18 20:19         ` Dmitry Torokhov
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-04-18 19:49 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Jiri Kosina

On Sun, 2010-04-18 at 12:43 -0700, Dmitry Torokhov wrote:
> On Sat, Apr 17, 2010 at 10:44:55PM +0100, Bastien Nocera wrote:
> > On Sat, 2010-04-17 at 01:12 -0700, Dmitry Torokhov wrote: 
> > > HI Bastien,
> > > 
> > > On Fri, Apr 16, 2010 at 05:19:52PM +0100, Bastien Nocera wrote:
> > > > This driver was originally written by James McKenzie, updated by
> > > > Greg Kroah-Hartman, further updated by myself, with suspend support
> > > > added.
> > > > 
> > > > More recent versions of the IR receiver are also supported through
> > > > a patch by Alex Karpenko.
> > > > 
> > > > Tested on a MacbookAir1,1
> > > > 
> > > 
> > > A few comments...
> > 
> > All fixed. I removed the suspend/resume code as it worked fine without
> > it (I was working of an old patch).
> > 
> > Sent the new patch separately.
> 
> Hmm, I am curious why suspend and resume is not necessary for this
> device... Are you relying on the USB core to tear down and re-create the
> device? Then you may lose user-applied settings (like changed keymap).

How could I test that?

> But if suspend and resume are really not needed then you need to
> complete cleanup and get rid of APPLIEIR_OPENED and APPLEIR_SUSPENDED
> and their handling in applieir_open() and appleir_close().

My mistake. I'll clean that up now.

> Right. I was just saying that Jiri needs to either take HID parts
> through his tree or give OK for me to take through mine.

OK.



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-17 21:44   ` Bastien Nocera
@ 2010-04-18 19:43     ` Dmitry Torokhov
  2010-04-18 19:49       ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Dmitry Torokhov @ 2010-04-18 19:43 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-input, Jiri Kosina

On Sat, Apr 17, 2010 at 10:44:55PM +0100, Bastien Nocera wrote:
> On Sat, 2010-04-17 at 01:12 -0700, Dmitry Torokhov wrote: 
> > HI Bastien,
> > 
> > On Fri, Apr 16, 2010 at 05:19:52PM +0100, Bastien Nocera wrote:
> > > This driver was originally written by James McKenzie, updated by
> > > Greg Kroah-Hartman, further updated by myself, with suspend support
> > > added.
> > > 
> > > More recent versions of the IR receiver are also supported through
> > > a patch by Alex Karpenko.
> > > 
> > > Tested on a MacbookAir1,1
> > > 
> > 
> > A few comments...
> 
> All fixed. I removed the suspend/resume code as it worked fine without
> it (I was working of an old patch).
> 
> Sent the new patch separately.

Hmm, I am curious why suspend and resume is not necessary for this
device... Are you relying on the USB core to tear down and re-create the
device? Then you may lose user-applied settings (like changed keymap).

But if suspend and resume are really not needed then you need to
complete cleanup and get rid of APPLIEIR_OPENED and APPLEIR_SUSPENDED
and their handling in applieir_open() and appleir_close().

> 
> > > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > > ---
> > >  Documentation/input/appleir.txt |   45 ++++
> > >  drivers/hid/hid-apple.c         |    4 -
> > >  drivers/hid/hid-core.c          |    5 +-
> > >  drivers/hid/hid-ids.h           |    1 +
> > 
> > HID pieces need to go through Jiri or he needs to ack them to go through
> > my tree...
> 
> The HID pieces are necessary to get the "lirc" part of the documentation
> working (in appleir.txt). The driver is fine without it, but it won't
> work with lirc until the HID patch is in.
> 

Right. I was just saying that Jiri needs to either take HID parts
through his tree or give OK for me to take through mine.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH] Input: add appleir USB driver
@ 2010-04-17 21:45 Bastien Nocera
  0 siblings, 0 replies; 57+ messages in thread
From: Bastien Nocera @ 2010-04-17 21:45 UTC (permalink / raw)
  To: linux-input, Jiri Kosina, Dmitry Torokhov

This driver was originally written by James McKenzie, updated by
Greg Kroah-Hartman, further updated by myself, with suspend support
added.

More recent versions of the IR receiver are also supported through
a patch by Alex Karpenko.

Tested on a MacbookAir1,1

Signed-off-by: Bastien Nocera <hadess@hadess.net>
---
 Documentation/input/appleir.txt |   45 +++++
 drivers/hid/hid-apple.c         |    4 -
 drivers/hid/hid-core.c          |    5 +-
 drivers/hid/hid-ids.h           |    1 +
 drivers/input/misc/Kconfig      |   13 ++
 drivers/input/misc/Makefile     |    1 +
 drivers/input/misc/appleir.c    |  399 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 462 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/input/appleir.txt
 create mode 100644 drivers/input/misc/appleir.c

diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
new file mode 100644
index 0000000..0267a4b
--- /dev/null
+++ b/Documentation/input/appleir.txt
@@ -0,0 +1,45 @@
+Apple IR receiver Driver (appleir)
+----------------------------------
+	Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+
+The appleir driver is a kernel input driver to handle Apple's IR
+receivers (and associated remotes) in the kernel.
+
+The driver is an input driver which only handles "official" remotes
+as built and sold by Apple.
+
+Authors
+-------
+
+James McKenzie (original driver)
+Alex Karpenko (05ac:8242 support)
+Greg Kroah-Hartman (cleanups and original submission)
+Bastien Nocera (further cleanups and suspend support)
+
+Supported hardware
+------------------
+
+- All Apple laptops and desktops from 2005 onwards, except:
+  - the unibody Macbook (2009)
+  - Mac Pro (all versions)
+- Apple TV (all revisions)
+
+The remote will only support the 6 buttons of the original remotes
+as sold by Apple. See the next section if you want to use other remotes
+or want to use lirc with the device instead of the kernel driver.
+
+Using lirc (native) instead of the kernel driver
+------------------------------------------------
+
+First, you will need to disable the kernel driver for the receiver.
+
+This can be achieved by passing quirks to the usbhid driver.
+The quirk line would be:
+usbhid.quirks=0x05ac:0x8242:0x40000010
+
+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
+With 0x8242 being the product ID (check the output of lsusb for your hardware)
+And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE"
+
+This should force the creation of a hiddev device for the receiver, and
+make it usable under lirc.
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 78286b1..5f2a731 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -360,10 +360,6 @@ static void apple_remove(struct hid_device *hdev)
 }
 
 static const struct hid_device_id apple_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
 		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
 
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 368fbb0..b57e5f7 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1253,8 +1253,6 @@ static const struct hid_device_id hid_blacklist[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
@@ -1553,6 +1551,9 @@ static const struct hid_device_id hid_ignore_list[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 72c05f9..66a2ca8 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -97,6 +97,7 @@
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
 #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
 
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 23140a3..46614b2 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -159,6 +159,19 @@ config INPUT_KEYSPAN_REMOTE
 	  To compile this driver as a module, choose M here: the module will
 	  be called keyspan_remote.
 
+config INPUT_APPLEIR
+	tristate "Apple infrared receiver (built in)"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use a Apple infrared remote control. All
+	  the Apple computers from 2005 onwards include such a port, except
+	  the unibody Macbook (2009), and Mac Pros. This receiver is also
+	  used in the Apple TV set-top box.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called appleir.
+
 config INPUT_POWERMATE
 	tristate "Griffin PowerMate and Contour Jog support"
 	depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 7e95a5d..3fa4404 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_INPUT_88PM860X_ONKEY)	+= 88pm860x_onkey.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
+obj-$(CONFIG_INPUT_APPLEIR)		+= appleir.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
new file mode 100644
index 0000000..6b2ec04
--- /dev/null
+++ b/drivers/input/misc/appleir.c
@@ -0,0 +1,399 @@
+/*
+ * appleir: USB driver for the apple ir device
+ *
+ * Original driver written by James McKenzie
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Copyright (C) 2006 James McKenzie
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2008 Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+
+#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>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#define DRIVER_VERSION "v1.2"
+#define DRIVER_AUTHOR "James McKenzie"
+#define DRIVER_DESC "Apple infrared receiver driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_APPLE			0x05ac
+#define USB_DEVICE_ID_APPLE_IRCONTROL		0x8240
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4		0x8242
+
+#define URB_SIZE	32
+
+#define MAX_KEYS	8
+#define MAX_KEYS_MASK	(MAX_KEYS - 1)
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+/* I have two devices both of which report the following */
+/* 25 87 ee 83 0a  	+  */
+/* 25 87 ee 83 0c  	-  */
+/* 25 87 ee 83 09	<< */
+/* 25 87 ee 83 06	>> */
+/* 25 87 ee 83 05	>" */
+/* 25 87 ee 83 03	menu */
+/* 26 00 00 00 00	for key repeat*/
+
+/* Thomas Glanzmann reports the following responses */
+/* 25 87 ee ca 0b	+  */
+/* 25 87 ee ca 0d	-  */
+/* 25 87 ee ca 08	<< */
+/* 25 87 ee ca 07	>> */
+/* 25 87 ee ca 04	>" */
+/* 25 87 ee ca 02 	menu */
+/* 26 00 00 00 00       for key repeat*/
+/* He also observes the following event sometimes */
+/* sent after a key is release, which I interpret */
+/* as a flat battery message */
+/* 25 87 e0 ca 06	flat battery */
+
+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
+/* 25 87 ee 47 0b	+  */
+/* 25 87 ee 47 0d	-  */
+/* 25 87 ee 47 08	<< */
+/* 25 87 ee 47 07	>> */
+/* 25 87 ee 47 04	>" */
+/* 25 87 ee 47 02 	menu */
+/* 26 87 ee 47 ** 	for key repeat (** is the code of the key being held) */
+
+static const unsigned short appleir_key_table[MAX_KEYS] = {
+	KEY_RESERVED,
+	KEY_MENU,
+	KEY_PLAYPAUSE,
+	KEY_FORWARD,
+	KEY_BACK,
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_RESERVED,
+};
+
+struct appleir {
+	struct input_dev *input_dev;
+	unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
+	u8 *data;
+	dma_addr_t dma_buf;
+	struct usb_device *usbdev;
+	unsigned int flags;
+	struct urb *urb;
+	struct timer_list key_up_timer;
+	int current_key;
+	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_ATV_IRCONTROL) },
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+	{}
+};
+MODULE_DEVICE_TABLE(usb, appleir_ids);
+
+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
+{
+	int i;
+
+	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
+
+	for (i = 0; i < len; ++i)
+		printk(" %02x", data[i]);
+	printk("\n");
+}
+
+static void key_up(struct appleir *appleir, int key)
+{
+	dbginfo(&appleir->input_dev->dev, "key %d up\n", key);
+	input_report_key(appleir->input_dev, key, 0);
+	input_sync(appleir->input_dev);
+}
+
+static void key_down(struct appleir *appleir, int key)
+{
+	dbginfo(&appleir->input_dev->dev, "key %d down\n", key);
+	input_report_key(appleir->input_dev, key, 1);
+	input_sync(appleir->input_dev);
+}
+
+static void battery_flat(struct appleir *appleir)
+{
+	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
+}
+
+static void key_up_tick(unsigned long data)
+{
+	struct appleir *appleir = (struct appleir *)data;
+
+	if (appleir->current_key) {
+		key_up(appleir, appleir->current_key);
+		appleir->current_key = 0;
+	}
+}
+
+static void new_data(struct appleir *appleir, u8 *data, int len)
+{
+	static const u8 keydown[] = { 0x25, 0x87, 0xee };
+	static const u8 keyrepeat[] = { 0x26, };
+	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
+
+	if (debug)
+		dump_packet(appleir, "received", data, len);
+
+	if (len != 5)
+		return;
+
+	if (!memcmp(data, keydown, sizeof(keydown))) {
+		/* If we already have a key down, take it up before marking
+		   this one down */
+		if (appleir->current_key)
+			key_up(appleir, appleir->current_key);
+		appleir->current_key = appleir->keymap[(data[4] >> 1) & MAX_KEYS_MASK];
+
+		key_down(appleir, appleir->current_key);
+		/* Remote doesn't do key up, either pull them up, in the test
+		   above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+
+		return;
+	}
+
+	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
+		key_down(appleir, appleir->current_key);
+		/* Remote doesn't do key up, either pull them up, in the test
+		   above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+		return;
+	}
+
+	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
+		battery_flat(appleir);
+		/* Fall through */
+	}
+
+	dump_packet(appleir, "unknown packet", data, len);
+}
+
+static void appleir_urb(struct urb *urb)
+{
+	struct appleir *appleir = urb->context;
+	int status = urb->status;
+	int retval;
+
+	switch (status) {
+	case 0:
+		new_data(appleir, urb->transfer_buffer, urb->actual_length);
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* This urb is terminated, clean up */
+		dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__,
+			urb->status);
+		return;
+	default:
+		dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__,
+			urb->status);
+	}
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result %d", __func__,
+		    retval);
+}
+
+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)) {
+		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);
+
+	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,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct appleir *appleir = NULL;
+	struct input_dev *input_dev;
+	int retval = -ENOMEM;
+	int i;
+
+	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
+	if (!appleir)
+		goto allocfail;
+
+	appleir->data = usb_buffer_alloc(dev, URB_SIZE, GFP_KERNEL,
+					 &appleir->dma_buf);
+	if (!appleir->data)
+		goto usbfail;
+
+	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!appleir->urb)
+		goto urbfail;
+
+	appleir->usbdev = dev;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		goto inputfail;
+
+	appleir->input_dev = input_dev;
+
+	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
+	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
+
+	input_dev->name = "Apple Infrared Remote Controller";
+	input_dev->phys = appleir->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+	input_set_drvdata(input_dev, appleir);
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+	memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
+	for (i = 0; i < MAX_KEYS; i++)
+		set_bit(appleir->keymap[i], input_dev->keybit);
+
+	input_dev->open = appleir_open;
+	input_dev->close = appleir_close;
+
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+	usb_fill_int_urb(appleir->urb, dev,
+			 usb_rcvintpipe(dev, 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;
+
+	setup_timer(&appleir->key_up_timer,
+		    key_up_tick, (unsigned long) appleir);
+
+	retval = input_register_device(appleir->input_dev);
+	if (retval)
+		goto inputfail;
+
+	usb_set_intfdata(intf, appleir);
+
+	return 0;
+
+inputfail:
+	input_free_device(appleir->input_dev);
+
+urbfail:
+	usb_free_urb(appleir->urb);
+
+usbfail:
+	usb_buffer_free(dev, URB_SIZE, appleir->data,
+			appleir->dma_buf);
+
+allocfail:
+	kfree(appleir);
+
+	return retval;
+}
+
+static void appleir_disconnect(struct usb_interface *intf)
+{
+	struct appleir *appleir = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	input_unregister_device(appleir->input_dev);
+	usb_free_urb(appleir->urb);
+	usb_buffer_free(interface_to_usbdev(intf), URB_SIZE,
+			appleir->data, appleir->dma_buf);
+	kfree(appleir);
+}
+
+static struct usb_driver appleir_driver = {
+	.name                 = "appleir",
+	.probe                = appleir_probe,
+	.disconnect           = appleir_disconnect,
+	.id_table             = appleir_ids,
+};
+
+static int __init appleir_init(void)
+{
+	return usb_register(&appleir_driver);
+}
+
+static void __exit appleir_exit(void)
+{
+	usb_deregister(&appleir_driver);
+}
+
+module_init(appleir_init);
+module_exit(appleir_exit);
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-17  8:12 ` Dmitry Torokhov
@ 2010-04-17 21:44   ` Bastien Nocera
  2010-04-18 19:43     ` Dmitry Torokhov
  2010-04-19  9:22   ` Jiri Kosina
  1 sibling, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-04-17 21:44 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Jiri Kosina

On Sat, 2010-04-17 at 01:12 -0700, Dmitry Torokhov wrote: 
> HI Bastien,
> 
> On Fri, Apr 16, 2010 at 05:19:52PM +0100, Bastien Nocera wrote:
> > This driver was originally written by James McKenzie, updated by
> > Greg Kroah-Hartman, further updated by myself, with suspend support
> > added.
> > 
> > More recent versions of the IR receiver are also supported through
> > a patch by Alex Karpenko.
> > 
> > Tested on a MacbookAir1,1
> > 
> 
> A few comments...

All fixed. I removed the suspend/resume code as it worked fine without
it (I was working of an old patch).

Sent the new patch separately.

> > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > ---
> >  Documentation/input/appleir.txt |   45 ++++
> >  drivers/hid/hid-apple.c         |    4 -
> >  drivers/hid/hid-core.c          |    5 +-
> >  drivers/hid/hid-ids.h           |    1 +
> 
> HID pieces need to go through Jiri or he needs to ack them to go through
> my tree...

The HID pieces are necessary to get the "lirc" part of the documentation
working (in appleir.txt). The driver is fine without it, but it won't
work with lirc until the HID patch is in.

Cheers 


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-04-16 16:19 Bastien Nocera
@ 2010-04-17  8:12 ` Dmitry Torokhov
  2010-04-17 21:44   ` Bastien Nocera
  2010-04-19  9:22   ` Jiri Kosina
  0 siblings, 2 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2010-04-17  8:12 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-input, Jiri Kosina

HI Bastien,

On Fri, Apr 16, 2010 at 05:19:52PM +0100, Bastien Nocera wrote:
> This driver was originally written by James McKenzie, updated by
> Greg Kroah-Hartman, further updated by myself, with suspend support
> added.
> 
> More recent versions of the IR receiver are also supported through
> a patch by Alex Karpenko.
> 
> Tested on a MacbookAir1,1
> 

A few comments...

> Signed-off-by: Bastien Nocera <hadess@hadess.net>
> ---
>  Documentation/input/appleir.txt |   45 ++++
>  drivers/hid/hid-apple.c         |    4 -
>  drivers/hid/hid-core.c          |    5 +-
>  drivers/hid/hid-ids.h           |    1 +

HID pieces need to go through Jiri or he needs to ack them to go through
my tree...

>  drivers/input/misc/Kconfig      |   13 +
>  drivers/input/misc/Makefile     |    1 +
>  drivers/input/misc/appleir.c    |  477 +++++++++++++++++++++++++++++++++++++++
>  7 files changed, 540 insertions(+), 6 deletions(-)
>  create mode 100644 Documentation/input/appleir.txt
>  create mode 100644 drivers/input/misc/appleir.c
> 
> diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
> new file mode 100644
> index 0000000..0267a4b
> --- /dev/null
> +++ b/Documentation/input/appleir.txt
> @@ -0,0 +1,45 @@
> +Apple IR receiver Driver (appleir)
> +----------------------------------
> +	Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
> +
> +The appleir driver is a kernel input driver to handle Apple's IR
> +receivers (and associated remotes) in the kernel.
> +
> +The driver is an input driver which only handles "official" remotes
> +as built and sold by Apple.
> +
> +Authors
> +-------
> +
> +James McKenzie (original driver)
> +Alex Karpenko (05ac:8242 support)
> +Greg Kroah-Hartman (cleanups and original submission)
> +Bastien Nocera (further cleanups and suspend support)
> +
> +Supported hardware
> +------------------
> +
> +- All Apple laptops and desktops from 2005 onwards, except:
> +  - the unibody Macbook (2009)
> +  - Mac Pro (all versions)
> +- Apple TV (all revisions)
> +
> +The remote will only support the 6 buttons of the original remotes
> +as sold by Apple. See the next section if you want to use other remotes
> +or want to use lirc with the device instead of the kernel driver.
> +
> +Using lirc (native) instead of the kernel driver
> +------------------------------------------------
> +
> +First, you will need to disable the kernel driver for the receiver.
> +
> +This can be achieved by passing quirks to the usbhid driver.
> +The quirk line would be:
> +usbhid.quirks=0x05ac:0x8242:0x40000010
> +
> +With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
> +With 0x8242 being the product ID (check the output of lsusb for your hardware)
> +And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE"
> +
> +This should force the creation of a hiddev device for the receiver, and
> +make it usable under lirc.
> diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
> index 78286b1..5f2a731 100644
> --- a/drivers/hid/hid-apple.c
> +++ b/drivers/hid/hid-apple.c
> @@ -360,10 +360,6 @@ static void apple_remove(struct hid_device *hdev)
>  }
>  
>  static const struct hid_device_id apple_devices[] = {
> -	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
> -		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
> -	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
> -		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
>  		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
>  
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 368fbb0..b57e5f7 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -1253,8 +1253,6 @@ static const struct hid_device_id hid_blacklist[] = {
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
> -	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
> -	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
>  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
> @@ -1553,6 +1551,9 @@ static const struct hid_device_id hid_ignore_list[] = {
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
> +	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
> +	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
> +	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 72c05f9..66a2ca8 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -97,6 +97,7 @@
>  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
>  #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
>  #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
> +#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
>  #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
>  #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
>  
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index 23140a3..46614b2 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -159,6 +159,19 @@ config INPUT_KEYSPAN_REMOTE
>  	  To compile this driver as a module, choose M here: the module will
>  	  be called keyspan_remote.
>  
> +config INPUT_APPLEIR
> +	tristate "Apple infrared receiver (built in)"
> +	depends on USB_ARCH_HAS_HCD
> +	select USB
> +	help
> +	  Say Y here if you want to use a Apple infrared remote control. All
> +	  the Apple computers from 2005 onwards include such a port, except
> +	  the unibody Macbook (2009), and Mac Pros. This receiver is also
> +	  used in the Apple TV set-top box.
> +
> +	  To compile this driver as a module, choose M here: the module will
> +	  be called appleir.
> +
>  config INPUT_POWERMATE
>  	tristate "Griffin PowerMate and Contour Jog support"
>  	depends on USB_ARCH_HAS_HCD
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index 7e95a5d..3fa4404 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -6,6 +6,7 @@
>  
>  obj-$(CONFIG_INPUT_88PM860X_ONKEY)	+= 88pm860x_onkey.o
>  obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
> +obj-$(CONFIG_INPUT_APPLEIR)		+= appleir.o
>  obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
>  obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
>  obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
> diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
> new file mode 100644
> index 0000000..138f4c8
> --- /dev/null
> +++ b/drivers/input/misc/appleir.c
> @@ -0,0 +1,477 @@
> +/*
> + * appleir: USB driver for the apple ir device
> + *
> + * Original driver written by James McKenzie
> + * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
> + *
> + * Copyright (C) 2006 James McKenzie
> + * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
> + * Copyright (C) 2008 Novell Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation, version 2.
> + *
> + */
> +
> +#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>
> +#include <linux/usb/input.h>
> +#include <asm/unaligned.h>
> +#include <asm/byteorder.h>
> +
> +#define DRIVER_VERSION "v1.2"
> +#define DRIVER_AUTHOR "James McKenzie"
> +#define DRIVER_DESC "Apple infrared receiver driver"
> +#define DRIVER_LICENSE "GPL"
> +
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE(DRIVER_LICENSE);
> +
> +#define USB_VENDOR_ID_APPLE			0x05ac
> +#define USB_DEVICE_ID_APPLE_IRCONTROL		0x8240
> +#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
> +#define USB_DEVICE_ID_APPLE_IRCONTROL4		0x8242
> +
> +#define URB_SIZE	32
> +
> +#define MAX_KEYS	8
> +#define MAX_KEYS_MASK	(MAX_KEYS - 1)
> +
> +#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
> +
> +struct appleir {
> +	struct input_dev *input_dev;
> +	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;
> +	int current_key;
> +	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_ATV_IRCONTROL) },
> +	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(usb, appleir_ids);
> +
> +/* I have two devices both of which report the following */
> +/* 25 87 ee 83 0a  	+  */
> +/* 25 87 ee 83 0c  	-  */
> +/* 25 87 ee 83 09	<< */
> +/* 25 87 ee 83 06	>> */
> +/* 25 87 ee 83 05	>" */
> +/* 25 87 ee 83 03	menu */
> +/* 26 00 00 00 00	for key repeat*/
> +
> +/* Thomas Glanzmann reports the following responses */
> +/* 25 87 ee ca 0b	+  */
> +/* 25 87 ee ca 0d	-  */
> +/* 25 87 ee ca 08	<< */
> +/* 25 87 ee ca 07	>> */
> +/* 25 87 ee ca 04	>" */
> +/* 25 87 ee ca 02 	menu */
> +/* 26 00 00 00 00       for key repeat*/
> +/* He also observes the following event sometimes */
> +/* sent after a key is release, which I interpret */
> +/* as a flat battery message */
> +/* 25 87 e0 ca 06	flat battery */
> +
> +/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
> +/* 25 87 ee 47 0b	+  */
> +/* 25 87 ee 47 0d	-  */
> +/* 25 87 ee 47 08	<< */
> +/* 25 87 ee 47 07	>> */
> +/* 25 87 ee 47 04	>" */
> +/* 25 87 ee 47 02 	menu */
> +/* 26 87 ee 47 ** 	for key repeat (** is the code of the key being held) */
> +
> +static int keymap[MAX_KEYS] = {
> +	KEY_RESERVED,
> +	KEY_MENU,
> +	KEY_PLAYPAUSE,
> +	KEY_FORWARD,
> +	KEY_BACK,
> +	KEY_VOLUMEUP,
> +	KEY_VOLUMEDOWN,
> +	KEY_RESERVED,
> +};
> +
> +static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
> +{
> +	int i;
> +
> +	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
> +
> +	for (i = 0; i < len; ++i)
> +		printk(" %02x", data[i]);
> +	printk("\n");
> +}
> +
> +static void key_up(struct appleir *appleir, int key)
> +{
> +	dbginfo (&appleir->input_dev->dev, "key %d up\n", key);

No space between function and opening parenthesis.

> +	input_report_key(appleir->input_dev, key, 0);
> +	input_sync(appleir->input_dev);
> +}
> +
> +static void key_down(struct appleir *appleir, int key)
> +{
> +	dbginfo (&appleir->input_dev->dev, "key %d down\n", key);
> +	input_report_key(appleir->input_dev, key, 1);
> +	input_sync(appleir->input_dev);
> +}
> +
> +static void battery_flat(struct appleir *appleir)
> +{
> +	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
> +}
> +
> +static void key_up_tick(unsigned long data)
> +{
> +	struct appleir *appleir = (struct appleir *)data;
> +
> +	if (appleir->current_key) {
> +		key_up(appleir, appleir->current_key);
> +		appleir->current_key = 0;
> +	}
> +}
> +
> +static void new_data(struct appleir *appleir, u8 *data, int len)
> +{
> +	static const u8 keydown[] = { 0x25, 0x87, 0xee };
> +	static const u8 keyrepeat[] = { 0x26, };
> +	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
> +
> +	if (debug)
> +		dump_packet(appleir, "received", data, len);
> +
> +	if (len != 5)
> +		return;
> +
> +	if (!memcmp(data, keydown, sizeof(keydown))) {
> +		/* If we already have a key down, take it up before marking
> +		   this one down */
> +		if (appleir->current_key)
> +			key_up(appleir, appleir->current_key);
> +		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
> +
> +		key_down(appleir, appleir->current_key);
> +		/* Remote doesn't do key up, either pull them up, in the test
> +		   above, or here set a timer which pulls them up after 1/8 s */
> +		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
> +
> +		return;
> +	}
> +
> +	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
> +		key_down(appleir, appleir->current_key);
> +		/* Remote doesn't do key up, either pull them up, in the test
> +		   above, or here set a timer which pulls them up after 1/8 s */
> +		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
> +		return;
> +	}
> +
> +	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
> +		battery_flat(appleir);
> +		/* Fall through */
> +	}
> +
> +	dump_packet(appleir, "unknown packet", data, len);
> +}
> +
> +static void appleir_urb(struct urb *urb)
> +{
> +	struct appleir *appleir = urb->context;
> +	int status = urb->status;
> +	int retval;
> +
> +	switch (status) {
> +	case 0:
> +		new_data(appleir, urb->transfer_buffer, urb->actual_length);
> +		break;
> +	case -ECONNRESET:
> +	case -ENOENT:
> +	case -ESHUTDOWN:
> +		/* This urb is terminated, clean up */
> +		dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__,
> +			urb->status);
> +		return;
> +	default:
> +		dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__,
> +			urb->status);
> +	}
> +
> +	retval = usb_submit_urb(urb, GFP_ATOMIC);
> +	if (retval)
> +		err("%s - usb_submit_urb failed with result %d", __func__,
> +		    retval);
> +}
> +
> +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)) {
> +		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);
> +
> +	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,
> +			 const struct usb_device_id *id)
> +{
> +	struct usb_device *dev = interface_to_usbdev(intf);
> +	struct usb_endpoint_descriptor *endpoint;
> +	struct appleir *appleir = NULL;
> +	struct input_dev *input_dev;
> +	int retval = -ENOMEM;
> +	int i;
> +
> +	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
> +	if (!appleir)
> +		goto fail;
> +
> +	appleir->data = usb_buffer_alloc(dev, URB_SIZE, GFP_KERNEL,
> +					 &appleir->dma_buf);
> +	if (!appleir->data)
> +		goto fail;
> +
> +	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
> +	if (!appleir->urb)
> +		goto fail;
> +
> +	appleir->usbdev = dev;
> +
> +	input_dev = input_allocate_device();
> +	if (!input_dev)
> +		goto fail;
> +
> +	appleir->input_dev = input_dev;
> +
> +	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
> +	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
> +
> +	input_dev->name = "Apple infrared remote control driver";

Device is not driver. So it should probably read:

	 "Apple Infrared Remote Controller"

> +	input_dev->phys = appleir->phys;
> +	usb_to_input_id(dev, &input_dev->id);
> +	input_dev->dev.parent = &intf->dev;
> +	input_set_drvdata(input_dev, appleir);
> +
> +	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
> +	input_dev->ledbit[0] = 0;

Input device is zeroed out by input_allocate_device().

> +
> +	for (i = 0; i < MAX_KEYS; i++)
> +		set_bit(keymap[i], input_dev->keybit);

Keymap should be part of appleir structure; also set up
input_dev->keycode, keycodemax and keycodesize so that keymap can be
adjusted from userspace on per-device basis.

> +
> +	clear_bit(0, input_dev->keybit);

Not needed anymore.

> +
> +	input_dev->open = appleir_open;
> +	input_dev->close = appleir_close;
> +
> +	endpoint = &intf->cur_altsetting->endpoint[0].desc;
> +
> +	usb_fill_int_urb(appleir->urb, dev,
> +			 usb_rcvintpipe(dev, 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;
> +
> +	usb_set_intfdata(intf, appleir);

Should go directly in front of "return 0;".
> +
> +	init_timer(&appleir->key_up_timer);
> +
> +	appleir->key_up_timer.function = key_up_tick;
> +	appleir->key_up_timer.data = (unsigned long)appleir;

setup_timer()?

> +
> +	appleir->timer_initted++;

Pointless, really.

> +
> +	retval = input_register_device(appleir->input_dev);
> +	if (retval)
> +		goto fail;
> +
> +	return 0;
> +
> +fail:

Generally I prefer having multiple fail points instead of teting
conditions in fail path.

> +	printk(KERN_WARNING "Failed to load appleir\n");

Not load but bind. And driver core will let us know already.

> +	if (appleir) {
> +		if (appleir->data)
> +			usb_buffer_free(dev, URB_SIZE, appleir->data,
> +					appleir->dma_buf);
> +
> +		if (appleir->timer_initted)
> +			del_timer_sync(&appleir->key_up_timer);
> +

No need (see comments in appleir_remove).

> +		if (appleir->input_dev)
> +			input_free_device(appleir->input_dev);
> +
> +		kfree(appleir);
> +	}
> +
> +	return retval;
> +}
> +
> +static void appleir_disconnect(struct usb_interface *intf)
> +{
> +	struct appleir *appleir = usb_get_intfdata(intf);
> +
> +	usb_set_intfdata(intf, NULL);
> +	if (appleir) {

Is it possible for appleir to be NULL at this point?

> +		input_unregister_device(appleir->input_dev);
> +		if (appleir->timer_initted)

How can this be possible?

> +			del_timer_sync(&appleir->key_up_timer);

If this is needed then you are doing it too late (input deviceis already
gone). However this should not be needed since appleir_close is
guaranteed to be called if you opened the device and it will cancel the
timer for you.

> +		usb_kill_urb(appleir->urb);

NOt needed here either.

> +		usb_free_urb(appleir->urb);
> +		usb_buffer_free(interface_to_usbdev(intf), URB_SIZE,
> +				appleir->data, appleir->dma_buf);
> +		kfree(appleir);
> +	}
> +}
> +
> +static int appleir_suspend(struct usb_interface *interface,
> +			   pm_message_t message)
> +{
> +	struct appleir *appleir;
> +
> +	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;
> +
> +	appleir = usb_get_intfdata(interface);

Combine definition with initialization?

> +
> +	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;

Why do you need to re-initialize the timer?

> +	}
> +
> +	appleir->flags &= ~APPLEIR_SUSPENDED;
> +
> +	mutex_unlock(&appleir_mutex);
> +
> +	return 0;
> +}
> +
> +static struct usb_driver appleir_driver = {
> +	.name                 = "appleir",
> +	.probe                = appleir_probe,
> +	.disconnect           = appleir_disconnect,
> +	.suspend              = appleir_suspend,
> +	.resume               = appleir_resume,
> +	.reset_resume         = NULL,
> +	.id_table             = appleir_ids,
> +	.supports_autosuspend = 1,
> +};
> +
> +static int __init appleir_init(void)
> +{
> +	int retval;
> +
> +	retval = usb_register(&appleir_driver);
> +	if (retval)
> +		goto out;
> +	printk(KERN_INFO DRIVER_VERSION ":" DRIVER_DESC);
> +out:
> +	return retval;

How about

	return usb_register(&appleir_driver);

?

Boot is noisy enough.

> +}
> +
> +static void __exit appleir_exit(void)
> +{
> +	usb_deregister(&appleir_driver);
> +}
> +
> +module_init(appleir_init);
> +module_exit(appleir_exit);

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH] Input: add appleir USB driver
@ 2010-04-16 16:19 Bastien Nocera
  2010-04-17  8:12 ` Dmitry Torokhov
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-04-16 16:19 UTC (permalink / raw)
  To: linux-input; +Cc: Dmitry Torokhov, Jiri Kosina

This driver was originally written by James McKenzie, updated by
Greg Kroah-Hartman, further updated by myself, with suspend support
added.

More recent versions of the IR receiver are also supported through
a patch by Alex Karpenko.

Tested on a MacbookAir1,1

Signed-off-by: Bastien Nocera <hadess@hadess.net>
---
 Documentation/input/appleir.txt |   45 ++++
 drivers/hid/hid-apple.c         |    4 -
 drivers/hid/hid-core.c          |    5 +-
 drivers/hid/hid-ids.h           |    1 +
 drivers/input/misc/Kconfig      |   13 +
 drivers/input/misc/Makefile     |    1 +
 drivers/input/misc/appleir.c    |  477 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 540 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/input/appleir.txt
 create mode 100644 drivers/input/misc/appleir.c

diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
new file mode 100644
index 0000000..0267a4b
--- /dev/null
+++ b/Documentation/input/appleir.txt
@@ -0,0 +1,45 @@
+Apple IR receiver Driver (appleir)
+----------------------------------
+	Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+
+The appleir driver is a kernel input driver to handle Apple's IR
+receivers (and associated remotes) in the kernel.
+
+The driver is an input driver which only handles "official" remotes
+as built and sold by Apple.
+
+Authors
+-------
+
+James McKenzie (original driver)
+Alex Karpenko (05ac:8242 support)
+Greg Kroah-Hartman (cleanups and original submission)
+Bastien Nocera (further cleanups and suspend support)
+
+Supported hardware
+------------------
+
+- All Apple laptops and desktops from 2005 onwards, except:
+  - the unibody Macbook (2009)
+  - Mac Pro (all versions)
+- Apple TV (all revisions)
+
+The remote will only support the 6 buttons of the original remotes
+as sold by Apple. See the next section if you want to use other remotes
+or want to use lirc with the device instead of the kernel driver.
+
+Using lirc (native) instead of the kernel driver
+------------------------------------------------
+
+First, you will need to disable the kernel driver for the receiver.
+
+This can be achieved by passing quirks to the usbhid driver.
+The quirk line would be:
+usbhid.quirks=0x05ac:0x8242:0x40000010
+
+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
+With 0x8242 being the product ID (check the output of lsusb for your hardware)
+And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE"
+
+This should force the creation of a hiddev device for the receiver, and
+make it usable under lirc.
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 78286b1..5f2a731 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -360,10 +360,6 @@ static void apple_remove(struct hid_device *hdev)
 }
 
 static const struct hid_device_id apple_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
 		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
 
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 368fbb0..b57e5f7 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1253,8 +1253,6 @@ static const struct hid_device_id hid_blacklist[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
@@ -1553,6 +1551,9 @@ static const struct hid_device_id hid_ignore_list[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 72c05f9..66a2ca8 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -97,6 +97,7 @@
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
 #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
 
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 23140a3..46614b2 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -159,6 +159,19 @@ config INPUT_KEYSPAN_REMOTE
 	  To compile this driver as a module, choose M here: the module will
 	  be called keyspan_remote.
 
+config INPUT_APPLEIR
+	tristate "Apple infrared receiver (built in)"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use a Apple infrared remote control. All
+	  the Apple computers from 2005 onwards include such a port, except
+	  the unibody Macbook (2009), and Mac Pros. This receiver is also
+	  used in the Apple TV set-top box.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called appleir.
+
 config INPUT_POWERMATE
 	tristate "Griffin PowerMate and Contour Jog support"
 	depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 7e95a5d..3fa4404 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_INPUT_88PM860X_ONKEY)	+= 88pm860x_onkey.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
+obj-$(CONFIG_INPUT_APPLEIR)		+= appleir.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
new file mode 100644
index 0000000..138f4c8
--- /dev/null
+++ b/drivers/input/misc/appleir.c
@@ -0,0 +1,477 @@
+/*
+ * appleir: USB driver for the apple ir device
+ *
+ * Original driver written by James McKenzie
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Copyright (C) 2006 James McKenzie
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2008 Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+
+#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>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#define DRIVER_VERSION "v1.2"
+#define DRIVER_AUTHOR "James McKenzie"
+#define DRIVER_DESC "Apple infrared receiver driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_APPLE			0x05ac
+#define USB_DEVICE_ID_APPLE_IRCONTROL		0x8240
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4		0x8242
+
+#define URB_SIZE	32
+
+#define MAX_KEYS	8
+#define MAX_KEYS_MASK	(MAX_KEYS - 1)
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+struct appleir {
+	struct input_dev *input_dev;
+	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;
+	int current_key;
+	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_ATV_IRCONTROL) },
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+	{}
+};
+MODULE_DEVICE_TABLE(usb, appleir_ids);
+
+/* I have two devices both of which report the following */
+/* 25 87 ee 83 0a  	+  */
+/* 25 87 ee 83 0c  	-  */
+/* 25 87 ee 83 09	<< */
+/* 25 87 ee 83 06	>> */
+/* 25 87 ee 83 05	>" */
+/* 25 87 ee 83 03	menu */
+/* 26 00 00 00 00	for key repeat*/
+
+/* Thomas Glanzmann reports the following responses */
+/* 25 87 ee ca 0b	+  */
+/* 25 87 ee ca 0d	-  */
+/* 25 87 ee ca 08	<< */
+/* 25 87 ee ca 07	>> */
+/* 25 87 ee ca 04	>" */
+/* 25 87 ee ca 02 	menu */
+/* 26 00 00 00 00       for key repeat*/
+/* He also observes the following event sometimes */
+/* sent after a key is release, which I interpret */
+/* as a flat battery message */
+/* 25 87 e0 ca 06	flat battery */
+
+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
+/* 25 87 ee 47 0b	+  */
+/* 25 87 ee 47 0d	-  */
+/* 25 87 ee 47 08	<< */
+/* 25 87 ee 47 07	>> */
+/* 25 87 ee 47 04	>" */
+/* 25 87 ee 47 02 	menu */
+/* 26 87 ee 47 ** 	for key repeat (** is the code of the key being held) */
+
+static int keymap[MAX_KEYS] = {
+	KEY_RESERVED,
+	KEY_MENU,
+	KEY_PLAYPAUSE,
+	KEY_FORWARD,
+	KEY_BACK,
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_RESERVED,
+};
+
+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
+{
+	int i;
+
+	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
+
+	for (i = 0; i < len; ++i)
+		printk(" %02x", data[i]);
+	printk("\n");
+}
+
+static void key_up(struct appleir *appleir, int key)
+{
+	dbginfo (&appleir->input_dev->dev, "key %d up\n", key);
+	input_report_key(appleir->input_dev, key, 0);
+	input_sync(appleir->input_dev);
+}
+
+static void key_down(struct appleir *appleir, int key)
+{
+	dbginfo (&appleir->input_dev->dev, "key %d down\n", key);
+	input_report_key(appleir->input_dev, key, 1);
+	input_sync(appleir->input_dev);
+}
+
+static void battery_flat(struct appleir *appleir)
+{
+	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
+}
+
+static void key_up_tick(unsigned long data)
+{
+	struct appleir *appleir = (struct appleir *)data;
+
+	if (appleir->current_key) {
+		key_up(appleir, appleir->current_key);
+		appleir->current_key = 0;
+	}
+}
+
+static void new_data(struct appleir *appleir, u8 *data, int len)
+{
+	static const u8 keydown[] = { 0x25, 0x87, 0xee };
+	static const u8 keyrepeat[] = { 0x26, };
+	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
+
+	if (debug)
+		dump_packet(appleir, "received", data, len);
+
+	if (len != 5)
+		return;
+
+	if (!memcmp(data, keydown, sizeof(keydown))) {
+		/* If we already have a key down, take it up before marking
+		   this one down */
+		if (appleir->current_key)
+			key_up(appleir, appleir->current_key);
+		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
+
+		key_down(appleir, appleir->current_key);
+		/* Remote doesn't do key up, either pull them up, in the test
+		   above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+
+		return;
+	}
+
+	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
+		key_down(appleir, appleir->current_key);
+		/* Remote doesn't do key up, either pull them up, in the test
+		   above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+		return;
+	}
+
+	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
+		battery_flat(appleir);
+		/* Fall through */
+	}
+
+	dump_packet(appleir, "unknown packet", data, len);
+}
+
+static void appleir_urb(struct urb *urb)
+{
+	struct appleir *appleir = urb->context;
+	int status = urb->status;
+	int retval;
+
+	switch (status) {
+	case 0:
+		new_data(appleir, urb->transfer_buffer, urb->actual_length);
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* This urb is terminated, clean up */
+		dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__,
+			urb->status);
+		return;
+	default:
+		dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__,
+			urb->status);
+	}
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result %d", __func__,
+		    retval);
+}
+
+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)) {
+		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);
+
+	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,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct appleir *appleir = NULL;
+	struct input_dev *input_dev;
+	int retval = -ENOMEM;
+	int i;
+
+	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
+	if (!appleir)
+		goto fail;
+
+	appleir->data = usb_buffer_alloc(dev, URB_SIZE, GFP_KERNEL,
+					 &appleir->dma_buf);
+	if (!appleir->data)
+		goto fail;
+
+	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!appleir->urb)
+		goto fail;
+
+	appleir->usbdev = dev;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		goto fail;
+
+	appleir->input_dev = input_dev;
+
+	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
+	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
+
+	input_dev->name = "Apple infrared remote control driver";
+	input_dev->phys = appleir->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+	input_set_drvdata(input_dev, appleir);
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+	input_dev->ledbit[0] = 0;
+
+	for (i = 0; i < MAX_KEYS; i++)
+		set_bit(keymap[i], input_dev->keybit);
+
+	clear_bit(0, input_dev->keybit);
+
+	input_dev->open = appleir_open;
+	input_dev->close = appleir_close;
+
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+	usb_fill_int_urb(appleir->urb, dev,
+			 usb_rcvintpipe(dev, 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;
+
+	usb_set_intfdata(intf, appleir);
+
+	init_timer(&appleir->key_up_timer);
+
+	appleir->key_up_timer.function = key_up_tick;
+	appleir->key_up_timer.data = (unsigned long)appleir;
+
+	appleir->timer_initted++;
+
+	retval = input_register_device(appleir->input_dev);
+	if (retval)
+		goto fail;
+
+	return 0;
+
+fail:
+	printk(KERN_WARNING "Failed to load appleir\n");
+	if (appleir) {
+		if (appleir->data)
+			usb_buffer_free(dev, URB_SIZE, appleir->data,
+					appleir->dma_buf);
+
+		if (appleir->timer_initted)
+			del_timer_sync(&appleir->key_up_timer);
+
+		if (appleir->input_dev)
+			input_free_device(appleir->input_dev);
+
+		kfree(appleir);
+	}
+
+	return retval;
+}
+
+static void appleir_disconnect(struct usb_interface *intf)
+{
+	struct appleir *appleir = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (appleir) {
+		input_unregister_device(appleir->input_dev);
+		if (appleir->timer_initted)
+			del_timer_sync(&appleir->key_up_timer);
+		usb_kill_urb(appleir->urb);
+		usb_free_urb(appleir->urb);
+		usb_buffer_free(interface_to_usbdev(intf), URB_SIZE,
+				appleir->data, appleir->dma_buf);
+		kfree(appleir);
+	}
+}
+
+static int appleir_suspend(struct usb_interface *interface,
+			   pm_message_t message)
+{
+	struct appleir *appleir;
+
+	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;
+
+	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,
+	.suspend              = appleir_suspend,
+	.resume               = appleir_resume,
+	.reset_resume         = NULL,
+	.id_table             = appleir_ids,
+	.supports_autosuspend = 1,
+};
+
+static int __init appleir_init(void)
+{
+	int retval;
+
+	retval = usb_register(&appleir_driver);
+	if (retval)
+		goto out;
+	printk(KERN_INFO DRIVER_VERSION ":" DRIVER_DESC);
+out:
+	return retval;
+}
+
+static void __exit appleir_exit(void)
+{
+	usb_deregister(&appleir_driver);
+}
+
+module_init(appleir_init);
+module_exit(appleir_exit);
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-02-10 12:52         ` Jiri Kosina
@ 2010-02-11 18:18           ` Bastien Nocera
  0 siblings, 0 replies; 57+ messages in thread
From: Bastien Nocera @ 2010-02-11 18:18 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-input, Dmitry Torokhov

On Wed, 2010-02-10 at 13:52 +0100, Jiri Kosina wrote:
> On Mon, 8 Feb 2010, Bastien Nocera wrote:
> 
> > > > > > +With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
> > > > > > +With 0x8242 being the product ID (check the output of lsusb for your hardware)
> > > > > > +And 0x08 being "HID_CONNECT_HIDDEV"
> > > > > 
> > > > > I am afraid this is not true, 0x08 is HID_QUIRK_NOGET.
> > > > > 
> > > > > We currently don't have dynamic quirk for forcing HIDDEV creation from the 
> > > > > module parameter.
> > > > 
> > > > Right. Any chance to change that?
> > > 
> > > This particular one might actually make enough sense to be added (although 
> > > I am really trying to avoid quirk additions completely), for backwards 
> > > compatibility reasons.
> > 
> > Should I remove the comments there altogether then? That kind of defeats
> > my "but you can use lirc with some tweaks" argument, even though I still
> > think that those people needing more keys would be in the minority...
> 
> I rather though that we could/should (re-)introduce the HID_QUIRK_HIDDEV 
> quirks so that it could still be applied manually.

The interaction between the HID and the input layer isn't really my
forte (well, the kernel's not my forte :).

Wouldn't we have some trouble getting the HID layer provide a hiddev
device for the receiver, whilst being serviced by an input driver?

I wouldn't mind trying to port the driver to be a full HID driver, and
enable hiddev all the time on it. We just wouldn't do anything in the
input part if the hiddev device was claimed, and parse the raw_report
from the device otherwise.

Opinions? If it's a good idea, I'd be interested in some examples in
devices that do their own raw_report event parsing, instead of letting
the hid layer handle it.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-02-08 16:32       ` Bastien Nocera
@ 2010-02-10 12:52         ` Jiri Kosina
  2010-02-11 18:18           ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Jiri Kosina @ 2010-02-10 12:52 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-input, Dmitry Torokhov

On Mon, 8 Feb 2010, Bastien Nocera wrote:

> > > > > +With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
> > > > > +With 0x8242 being the product ID (check the output of lsusb for your hardware)
> > > > > +And 0x08 being "HID_CONNECT_HIDDEV"
> > > > 
> > > > I am afraid this is not true, 0x08 is HID_QUIRK_NOGET.
> > > > 
> > > > We currently don't have dynamic quirk for forcing HIDDEV creation from the 
> > > > module parameter.
> > > 
> > > Right. Any chance to change that?
> > 
> > This particular one might actually make enough sense to be added (although 
> > I am really trying to avoid quirk additions completely), for backwards 
> > compatibility reasons.
> 
> Should I remove the comments there altogether then? That kind of defeats
> my "but you can use lirc with some tweaks" argument, even though I still
> think that those people needing more keys would be in the minority...

I rather though that we could/should (re-)introduce the HID_QUIRK_HIDDEV 
quirks so that it could still be applied manually.

Thanks,

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-02-03 15:54     ` Jiri Kosina
@ 2010-02-08 16:32       ` Bastien Nocera
  2010-02-10 12:52         ` Jiri Kosina
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-02-08 16:32 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-input, Dmitry Torokhov

On Wed, 2010-02-03 at 16:54 +0100, Jiri Kosina wrote:
> On Mon, 1 Feb 2010, Bastien Nocera wrote:
> 
> > > > +With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
> > > > +With 0x8242 being the product ID (check the output of lsusb for your hardware)
> > > > +And 0x08 being "HID_CONNECT_HIDDEV"
> > > 
> > > I am afraid this is not true, 0x08 is HID_QUIRK_NOGET.
> > > 
> > > We currently don't have dynamic quirk for forcing HIDDEV creation from the 
> > > module parameter.
> > 
> > Right. Any chance to change that?
> 
> This particular one might actually make enough sense to be added (although 
> I am really trying to avoid quirk additions completely), for backwards 
> compatibility reasons.

Should I remove the comments there altogether then? That kind of defeats
my "but you can use lirc with some tweaks" argument, even though I still
think that those people needing more keys would be in the minority...

> > > > +	if (!memcmp(data, keydown, sizeof(keydown))) {
> > > > +		/*If we already have a key down, take it up before marking */
> > > > +		/*this one down */
> > > > +		if (appleir->current_key)
> > > > +			key_up(appleir, appleir->current_key);
> > > > +		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
> > > > +
> > > > +		key_down(appleir, appleir->current_key);
> > > > +		/*remote doesn't do key up, either pull them up, in the test */
> > > > +		/*above, or here set a timer which pulls them up after 1/8 s */
> > > 
> > > Could you please place spaces after the comment starters?
> > 
> > I've done that on my local copy. I'm now trying to get in touch with
> > Matthew Garrett so he can help me out with the suspend parts of the
> > patch. I'll resubmit when that's done.
> 
> OK, thanks.

Jarod gave me a hand, and the problem is the same as with the bcm5974
driver, the platform reset_resume will work just fine.

Updated patch coming up.

Cheers


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-02-01 13:52   ` Bastien Nocera
@ 2010-02-03 15:54     ` Jiri Kosina
  2010-02-08 16:32       ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Jiri Kosina @ 2010-02-03 15:54 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-input, Dmitry Torokhov

On Mon, 1 Feb 2010, Bastien Nocera wrote:

> > > +With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
> > > +With 0x8242 being the product ID (check the output of lsusb for your hardware)
> > > +And 0x08 being "HID_CONNECT_HIDDEV"
> > 
> > I am afraid this is not true, 0x08 is HID_QUIRK_NOGET.
> > 
> > We currently don't have dynamic quirk for forcing HIDDEV creation from the 
> > module parameter.
> 
> Right. Any chance to change that?

This particular one might actually make enough sense to be added (although 
I am really trying to avoid quirk additions completely), for backwards 
compatibility reasons.

> > > +	if (!memcmp(data, keydown, sizeof(keydown))) {
> > > +		/*If we already have a key down, take it up before marking */
> > > +		/*this one down */
> > > +		if (appleir->current_key)
> > > +			key_up(appleir, appleir->current_key);
> > > +		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
> > > +
> > > +		key_down(appleir, appleir->current_key);
> > > +		/*remote doesn't do key up, either pull them up, in the test */
> > > +		/*above, or here set a timer which pulls them up after 1/8 s */
> > 
> > Could you please place spaces after the comment starters?
> 
> I've done that on my local copy. I'm now trying to get in touch with
> Matthew Garrett so he can help me out with the suspend parts of the
> patch. I'll resubmit when that's done.

OK, thanks.

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-01-27 15:40 ` Jiri Kosina
@ 2010-02-01 13:52   ` Bastien Nocera
  2010-02-03 15:54     ` Jiri Kosina
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-02-01 13:52 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-input, Dmitry Torokhov

On Wed, 2010-01-27 at 16:40 +0100, Jiri Kosina wrote:
> On Wed, 20 Jan 2010, Bastien Nocera wrote:
> 
> > +First, you will need to disable the kernel driver for the receiver.
> > +
> > +This can be achieved by passing quirks to the usbhid driver.
> > +The quirk line would be:
> > +usbhid.quirks=0x05ac:0x8242:0x08
> > +
> > +With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
> > +With 0x8242 being the product ID (check the output of lsusb for your hardware)
> > +And 0x08 being "HID_CONNECT_HIDDEV"
> 
> I am afraid this is not true, 0x08 is HID_QUIRK_NOGET.
> 
> We currently don't have dynamic quirk for forcing HIDDEV creation from the 
> module parameter.

Right. Any chance to change that?

> > +	if (!memcmp(data, keydown, sizeof(keydown))) {
> > +		/*If we already have a key down, take it up before marking */
> > +		/*this one down */
> > +		if (appleir->current_key)
> > +			key_up(appleir, appleir->current_key);
> > +		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
> > +
> > +		key_down(appleir, appleir->current_key);
> > +		/*remote doesn't do key up, either pull them up, in the test */
> > +		/*above, or here set a timer which pulls them up after 1/8 s */
> 
> Could you please place spaces after the comment starters?

I've done that on my local copy. I'm now trying to get in touch with
Matthew Garrett so he can help me out with the suspend parts of the
patch. I'll resubmit when that's done.

Cheers


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2010-01-20 14:17 Bastien Nocera
@ 2010-01-27 15:40 ` Jiri Kosina
  2010-02-01 13:52   ` Bastien Nocera
  0 siblings, 1 reply; 57+ messages in thread
From: Jiri Kosina @ 2010-01-27 15:40 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-input, Dmitry Torokhov

On Wed, 20 Jan 2010, Bastien Nocera wrote:

> +First, you will need to disable the kernel driver for the receiver.
> +
> +This can be achieved by passing quirks to the usbhid driver.
> +The quirk line would be:
> +usbhid.quirks=0x05ac:0x8242:0x08
> +
> +With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
> +With 0x8242 being the product ID (check the output of lsusb for your hardware)
> +And 0x08 being "HID_CONNECT_HIDDEV"

I am afraid this is not true, 0x08 is HID_QUIRK_NOGET.

We currently don't have dynamic quirk for forcing HIDDEV creation from the 
module parameter.

> +	if (!memcmp(data, keydown, sizeof(keydown))) {
> +		/*If we already have a key down, take it up before marking */
> +		/*this one down */
> +		if (appleir->current_key)
> +			key_up(appleir, appleir->current_key);
> +		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
> +
> +		key_down(appleir, appleir->current_key);
> +		/*remote doesn't do key up, either pull them up, in the test */
> +		/*above, or here set a timer which pulls them up after 1/8 s */

Could you please place spaces after the comment starters?

Thanks,

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH] Input: add appleir USB driver
@ 2010-01-20 14:17 Bastien Nocera
  2010-01-27 15:40 ` Jiri Kosina
  0 siblings, 1 reply; 57+ messages in thread
From: Bastien Nocera @ 2010-01-20 14:17 UTC (permalink / raw)
  To: linux-input, Dmitry Torokhov, Jiri Kosina

From: Bastien Nocera <hadess@hadess.net>

This driver was originally written by James McKenzie, updated by
Greg Kroah-Hartman, further updated by myself, with suspend support
added.

More recent versions of the IR receiver are also supported through
a patch by Alex Karpenko.

Tested on a MacbookAir1,1

Signed-off-by: Bastien Nocera <hadess@hadess.net>
---
 Documentation/input/appleir.txt |   46 ++++
 drivers/hid/hid-apple.c         |    4 -
 drivers/hid/hid-core.c          |    5 +-
 drivers/hid/hid-ids.h           |    1 +
 drivers/input/misc/Kconfig      |   13 +
 drivers/input/misc/Makefile     |    1 +
 drivers/input/misc/appleir.c    |  477 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 541 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/input/appleir.txt
 create mode 100644 drivers/input/misc/appleir.c

diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
new file mode 100644
index 0000000..0aaf5fe
--- /dev/null
+++ b/Documentation/input/appleir.txt
@@ -0,0 +1,46 @@
+Apple IR receiver Driver (appleir)
+----------------------------------
+	Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+
+The appleir driver is a kernel input driver to handle Apple's IR
+receivers (and associated remotes) in the kernel.
+
+The driver is an input driver which only handles "official" remotes
+as built and sold by Apple.
+
+Authors
+-------
+
+James McKenzie (original driver)
+Alex Karpenko (05ac:8242 support)
+Greg Kroah-Hartman (cleanups and original submission)
+Bastien Nocera (further cleanups and suspend support)
+
+Supported hardware
+------------------
+
+- All Apple laptops and desktops from 2005 onwards, except:
+  - the unibody Macbook (2009)
+  - Mac Pro (all versions)
+- Apple TV (all revisions)
+
+The remote will only support the 6 buttons of the original remotes
+as sold by Apple. See the next section if you want to use other remotes
+or want to use lirc with the device instead of the kernel driver.
+
+Using lirc (native) instead of the kernel driver
+------------------------------------------------
+
+First, you will need to disable the kernel driver for the receiver.
+
+This can be achieved by passing quirks to the usbhid driver.
+The quirk line would be:
+usbhid.quirks=0x05ac:0x8242:0x08
+
+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
+With 0x8242 being the product ID (check the output of lsusb for your hardware)
+And 0x08 being "HID_CONNECT_HIDDEV"
+
+This should force the creation of a hiddev device for the receiver, and
+make it usable under lirc.
+
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 4b96e7a..d1fdcd0 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -353,10 +353,6 @@ static void apple_remove(struct hid_device *hdev)
 }
 
 static const struct hid_device_id apple_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
-		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
 		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
 
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 80792d3..61b199e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1250,8 +1250,6 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
 static const struct hid_device_id hid_blacklist[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
@@ -1540,6 +1538,9 @@ static const struct hid_device_id hid_ignore_list[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3839340..8b29a88 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -90,6 +90,7 @@
 #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS	0x0238
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
 #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
 
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 16ec523..4340986 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -149,6 +149,19 @@ config INPUT_KEYSPAN_REMOTE
 	  To compile this driver as a module, choose M here: the module will
 	  be called keyspan_remote.
 
+config INPUT_APPLEIR
+	tristate "Apple infrared receiver (built in)"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use a Apple infrared remote control. All
+	  the Apple computers from 2005 onwards include such a port, except
+	  the unibody Macbook (2009), and Mac Pros. This receiver is also
+	  used in the Apple TV set-top box.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called appleir.
+
 config INPUT_POWERMATE
 	tristate "Griffin PowerMate and Contour Jog support"
 	depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index a8b8485..041e6f5 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -5,6 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
+obj-$(CONFIG_INPUT_APPLEIR)		+= appleir.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
new file mode 100644
index 0000000..6e332ab
--- /dev/null
+++ b/drivers/input/misc/appleir.c
@@ -0,0 +1,477 @@
+/*
+ * appleir: USB driver for the apple ir device
+ *
+ * Original driver written by James McKenzie
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Copyright (C) 2006 James McKenzie
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2008 Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+
+#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>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#define DRIVER_VERSION "v1.2"
+#define DRIVER_AUTHOR "James McKenzie"
+#define DRIVER_DESC "Apple infrared receiver driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_APPLE			0x05ac
+#define USB_DEVICE_ID_APPLE_IRCONTROL		0x8240
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4		0x8242
+
+#define URB_SIZE	32
+
+#define MAX_KEYS	8
+#define MAX_KEYS_MASK	(MAX_KEYS - 1)
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+struct appleir {
+	struct input_dev *input_dev;
+	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;
+	int current_key;
+	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_ATV_IRCONTROL) },
+	{ USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+	{}
+};
+MODULE_DEVICE_TABLE(usb, appleir_ids);
+
+/* I have two devices both of which report the following */
+/* 25 87 ee 83 0a  	+  */
+/* 25 87 ee 83 0c  	-  */
+/* 25 87 ee 83 09	<< */
+/* 25 87 ee 83 06	>> */
+/* 25 87 ee 83 05	>" */
+/* 25 87 ee 83 03	menu */
+/* 26 00 00 00 00	for key repeat*/
+
+/* Thomas Glanzmann reports the following responses */
+/* 25 87 ee ca 0b	+  */
+/* 25 87 ee ca 0d	-  */
+/* 25 87 ee ca 08	<< */
+/* 25 87 ee ca 07	>> */
+/* 25 87 ee ca 04	>" */
+/* 25 87 ee ca 02 	menu */
+/* 26 00 00 00 00       for key repeat*/
+/* He also observes the following event sometimes */
+/* sent after a key is release, which I interpret */
+/* as a flat battery message */
+/* 25 87 e0 ca 06	flat battery */
+
+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
+/* 25 87 ee 47 0b	+  */
+/* 25 87 ee 47 0d	-  */
+/* 25 87 ee 47 08	<< */
+/* 25 87 ee 47 07	>> */
+/* 25 87 ee 47 04	>" */
+/* 25 87 ee 47 02 	menu */
+/* 26 87 ee 47 ** 	for key repeat (** is the code of the key being held) */
+
+static int keymap[MAX_KEYS] = {
+	KEY_RESERVED,
+	KEY_MENU,
+	KEY_PLAYPAUSE,
+	KEY_FORWARD,
+	KEY_BACK,
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_RESERVED,
+};
+
+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
+{
+	int i;
+
+	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
+
+	for (i = 0; i < len; ++i)
+		printk(" %02x", data[i]);
+	printk("\n");
+}
+
+static void key_up(struct appleir *appleir, int key)
+{
+	dbginfo (&appleir->input_dev->dev, "key %d up\n", key);
+	input_report_key(appleir->input_dev, key, 0);
+	input_sync(appleir->input_dev);
+}
+
+static void key_down(struct appleir *appleir, int key)
+{
+	dbginfo (&appleir->input_dev->dev, "key %d down\n", key);
+	input_report_key(appleir->input_dev, key, 1);
+	input_sync(appleir->input_dev);
+}
+
+static void battery_flat(struct appleir *appleir)
+{
+	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
+}
+
+static void key_up_tick(unsigned long data)
+{
+	struct appleir *appleir = (struct appleir *)data;
+
+	if (appleir->current_key) {
+		key_up(appleir, appleir->current_key);
+		appleir->current_key = 0;
+	}
+}
+
+static void new_data(struct appleir *appleir, u8 *data, int len)
+{
+	static const u8 keydown[] = { 0x25, 0x87, 0xee };
+	static const u8 keyrepeat[] = { 0x26, };
+	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
+
+	if (debug)
+		dump_packet(appleir, "received", data, len);
+
+	if (len != 5)
+		return;
+
+	if (!memcmp(data, keydown, sizeof(keydown))) {
+		/*If we already have a key down, take it up before marking */
+		/*this one down */
+		if (appleir->current_key)
+			key_up(appleir, appleir->current_key);
+		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
+
+		key_down(appleir, appleir->current_key);
+		/*remote doesn't do key up, either pull them up, in the test */
+		/*above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+
+		return;
+	}
+
+	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
+		key_down(appleir, appleir->current_key);
+		/*remote doesn't do key up, either pull them up, in the test */
+		/*above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+		return;
+	}
+
+	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
+		battery_flat(appleir);
+		/* Fall through */
+	}
+
+	dump_packet(appleir, "unknown packet", data, len);
+}
+
+static void appleir_urb(struct urb *urb)
+{
+	struct appleir *appleir = urb->context;
+	int status = urb->status;
+	int retval;
+
+	switch (status) {
+	case 0:
+		new_data(appleir, urb->transfer_buffer, urb->actual_length);
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__,
+			urb->status);
+		return;
+	default:
+		dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__,
+			urb->status);
+	}
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result %d", __func__,
+		    retval);
+}
+
+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)) {
+		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);
+
+	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,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct appleir *appleir = NULL;
+	struct input_dev *input_dev;
+	int retval = -ENOMEM;
+	int i;
+
+	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
+	if (!appleir)
+		goto fail;
+
+	appleir->data = usb_buffer_alloc(dev, URB_SIZE, GFP_KERNEL,
+					 &appleir->dma_buf);
+	if (!appleir->data)
+		goto fail;
+
+	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!appleir->urb)
+		goto fail;
+
+	appleir->usbdev = dev;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		goto fail;
+
+	appleir->input_dev = input_dev;
+
+	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
+	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
+
+	input_dev->name = "Apple infrared remote control driver";
+	input_dev->phys = appleir->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+	input_set_drvdata(input_dev, appleir);
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+	input_dev->ledbit[0] = 0;
+
+	for (i = 0; i < MAX_KEYS; i++)
+		set_bit(keymap[i], input_dev->keybit);
+
+	clear_bit(0, input_dev->keybit);
+
+	input_dev->open = appleir_open;
+	input_dev->close = appleir_close;
+
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+	usb_fill_int_urb(appleir->urb, dev,
+			 usb_rcvintpipe(dev, 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;
+
+	usb_set_intfdata(intf, appleir);
+
+	init_timer(&appleir->key_up_timer);
+
+	appleir->key_up_timer.function = key_up_tick;
+	appleir->key_up_timer.data = (unsigned long)appleir;
+
+	appleir->timer_initted++;
+
+	retval = input_register_device(appleir->input_dev);
+	if (retval)
+		goto fail;
+
+	return 0;
+
+fail:
+	printk(KERN_WARNING "Failed to load appleir\n");
+	if (appleir) {
+		if (appleir->data)
+			usb_buffer_free(dev, URB_SIZE, appleir->data,
+					appleir->dma_buf);
+
+		if (appleir->timer_initted)
+			del_timer_sync(&appleir->key_up_timer);
+
+		if (appleir->input_dev)
+			input_free_device(appleir->input_dev);
+
+		kfree(appleir);
+	}
+
+	return retval;
+}
+
+static void appleir_disconnect(struct usb_interface *intf)
+{
+	struct appleir *appleir = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (appleir) {
+		input_unregister_device(appleir->input_dev);
+		if (appleir->timer_initted)
+			del_timer_sync(&appleir->key_up_timer);
+		usb_kill_urb(appleir->urb);
+		usb_free_urb(appleir->urb);
+		usb_buffer_free(interface_to_usbdev(intf), URB_SIZE,
+				appleir->data, appleir->dma_buf);
+		kfree(appleir);
+	}
+}
+
+static int appleir_suspend(struct usb_interface *interface,
+			   pm_message_t message)
+{
+	struct appleir *appleir;
+
+	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;
+
+	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,
+	.suspend              = appleir_suspend,
+	.resume               = appleir_resume,
+	.reset_resume         = appleir_resume,
+	.id_table             = appleir_ids,
+	.supports_autosuspend = 1,
+};
+
+static int __init appleir_init(void)
+{
+	int retval;
+
+	retval = usb_register(&appleir_driver);
+	if (retval)
+		goto out;
+	printk(KERN_INFO DRIVER_VERSION ":" DRIVER_DESC);
+out:
+	return retval;
+}
+
+static void __exit appleir_exit(void)
+{
+	usb_deregister(&appleir_driver);
+}
+
+module_init(appleir_init);
+module_exit(appleir_exit);
-- 
1.6.6



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
       [not found]                       ` <20080516095218.ZZRA012-NG0XCrj25/nJrYCpivWRnl5pS2h4L8biXqFh9Ls21Oc@public.gmane.org>
@ 2008-05-16 14:07                         ` Tino Keitel
  0 siblings, 0 replies; 57+ messages in thread
From: Tino Keitel @ 2008-05-16 14:07 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Greg KH, jkosina-AlSwsSmVLrQ, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On Fri, May 16, 2008 at 09:53:47 -0400, Dmitry Torokhov wrote:
> On Fri, May 16, 2008 at 03:32:34PM +0200, Tino Keitel wrote:
> > On Fri, May 16, 2008 at 09:13:41 -0400, Dmitry Torokhov wrote:
> > 
> > [...]
> > 
> > > Does the learning remote have the same VID/PID as AppleIr? If not I am
> > > not sure why you are btringing it here.
> > 
> > It has no VID/PID at all, as it is not connected to the computer. It
> > just sends IR codes to the IR sensor in the Mac mini (the builtin USB
> > device that the appleir driver is for). And as the learning remote has
> > more than 6 keys, it can send more than 6 different codes. The Apple
> > remote has only 6 keys, and only these keys are handled by the driver.
> > 
> 
> OK, I see.. How many codes does the sensor support? We should simply
> allow for the key table big enough and allow userpsace to
> assign/modify keycodes.

I have no idea. I currently don't have access to my lircd.conf, but
IIRC the keycodes differ in 2 changing bytes.

Regards,
Tino
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
       [not found]                   ` <20080516133234.GA10193-Zv899e0YUSaDCaQdYfVI6sM6rOWSkUom@public.gmane.org>
@ 2008-05-16 13:53                     ` Dmitry Torokhov
       [not found]                       ` <20080516095218.ZZRA012-NG0XCrj25/nJrYCpivWRnl5pS2h4L8biXqFh9Ls21Oc@public.gmane.org>
  0 siblings, 1 reply; 57+ messages in thread
From: Dmitry Torokhov @ 2008-05-16 13:53 UTC (permalink / raw)
  To: Greg KH, jkosina-AlSwsSmVLrQ, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On Fri, May 16, 2008 at 03:32:34PM +0200, Tino Keitel wrote:
> On Fri, May 16, 2008 at 09:13:41 -0400, Dmitry Torokhov wrote:
> 
> [...]
> 
> > Does the learning remote have the same VID/PID as AppleIr? If not I am
> > not sure why you are btringing it here.
> 
> It has no VID/PID at all, as it is not connected to the computer. It
> just sends IR codes to the IR sensor in the Mac mini (the builtin USB
> device that the appleir driver is for). And as the learning remote has
> more than 6 keys, it can send more than 6 different codes. The Apple
> remote has only 6 keys, and only these keys are handled by the driver.
> 

OK, I see.. How many codes does the sensor support? We should simply
allow for the key table big enough and allow userpsace to
assign/modify keycodes.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-16 13:13               ` Dmitry Torokhov
@ 2008-05-16 13:32                 ` Tino Keitel
       [not found]                   ` <20080516133234.GA10193-Zv899e0YUSaDCaQdYfVI6sM6rOWSkUom@public.gmane.org>
  0 siblings, 1 reply; 57+ messages in thread
From: Tino Keitel @ 2008-05-16 13:32 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Greg KH, jkosina, linux-input, linux-usb, linux-kernel

On Fri, May 16, 2008 at 09:13:41 -0400, Dmitry Torokhov wrote:

[...]

> Does the learning remote have the same VID/PID as AppleIr? If not I am
> not sure why you are btringing it here.

It has no VID/PID at all, as it is not connected to the computer. It
just sends IR codes to the IR sensor in the Mac mini (the builtin USB
device that the appleir driver is for). And as the learning remote has
more than 6 keys, it can send more than 6 different codes. The Apple
remote has only 6 keys, and only these keys are handled by the driver.

Regards,
Tino

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-15 20:59             ` Tino Keitel
  2008-05-16  7:19               ` Jiri Kosina
@ 2008-05-16 13:13               ` Dmitry Torokhov
  2008-05-16 13:32                 ` Tino Keitel
  1 sibling, 1 reply; 57+ messages in thread
From: Dmitry Torokhov @ 2008-05-16 13:13 UTC (permalink / raw)
  To: Greg KH, jkosina, linux-input, linux-usb, linux-kernel

On Thu, May 15, 2008 at 10:59:50PM +0200, Tino Keitel wrote:
> On Thu, May 15, 2008 at 14:35:54 -0400, Dmitry Torokhov wrote:
> > On Thu, May 15, 2008 at 07:49:39PM +0200, Tino Keitel wrote:
> > 
> > > From the user's point of view: There are no official kernel release
> > > notes about what devices are added/removed to/from the various
> > > ignore lists and blacklists. The kernel doesn't produce any output
> > > about devices that are ignored or blacklisted in may cases (and
> > > also this one). The user has no indication why his LIRC setup stops
> > > working with the new kernel.
> > >
> > 
> > Not sure what we can do here... The only thing I guess is better
> > commit message mentioning LIRC setup concerns.
> 
> Who reads commit messages? I think it should be easy to add some
> printk()s saying something like "skipping device foo, because it is on
> the ignore list".

Then every user of Wacom tablet will be alarmed and ask "why my tablet
is ignored". The only thing that I can think of is making that quirk
compiled in depending on whether CONFIG_APPLEIR is selected.

> 
> > > Even if all LIRC users switch to the appleir driver, what about
> > > people who use a learning remote to have more than 6 keys that the
> > > Apple remote has? Does this work at all? After a quick look at the
> > > key handling it seems to me that the codes of the 6 keys are
> > > hardcoded in the driver. So a learning remote with more keys
> > > wouldn't work anymore.
> > >
> > 
> > We'll have to adjust the driver to allow changing keymap on a
> > per-device base from userspace. That's pretty easy actually.
> 
> I'm not talking about the keymap that is visible in userspace, but
> about the keys on the remote that are detected by the kernel. The Apple
> remote has only 6 keys, and they are mapped in a static array:
> 
> #define MAX_KEYS       8
> static int keymap[MAX_KEYS] = ...
> 
> With the LIRC driver, I can use a learning remote with much more keys,
> and then just use irrecord to create a LIRC config file.
> 

Does the learning remote have the same VID/PID as AppleIr? If not I am
not sure why you are btringing it here.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-16  7:19               ` Jiri Kosina
@ 2008-05-16  7:26                 ` Tino Keitel
  0 siblings, 0 replies; 57+ messages in thread
From: Tino Keitel @ 2008-05-16  7:26 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: Dmitry Torokhov, Greg KH, linux-input, linux-usb, linux-kernel

On Fri, May 16, 2008 at 09:19:39 +0200, Jiri Kosina wrote:
> On Thu, 15 May 2008, Tino Keitel wrote:
> 
> > Does setting the quirks to 0 lead to the creation of a HID device 
> > immediately? 
> 
> The easiest way is either to handle this in the early stage, i.e. specify 
> 'quirks' module parameter during the module insertion.
> 
> Other possibility is to detach the driver from the device using 'unbind' 
> functionality of sysfs. libusb has a call for this too.

Thanks for the hint.

So I guess that the LIRC driver should be extended to watch out for a
USB device with the prober vendor/device ID and unbind it before usage,
right?

This wouldn't help users who use the current LIRC with a kernel that
has the HID ignore quirk enabled by default, though (i.e., it would be
a regression).

Regards,
Tino

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-15 20:59             ` Tino Keitel
@ 2008-05-16  7:19               ` Jiri Kosina
  2008-05-16  7:26                 ` Tino Keitel
  2008-05-16 13:13               ` Dmitry Torokhov
  1 sibling, 1 reply; 57+ messages in thread
From: Jiri Kosina @ 2008-05-16  7:19 UTC (permalink / raw)
  To: Tino Keitel
  Cc: Dmitry Torokhov, Greg KH, linux-input, linux-usb, linux-kernel

On Thu, 15 May 2008, Tino Keitel wrote:

> Does setting the quirks to 0 lead to the creation of a HID device 
> immediately? 

The easiest way is either to handle this in the early stage, i.e. specify 
'quirks' module parameter during the module insertion.

Other possibility is to detach the driver from the device using 'unbind' 
functionality of sysfs. libusb has a call for this too.

> Where is this documented? 

modinfo usbhid.ko

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-16  2:32                   ` Greg KH
@ 2008-05-16  5:44                     ` Tino Keitel
  0 siblings, 0 replies; 57+ messages in thread
From: Tino Keitel @ 2008-05-16  5:44 UTC (permalink / raw)
  To: Greg KH; +Cc: Dmitry Torokhov, jkosina, linux-input, linux-usb, linux-kernel

On Thu, May 15, 2008 at 19:32:36 -0700, Greg KH wrote:
> On Fri, May 16, 2008 at 01:27:33AM +0200, Tino Keitel wrote:

[...]

> > When the appleir kernel driver is used, the IR device acts as in input
> > device, not as a HID device. LIRC has to be configured to use its
> > dev/input driver in this case. This is a generic driver to use any
> > input device as lirc device. The dev/input driver relies on the key
> > events that are generated by the kernel.
> 
> Hm, I just got a private email (for some odd reason) saying this driver
> isn't needed at all, they just add a hid quirk line.

Maybe this email came from a person who uses a distro kernel that
already included the appleir driver? IIRC at least Ubuntu did that
once. If not, I'd be interested in the detailed setup.

> Now why that hid quirk line hadn't been added for the year or so that
> the person knew about it, sure is odd to me...

There was a quirk line in the past. It was introduced by accident with
2.6.22 with commit a417a21e10831bca695b4ba9c74f4ddf5a95ac06. The commit
message only mentions keyboard and mouse devices, so I think the quirk
for the IR device was unintended.

Then I wasted several hours when I tried to use the macmini LIRC driver
with 2.6.22. The HID device that I saw came from my LCD, not from the
IR device, and I wasn't aware of the HID ignore quirk as the kernel
didn't mention it when the device was detected. That's why I also
suggested that the kernel should be more verbose about such ignore
quirks and blacklists.

In the end I found that quirk an requested to remove it. This was done
in 2.6.23-rc2.

Regards,
Tino

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-15 23:27                 ` Tino Keitel
@ 2008-05-16  2:32                   ` Greg KH
  2008-05-16  5:44                     ` Tino Keitel
  0 siblings, 1 reply; 57+ messages in thread
From: Greg KH @ 2008-05-16  2:32 UTC (permalink / raw)
  To: Dmitry Torokhov, jkosina, linux-input, linux-usb, linux-kernel

On Fri, May 16, 2008 at 01:27:33AM +0200, Tino Keitel wrote:
> On Thu, May 15, 2008 at 14:11:17 -0700, Greg KH wrote:
> > On Thu, May 15, 2008 at 10:59:59PM +0200, Tino Keitel wrote:
> 
> [...]
> 
> > > The macmini LIRC driver is a pure userspace driver, so nothing
> > > needs to
> > > be ever included in the kernel.
> >
> > So does this driver work with the macmini USB ir device today
> > somehow?
> 
> Yes, I'm using it for months.
> 
> > From what I can tell, this driver is still necessary for things to
> > work
> > properly for this hardware, right?
> 
> When the appleir kernel driver is used, the IR device acts as in input
> device, not as a HID device. LIRC has to be configured to use its
> dev/input driver in this case. This is a generic driver to use any
> input device as lirc device. The dev/input driver relies on the key
> events that are generated by the kernel.

Hm, I just got a private email (for some odd reason) saying this driver
isn't needed at all, they just add a hid quirk line.

Now why that hid quirk line hadn't been added for the year or so that
the person knew about it, sure is odd to me...

I'll test it out and probably reduce this whole thing to a one-line
hid-quirk patch...

ugh, why do people not send stuff upstream, it just wastes everyone's
time in the end :(

greg k-h

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-15 21:11               ` Greg KH
@ 2008-05-15 23:27                 ` Tino Keitel
  2008-05-16  2:32                   ` Greg KH
  0 siblings, 1 reply; 57+ messages in thread
From: Tino Keitel @ 2008-05-15 23:27 UTC (permalink / raw)
  To: Greg KH; +Cc: Dmitry Torokhov, jkosina, linux-input, linux-usb, linux-kernel

On Thu, May 15, 2008 at 14:11:17 -0700, Greg KH wrote:
> On Thu, May 15, 2008 at 10:59:59PM +0200, Tino Keitel wrote:

[...]

> > The macmini LIRC driver is a pure userspace driver, so nothing
> > needs to
> > be ever included in the kernel.
>
> So does this driver work with the macmini USB ir device today
> somehow?

Yes, I'm using it for months.

> From what I can tell, this driver is still necessary for things to
> work
> properly for this hardware, right?

When the appleir kernel driver is used, the IR device acts as in input
device, not as a HID device. LIRC has to be configured to use its
dev/input driver in this case. This is a generic driver to use any
input device as lirc device. The dev/input driver relies on the key
events that are generated by the kernel.

Regards,
Tino

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
       [not found]             ` <20080515205959.GA11683-z7fNteJZwjmqk56C3691EA@public.gmane.org>
@ 2008-05-15 21:11               ` Greg KH
  2008-05-15 23:27                 ` Tino Keitel
  0 siblings, 1 reply; 57+ messages in thread
From: Greg KH @ 2008-05-15 21:11 UTC (permalink / raw)
  To: Dmitry Torokhov, jkosina-AlSwsSmVLrQ,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On Thu, May 15, 2008 at 10:59:59PM +0200, Tino Keitel wrote:
> On Thu, May 15, 2008 at 11:40:34 -0700, Greg KH wrote:
> > On Thu, May 15, 2008 at 09:45:52AM -0400, Dmitry Torokhov wrote:
> > > Hi Tino,
> > > 
> > > On Thu, May 15, 2008 at 03:21:08PM +0200, Tino Keitel wrote:
> > > > Hi,
> > > >
> > > > I'm pretty sure that this breaks the macmini LIRC driver again, see
> > > > commit 3e1928e8793208802589aae851b6685671187242.
> > > >
> > > 
> > > But with in-kernel driver can't LIRC feed of event device? Ane people
> > > that dont use LIRC can also have access to the remote?
> > 
> > And, to be blunt, why would an in-kernel driver be concerned about an
> > out-of-tree-project-that-refuses-to-be-included chunk of code?
> 
> The macmini LIRC driver is a pure userspace driver, so nothing needs to
> be ever included in the kernel.

So does this driver work with the macmini USB ir device today somehow?

>From what I can tell, this driver is still necessary for things to work
properly for this hardware, right?

I'm totally confused now...

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
       [not found]         ` <20080515184034.GB15231-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
@ 2008-05-15 20:59           ` Tino Keitel
       [not found]             ` <20080515205959.GA11683-z7fNteJZwjmqk56C3691EA@public.gmane.org>
  0 siblings, 1 reply; 57+ messages in thread
From: Tino Keitel @ 2008-05-15 20:59 UTC (permalink / raw)
  To: Greg KH
  Cc: Dmitry Torokhov, jkosina-AlSwsSmVLrQ,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On Thu, May 15, 2008 at 11:40:34 -0700, Greg KH wrote:
> On Thu, May 15, 2008 at 09:45:52AM -0400, Dmitry Torokhov wrote:
> > Hi Tino,
> > 
> > On Thu, May 15, 2008 at 03:21:08PM +0200, Tino Keitel wrote:
> > > Hi,
> > >
> > > I'm pretty sure that this breaks the macmini LIRC driver again, see
> > > commit 3e1928e8793208802589aae851b6685671187242.
> > >
> > 
> > But with in-kernel driver can't LIRC feed of event device? Ane people
> > that dont use LIRC can also have access to the remote?
> 
> And, to be blunt, why would an in-kernel driver be concerned about an
> out-of-tree-project-that-refuses-to-be-included chunk of code?

The macmini LIRC driver is a pure userspace driver, so nothing needs to
be ever included in the kernel.

Regards,
Tino

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-15 18:35           ` Dmitry Torokhov
@ 2008-05-15 20:59             ` Tino Keitel
  2008-05-16  7:19               ` Jiri Kosina
  2008-05-16 13:13               ` Dmitry Torokhov
  0 siblings, 2 replies; 57+ messages in thread
From: Tino Keitel @ 2008-05-15 20:59 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Greg KH, jkosina, linux-input, linux-usb, linux-kernel

On Thu, May 15, 2008 at 14:35:54 -0400, Dmitry Torokhov wrote:
> On Thu, May 15, 2008 at 07:49:39PM +0200, Tino Keitel wrote:

[...]

> > I know. I just wanted to point out that this is a regression for all
> > people who use the macmini LIRC driver. This driver was present at
> > least in the last 2 LIRC releases. The quirks stuff in the above patch
> > looks like there is no way to make the macmini LIRC driver work with
> > the patch applied. It relies on a USB HID device, which wouldn't be
> > created anymore, and the user has no way to bring it back. Please
> > correct me with a pointer to the appropriate documentation if I'm
> > wrong.
> >
> 
> There is a way to dynamically manipulate quirks for a VID/PID pair
> via sysfs. I think if you set the quirk to 0 it will efefctively
> disable the ignore quirk restoring the old behaviour.

Where in sysfs? I found module/usbhid/parameters/quirks and quirks
files in several devices/pci0000:00/* directories. I guess you are
talking about the latter.

How can I tell what device I need to use, or what is the recommended
way? I can only think of something ugly like

$ find /sys -name "idProduct" | xargs grep 8240

and similar with idVendor.

Does setting the quirks to 0 lead to the creation of a HID device
immediately? Where is this documented? Could it be implemented in a way
such that the user has a HID device, as long as he doesn't enable the
appleir driver?

> 
> > From the user's point of view: There are no official kernel release
> > notes about what devices are added/removed to/from the various
> > ignore lists and blacklists. The kernel doesn't produce any output
> > about devices that are ignored or blacklisted in may cases (and
> > also this one). The user has no indication why his LIRC setup stops
> > working with the new kernel.
> >
> 
> Not sure what we can do here... The only thing I guess is better
> commit message mentioning LIRC setup concerns.

Who reads commit messages? I think it should be easy to add some
printk()s saying something like "skipping device foo, because it is on
the ignore list".

> > Even if all LIRC users switch to the appleir driver, what about
> > people who use a learning remote to have more than 6 keys that the
> > Apple remote has? Does this work at all? After a quick look at the
> > key handling it seems to me that the codes of the 6 keys are
> > hardcoded in the driver. So a learning remote with more keys
> > wouldn't work anymore.
> >
> 
> We'll have to adjust the driver to allow changing keymap on a
> per-device base from userspace. That's pretty easy actually.

I'm not talking about the keymap that is visible in userspace, but
about the keys on the remote that are detected by the kernel. The Apple
remote has only 6 keys, and they are mapped in a static array:

#define MAX_KEYS       8
static int keymap[MAX_KEYS] = ...

With the LIRC driver, I can use a learning remote with much more keys,
and then just use irrecord to create a LIRC config file.

Regards,
Tino

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-15 13:40   ` Tino Keitel
@ 2008-05-15 18:41     ` Greg KH
  0 siblings, 0 replies; 57+ messages in thread
From: Greg KH @ 2008-05-15 18:41 UTC (permalink / raw)
  To: Dmitry Torokhov, jkosina, linux-input, linux-usb, linux-kernel

On Thu, May 15, 2008 at 03:40:46PM +0200, Tino Keitel wrote:
> On Wed, May 14, 2008 at 15:15:19 -0700, Greg KH wrote:
> > From: Greg Kroah-Hartman <gregkh@suse.de>
> > 
> > This driver was originally written by James McKenzie but forward ported
> > and cleaned up by me to get it to work with modern kernel versions.
> > 
> > Tested on my mac mini and it actually works!
> 
> Did you test suspend to RAM? Last time I used the original driver, I
> had to reload it after resume, otherwise LIRC didn't receive events
> anymore.

Yes, suspend to ram did seem to work for me with this driver.  But I
haven't tested that in a while, will do so later today.

I don't use LIRC though, so I really can not speak for that chunk of
code at all.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-15 13:45     ` Dmitry Torokhov
  2008-05-15 17:49       ` Tino Keitel
@ 2008-05-15 18:40       ` Greg KH
       [not found]         ` <20080515184034.GB15231-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
  1 sibling, 1 reply; 57+ messages in thread
From: Greg KH @ 2008-05-15 18:40 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: jkosina, linux-input, linux-usb, linux-kernel

On Thu, May 15, 2008 at 09:45:52AM -0400, Dmitry Torokhov wrote:
> Hi Tino,
> 
> On Thu, May 15, 2008 at 03:21:08PM +0200, Tino Keitel wrote:
> > Hi,
> >
> > I'm pretty sure that this breaks the macmini LIRC driver again, see
> > commit 3e1928e8793208802589aae851b6685671187242.
> >
> 
> But with in-kernel driver can't LIRC feed of event device? Ane people
> that dont use LIRC can also have access to the remote?

And, to be blunt, why would an in-kernel driver be concerned about an
out-of-tree-project-that-refuses-to-be-included chunk of code?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
       [not found]         ` <20080515174939.GA10881-z7fNteJZwjmqk56C3691EA@public.gmane.org>
@ 2008-05-15 18:35           ` Dmitry Torokhov
  2008-05-15 20:59             ` Tino Keitel
  0 siblings, 1 reply; 57+ messages in thread
From: Dmitry Torokhov @ 2008-05-15 18:35 UTC (permalink / raw)
  To: Greg KH, jkosina-AlSwsSmVLrQ, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On Thu, May 15, 2008 at 07:49:39PM +0200, Tino Keitel wrote:
> On Thu, May 15, 2008 at 09:45:52 -0400, Dmitry Torokhov wrote:
> > Hi Tino,
> > 
> > On Thu, May 15, 2008 at 03:21:08PM +0200, Tino Keitel wrote:
> > > Hi,
> > >
> > > I'm pretty sure that this breaks the macmini LIRC driver again, see
> > > commit 3e1928e8793208802589aae851b6685671187242.
> > >
> > 
> > But with in-kernel driver can't LIRC feed of event device?
> 
> Sure, it can. But in its current state, it breaks existing scenarios
> and seems to have restrictions. See the comment below regarding
> learning remotes, and my other mail in this thread regarding broken
> suspend with the appleir driver.
> 

These needs to be fixed before it is in mainline, no argument here.

> > Ane people that dont use LIRC can also have access to the remote?
> 
> I know. I just wanted to point out that this is a regression for all
> people who use the macmini LIRC driver. This driver was present at
> least in the last 2 LIRC releases. The quirks stuff in the above patch
> looks like there is no way to make the macmini LIRC driver work with
> the patch applied. It relies on a USB HID device, which wouldn't be
> created anymore, and the user has no way to bring it back. Please
> correct me with a pointer to the appropriate documentation if I'm
> wrong.
>

There is a way to dynamically manipulate quirks for a VID/PID pair via
sysfs. I think if you set the quirk to 0 it will efefctively disable
the ignore quirk restoring the old behaviour.

> From the user's point of view: There are no official kernel release
> notes about what devices are added/removed to/from the various ignore
> lists and blacklists. The kernel doesn't produce any output about
> devices that are ignored or blacklisted in may cases (and also this
> one). The user has no indication why his LIRC setup stops working with
> the new kernel.
>

Not sure what we can do here... The only thing I guess is better
commit message mentioning LIRC setup concerns.

> Even if all LIRC users switch to the appleir driver, what about people
> who use a learning remote to have more than 6 keys that the Apple
> remote has? Does this work at all? After a quick look at the key
> handling it seems to me that the codes of the 6 keys are hardcoded in
> the driver. So a learning remote with more keys wouldn't work anymore.
>

We'll have to adjust the driver to allow changing keymap on a
per-device base from userspace. That's pretty easy actually.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-15 13:45     ` Dmitry Torokhov
@ 2008-05-15 17:49       ` Tino Keitel
       [not found]         ` <20080515174939.GA10881-z7fNteJZwjmqk56C3691EA@public.gmane.org>
  2008-05-15 18:40       ` Greg KH
  1 sibling, 1 reply; 57+ messages in thread
From: Tino Keitel @ 2008-05-15 17:49 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Greg KH, jkosina, linux-input, linux-usb, linux-kernel

On Thu, May 15, 2008 at 09:45:52 -0400, Dmitry Torokhov wrote:
> Hi Tino,
> 
> On Thu, May 15, 2008 at 03:21:08PM +0200, Tino Keitel wrote:
> > Hi,
> >
> > I'm pretty sure that this breaks the macmini LIRC driver again, see
> > commit 3e1928e8793208802589aae851b6685671187242.
> >
> 
> But with in-kernel driver can't LIRC feed of event device?

Sure, it can. But in its current state, it breaks existing scenarios
and seems to have restrictions. See the comment below regarding
learning remotes, and my other mail in this thread regarding broken
suspend with the appleir driver.

> Ane people that dont use LIRC can also have access to the remote?

I know. I just wanted to point out that this is a regression for all
people who use the macmini LIRC driver. This driver was present at
least in the last 2 LIRC releases. The quirks stuff in the above patch
looks like there is no way to make the macmini LIRC driver work with
the patch applied. It relies on a USB HID device, which wouldn't be
created anymore, and the user has no way to bring it back. Please
correct me with a pointer to the appropriate documentation if I'm
wrong.

>From the user's point of view: There are no official kernel release
notes about what devices are added/removed to/from the various ignore
lists and blacklists. The kernel doesn't produce any output about
devices that are ignored or blacklisted in may cases (and also this
one). The user has no indication why his LIRC setup stops working with
the new kernel.

Even if all LIRC users switch to the appleir driver, what about people
who use a learning remote to have more than 6 keys that the Apple
remote has? Does this work at all? After a quick look at the key
handling it seems to me that the codes of the 6 keys are hardcoded in
the driver. So a learning remote with more keys wouldn't work anymore.

Regards,
Tino

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
       [not found]   ` <20080515132108.GA9327-z7fNteJZwjmqk56C3691EA@public.gmane.org>
@ 2008-05-15 13:45     ` Dmitry Torokhov
  2008-05-15 17:49       ` Tino Keitel
  2008-05-15 18:40       ` Greg KH
  0 siblings, 2 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2008-05-15 13:45 UTC (permalink / raw)
  To: Greg KH, jkosina-AlSwsSmVLrQ, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Hi Tino,

On Thu, May 15, 2008 at 03:21:08PM +0200, Tino Keitel wrote:
> Hi,
>
> I'm pretty sure that this breaks the macmini LIRC driver again, see
> commit 3e1928e8793208802589aae851b6685671187242.
>

But with in-kernel driver can't LIRC feed of event device? Ane people
that dont use LIRC can also have access to the remote?

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
       [not found] ` <20080514221519.GA6575-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
@ 2008-05-15 13:40   ` Tino Keitel
  2008-05-15 18:41     ` Greg KH
  0 siblings, 1 reply; 57+ messages in thread
From: Tino Keitel @ 2008-05-15 13:40 UTC (permalink / raw)
  To: Greg KH
  Cc: Dmitry Torokhov, jkosina-AlSwsSmVLrQ,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On Wed, May 14, 2008 at 15:15:19 -0700, Greg KH wrote:
> From: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
> 
> This driver was originally written by James McKenzie but forward ported
> and cleaned up by me to get it to work with modern kernel versions.
> 
> Tested on my mac mini and it actually works!

Did you test suspend to RAM? Last time I used the original driver, I
had to reload it after resume, otherwise LIRC didn't receive events
anymore.

Regards,
Tino
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-14 22:15 Greg KH
  2008-05-14 23:27 ` Matthew Garrett
  2008-05-15  3:50 ` Dmitry Torokhov
@ 2008-05-15 13:21 ` Tino Keitel
       [not found]   ` <20080515132108.GA9327-z7fNteJZwjmqk56C3691EA@public.gmane.org>
       [not found] ` <20080514221519.GA6575-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
  3 siblings, 1 reply; 57+ messages in thread
From: Tino Keitel @ 2008-05-15 13:21 UTC (permalink / raw)
  To: Greg KH; +Cc: Dmitry Torokhov, jkosina, linux-input, linux-usb, linux-kernel

On Wed, May 14, 2008 at 15:15:19 -0700, Greg KH wrote:
> From: Greg Kroah-Hartman <gregkh@suse.de>
> 
> This driver was originally written by James McKenzie but forward ported
> and cleaned up by me to get it to work with modern kernel versions.
> 
> Tested on my mac mini and it actually works!
> 
> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
> 
> ---
> 
> Jiri, is it ok for this quirks addtion to go through Dmitry's triee?  Or
> do you want me to split it out into two different patches?
> 
> Dmitry, is this ok to go through your tree?  Or I can take it as well if
> you don't want it :)
> 
>  drivers/hid/usbhid/hid-quirks.c |    2 
>  drivers/input/misc/Kconfig      |   12 +
>  drivers/input/misc/Makefile     |    1 
>  drivers/input/misc/appleir.c    |  361 ++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 376 insertions(+)
> 
> --- a/drivers/hid/usbhid/hid-quirks.c
> +++ b/drivers/hid/usbhid/hid-quirks.c
> @@ -77,6 +77,7 @@
>  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS   0x022e
>  #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
>  #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
> +#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
>  #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
>  
>  #define USB_VENDOR_ID_ASUS		0x0b05
> @@ -443,6 +444,7 @@ static const struct hid_blacklist {
>  	{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
>  
>  	{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
> +	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL, HID_QUIRK_IGNORE },
>  	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
>  	{ USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
>  	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },

Hi,                                                                             
                                                                                
I'm pretty sure that this breaks the macmini LIRC driver again, see             
commit 3e1928e8793208802589aae851b6685671187242.                                
                                                                                
Regards,                                                                        
Tino                                                                            

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-14 23:49   ` Greg KH
@ 2008-05-15  6:20     ` Sitsofe Wheeler
  0 siblings, 0 replies; 57+ messages in thread
From: Sitsofe Wheeler @ 2008-05-15  6:20 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-input, linux-usb

On Wed, 14 May 2008 16:49:09 -0700, Greg KH wrote:

> On Thu, May 15, 2008 at 12:27:22AM +0100, Matthew Garrett wrote:
>> On Wed, May 14, 2008 at 03:15:19PM -0700, Greg KH wrote:
>> 
>> > +	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL,
>> > HID_QUIRK_IGNORE },
>> >  	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4,
>> >  	HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
>> 
>> Hm. How is the IRCONTROL4 handled? Is the protocol completely
>> different?
> 
> I know nothing about that device, sorry.  I think it is a totally
> different protocol from what I can tell looking at the code.
> 
>> > +	  Say Y here if you want to use a Apple USB remote control.  This 
+
>> >   device is traditionally inside an Intel Apple Mac Mini, but might +
>> >   show up in other places.
>> 
>> Minor nit, but it's supported on all the desktop Intel Macs and not
>> just the Mini.
> 
> Ah, didn't realize that, nice to know, we should have a wider userbase
> then :)

I'm not 100% sure whether Mac Pro desktops support the remote controls. 
Additionally saying USB remote makes it sound like a tethered device - 
perhaps it should be "USB IR remote" (although maybe that's acronym 
overload).

Do modern Mac Laptops (MacBook / MacBook Pro) support their IR remotes 
some other way?

-- 
Sitsofe | http://sucs.org/~sits/

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-14 22:15 Greg KH
  2008-05-14 23:27 ` Matthew Garrett
@ 2008-05-15  3:50 ` Dmitry Torokhov
  2008-05-15 13:21 ` Tino Keitel
       [not found] ` <20080514221519.GA6575-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
  3 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2008-05-15  3:50 UTC (permalink / raw)
  To: Greg KH; +Cc: jkosina, linux-input, linux-usb, linux-kernel

Hi Greg,

On Wed, May 14, 2008 at 03:15:19PM -0700, Greg KH wrote:
> From: Greg Kroah-Hartman <gregkh@suse.de>
> 
> This driver was originally written by James McKenzie but forward ported
> and cleaned up by me to get it to work with modern kernel versions.
> 
> Tested on my mac mini and it actually works!
> 
> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
> 
> ---
> 
> Jiri, is it ok for this quirks addtion to go through Dmitry's triee?  Or
> do you want me to split it out into two different patches?
> 
> Dmitry, is this ok to go through your tree?  Or I can take it as well if
> you don't want it :)
>

I'll take it, although I have a couple of comments.

> +
> +struct appleir {
> +	struct input_dev *input_dev;
> +	u8 *data;
> +	dma_addr_t dma_buf;
> +	struct usb_device *usbdev;
> +	struct urb *urb;
> +	int timer_initted;
> +	struct timer_list key_up_timer;
> +	int current_key;
> +	char phys[32];
> +};
> +
> +static struct usb_device_id appleir_ids[] = {
> +	{USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR)},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(usb, appleir_ids);
> +
> +/* I have two devices both of which report the following */
> +/* 25 87 ee 83 0a  	+  */
> +/* 25 87 ee 83 0c  	-  */
> +/* 25 87 ee 83 09	<< */
> +/* 25 87 ee 83 06	>> */
> +/* 25 87 ee 83 05	>" */
> +/* 25 87 ee 83 03	menu */
> +/* 26 00 00 00 00	for key repeat*/
> +
> +/* Thomas Glanzmann reports the following responses */
> +/* 25 87 ee ca 0b	+  */
> +/* 25 87 ee ca 0d	-  */
> +/* 25 87 ee ca 08	<< */
> +/* 25 87 ee ca 07	>> */
> +/* 25 87 ee ca 04	>" */
> +/* 25 87 ee ca 02 	menu */
> +/* 26 00 00 00 00       for key repeat*/
> +/* He also observes the following event sometimes */
> +/* sent after a key is release, which I interpret */
> +/* as a flat battery message */
> +/* 25 87 e0 ca 06	flat battery */
> +
> +static int keymap[MAX_KEYS] = {
> +	KEY_RESERVED,
> +	KEY_MENU,
> +	KEY_PLAYPAUSE,
> +	KEY_NEXTSONG,
> +	KEY_PREVIOUSSONG,
> +	KEY_VOLUMEUP,
> +	KEY_VOLUMEDOWN,
> +	KEY_RESERVED,
> +};
> +
> +static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
> +{
> +	int i;
> +
> +	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
> +
> +	for (i = 0; i < len; ++i)
> +		printk(" %02x", data[i]);
> +	printk("\n");
> +}
> +
> +static void key_up(struct appleir *appleir, int key)
> +{
> +	/* printk (KERN_ERR "key %d up\n", key); */
> +	input_report_key(appleir->input_dev, key, 0);
> +	input_sync(appleir->input_dev);
> +}
> +
> +static void key_down(struct appleir *appleir, int key)
> +{
> +	/* printk (KERN_ERR "key %d down\n", key); */
> +	input_report_key(appleir->input_dev, key, 1);
> +	input_sync(appleir->input_dev);
> +}
> +
> +static void battery_flat(struct appleir *appleir)
> +{
> +	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
> +}
> +
> +static void key_up_tick(unsigned long data)
> +{
> +	struct appleir *appleir = (struct appleir *)data;
> +
> +	if (appleir->current_key) {
> +		key_up(appleir, appleir->current_key);
> +		appleir->current_key = 0;
> +	}
> +}
> +
> +static void new_data(struct appleir *appleir, u8 *data, int len)
> +{
> +	static const u8 keydown[] = { 0x25, 0x87, 0xee };
> +	static const u8 keyrepeat[] = { 0x26, 0x00, 0x00, 0x00, 0x00 };
> +	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
> +
> +#if 0
> +	dump_packet(appleir, "received", data, len);
> +#endif
> +
> +	if (len != 5)
> +		return;
> +
> +	if (!memcmp(data, keydown, sizeof(keydown))) {
> +		/*If we already have a key down, take it up before marking */
> +		/*this one down */
> +		if (appleir->current_key)
> +			key_up(appleir, appleir->current_key);
> +		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
> +
> +		key_down(appleir, appleir->current_key);
> +		/*remote doesn't do key up, either pull them up, in the test */
> +		/*above, or here set a timer which pulls them up after 1/8 s */
> +		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
> +
> +		return;
> +	}
> +
> +	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
> +		key_down(appleir, appleir->current_key);

Repeats are usually transmitted as an event different from normal
key down (event values for repeat is 2 vs 1 for key down).

> +		/*remote doesn't do key up, either pull them up, in the test */
> +		/*above, or here set a timer which pulls them up after 1/8 s */
> +		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
> +		return;
> +	}
> +
> +	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
> +		battery_flat(appleir);
> +		/* Fall through */
> +	}
> +
> +	dump_packet(appleir, "unknown packet", data, len);
> +}
> +
> +static void appleir_urb(struct urb *urb)
> +{
> +	struct appleir *appleir = urb->context;
> +	int status = urb->status;
> +	int retval;
> +
> +	switch (status) {
> +	case 0:
> +		new_data(appleir, urb->transfer_buffer, urb->actual_length);
> +		break;
> +	case -ECONNRESET:
> +	case -ENOENT:
> +	case -ESHUTDOWN:
> +		/* this urb is terminated, clean up */
> +		dbg("%s - urb shutting down with status: %d", __func__,
> +		    urb->status);
> +		return;
> +	default:
> +		dbg("%s - nonzero urb status received: %d", __func__,
> +		    urb->status);
> +	}
> +
> +	retval = usb_submit_urb(urb, GFP_ATOMIC);
> +	if (retval)
> +		err("%s - usb_submit_urb failed with result %d", __func__,
> +		    retval);
> +}
> +
> +static int appleir_open(struct input_dev *dev)
> +{
> +	struct appleir *appleir = input_get_drvdata(dev);
> +
> +	if (usb_submit_urb(appleir->urb, GFP_KERNEL))
> +		return -EIO;
> +
> +	return 0;
> +}
> +
> +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);
> +}
> +
> +static int appleir_probe(struct usb_interface *intf,
> +			 const struct usb_device_id *id)
> +{
> +	struct usb_device *dev = interface_to_usbdev(intf);
> +	struct usb_endpoint_descriptor *endpoint;
> +	struct appleir *appleir = NULL;

The assigment is not needed.

> +	struct input_dev *input_dev;
> +	int retval = -ENOMEM;
> +	int i;
> +
> +	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
> +	if (!appleir)
> +		goto fail;
> +
> +	appleir->data = usb_buffer_alloc(dev, URB_SIZE, GFP_KERNEL,
> +					 &appleir->dma_buf);
> +	if (!appleir->data)
> +		goto fail;
> +
> +	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
> +	if (!appleir->urb)
> +		goto fail;
> +
> +	appleir->usbdev = dev;
> +
> +	input_dev = input_allocate_device();
> +	if (!input_dev)
> +		goto fail;
> +
> +	appleir->input_dev = input_dev;
> +
> +	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
> +	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
> +
> +	input_dev->name = "Apple Mac mini infrared remote control driver";
> +	input_dev->phys = appleir->phys;
> +	usb_to_input_id(dev, &input_dev->id);
> +	input_dev->dev.parent = &intf->dev;
> +	input_set_drvdata(input_dev, appleir);
> +
> +	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
> +	input_dev->ledbit[0] = 0;
> +
> +	for (i = 0; i < MAX_KEYS; i++)
> +		set_bit(keymap[i], input_dev->keybit);
> +
> +	clear_bit(0, input_dev->keybit);
> +
> +	input_dev->open = appleir_open;
> +	input_dev->close = appleir_close;
> +
> +	endpoint = &intf->cur_altsetting->endpoint[0].desc;
> +
> +	usb_fill_int_urb(appleir->urb, dev,
> +			 usb_rcvintpipe(dev, 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;
> +
> +	usb_set_intfdata(intf, appleir);
> +
> +	init_timer(&appleir->key_up_timer);
> +
> +	appleir->key_up_timer.function = key_up_tick;
> +	appleir->key_up_timer.data = (unsigned long)appleir;
> +
> +	appleir->timer_initted++;
> +
> +	retval = input_register_device(appleir->input_dev);
> +	if (retval)
> +		goto fail;
> +
> +	return 0;
> +
> +fail:
> +	if (appleir) {
> +		if (appleir->data)
> +			usb_buffer_free(dev, URB_SIZE, appleir->data,
> +					appleir->dma_buf);
> +
> +		if (appleir->timer_initted)
> +			del_timer_sync(&appleir->key_up_timer);

You dont need to do it here. The timer is guranteed to be not running
since it is starte din ->open().

> +
> +		if (appleir->input_dev)
> +			input_free_device(appleir->input_dev);
> +
> +		kfree(appleir);
> +	}
> +
> +	return retval;
> +}
> +
> +static void appleir_disconnect(struct usb_interface *intf)
> +{
> +	struct appleir *appleir = usb_get_intfdata(intf);
> +
> +	usb_set_intfdata(intf, NULL);
> +	if (appleir) {
> +		input_unregister_device(appleir->input_dev);
> +		if (appleir->timer_initted)
> +			del_timer_sync(&appleir->key_up_timer);
> +		usb_kill_urb(appleir->urb);

Already done in ->close()

> +		usb_free_urb(appleir->urb);
> +		usb_buffer_free(interface_to_usbdev(intf), URB_SIZE,
> +				appleir->data, appleir->dma_buf);
> +		kfree(appleir);
> +	}
> +}
> +
> +static struct usb_driver appleir_driver = {
> +	.name = "appleir",
> +	.probe = appleir_probe,
> +	.disconnect = appleir_disconnect,
> +	.id_table = appleir_ids,
> +};
> +
> +static int __init appleir_init(void)
> +{
> +	int retval;
> +
> +	retval = usb_register(&appleir_driver);
> +	if (retval)
> +		goto out;
> +	info(DRIVER_VERSION ":" DRIVER_DESC);

Do we need to print the driver identification? I personally like drivers
to be silent unless they find a device but if you prefer to have it
that's fine.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-14 23:27 ` Matthew Garrett
@ 2008-05-14 23:49   ` Greg KH
  2008-05-15  6:20     ` Sitsofe Wheeler
  0 siblings, 1 reply; 57+ messages in thread
From: Greg KH @ 2008-05-14 23:49 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Dmitry Torokhov, jkosina, linux-input, linux-usb, linux-kernel

On Thu, May 15, 2008 at 12:27:22AM +0100, Matthew Garrett wrote:
> On Wed, May 14, 2008 at 03:15:19PM -0700, Greg KH wrote:
> 
> > +	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL, HID_QUIRK_IGNORE },
> >  	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
> 
> Hm. How is the IRCONTROL4 handled? Is the protocol completely different?

I know nothing about that device, sorry.  I think it is a totally
different protocol from what I can tell looking at the code.

> > +	  Say Y here if you want to use a Apple USB remote control.  This
> > +	  device is traditionally inside an Intel Apple Mac Mini, but might
> > +	  show up in other places.
> 
> Minor nit, but it's supported on all the desktop Intel Macs and not just 
> the Mini.

Ah, didn't realize that, nice to know, we should have a wider userbase
then :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH] Input: add appleir USB driver
  2008-05-14 22:15 Greg KH
@ 2008-05-14 23:27 ` Matthew Garrett
  2008-05-14 23:49   ` Greg KH
  2008-05-15  3:50 ` Dmitry Torokhov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 57+ messages in thread
From: Matthew Garrett @ 2008-05-14 23:27 UTC (permalink / raw)
  To: Greg KH; +Cc: Dmitry Torokhov, jkosina, linux-input, linux-usb, linux-kernel

On Wed, May 14, 2008 at 03:15:19PM -0700, Greg KH wrote:

> +	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL, HID_QUIRK_IGNORE },
>  	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },

Hm. How is the IRCONTROL4 handled? Is the protocol completely different?

> +	  Say Y here if you want to use a Apple USB remote control.  This
> +	  device is traditionally inside an Intel Apple Mac Mini, but might
> +	  show up in other places.

Minor nit, but it's supported on all the desktop Intel Macs and not just 
the Mini.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH] Input: add appleir USB driver
@ 2008-05-14 22:15 Greg KH
  2008-05-14 23:27 ` Matthew Garrett
                   ` (3 more replies)
  0 siblings, 4 replies; 57+ messages in thread
From: Greg KH @ 2008-05-14 22:15 UTC (permalink / raw)
  To: Dmitry Torokhov, jkosina; +Cc: linux-input, linux-usb, linux-kernel

From: Greg Kroah-Hartman <gregkh@suse.de>

This driver was originally written by James McKenzie but forward ported
and cleaned up by me to get it to work with modern kernel versions.

Tested on my mac mini and it actually works!

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---

Jiri, is it ok for this quirks addtion to go through Dmitry's triee?  Or
do you want me to split it out into two different patches?

Dmitry, is this ok to go through your tree?  Or I can take it as well if
you don't want it :)

 drivers/hid/usbhid/hid-quirks.c |    2 
 drivers/input/misc/Kconfig      |   12 +
 drivers/input/misc/Makefile     |    1 
 drivers/input/misc/appleir.c    |  361 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 376 insertions(+)

--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -77,6 +77,7 @@
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS   0x022e
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL	0x8240
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
 
 #define USB_VENDOR_ID_ASUS		0x0b05
@@ -443,6 +444,7 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
 
 	{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
 	{ USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
 	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
--- /dev/null
+++ b/drivers/input/misc/appleir.c
@@ -0,0 +1,361 @@
+/*
+ * appleir: USB driver for the apple ir device
+ *
+ * Original driver written by James McKenzie
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Copyright (C) 2006 James McKenzie
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2008 Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#define DRIVER_VERSION "v1.2"
+#define DRIVER_AUTHOR "James McKenzie"
+#define DRIVER_DESC "USB Apple MacMini IR Receiver driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_APPLE	0x05ac
+#define USB_DEVICE_ID_APPLE_IR	0x8240
+
+#define URB_SIZE	32
+
+#define MAX_KEYS	8
+#define MAX_KEYS_MASK	(MAX_KEYS - 1)
+
+struct appleir {
+	struct input_dev *input_dev;
+	u8 *data;
+	dma_addr_t dma_buf;
+	struct usb_device *usbdev;
+	struct urb *urb;
+	int timer_initted;
+	struct timer_list key_up_timer;
+	int current_key;
+	char phys[32];
+};
+
+static struct usb_device_id appleir_ids[] = {
+	{USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, appleir_ids);
+
+/* I have two devices both of which report the following */
+/* 25 87 ee 83 0a  	+  */
+/* 25 87 ee 83 0c  	-  */
+/* 25 87 ee 83 09	<< */
+/* 25 87 ee 83 06	>> */
+/* 25 87 ee 83 05	>" */
+/* 25 87 ee 83 03	menu */
+/* 26 00 00 00 00	for key repeat*/
+
+/* Thomas Glanzmann reports the following responses */
+/* 25 87 ee ca 0b	+  */
+/* 25 87 ee ca 0d	-  */
+/* 25 87 ee ca 08	<< */
+/* 25 87 ee ca 07	>> */
+/* 25 87 ee ca 04	>" */
+/* 25 87 ee ca 02 	menu */
+/* 26 00 00 00 00       for key repeat*/
+/* He also observes the following event sometimes */
+/* sent after a key is release, which I interpret */
+/* as a flat battery message */
+/* 25 87 e0 ca 06	flat battery */
+
+static int keymap[MAX_KEYS] = {
+	KEY_RESERVED,
+	KEY_MENU,
+	KEY_PLAYPAUSE,
+	KEY_NEXTSONG,
+	KEY_PREVIOUSSONG,
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_RESERVED,
+};
+
+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
+{
+	int i;
+
+	printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
+
+	for (i = 0; i < len; ++i)
+		printk(" %02x", data[i]);
+	printk("\n");
+}
+
+static void key_up(struct appleir *appleir, int key)
+{
+	/* printk (KERN_ERR "key %d up\n", key); */
+	input_report_key(appleir->input_dev, key, 0);
+	input_sync(appleir->input_dev);
+}
+
+static void key_down(struct appleir *appleir, int key)
+{
+	/* printk (KERN_ERR "key %d down\n", key); */
+	input_report_key(appleir->input_dev, key, 1);
+	input_sync(appleir->input_dev);
+}
+
+static void battery_flat(struct appleir *appleir)
+{
+	dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
+}
+
+static void key_up_tick(unsigned long data)
+{
+	struct appleir *appleir = (struct appleir *)data;
+
+	if (appleir->current_key) {
+		key_up(appleir, appleir->current_key);
+		appleir->current_key = 0;
+	}
+}
+
+static void new_data(struct appleir *appleir, u8 *data, int len)
+{
+	static const u8 keydown[] = { 0x25, 0x87, 0xee };
+	static const u8 keyrepeat[] = { 0x26, 0x00, 0x00, 0x00, 0x00 };
+	static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
+
+#if 0
+	dump_packet(appleir, "received", data, len);
+#endif
+
+	if (len != 5)
+		return;
+
+	if (!memcmp(data, keydown, sizeof(keydown))) {
+		/*If we already have a key down, take it up before marking */
+		/*this one down */
+		if (appleir->current_key)
+			key_up(appleir, appleir->current_key);
+		appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK];
+
+		key_down(appleir, appleir->current_key);
+		/*remote doesn't do key up, either pull them up, in the test */
+		/*above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+
+		return;
+	}
+
+	if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
+		key_down(appleir, appleir->current_key);
+		/*remote doesn't do key up, either pull them up, in the test */
+		/*above, or here set a timer which pulls them up after 1/8 s */
+		mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+		return;
+	}
+
+	if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
+		battery_flat(appleir);
+		/* Fall through */
+	}
+
+	dump_packet(appleir, "unknown packet", data, len);
+}
+
+static void appleir_urb(struct urb *urb)
+{
+	struct appleir *appleir = urb->context;
+	int status = urb->status;
+	int retval;
+
+	switch (status) {
+	case 0:
+		new_data(appleir, urb->transfer_buffer, urb->actual_length);
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __func__,
+		    urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d", __func__,
+		    urb->status);
+	}
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result %d", __func__,
+		    retval);
+}
+
+static int appleir_open(struct input_dev *dev)
+{
+	struct appleir *appleir = input_get_drvdata(dev);
+
+	if (usb_submit_urb(appleir->urb, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+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);
+}
+
+static int appleir_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct appleir *appleir = NULL;
+	struct input_dev *input_dev;
+	int retval = -ENOMEM;
+	int i;
+
+	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
+	if (!appleir)
+		goto fail;
+
+	appleir->data = usb_buffer_alloc(dev, URB_SIZE, GFP_KERNEL,
+					 &appleir->dma_buf);
+	if (!appleir->data)
+		goto fail;
+
+	appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!appleir->urb)
+		goto fail;
+
+	appleir->usbdev = dev;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		goto fail;
+
+	appleir->input_dev = input_dev;
+
+	usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
+	strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
+
+	input_dev->name = "Apple Mac mini infrared remote control driver";
+	input_dev->phys = appleir->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+	input_set_drvdata(input_dev, appleir);
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+	input_dev->ledbit[0] = 0;
+
+	for (i = 0; i < MAX_KEYS; i++)
+		set_bit(keymap[i], input_dev->keybit);
+
+	clear_bit(0, input_dev->keybit);
+
+	input_dev->open = appleir_open;
+	input_dev->close = appleir_close;
+
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+	usb_fill_int_urb(appleir->urb, dev,
+			 usb_rcvintpipe(dev, 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;
+
+	usb_set_intfdata(intf, appleir);
+
+	init_timer(&appleir->key_up_timer);
+
+	appleir->key_up_timer.function = key_up_tick;
+	appleir->key_up_timer.data = (unsigned long)appleir;
+
+	appleir->timer_initted++;
+
+	retval = input_register_device(appleir->input_dev);
+	if (retval)
+		goto fail;
+
+	return 0;
+
+fail:
+	if (appleir) {
+		if (appleir->data)
+			usb_buffer_free(dev, URB_SIZE, appleir->data,
+					appleir->dma_buf);
+
+		if (appleir->timer_initted)
+			del_timer_sync(&appleir->key_up_timer);
+
+		if (appleir->input_dev)
+			input_free_device(appleir->input_dev);
+
+		kfree(appleir);
+	}
+
+	return retval;
+}
+
+static void appleir_disconnect(struct usb_interface *intf)
+{
+	struct appleir *appleir = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (appleir) {
+		input_unregister_device(appleir->input_dev);
+		if (appleir->timer_initted)
+			del_timer_sync(&appleir->key_up_timer);
+		usb_kill_urb(appleir->urb);
+		usb_free_urb(appleir->urb);
+		usb_buffer_free(interface_to_usbdev(intf), URB_SIZE,
+				appleir->data, appleir->dma_buf);
+		kfree(appleir);
+	}
+}
+
+static struct usb_driver appleir_driver = {
+	.name = "appleir",
+	.probe = appleir_probe,
+	.disconnect = appleir_disconnect,
+	.id_table = appleir_ids,
+};
+
+static int __init appleir_init(void)
+{
+	int retval;
+
+	retval = usb_register(&appleir_driver);
+	if (retval)
+		goto out;
+	info(DRIVER_VERSION ":" DRIVER_DESC);
+out:
+	return retval;
+}
+
+static void __exit appleir_exit(void)
+{
+	usb_deregister(&appleir_driver);
+}
+
+module_init(appleir_init);
+module_exit(appleir_exit);
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -149,6 +149,18 @@ config INPUT_KEYSPAN_REMOTE
 	  To compile this driver as a module, choose M here: the module will
 	  be called keyspan_remote.
 
+config INPUT_APPLEIR
+	tristate "Apple Mac Mini USB IR receiver (built in)"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use a Apple USB remote control.  This
+	  device is traditionally inside an Intel Apple Mac Mini, but might
+	  show up in other places.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called appleir.
+
 config INPUT_POWERMATE
 	tristate "Griffin PowerMate and Contour Jog support"
 	depends on USB_ARCH_HAS_HCD
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_INPUT_YEALINK)		+= yealink.
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
+obj-$(CONFIG_INPUT_APPLEIR)		+= appleir.o

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2012-11-19 16:01 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-08 16:32 [PATCH] Input: add appleir USB driver Bastien Nocera
  -- strict thread matches above, loose matches on Subject: below --
2012-11-15 18:13 Bastien Nocera
2012-11-19 15:32 ` Benjamin Tissoires
2012-11-19 15:44   ` Bastien Nocera
2012-11-19 16:01     ` Benjamin Tissoires
2010-09-10 15:19 Bastien Nocera
2010-04-21 13:51 Bastien Nocera
2010-04-17 21:45 Bastien Nocera
2010-04-16 16:19 Bastien Nocera
2010-04-17  8:12 ` Dmitry Torokhov
2010-04-17 21:44   ` Bastien Nocera
2010-04-18 19:43     ` Dmitry Torokhov
2010-04-18 19:49       ` Bastien Nocera
2010-04-18 20:19         ` Dmitry Torokhov
2010-04-19  0:31           ` Bastien Nocera
2010-04-19  7:28             ` Dmitry Torokhov
2010-04-19 10:08               ` Bastien Nocera
2010-04-21  6:31                 ` Dmitry Torokhov
2010-04-21 14:06                   ` Bastien Nocera
2010-04-19  9:22   ` Jiri Kosina
2010-04-19  9:31     ` Bastien Nocera
2010-04-19 10:00       ` Jiri Kosina
2010-04-19 10:14         ` Bastien Nocera
2010-04-19 11:08           ` Jiri Kosina
2010-04-21 20:09             ` Dmitry Torokhov
2010-09-03 16:58               ` Bastien Nocera
2010-01-20 14:17 Bastien Nocera
2010-01-27 15:40 ` Jiri Kosina
2010-02-01 13:52   ` Bastien Nocera
2010-02-03 15:54     ` Jiri Kosina
2010-02-08 16:32       ` Bastien Nocera
2010-02-10 12:52         ` Jiri Kosina
2010-02-11 18:18           ` Bastien Nocera
2008-05-14 22:15 Greg KH
2008-05-14 23:27 ` Matthew Garrett
2008-05-14 23:49   ` Greg KH
2008-05-15  6:20     ` Sitsofe Wheeler
2008-05-15  3:50 ` Dmitry Torokhov
2008-05-15 13:21 ` Tino Keitel
     [not found]   ` <20080515132108.GA9327-z7fNteJZwjmqk56C3691EA@public.gmane.org>
2008-05-15 13:45     ` Dmitry Torokhov
2008-05-15 17:49       ` Tino Keitel
     [not found]         ` <20080515174939.GA10881-z7fNteJZwjmqk56C3691EA@public.gmane.org>
2008-05-15 18:35           ` Dmitry Torokhov
2008-05-15 20:59             ` Tino Keitel
2008-05-16  7:19               ` Jiri Kosina
2008-05-16  7:26                 ` Tino Keitel
2008-05-16 13:13               ` Dmitry Torokhov
2008-05-16 13:32                 ` Tino Keitel
     [not found]                   ` <20080516133234.GA10193-Zv899e0YUSaDCaQdYfVI6sM6rOWSkUom@public.gmane.org>
2008-05-16 13:53                     ` Dmitry Torokhov
     [not found]                       ` <20080516095218.ZZRA012-NG0XCrj25/nJrYCpivWRnl5pS2h4L8biXqFh9Ls21Oc@public.gmane.org>
2008-05-16 14:07                         ` Tino Keitel
2008-05-15 18:40       ` Greg KH
     [not found]         ` <20080515184034.GB15231-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2008-05-15 20:59           ` Tino Keitel
     [not found]             ` <20080515205959.GA11683-z7fNteJZwjmqk56C3691EA@public.gmane.org>
2008-05-15 21:11               ` Greg KH
2008-05-15 23:27                 ` Tino Keitel
2008-05-16  2:32                   ` Greg KH
2008-05-16  5:44                     ` Tino Keitel
     [not found] ` <20080514221519.GA6575-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2008-05-15 13:40   ` Tino Keitel
2008-05-15 18:41     ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).