linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/1] Input: ati_remote - extend keytable for medion remotes
@ 2011-04-18 10:41 Jan Losinski
  2011-04-18 10:45 ` [PATCH 1/1] " Jan Losinski
  0 siblings, 1 reply; 18+ messages in thread
From: Jan Losinski @ 2011-04-18 10:41 UTC (permalink / raw)
  To: Dmitry Torokhov, linux-input, linux-kernel; +Cc: losinski

[-- Attachment #1: Type: text/plain, Size: 677 bytes --]

Hello,

the following patch will extend the ati_remote input driver to support
multiple key translation tables. I have a device produced by medion that
is supported by this driver. Unfortunately the single hardcoded key
translation table does not enable all the keys and maps some of them to
completely wrong key events.

So I changed the driver to choose another table if the product-id is the
one this device has. For any other device the old "default" table will
be used. I also provide a full table with meaningful key events for my
device.

I hope you can merge this patch to the mainline version. Please let me
know if this patch causes any issues.

Thanks,
Jan Losinski

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* [PATCH 1/1] Input: ati_remote - extend keytable for medion remotes
  2011-04-18 10:41 [PATCH 0/1] Input: ati_remote - extend keytable for medion remotes Jan Losinski
@ 2011-04-18 10:45 ` Jan Losinski
  2011-05-19  8:54   ` Jan Losinski
  2011-05-25 16:32   ` Dmitry Torokhov
  0 siblings, 2 replies; 18+ messages in thread
From: Jan Losinski @ 2011-04-18 10:45 UTC (permalink / raw)
  To: Dmitry Torokhov, linux-input, linux-kernel; +Cc: losinski

[-- Attachment #1: Type: text/plain, Size: 11006 bytes --]

This extends the ati_remote to support multiple keytables. The table
will be selected with the productId of the device.

It also provides a table for the medion rf remote control that enables
all buttons on it.

Signed-off-by: Jan Losinski <losinski@wh2.tu-dresden.de>
---
 drivers/input/misc/ati_remote.c |  155 ++++++++++++++++++++++++++++++++-------
 1 files changed, 128 insertions(+), 27 deletions(-)

diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
index bce5712..74a3d5c 100644
--- a/drivers/input/misc/ati_remote.c
+++ b/drivers/input/misc/ati_remote.c
@@ -165,6 +165,14 @@ MODULE_DEVICE_TABLE(usb, ati_remote_table);
 static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
 static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
 
+struct ati_event_table {
+	short kind;
+	unsigned char data1, data2;
+	int type;
+	unsigned int code;
+	int value;
+};
+
 struct ati_remote {
 	struct input_dev *idev;
 	struct usb_device *udev;
@@ -191,6 +199,8 @@ struct ati_remote {
 
 	wait_queue_head_t wait;
 	int send_flags;
+
+	const struct ati_event_table *event_table;
 };
 
 /* "Kinds" of messages sent from the hardware to the driver. */
@@ -204,13 +214,7 @@ struct ati_remote {
 #define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
 
 /* Translation table from hardware messages to input events. */
-static const struct {
-	short kind;
-	unsigned char data1, data2;
-	int type;
-	unsigned int code;
-	int value;
-}  ati_remote_tbl[] = {
+static const struct  ati_event_table ati_dflt_event_tbl[] = {
 	/* Directional control pad axes */
 	{KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},	 /* left */
 	{KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
@@ -288,6 +292,88 @@ static const struct {
 	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
 };
 
+/* Translation table from hardware messages to input events.
+ * Special version for the Medion Remote */
+static const struct ati_event_table ati_medion_event_tbl[] = {
+
+	{KIND_FILTERED, 0xf1, 0x2c, EV_KEY, KEY_TV, 1},    /* TV */
+	{KIND_FILTERED, 0xf2, 0x2d, EV_KEY, KEY_VCR, 1},   /* VCR */
+	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},   /* DVD */
+	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_AUDIO, 1}, /* MUSIC */
+
+	{KIND_FILTERED, 0xf3, 0x2e, EV_KEY, KEY_RADIO, 1},     /* RADIO */
+	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_DIRECTORY, 1}, /* PHOTO */
+	{KIND_FILTERED, 0xf4, 0x2f, EV_KEY, KEY_INFO, 1},      /* TV-PREVIEW */
+	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_LIST, 1},      /* CHANNEL-LST */
+
+	{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_SETUP, 1}, /* SETUP */
+	{KIND_FILTERED, 0xf6, 0x31, EV_KEY, KEY_VIDEO, 1}, /* VIDEO DESKTOP */
+
+	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEDOWN, 1},  /* VOL - */
+	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEUP, 1},    /* VOL + */
+	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},   /* CHAN + */
+	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1}, /* CHAN - */
+	{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_MUTE, 1},        /* MUTE */
+
+	{KIND_FILTERED, 0xf7, 0x32, EV_KEY, KEY_RED, 1}, /* red */
+	{KIND_FILTERED, 0xf8, 0x33, EV_KEY, KEY_GREEN, 1}, /* green */
+	{KIND_FILTERED, 0xf9, 0x34, EV_KEY, KEY_YELLOW, 1}, /* yellow */
+	{KIND_FILTERED, 0xfa, 0x35, EV_KEY, KEY_BLUE, 1}, /* blue */
+	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_TEXT, 1}, /* TXT */
+
+	/* keyboard. */
+	{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
+	{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
+	{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
+	{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
+	{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
+	{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
+	{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
+	{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
+	{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
+	{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
+	{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_SEARCH, 1}, /* TV/RAD, CH SRC */
+	{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_DELETE, 1}, /* DELETE */
+
+	{KIND_FILTERED, 0xfb, 0x36, EV_KEY, KEY_KEYBOARD, 1}, /* RENAME */
+	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_SCREEN, 1},   /* SNAPSHOT */
+
+	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},    /* up */
+	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},  /* down */
+	{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},  /* left */
+	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */
+	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},    /* OK */
+
+	{KIND_FILTERED, 0xfc, 0x37, EV_KEY, KEY_SELECT, 1}, /* AQUIRE IMAGE */
+	{KIND_FILTERED, 0xfd, 0x38, EV_KEY, KEY_EDIT, 1},   /* EDIT IMAGE */
+
+	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},   /* rewind  (<<) */
+	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},     /* play    ( >) */
+	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},  /* forward (>>) */
+	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},   /* record  ( o) */
+	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},     /* stop    ([]) */
+	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PLAYPAUSE, 1},/* pause   ('') */
+
+	{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_PREVIOUS, 1},        /* prev */
+	{KIND_FILTERED, 0xfe, 0x39, EV_KEY, KEY_SWITCHVIDEOMODE, 1}, /* F SCR */
+	{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_NEXT, 1},            /* next */
+	{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_MENU, 1},            /* MENU */
+	{KIND_FILTERED, 0xff, 0x3a, EV_KEY, KEY_LANGUAGE, 1},        /* AUDIO */
+
+	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* POWER */
+
+	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
+};
+
+/* key translation assignment table */
+static const struct {
+	__u16 product_id;
+	const struct ati_event_table * const table;
+} ati_remotes_table[] = {
+	{MEDION_REMOTE_PRODUCT_ID, ati_medion_event_tbl},
+	{}	/* Terminating entry */
+};
+
 /* Local function prototypes */
 static int ati_remote_open		(struct input_dev *inputdev);
 static void ati_remote_close		(struct input_dev *inputdev);
@@ -405,7 +491,8 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne
 /*
  *	ati_remote_event_lookup
  */
-static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
+static int ati_remote_event_lookup(const struct ati_event_table *ati_remote_tbl,
+				   int rem, unsigned char d1, unsigned char d2)
 {
 	int i;
 
@@ -489,7 +576,8 @@ static void ati_remote_input_report(struct urb *urb)
 	}
 
 	/* Look up event code index in translation table */
-	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
+	index = ati_remote_event_lookup(ati_remote->event_table,
+					remote_num, data[1], data[2]);
 	if (index < 0) {
 		dev_warn(&ati_remote->interface->dev,
 			 "Unknown input from channel 0x%02x: data %02x,%02x\n",
@@ -498,19 +586,20 @@ static void ati_remote_input_report(struct urb *urb)
 	}
 	dbginfo(&ati_remote->interface->dev,
 		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
-		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
+		remote_num, data[1], data[2], index,
+		ati_remote->event_table[index].code);
 
-	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code,
-			ati_remote_tbl[index].value);
+	if (ati_remote->event_table[index].kind == KIND_LITERAL) {
+		input_event(dev, ati_remote->event_table[index].type,
+			ati_remote->event_table[index].code,
+			ati_remote->event_table[index].value);
 		input_sync(dev);
 
 		ati_remote->old_jiffies = jiffies;
 		return;
 	}
 
-	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
+	if (ati_remote->event_table[index].kind == KIND_FILTERED) {
 		unsigned long now = jiffies;
 
 		/* Filter duplicate events which happen "too close" together. */
@@ -539,11 +628,11 @@ static void ati_remote_input_report(struct urb *urb)
 			return;
 
 
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code, 1);
+		input_event(dev, ati_remote->event_table[index].type,
+			ati_remote->event_table[index].code, 1);
 		input_sync(dev);
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code, 0);
+		input_event(dev, ati_remote->event_table[index].type,
+			ati_remote->event_table[index].code, 0);
 		input_sync(dev);
 
 	} else {
@@ -555,11 +644,11 @@ static void ati_remote_input_report(struct urb *urb)
 		 */
 		acc = ati_remote_compute_accel(ati_remote);
 
-		switch (ati_remote_tbl[index].kind) {
+		switch (ati_remote->event_table[index].kind) {
 		case KIND_ACCEL:
-			input_event(dev, ati_remote_tbl[index].type,
-				ati_remote_tbl[index].code,
-				ati_remote_tbl[index].value * acc);
+			input_event(dev, ati_remote->event_table[index].type,
+				ati_remote->event_table[index].code,
+				ati_remote->event_table[index].value * acc);
 			break;
 		case KIND_LU:
 			input_report_rel(dev, REL_X, -acc);
@@ -579,7 +668,7 @@ static void ati_remote_input_report(struct urb *urb)
 			break;
 		default:
 			dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
-				ati_remote_tbl[index].kind);
+				ati_remote->event_table[index].kind);
 		}
 		input_sync(dev);
 
@@ -669,9 +758,9 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
 	idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
 		BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
 	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
-		if (ati_remote_tbl[i].type == EV_KEY)
-			set_bit(ati_remote_tbl[i].code, idev->keybit);
+	for (i = 0; ati_remote->event_table[i].kind != KIND_END; i++)
+		if (ati_remote->event_table[i].type == EV_KEY)
+			set_bit(ati_remote->event_table[i].code, idev->keybit);
 
 	input_set_drvdata(idev, ati_remote);
 
@@ -736,6 +825,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
 	struct ati_remote *ati_remote;
 	struct input_dev *input_dev;
 	int err = -ENOMEM;
+	int i;
 
 	if (iface_host->desc.bNumEndpoints != 2) {
 		err("%s: Unexpected desc.bNumEndpoints\n", __func__);
@@ -785,6 +875,17 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
 			le16_to_cpu(ati_remote->udev->descriptor.idVendor),
 			le16_to_cpu(ati_remote->udev->descriptor.idProduct));
 
+	/* choose the right translation table */
+	ati_remote->event_table = ati_dflt_event_tbl;
+	for (i = 0; ati_remotes_table[i].product_id ||
+	     ati_remotes_table[i].table; i++) {
+		if (le16_to_cpu(ati_remote->udev->descriptor.idProduct) ==
+		    ati_remotes_table[i].product_id) {
+			ati_remote->event_table = ati_remotes_table[i].table;
+			break;
+		}
+	}
+
 	ati_remote_input_init(ati_remote);
 
 	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
-- 
1.7.4.1


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [PATCH 1/1] Input: ati_remote - extend keytable for medion remotes
  2011-04-18 10:45 ` [PATCH 1/1] " Jan Losinski
@ 2011-05-19  8:54   ` Jan Losinski
  2011-05-25 16:32   ` Dmitry Torokhov
  1 sibling, 0 replies; 18+ messages in thread
From: Jan Losinski @ 2011-05-19  8:54 UTC (permalink / raw)
  To: Dmitry Torokhov, linux-input, linux-kernel; +Cc: losinski

[-- Attachment #1: Type: text/plain, Size: 150 bytes --]

Hello,

can please give me some reply if my patch is ok or not. It was a lot of
work for me and I wont that it was for nothing.

Thanks, Jan Losinski

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [PATCH 1/1] Input: ati_remote - extend keytable for medion remotes
  2011-04-18 10:45 ` [PATCH 1/1] " Jan Losinski
  2011-05-19  8:54   ` Jan Losinski
@ 2011-05-25 16:32   ` Dmitry Torokhov
  2011-07-01 14:01     ` Steffen Barszus
                       ` (2 more replies)
  1 sibling, 3 replies; 18+ messages in thread
From: Dmitry Torokhov @ 2011-05-25 16:32 UTC (permalink / raw)
  To: linux-input, linux-kernel; +Cc: Anssi Hannula

Hi Jan,

On Mon, Apr 18, 2011 at 12:45:47PM +0200, Jan Losinski wrote:
> This extends the ati_remote to support multiple keytables. The table
> will be selected with the productId of the device.
> 
> It also provides a table for the medion rf remote control that enables
> all buttons on it.
> 

I am not a big fan of static keymaps in kernel drivers and would much
more prefer driver supporting adjusting keymaps via EVIOCSKEYCODE
ioctls. Unfortunately ati_remote key handling code is kind of involved
and I am not sure what is the best way of wiring it up.

I believe Anssi Hannula (CCed) mentioned that he has a version of
ati_remove ported to rc-core infrastructure that supports such
remapping. Anssi, could you tell me what is the status of that driver?
Is it usable with rc-core?

Thanks.

> Signed-off-by: Jan Losinski <losinski@wh2.tu-dresden.de>
> ---
>  drivers/input/misc/ati_remote.c |  155 ++++++++++++++++++++++++++++++++-------
>  1 files changed, 128 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
> index bce5712..74a3d5c 100644
> --- a/drivers/input/misc/ati_remote.c
> +++ b/drivers/input/misc/ati_remote.c
> @@ -165,6 +165,14 @@ MODULE_DEVICE_TABLE(usb, ati_remote_table);
>  static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
>  static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
>  
> +struct ati_event_table {
> +	short kind;
> +	unsigned char data1, data2;
> +	int type;
> +	unsigned int code;
> +	int value;
> +};
> +
>  struct ati_remote {
>  	struct input_dev *idev;
>  	struct usb_device *udev;
> @@ -191,6 +199,8 @@ struct ati_remote {
>  
>  	wait_queue_head_t wait;
>  	int send_flags;
> +
> +	const struct ati_event_table *event_table;
>  };
>  
>  /* "Kinds" of messages sent from the hardware to the driver. */
> @@ -204,13 +214,7 @@ struct ati_remote {
>  #define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
>  
>  /* Translation table from hardware messages to input events. */
> -static const struct {
> -	short kind;
> -	unsigned char data1, data2;
> -	int type;
> -	unsigned int code;
> -	int value;
> -}  ati_remote_tbl[] = {
> +static const struct  ati_event_table ati_dflt_event_tbl[] = {
>  	/* Directional control pad axes */
>  	{KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},	 /* left */
>  	{KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
> @@ -288,6 +292,88 @@ static const struct {
>  	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
>  };
>  
> +/* Translation table from hardware messages to input events.
> + * Special version for the Medion Remote */
> +static const struct ati_event_table ati_medion_event_tbl[] = {
> +
> +	{KIND_FILTERED, 0xf1, 0x2c, EV_KEY, KEY_TV, 1},    /* TV */
> +	{KIND_FILTERED, 0xf2, 0x2d, EV_KEY, KEY_VCR, 1},   /* VCR */
> +	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},   /* DVD */
> +	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_AUDIO, 1}, /* MUSIC */
> +
> +	{KIND_FILTERED, 0xf3, 0x2e, EV_KEY, KEY_RADIO, 1},     /* RADIO */
> +	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_DIRECTORY, 1}, /* PHOTO */
> +	{KIND_FILTERED, 0xf4, 0x2f, EV_KEY, KEY_INFO, 1},      /* TV-PREVIEW */
> +	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_LIST, 1},      /* CHANNEL-LST */
> +
> +	{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_SETUP, 1}, /* SETUP */
> +	{KIND_FILTERED, 0xf6, 0x31, EV_KEY, KEY_VIDEO, 1}, /* VIDEO DESKTOP */
> +
> +	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEDOWN, 1},  /* VOL - */
> +	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEUP, 1},    /* VOL + */
> +	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},   /* CHAN + */
> +	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1}, /* CHAN - */
> +	{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_MUTE, 1},        /* MUTE */
> +
> +	{KIND_FILTERED, 0xf7, 0x32, EV_KEY, KEY_RED, 1}, /* red */
> +	{KIND_FILTERED, 0xf8, 0x33, EV_KEY, KEY_GREEN, 1}, /* green */
> +	{KIND_FILTERED, 0xf9, 0x34, EV_KEY, KEY_YELLOW, 1}, /* yellow */
> +	{KIND_FILTERED, 0xfa, 0x35, EV_KEY, KEY_BLUE, 1}, /* blue */
> +	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_TEXT, 1}, /* TXT */
> +
> +	/* keyboard. */
> +	{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
> +	{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
> +	{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
> +	{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
> +	{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
> +	{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
> +	{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
> +	{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
> +	{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
> +	{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
> +	{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_SEARCH, 1}, /* TV/RAD, CH SRC */
> +	{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_DELETE, 1}, /* DELETE */
> +
> +	{KIND_FILTERED, 0xfb, 0x36, EV_KEY, KEY_KEYBOARD, 1}, /* RENAME */
> +	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_SCREEN, 1},   /* SNAPSHOT */
> +
> +	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},    /* up */
> +	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},  /* down */
> +	{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},  /* left */
> +	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */
> +	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},    /* OK */
> +
> +	{KIND_FILTERED, 0xfc, 0x37, EV_KEY, KEY_SELECT, 1}, /* AQUIRE IMAGE */
> +	{KIND_FILTERED, 0xfd, 0x38, EV_KEY, KEY_EDIT, 1},   /* EDIT IMAGE */
> +
> +	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},   /* rewind  (<<) */
> +	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},     /* play    ( >) */
> +	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},  /* forward (>>) */
> +	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},   /* record  ( o) */
> +	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},     /* stop    ([]) */
> +	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PLAYPAUSE, 1},/* pause   ('') */
> +
> +	{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_PREVIOUS, 1},        /* prev */
> +	{KIND_FILTERED, 0xfe, 0x39, EV_KEY, KEY_SWITCHVIDEOMODE, 1}, /* F SCR */
> +	{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_NEXT, 1},            /* next */
> +	{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_MENU, 1},            /* MENU */
> +	{KIND_FILTERED, 0xff, 0x3a, EV_KEY, KEY_LANGUAGE, 1},        /* AUDIO */
> +
> +	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* POWER */
> +
> +	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
> +};
> +
> +/* key translation assignment table */
> +static const struct {
> +	__u16 product_id;
> +	const struct ati_event_table * const table;
> +} ati_remotes_table[] = {
> +	{MEDION_REMOTE_PRODUCT_ID, ati_medion_event_tbl},
> +	{}	/* Terminating entry */
> +};
> +
>  /* Local function prototypes */
>  static int ati_remote_open		(struct input_dev *inputdev);
>  static void ati_remote_close		(struct input_dev *inputdev);
> @@ -405,7 +491,8 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne
>  /*
>   *	ati_remote_event_lookup
>   */
> -static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
> +static int ati_remote_event_lookup(const struct ati_event_table *ati_remote_tbl,
> +				   int rem, unsigned char d1, unsigned char d2)
>  {
>  	int i;
>  
> @@ -489,7 +576,8 @@ static void ati_remote_input_report(struct urb *urb)
>  	}
>  
>  	/* Look up event code index in translation table */
> -	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
> +	index = ati_remote_event_lookup(ati_remote->event_table,
> +					remote_num, data[1], data[2]);
>  	if (index < 0) {
>  		dev_warn(&ati_remote->interface->dev,
>  			 "Unknown input from channel 0x%02x: data %02x,%02x\n",
> @@ -498,19 +586,20 @@ static void ati_remote_input_report(struct urb *urb)
>  	}
>  	dbginfo(&ati_remote->interface->dev,
>  		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
> -		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
> +		remote_num, data[1], data[2], index,
> +		ati_remote->event_table[index].code);
>  
> -	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
> -		input_event(dev, ati_remote_tbl[index].type,
> -			ati_remote_tbl[index].code,
> -			ati_remote_tbl[index].value);
> +	if (ati_remote->event_table[index].kind == KIND_LITERAL) {
> +		input_event(dev, ati_remote->event_table[index].type,
> +			ati_remote->event_table[index].code,
> +			ati_remote->event_table[index].value);
>  		input_sync(dev);
>  
>  		ati_remote->old_jiffies = jiffies;
>  		return;
>  	}
>  
> -	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
> +	if (ati_remote->event_table[index].kind == KIND_FILTERED) {
>  		unsigned long now = jiffies;
>  
>  		/* Filter duplicate events which happen "too close" together. */
> @@ -539,11 +628,11 @@ static void ati_remote_input_report(struct urb *urb)
>  			return;
>  
>  
> -		input_event(dev, ati_remote_tbl[index].type,
> -			ati_remote_tbl[index].code, 1);
> +		input_event(dev, ati_remote->event_table[index].type,
> +			ati_remote->event_table[index].code, 1);
>  		input_sync(dev);
> -		input_event(dev, ati_remote_tbl[index].type,
> -			ati_remote_tbl[index].code, 0);
> +		input_event(dev, ati_remote->event_table[index].type,
> +			ati_remote->event_table[index].code, 0);
>  		input_sync(dev);
>  
>  	} else {
> @@ -555,11 +644,11 @@ static void ati_remote_input_report(struct urb *urb)
>  		 */
>  		acc = ati_remote_compute_accel(ati_remote);
>  
> -		switch (ati_remote_tbl[index].kind) {
> +		switch (ati_remote->event_table[index].kind) {
>  		case KIND_ACCEL:
> -			input_event(dev, ati_remote_tbl[index].type,
> -				ati_remote_tbl[index].code,
> -				ati_remote_tbl[index].value * acc);
> +			input_event(dev, ati_remote->event_table[index].type,
> +				ati_remote->event_table[index].code,
> +				ati_remote->event_table[index].value * acc);
>  			break;
>  		case KIND_LU:
>  			input_report_rel(dev, REL_X, -acc);
> @@ -579,7 +668,7 @@ static void ati_remote_input_report(struct urb *urb)
>  			break;
>  		default:
>  			dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
> -				ati_remote_tbl[index].kind);
> +				ati_remote->event_table[index].kind);
>  		}
>  		input_sync(dev);
>  
> @@ -669,9 +758,9 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
>  	idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
>  		BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
>  	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
> -	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
> -		if (ati_remote_tbl[i].type == EV_KEY)
> -			set_bit(ati_remote_tbl[i].code, idev->keybit);
> +	for (i = 0; ati_remote->event_table[i].kind != KIND_END; i++)
> +		if (ati_remote->event_table[i].type == EV_KEY)
> +			set_bit(ati_remote->event_table[i].code, idev->keybit);
>  
>  	input_set_drvdata(idev, ati_remote);
>  
> @@ -736,6 +825,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
>  	struct ati_remote *ati_remote;
>  	struct input_dev *input_dev;
>  	int err = -ENOMEM;
> +	int i;
>  
>  	if (iface_host->desc.bNumEndpoints != 2) {
>  		err("%s: Unexpected desc.bNumEndpoints\n", __func__);
> @@ -785,6 +875,17 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
>  			le16_to_cpu(ati_remote->udev->descriptor.idVendor),
>  			le16_to_cpu(ati_remote->udev->descriptor.idProduct));
>  
> +	/* choose the right translation table */
> +	ati_remote->event_table = ati_dflt_event_tbl;
> +	for (i = 0; ati_remotes_table[i].product_id ||
> +	     ati_remotes_table[i].table; i++) {
> +		if (le16_to_cpu(ati_remote->udev->descriptor.idProduct) ==
> +		    ati_remotes_table[i].product_id) {
> +			ati_remote->event_table = ati_remotes_table[i].table;
> +			break;
> +		}
> +	}
> +
>  	ati_remote_input_init(ati_remote);
>  
>  	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
> -- 
> 1.7.4.1
> 



-- 
Dmitry

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

* Re: [PATCH 1/1] Input: ati_remote - extend keytable for medion remotes
  2011-05-25 16:32   ` Dmitry Torokhov
@ 2011-07-01 14:01     ` Steffen Barszus
  2011-08-06 15:32     ` Steffen Barszus
  2011-08-06 21:31     ` Anssi Hannula
  2 siblings, 0 replies; 18+ messages in thread
From: Steffen Barszus @ 2011-07-01 14:01 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, Anssi Hannula

2011/5/25 Dmitry Torokhov <dmitry.torokhov@gmail.com>:
> Hi Jan,
>
> On Mon, Apr 18, 2011 at 12:45:47PM +0200, Jan Losinski wrote:
>> This extends the ati_remote to support multiple keytables. The table
>> will be selected with the productId of the device.
>>
>> It also provides a table for the medion rf remote control that enables
>> all buttons on it.
>>
>
> I am not a big fan of static keymaps in kernel drivers and would much
> more prefer driver supporting adjusting keymaps via EVIOCSKEYCODE
> ioctls. Unfortunately ati_remote key handling code is kind of involved
> and I am not sure what is the best way of wiring it up.
>
> I believe Anssi Hannula (CCed) mentioned that he has a version of
> ati_remove ported to rc-core infrastructure that supports such
> remapping. Anssi, could you tell me what is the status of that driver?
> Is it usable with rc-core?
>

That would be cool - being a remote it might be the right framework.

Until then this patch might improve the situation.

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

* Re: [PATCH 1/1] Input: ati_remote - extend keytable for medion remotes
  2011-05-25 16:32   ` Dmitry Torokhov
  2011-07-01 14:01     ` Steffen Barszus
@ 2011-08-06 15:32     ` Steffen Barszus
  2011-08-06 21:31     ` Anssi Hannula
  2 siblings, 0 replies; 18+ messages in thread
From: Steffen Barszus @ 2011-08-06 15:32 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, Anssi Hannula

On Wed, 25 May 2011 09:32:04 -0700
Dmitry Torokhov <dmitry.torokhov@gmail.com> wrote:

> Hi Jan,
> 
> On Mon, Apr 18, 2011 at 12:45:47PM +0200, Jan Losinski wrote:
> > This extends the ati_remote to support multiple keytables. The table
> > will be selected with the productId of the device.
> > 
> > It also provides a table for the medion rf remote control that
> > enables all buttons on it.
> > 
> 
> I am not a big fan of static keymaps in kernel drivers and would much
> more prefer driver supporting adjusting keymaps via EVIOCSKEYCODE
> ioctls. Unfortunately ati_remote key handling code is kind of involved
> and I am not sure what is the best way of wiring it up.
> 
> I believe Anssi Hannula (CCed) mentioned that he has a version of
> ati_remove ported to rc-core infrastructure that supports such
> remapping. Anssi, could you tell me what is the status of that driver?
> Is it usable with rc-core?

Jarod also had some interest in moving this to rc-core (but as he
stated no time soon) 

Could this be added in the meantime ? Anyone ? Whats missing ? 

:) 

Thanks

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

* Re: [PATCH 1/1] Input: ati_remote - extend keytable for medion remotes
  2011-05-25 16:32   ` Dmitry Torokhov
  2011-07-01 14:01     ` Steffen Barszus
  2011-08-06 15:32     ` Steffen Barszus
@ 2011-08-06 21:31     ` Anssi Hannula
  2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
  2 siblings, 1 reply; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 21:31 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, linux-kernel

On 25.05.2011 19:32, Dmitry Torokhov wrote:
> Hi Jan,
> 
> On Mon, Apr 18, 2011 at 12:45:47PM +0200, Jan Losinski wrote:
>> This extends the ati_remote to support multiple keytables. The table
>> will be selected with the productId of the device.
>>
>> It also provides a table for the medion rf remote control that enables
>> all buttons on it.
>>
> 
> I am not a big fan of static keymaps in kernel drivers and would much
> more prefer driver supporting adjusting keymaps via EVIOCSKEYCODE
> ioctls. Unfortunately ati_remote key handling code is kind of involved
> and I am not sure what is the best way of wiring it up.
> 
> I believe Anssi Hannula (CCed) mentioned that he has a version of
> ati_remove ported to rc-core infrastructure that supports such
> remapping. Anssi, could you tell me what is the status of that driver?
> Is it usable with rc-core?

Sorry, it seems for some reason I didn't receive your message via CC and
only now saw it while looking at linux-input@ messages.

Indeed I have a patchset that makes it work with rc-core which I didn't
get around to posting yet (sorry about that).

I'll try to look over it now and do some more testing, and then post the
set.

Some notes about the patchset:
- The mouse handling is left as-is, and it now appears as a separate
  input device (that part of the keymap is the same for all remotes
  with mouse). The mouse device is created regardless of receiver,
  in case another type of remote is used with the receiver.
- The driver sends rc_keyup immediately after every rc_keydown, as that
  is what the driver has always done for input events as well. Doing
  otherwise would cause a regression as ghost repeats would appear
  with this driver while they didn't before.

-- 
Anssi Hannula

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

* [PATCH 0/7] ati_remote: move to rc-core and other updates
  2011-08-06 21:31     ` Anssi Hannula
@ 2011-08-06 22:18       ` Anssi Hannula
  2011-08-06 22:18         ` [PATCH 1/7] [media] move ati_remote driver from input/misc to media/rc Anssi Hannula
                           ` (6 more replies)
  0 siblings, 7 replies; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 22:18 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-media, linux-input, linux-kernel

Anssi Hannula wrote:
> On 25.05.2011 19:32, Dmitry Torokhov wrote:
>> I believe Anssi Hannula (CCed) mentioned that he has a version of
>> ati_remove ported to rc-core infrastructure that supports such
>> remapping. Anssi, could you tell me what is the status of that driver?
>> Is it usable with rc-core?
> 
> Sorry, it seems for some reason I didn't receive your message via CC and
> only now saw it while looking at linux-input@ messages.
> 
> Indeed I have a patchset that makes it work with rc-core which I didn't
> get around to posting yet (sorry about that).
> 
> I'll try to look over it now and do some more testing, and then post the
> set.
> 
> Some notes about the patchset:
> - The mouse handling is left as-is, and it now appears as a separate
>   input device (that part of the keymap is the same for all remotes
>   with mouse). The mouse device is created regardless of receiver,
>   in case another type of remote is used with the receiver.
> - The driver sends rc_keyup immediately after every rc_keydown, as that
>   is what the driver has always done for input events as well. Doing
>   otherwise would cause a regression as ghost repeats would appear
>   with this driver while they didn't before.


Here goes the patchset, comments welcome.


Anssi Hannula (7):
      [media] move ati_remote driver from input/misc to media/rc
      [media] ati_remote: migrate to the rc subsystem
      [media] ati_remote: parent input devices to usb interface
      [media] ati_remote: fix check for a weird byte
      [media] ati_remote: add keymap for Medion X10 RF remote
      [media] ati_remote: add support for SnapStream Firefly remote
      [media] ati_remote: update Kconfig description

---
 drivers/input/misc/Kconfig                       |   16 -
 drivers/input/misc/Makefile                      |    1 -
 drivers/input/misc/ati_remote.c                  |  867 --------------------
 drivers/media/rc/Kconfig                         |   23 +-
 drivers/media/rc/Makefile                        |    1 +
 drivers/media/rc/ati_remote.c                    |  946 ++++++++++++++++++++++
 drivers/media/rc/keymaps/Makefile                |    3 +
 drivers/media/rc/keymaps/rc-ati-x10.c            |  103 +++
 drivers/media/rc/keymaps/rc-medion-x10.c         |  116 +++
 drivers/media/rc/keymaps/rc-snapstream-firefly.c |  106 +++
 include/media/rc-map.h                           |    3 +
 11 files changed, 1299 insertions(+), 886 deletions(-)

-- 
Anssi Hannula


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

* [PATCH 1/7] [media] move ati_remote driver from input/misc to media/rc
  2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
@ 2011-08-06 22:18         ` Anssi Hannula
  2011-08-06 22:18         ` [PATCH 2/7] [media] ati_remote: migrate to the rc subsystem Anssi Hannula
                           ` (5 subsequent siblings)
  6 siblings, 0 replies; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 22:18 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-media, linux-input, linux-kernel

The driver will be migrated to the RC driver API in a following
commit.

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
---
 drivers/input/misc/Kconfig      |   16 -
 drivers/input/misc/Makefile     |    1 -
 drivers/input/misc/ati_remote.c |  867 ---------------------------------------
 drivers/media/rc/Kconfig        |   20 +-
 drivers/media/rc/Makefile       |    1 +
 drivers/media/rc/ati_remote.c   |  867 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 886 insertions(+), 886 deletions(-)
 delete mode 100644 drivers/input/misc/ati_remote.c
 create mode 100644 drivers/media/rc/ati_remote.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index f9cf088..2a33413 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -162,22 +162,6 @@ config INPUT_ATLAS_BTNS
 	  To compile this driver as a module, choose M here: the module will
 	  be called atlas_btns.
 
-config INPUT_ATI_REMOTE
-	tristate "ATI / X10 USB RF remote control"
-	depends on USB_ARCH_HAS_HCD
-	select USB
-	help
-	  Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
-	  These are RF remotes with USB receivers.
-	  The ATI remote comes with many of ATI's All-In-Wonder video cards.
-	  The X10 "Lola" remote is available at:
-	     <http://www.x10.com/products/lola_sg1.htm>
-	  This driver provides mouse pointer, left and right mouse buttons,
-	  and maps all the other remote buttons to keypress events.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called ati_remote.
-
 config INPUT_ATI_REMOTE2
 	tristate "ATI / Philips USB RF remote control"
 	depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index e3f7984..b11c25a 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -13,7 +13,6 @@ 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_ATI_REMOTE)		+= ati_remote.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/ati_remote.c b/drivers/input/misc/ati_remote.c
deleted file mode 100644
index bce5712..0000000
--- a/drivers/input/misc/ati_remote.c
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- *  USB ATI Remote support
- *
- *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
- *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
- *
- *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
- *  porting to the 2.6 kernel interfaces, along with other modification
- *  to better match the style of the existing usb/input drivers.  However, the
- *  protocol and hardware handling is essentially unchanged from 2.1.1.
- *
- *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
- *  Vojtech Pavlik.
- *
- *  Changes:
- *
- *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
- *            Version 2.2.0
- *  Jun 2004: Torrey Hoffman <thoffman@arnor.net>
- *            Version 2.2.1
- *            Added key repeat support contributed by:
- *                Vincent Vanackere <vanackere@lif.univ-mrs.fr>
- *            Added support for the "Lola" remote contributed by:
- *                Seth Cohn <sethcohn@yahoo.com>
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Hardware & software notes
- *
- * These remote controls are distributed by ATI as part of their
- * "All-In-Wonder" video card packages.  The receiver self-identifies as a
- * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
- *
- * The "Lola" remote is available from X10.  See:
- *    http://www.x10.com/products/lola_sg1.htm
- * The Lola is similar to the ATI remote but has no mouse support, and slightly
- * different keys.
- *
- * It is possible to use multiple receivers and remotes on multiple computers
- * simultaneously by configuring them to use specific channels.
- *
- * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
- * Actually, it may even support more, at least in some revisions of the
- * hardware.
- *
- * Each remote can be configured to transmit on one channel as follows:
- *   - Press and hold the "hand icon" button.
- *   - When the red LED starts to blink, let go of the "hand icon" button.
- *   - When it stops blinking, input the channel code as two digits, from 01
- *     to 16, and press the hand icon again.
- *
- * The timing can be a little tricky.  Try loading the module with debug=1
- * to have the kernel print out messages about the remote control number
- * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
- *
- * The driver has a "channel_mask" parameter. This bitmask specifies which
- * channels will be ignored by the module.  To mask out channels, just add
- * all the 2^channel_number values together.
- *
- * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
- * ignore signals coming from remote controls transmitting on channel 4, but
- * accept all other channels.
- *
- * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
- * ignored.
- *
- * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
- * parameter are unused.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb/input.h>
-#include <linux/wait.h>
-#include <linux/jiffies.h>
-
-/*
- * Module and Version Information, Module Parameters
- */
-
-#define ATI_REMOTE_VENDOR_ID		0x0bc7
-#define LOLA_REMOTE_PRODUCT_ID		0x0002
-#define LOLA2_REMOTE_PRODUCT_ID		0x0003
-#define ATI_REMOTE_PRODUCT_ID		0x0004
-#define NVIDIA_REMOTE_PRODUCT_ID	0x0005
-#define MEDION_REMOTE_PRODUCT_ID	0x0006
-
-#define DRIVER_VERSION	        "2.2.1"
-#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
-#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
-
-#define NAME_BUFSIZE      80    /* size of product name, path buffers */
-#define DATA_BUFSIZE      63    /* size of URB data buffers */
-
-/*
- * Duplicate event filtering time.
- * Sequential, identical KIND_FILTERED inputs with less than
- * FILTER_TIME milliseconds between them are considered as repeat
- * events. The hardware generates 5 events for the first keypress
- * and we have to take this into account for an accurate repeat
- * behaviour.
- */
-#define FILTER_TIME	60 /* msec */
-#define REPEAT_DELAY	500 /* msec */
-
-static unsigned long channel_mask;
-module_param(channel_mask, ulong, 0644);
-MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
-
-static int repeat_filter = FILTER_TIME;
-module_param(repeat_filter, int, 0644);
-MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
-
-static int repeat_delay = REPEAT_DELAY;
-module_param(repeat_delay, int, 0644);
-MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec");
-
-#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
-#undef err
-#define err(format, arg...) printk(KERN_ERR format , ## arg)
-
-static struct usb_device_id ati_remote_table[] = {
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
-	{}	/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ati_remote_table);
-
-/* Get hi and low bytes of a 16-bits int */
-#define HI(a)	((unsigned char)((a) >> 8))
-#define LO(a)	((unsigned char)((a) & 0xff))
-
-#define SEND_FLAG_IN_PROGRESS	1
-#define SEND_FLAG_COMPLETE	2
-
-/* Device initialization strings */
-static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
-static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
-
-struct ati_remote {
-	struct input_dev *idev;
-	struct usb_device *udev;
-	struct usb_interface *interface;
-
-	struct urb *irq_urb;
-	struct urb *out_urb;
-	struct usb_endpoint_descriptor *endpoint_in;
-	struct usb_endpoint_descriptor *endpoint_out;
-	unsigned char *inbuf;
-	unsigned char *outbuf;
-	dma_addr_t inbuf_dma;
-	dma_addr_t outbuf_dma;
-
-	unsigned char old_data[2];  /* Detect duplicate events */
-	unsigned long old_jiffies;
-	unsigned long acc_jiffies;  /* handle acceleration */
-	unsigned long first_jiffies;
-
-	unsigned int repeat_count;
-
-	char name[NAME_BUFSIZE];
-	char phys[NAME_BUFSIZE];
-
-	wait_queue_head_t wait;
-	int send_flags;
-};
-
-/* "Kinds" of messages sent from the hardware to the driver. */
-#define KIND_END        0
-#define KIND_LITERAL    1   /* Simply pass to input system */
-#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
-#define KIND_LU         3   /* Directional keypad diagonals - left up, */
-#define KIND_RU         4   /*   right up,  */
-#define KIND_LD         5   /*   left down, */
-#define KIND_RD         6   /*   right down */
-#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
-
-/* Translation table from hardware messages to input events. */
-static const struct {
-	short kind;
-	unsigned char data1, data2;
-	int type;
-	unsigned int code;
-	int value;
-}  ati_remote_tbl[] = {
-	/* Directional control pad axes */
-	{KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},	 /* left */
-	{KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
-	{KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},	 /* up */
-	{KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
-	/* Directional control pad diagonals */
-	{KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
-	{KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
-	{KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
-	{KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
-
-	/* "Mouse button" buttons */
-	{KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
-	{KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
-	{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
-	{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
-
-	/* Artificial "doubleclick" events are generated by the hardware.
-	 * They are mapped to the "side" and "extra" mouse buttons here. */
-	{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
-	{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
-
-	/* keyboard. */
-	{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
-	{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
-	{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
-	{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
-	{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
-	{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
-	{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
-	{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
-	{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
-	{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
-	{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
-	{KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
-	{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
-	{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
-	{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
-	{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
-
-	/* "special" keys */
-	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
-	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
-	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
-	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
-	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
-	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
-	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
-	{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
-	{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
-	{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
-	{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
-	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
-	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
-	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
-	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
-	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
-	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
-	{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
-	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
-	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
-	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
-	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
-	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
-	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
-	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
-	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
-	{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
-	{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
-	{KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
-	{KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
-	{KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
-	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
-
-	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
-};
-
-/* Local function prototypes */
-static int ati_remote_open		(struct input_dev *inputdev);
-static void ati_remote_close		(struct input_dev *inputdev);
-static int ati_remote_sendpacket	(struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
-static void ati_remote_irq_out		(struct urb *urb);
-static void ati_remote_irq_in		(struct urb *urb);
-static void ati_remote_input_report	(struct urb *urb);
-static int ati_remote_initialize	(struct ati_remote *ati_remote);
-static int ati_remote_probe		(struct usb_interface *interface, const struct usb_device_id *id);
-static void ati_remote_disconnect	(struct usb_interface *interface);
-
-/* usb specific object to register with the usb subsystem */
-static struct usb_driver ati_remote_driver = {
-	.name         = "ati_remote",
-	.probe        = ati_remote_probe,
-	.disconnect   = ati_remote_disconnect,
-	.id_table     = ati_remote_table,
-};
-
-/*
- *	ati_remote_dump_input
- */
-static void ati_remote_dump(struct device *dev, unsigned char *data,
-			    unsigned int len)
-{
-	if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
-		dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
-	else if (len == 4)
-		dev_warn(dev, "Weird key %02x %02x %02x %02x\n",
-		     data[0], data[1], data[2], data[3]);
-	else
-		dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
-		     len, data[0], data[1], data[2], data[3], data[4], data[5]);
-}
-
-/*
- *	ati_remote_open
- */
-static int ati_remote_open(struct input_dev *inputdev)
-{
-	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
-
-	/* On first open, submit the read urb which was set up previously. */
-	ati_remote->irq_urb->dev = ati_remote->udev;
-	if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
-		dev_err(&ati_remote->interface->dev,
-			"%s: usb_submit_urb failed!\n", __func__);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/*
- *	ati_remote_close
- */
-static void ati_remote_close(struct input_dev *inputdev)
-{
-	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
-
-	usb_kill_urb(ati_remote->irq_urb);
-}
-
-/*
- *		ati_remote_irq_out
- */
-static void ati_remote_irq_out(struct urb *urb)
-{
-	struct ati_remote *ati_remote = urb->context;
-
-	if (urb->status) {
-		dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
-			__func__, urb->status);
-		return;
-	}
-
-	ati_remote->send_flags |= SEND_FLAG_COMPLETE;
-	wmb();
-	wake_up(&ati_remote->wait);
-}
-
-/*
- *	ati_remote_sendpacket
- *
- *	Used to send device initialization strings
- */
-static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
-{
-	int retval = 0;
-
-	/* Set up out_urb */
-	memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
-	((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
-
-	ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
-	ati_remote->out_urb->dev = ati_remote->udev;
-	ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
-
-	retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
-	if (retval) {
-		dev_dbg(&ati_remote->interface->dev,
-			 "sendpacket: usb_submit_urb failed: %d\n", retval);
-		return retval;
-	}
-
-	wait_event_timeout(ati_remote->wait,
-		((ati_remote->out_urb->status != -EINPROGRESS) ||
-			(ati_remote->send_flags & SEND_FLAG_COMPLETE)),
-		HZ);
-	usb_kill_urb(ati_remote->out_urb);
-
-	return retval;
-}
-
-/*
- *	ati_remote_event_lookup
- */
-static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
-{
-	int i;
-
-	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
-		/*
-		 * Decide if the table entry matches the remote input.
-		 */
-		if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
-		    ((((ati_remote_tbl[i].data1 >> 4) -
-		       (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
-		    (ati_remote_tbl[i].data2 == d2))
-			return i;
-
-	}
-	return -1;
-}
-
-/*
- *	ati_remote_compute_accel
- *
- * Implements acceleration curve for directional control pad
- * If elapsed time since last event is > 1/4 second, user "stopped",
- * so reset acceleration. Otherwise, user is probably holding the control
- * pad down, so we increase acceleration, ramping up over two seconds to
- * a maximum speed.
- */
-static int ati_remote_compute_accel(struct ati_remote *ati_remote)
-{
-	static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
-	unsigned long now = jiffies;
-	int acc;
-
-	if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
-		acc = 1;
-		ati_remote->acc_jiffies = now;
-	}
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
-		acc = accel[0];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
-		acc = accel[1];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
-		acc = accel[2];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
-		acc = accel[3];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
-		acc = accel[4];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
-		acc = accel[5];
-	else
-		acc = accel[6];
-
-	return acc;
-}
-
-/*
- *	ati_remote_report_input
- */
-static void ati_remote_input_report(struct urb *urb)
-{
-	struct ati_remote *ati_remote = urb->context;
-	unsigned char *data= ati_remote->inbuf;
-	struct input_dev *dev = ati_remote->idev;
-	int index, acc;
-	int remote_num;
-
-	/* Deal with strange looking inputs */
-	if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
-		((data[3] & 0x0f) != 0x00) ) {
-		ati_remote_dump(&urb->dev->dev, data, urb->actual_length);
-		return;
-	}
-
-	/* Mask unwanted remote channels.  */
-	/* note: remote_num is 0-based, channel 1 on remote == 0 here */
-	remote_num = (data[3] >> 4) & 0x0f;
-        if (channel_mask & (1 << (remote_num + 1))) {
-		dbginfo(&ati_remote->interface->dev,
-			"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
-			remote_num, data[1], data[2], channel_mask);
-		return;
-	}
-
-	/* Look up event code index in translation table */
-	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
-	if (index < 0) {
-		dev_warn(&ati_remote->interface->dev,
-			 "Unknown input from channel 0x%02x: data %02x,%02x\n",
-			 remote_num, data[1], data[2]);
-		return;
-	}
-	dbginfo(&ati_remote->interface->dev,
-		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
-		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
-
-	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code,
-			ati_remote_tbl[index].value);
-		input_sync(dev);
-
-		ati_remote->old_jiffies = jiffies;
-		return;
-	}
-
-	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
-		unsigned long now = jiffies;
-
-		/* Filter duplicate events which happen "too close" together. */
-		if (ati_remote->old_data[0] == data[1] &&
-		    ati_remote->old_data[1] == data[2] &&
-		    time_before(now, ati_remote->old_jiffies +
-				     msecs_to_jiffies(repeat_filter))) {
-			ati_remote->repeat_count++;
-		} else {
-			ati_remote->repeat_count = 0;
-			ati_remote->first_jiffies = now;
-		}
-
-		ati_remote->old_data[0] = data[1];
-		ati_remote->old_data[1] = data[2];
-		ati_remote->old_jiffies = now;
-
-		/* Ensure we skip at least the 4 first duplicate events (generated
-		 * by a single keypress), and continue skipping until repeat_delay
-		 * msecs have passed
-		 */
-		if (ati_remote->repeat_count > 0 &&
-		    (ati_remote->repeat_count < 5 ||
-		     time_before(now, ati_remote->first_jiffies +
-				      msecs_to_jiffies(repeat_delay))))
-			return;
-
-
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code, 1);
-		input_sync(dev);
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code, 0);
-		input_sync(dev);
-
-	} else {
-
-		/*
-		 * Other event kinds are from the directional control pad, and have an
-		 * acceleration factor applied to them.  Without this acceleration, the
-		 * control pad is mostly unusable.
-		 */
-		acc = ati_remote_compute_accel(ati_remote);
-
-		switch (ati_remote_tbl[index].kind) {
-		case KIND_ACCEL:
-			input_event(dev, ati_remote_tbl[index].type,
-				ati_remote_tbl[index].code,
-				ati_remote_tbl[index].value * acc);
-			break;
-		case KIND_LU:
-			input_report_rel(dev, REL_X, -acc);
-			input_report_rel(dev, REL_Y, -acc);
-			break;
-		case KIND_RU:
-			input_report_rel(dev, REL_X, acc);
-			input_report_rel(dev, REL_Y, -acc);
-			break;
-		case KIND_LD:
-			input_report_rel(dev, REL_X, -acc);
-			input_report_rel(dev, REL_Y, acc);
-			break;
-		case KIND_RD:
-			input_report_rel(dev, REL_X, acc);
-			input_report_rel(dev, REL_Y, acc);
-			break;
-		default:
-			dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
-				ati_remote_tbl[index].kind);
-		}
-		input_sync(dev);
-
-		ati_remote->old_jiffies = jiffies;
-		ati_remote->old_data[0] = data[1];
-		ati_remote->old_data[1] = data[2];
-	}
-}
-
-/*
- *	ati_remote_irq_in
- */
-static void ati_remote_irq_in(struct urb *urb)
-{
-	struct ati_remote *ati_remote = urb->context;
-	int retval;
-
-	switch (urb->status) {
-	case 0:			/* success */
-		ati_remote_input_report(urb);
-		break;
-	case -ECONNRESET:	/* unlink */
-	case -ENOENT:
-	case -ESHUTDOWN:
-		dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
-			__func__);
-		return;
-	default:		/* error */
-		dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
-			__func__, urb->status);
-	}
-
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval)
-		dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
-			__func__, retval);
-}
-
-/*
- *	ati_remote_alloc_buffers
- */
-static int ati_remote_alloc_buffers(struct usb_device *udev,
-				    struct ati_remote *ati_remote)
-{
-	ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
-					       &ati_remote->inbuf_dma);
-	if (!ati_remote->inbuf)
-		return -1;
-
-	ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
-					        &ati_remote->outbuf_dma);
-	if (!ati_remote->outbuf)
-		return -1;
-
-	ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!ati_remote->irq_urb)
-		return -1;
-
-	ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!ati_remote->out_urb)
-		return -1;
-
-	return 0;
-}
-
-/*
- *	ati_remote_free_buffers
- */
-static void ati_remote_free_buffers(struct ati_remote *ati_remote)
-{
-	usb_free_urb(ati_remote->irq_urb);
-	usb_free_urb(ati_remote->out_urb);
-
-	usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
-		ati_remote->inbuf, ati_remote->inbuf_dma);
-
-	usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
-		ati_remote->outbuf, ati_remote->outbuf_dma);
-}
-
-static void ati_remote_input_init(struct ati_remote *ati_remote)
-{
-	struct input_dev *idev = ati_remote->idev;
-	int i;
-
-	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-	idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
-		BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
-	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
-		if (ati_remote_tbl[i].type == EV_KEY)
-			set_bit(ati_remote_tbl[i].code, idev->keybit);
-
-	input_set_drvdata(idev, ati_remote);
-
-	idev->open = ati_remote_open;
-	idev->close = ati_remote_close;
-
-	idev->name = ati_remote->name;
-	idev->phys = ati_remote->phys;
-
-	usb_to_input_id(ati_remote->udev, &idev->id);
-	idev->dev.parent = &ati_remote->udev->dev;
-}
-
-static int ati_remote_initialize(struct ati_remote *ati_remote)
-{
-	struct usb_device *udev = ati_remote->udev;
-	int pipe, maxp;
-
-	init_waitqueue_head(&ati_remote->wait);
-
-	/* Set up irq_urb */
-	pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
-	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
-	usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
-			 maxp, ati_remote_irq_in, ati_remote,
-			 ati_remote->endpoint_in->bInterval);
-	ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
-	ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	/* Set up out_urb */
-	pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
-	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
-	usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
-			 maxp, ati_remote_irq_out, ati_remote,
-			 ati_remote->endpoint_out->bInterval);
-	ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
-	ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	/* send initialization strings */
-	if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
-	    (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
-		dev_err(&ati_remote->interface->dev,
-			 "Initializing ati_remote hardware failed.\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/*
- *	ati_remote_probe
- */
-static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(interface);
-	struct usb_host_interface *iface_host = interface->cur_altsetting;
-	struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
-	struct ati_remote *ati_remote;
-	struct input_dev *input_dev;
-	int err = -ENOMEM;
-
-	if (iface_host->desc.bNumEndpoints != 2) {
-		err("%s: Unexpected desc.bNumEndpoints\n", __func__);
-		return -ENODEV;
-	}
-
-	endpoint_in = &iface_host->endpoint[0].desc;
-	endpoint_out = &iface_host->endpoint[1].desc;
-
-	if (!usb_endpoint_is_int_in(endpoint_in)) {
-		err("%s: Unexpected endpoint_in\n", __func__);
-		return -ENODEV;
-	}
-	if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
-		err("%s: endpoint_in message size==0? \n", __func__);
-		return -ENODEV;
-	}
-
-	ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!ati_remote || !input_dev)
-		goto fail1;
-
-	/* Allocate URB buffers, URBs */
-	if (ati_remote_alloc_buffers(udev, ati_remote))
-		goto fail2;
-
-	ati_remote->endpoint_in = endpoint_in;
-	ati_remote->endpoint_out = endpoint_out;
-	ati_remote->udev = udev;
-	ati_remote->idev = input_dev;
-	ati_remote->interface = interface;
-
-	usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys));
-	strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys));
-
-	if (udev->manufacturer)
-		strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
-
-	if (udev->product)
-		snprintf(ati_remote->name, sizeof(ati_remote->name),
-			 "%s %s", ati_remote->name, udev->product);
-
-	if (!strlen(ati_remote->name))
-		snprintf(ati_remote->name, sizeof(ati_remote->name),
-			DRIVER_DESC "(%04x,%04x)",
-			le16_to_cpu(ati_remote->udev->descriptor.idVendor),
-			le16_to_cpu(ati_remote->udev->descriptor.idProduct));
-
-	ati_remote_input_init(ati_remote);
-
-	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
-	err = ati_remote_initialize(ati_remote);
-	if (err)
-		goto fail3;
-
-	/* Set up and register input device */
-	err = input_register_device(ati_remote->idev);
-	if (err)
-		goto fail3;
-
-	usb_set_intfdata(interface, ati_remote);
-	return 0;
-
- fail3:	usb_kill_urb(ati_remote->irq_urb);
-	usb_kill_urb(ati_remote->out_urb);
- fail2:	ati_remote_free_buffers(ati_remote);
- fail1:	input_free_device(input_dev);
-	kfree(ati_remote);
-	return err;
-}
-
-/*
- *	ati_remote_disconnect
- */
-static void ati_remote_disconnect(struct usb_interface *interface)
-{
-	struct ati_remote *ati_remote;
-
-	ati_remote = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
-	if (!ati_remote) {
-		dev_warn(&interface->dev, "%s - null device?\n", __func__);
-		return;
-	}
-
-	usb_kill_urb(ati_remote->irq_urb);
-	usb_kill_urb(ati_remote->out_urb);
-	input_unregister_device(ati_remote->idev);
-	ati_remote_free_buffers(ati_remote);
-	kfree(ati_remote);
-}
-
-/*
- *	ati_remote_init
- */
-static int __init ati_remote_init(void)
-{
-	int result;
-
-	result = usb_register(&ati_remote_driver);
-	if (result)
-		printk(KERN_ERR KBUILD_MODNAME
-		       ": usb_register error #%d\n", result);
-	else
-		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-		       DRIVER_DESC "\n");
-
-	return result;
-}
-
-/*
- *	ati_remote_exit
- */
-static void __exit ati_remote_exit(void)
-{
-	usb_deregister(&ati_remote_driver);
-}
-
-/*
- *	module specification
- */
-
-module_init(ati_remote_init);
-module_exit(ati_remote_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 7f03142..4a5b4a6 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -4,8 +4,8 @@ menuconfig RC_CORE
 	default INPUT
 	---help---
 	  Enable support for Remote Controllers on Linux. This is
-	  needed in order to support several video capture adapters.
-	  Currently, all supported devices use InfraRed.
+	  needed in order to support several video capture adapters,
+	  standalone IR receivers/transmitters, and RF receivers.
 
 	  Enable this option if you have a video capture board even
 	  if you don't need IR, as otherwise, you may not be able to
@@ -97,6 +97,22 @@ config IR_LIRC_CODEC
 	   Enable this option to pass raw IR to and from userspace via
 	   the LIRC interface.
 
+config RC_ATI_REMOTE
+	tristate "ATI / X10 USB RF remote control"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	   Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
+	   These are RF remotes with USB receivers.
+	   The ATI remote comes with many of ATI's All-In-Wonder video cards.
+	   The X10 "Lola" remote is available at:
+	      <http://www.x10.com/products/lola_sg1.htm>
+	   This driver provides mouse pointer, left and right mouse buttons,
+	   and maps all the other remote buttons to keypress events.
+
+	   To compile this driver as a module, choose M here: the module will be
+	   called ati_remote.
+
 config IR_ENE
 	tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
 	depends on PNP
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index c6cfe70..d8727e3 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
 obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 
 # stand-alone IR receivers/transmitters
+obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
 obj-$(CONFIG_IR_IMON) += imon.o
 obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
 obj-$(CONFIG_IR_MCEUSB) += mceusb.o
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
new file mode 100644
index 0000000..bce5712
--- /dev/null
+++ b/drivers/media/rc/ati_remote.c
@@ -0,0 +1,867 @@
+/*
+ *  USB ATI Remote support
+ *
+ *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
+ *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
+ *
+ *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
+ *  porting to the 2.6 kernel interfaces, along with other modification
+ *  to better match the style of the existing usb/input drivers.  However, the
+ *  protocol and hardware handling is essentially unchanged from 2.1.1.
+ *
+ *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
+ *  Vojtech Pavlik.
+ *
+ *  Changes:
+ *
+ *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.0
+ *  Jun 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.1
+ *            Added key repeat support contributed by:
+ *                Vincent Vanackere <vanackere@lif.univ-mrs.fr>
+ *            Added support for the "Lola" remote contributed by:
+ *                Seth Cohn <sethcohn@yahoo.com>
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * Hardware & software notes
+ *
+ * These remote controls are distributed by ATI as part of their
+ * "All-In-Wonder" video card packages.  The receiver self-identifies as a
+ * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
+ *
+ * The "Lola" remote is available from X10.  See:
+ *    http://www.x10.com/products/lola_sg1.htm
+ * The Lola is similar to the ATI remote but has no mouse support, and slightly
+ * different keys.
+ *
+ * It is possible to use multiple receivers and remotes on multiple computers
+ * simultaneously by configuring them to use specific channels.
+ *
+ * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
+ * Actually, it may even support more, at least in some revisions of the
+ * hardware.
+ *
+ * Each remote can be configured to transmit on one channel as follows:
+ *   - Press and hold the "hand icon" button.
+ *   - When the red LED starts to blink, let go of the "hand icon" button.
+ *   - When it stops blinking, input the channel code as two digits, from 01
+ *     to 16, and press the hand icon again.
+ *
+ * The timing can be a little tricky.  Try loading the module with debug=1
+ * to have the kernel print out messages about the remote control number
+ * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
+ *
+ * The driver has a "channel_mask" parameter. This bitmask specifies which
+ * channels will be ignored by the module.  To mask out channels, just add
+ * all the 2^channel_number values together.
+ *
+ * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
+ * ignore signals coming from remote controls transmitting on channel 4, but
+ * accept all other channels.
+ *
+ * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
+ * ignored.
+ *
+ * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
+ * parameter are unused.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb/input.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+
+/*
+ * Module and Version Information, Module Parameters
+ */
+
+#define ATI_REMOTE_VENDOR_ID		0x0bc7
+#define LOLA_REMOTE_PRODUCT_ID		0x0002
+#define LOLA2_REMOTE_PRODUCT_ID		0x0003
+#define ATI_REMOTE_PRODUCT_ID		0x0004
+#define NVIDIA_REMOTE_PRODUCT_ID	0x0005
+#define MEDION_REMOTE_PRODUCT_ID	0x0006
+
+#define DRIVER_VERSION	        "2.2.1"
+#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
+#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
+
+#define NAME_BUFSIZE      80    /* size of product name, path buffers */
+#define DATA_BUFSIZE      63    /* size of URB data buffers */
+
+/*
+ * Duplicate event filtering time.
+ * Sequential, identical KIND_FILTERED inputs with less than
+ * FILTER_TIME milliseconds between them are considered as repeat
+ * events. The hardware generates 5 events for the first keypress
+ * and we have to take this into account for an accurate repeat
+ * behaviour.
+ */
+#define FILTER_TIME	60 /* msec */
+#define REPEAT_DELAY	500 /* msec */
+
+static unsigned long channel_mask;
+module_param(channel_mask, ulong, 0644);
+MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+static int repeat_filter = FILTER_TIME;
+module_param(repeat_filter, int, 0644);
+MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
+
+static int repeat_delay = REPEAT_DELAY;
+module_param(repeat_delay, int, 0644);
+MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec");
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+#undef err
+#define err(format, arg...) printk(KERN_ERR format , ## arg)
+
+static struct usb_device_id ati_remote_table[] = {
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
+	{}	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ati_remote_table);
+
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a)	((unsigned char)((a) >> 8))
+#define LO(a)	((unsigned char)((a) & 0xff))
+
+#define SEND_FLAG_IN_PROGRESS	1
+#define SEND_FLAG_COMPLETE	2
+
+/* Device initialization strings */
+static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
+static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
+
+struct ati_remote {
+	struct input_dev *idev;
+	struct usb_device *udev;
+	struct usb_interface *interface;
+
+	struct urb *irq_urb;
+	struct urb *out_urb;
+	struct usb_endpoint_descriptor *endpoint_in;
+	struct usb_endpoint_descriptor *endpoint_out;
+	unsigned char *inbuf;
+	unsigned char *outbuf;
+	dma_addr_t inbuf_dma;
+	dma_addr_t outbuf_dma;
+
+	unsigned char old_data[2];  /* Detect duplicate events */
+	unsigned long old_jiffies;
+	unsigned long acc_jiffies;  /* handle acceleration */
+	unsigned long first_jiffies;
+
+	unsigned int repeat_count;
+
+	char name[NAME_BUFSIZE];
+	char phys[NAME_BUFSIZE];
+
+	wait_queue_head_t wait;
+	int send_flags;
+};
+
+/* "Kinds" of messages sent from the hardware to the driver. */
+#define KIND_END        0
+#define KIND_LITERAL    1   /* Simply pass to input system */
+#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
+#define KIND_LU         3   /* Directional keypad diagonals - left up, */
+#define KIND_RU         4   /*   right up,  */
+#define KIND_LD         5   /*   left down, */
+#define KIND_RD         6   /*   right down */
+#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
+
+/* Translation table from hardware messages to input events. */
+static const struct {
+	short kind;
+	unsigned char data1, data2;
+	int type;
+	unsigned int code;
+	int value;
+}  ati_remote_tbl[] = {
+	/* Directional control pad axes */
+	{KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},	 /* left */
+	{KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
+	{KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},	 /* up */
+	{KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
+	/* Directional control pad diagonals */
+	{KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
+	{KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
+	{KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
+	{KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
+
+	/* "Mouse button" buttons */
+	{KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
+	{KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
+	{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
+	{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
+
+	/* Artificial "doubleclick" events are generated by the hardware.
+	 * They are mapped to the "side" and "extra" mouse buttons here. */
+	{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
+	{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
+
+	/* keyboard. */
+	{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
+	{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
+	{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
+	{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
+	{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
+	{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
+	{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
+	{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
+	{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
+	{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
+	{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
+	{KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
+	{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
+	{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
+	{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
+	{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
+
+	/* "special" keys */
+	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
+	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
+	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
+	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
+	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
+	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
+	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
+	{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
+	{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
+	{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
+	{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
+	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
+	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
+	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
+	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
+	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
+	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
+	{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
+	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
+	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
+	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
+	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
+	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
+	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
+	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
+	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
+	{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
+	{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
+	{KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
+	{KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
+	{KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
+	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
+
+	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
+};
+
+/* Local function prototypes */
+static int ati_remote_open		(struct input_dev *inputdev);
+static void ati_remote_close		(struct input_dev *inputdev);
+static int ati_remote_sendpacket	(struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
+static void ati_remote_irq_out		(struct urb *urb);
+static void ati_remote_irq_in		(struct urb *urb);
+static void ati_remote_input_report	(struct urb *urb);
+static int ati_remote_initialize	(struct ati_remote *ati_remote);
+static int ati_remote_probe		(struct usb_interface *interface, const struct usb_device_id *id);
+static void ati_remote_disconnect	(struct usb_interface *interface);
+
+/* usb specific object to register with the usb subsystem */
+static struct usb_driver ati_remote_driver = {
+	.name         = "ati_remote",
+	.probe        = ati_remote_probe,
+	.disconnect   = ati_remote_disconnect,
+	.id_table     = ati_remote_table,
+};
+
+/*
+ *	ati_remote_dump_input
+ */
+static void ati_remote_dump(struct device *dev, unsigned char *data,
+			    unsigned int len)
+{
+	if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
+		dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
+	else if (len == 4)
+		dev_warn(dev, "Weird key %02x %02x %02x %02x\n",
+		     data[0], data[1], data[2], data[3]);
+	else
+		dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
+		     len, data[0], data[1], data[2], data[3], data[4], data[5]);
+}
+
+/*
+ *	ati_remote_open
+ */
+static int ati_remote_open(struct input_dev *inputdev)
+{
+	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+
+	/* On first open, submit the read urb which was set up previously. */
+	ati_remote->irq_urb->dev = ati_remote->udev;
+	if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
+		dev_err(&ati_remote->interface->dev,
+			"%s: usb_submit_urb failed!\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ *	ati_remote_close
+ */
+static void ati_remote_close(struct input_dev *inputdev)
+{
+	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+
+	usb_kill_urb(ati_remote->irq_urb);
+}
+
+/*
+ *		ati_remote_irq_out
+ */
+static void ati_remote_irq_out(struct urb *urb)
+{
+	struct ati_remote *ati_remote = urb->context;
+
+	if (urb->status) {
+		dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
+			__func__, urb->status);
+		return;
+	}
+
+	ati_remote->send_flags |= SEND_FLAG_COMPLETE;
+	wmb();
+	wake_up(&ati_remote->wait);
+}
+
+/*
+ *	ati_remote_sendpacket
+ *
+ *	Used to send device initialization strings
+ */
+static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
+{
+	int retval = 0;
+
+	/* Set up out_urb */
+	memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
+	((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
+
+	ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
+	ati_remote->out_urb->dev = ati_remote->udev;
+	ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
+
+	retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
+	if (retval) {
+		dev_dbg(&ati_remote->interface->dev,
+			 "sendpacket: usb_submit_urb failed: %d\n", retval);
+		return retval;
+	}
+
+	wait_event_timeout(ati_remote->wait,
+		((ati_remote->out_urb->status != -EINPROGRESS) ||
+			(ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+		HZ);
+	usb_kill_urb(ati_remote->out_urb);
+
+	return retval;
+}
+
+/*
+ *	ati_remote_event_lookup
+ */
+static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
+{
+	int i;
+
+	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
+		/*
+		 * Decide if the table entry matches the remote input.
+		 */
+		if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
+		    ((((ati_remote_tbl[i].data1 >> 4) -
+		       (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
+		    (ati_remote_tbl[i].data2 == d2))
+			return i;
+
+	}
+	return -1;
+}
+
+/*
+ *	ati_remote_compute_accel
+ *
+ * Implements acceleration curve for directional control pad
+ * If elapsed time since last event is > 1/4 second, user "stopped",
+ * so reset acceleration. Otherwise, user is probably holding the control
+ * pad down, so we increase acceleration, ramping up over two seconds to
+ * a maximum speed.
+ */
+static int ati_remote_compute_accel(struct ati_remote *ati_remote)
+{
+	static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
+	unsigned long now = jiffies;
+	int acc;
+
+	if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
+		acc = 1;
+		ati_remote->acc_jiffies = now;
+	}
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
+		acc = accel[0];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
+		acc = accel[1];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
+		acc = accel[2];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
+		acc = accel[3];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
+		acc = accel[4];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
+		acc = accel[5];
+	else
+		acc = accel[6];
+
+	return acc;
+}
+
+/*
+ *	ati_remote_report_input
+ */
+static void ati_remote_input_report(struct urb *urb)
+{
+	struct ati_remote *ati_remote = urb->context;
+	unsigned char *data= ati_remote->inbuf;
+	struct input_dev *dev = ati_remote->idev;
+	int index, acc;
+	int remote_num;
+
+	/* Deal with strange looking inputs */
+	if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
+		((data[3] & 0x0f) != 0x00) ) {
+		ati_remote_dump(&urb->dev->dev, data, urb->actual_length);
+		return;
+	}
+
+	/* Mask unwanted remote channels.  */
+	/* note: remote_num is 0-based, channel 1 on remote == 0 here */
+	remote_num = (data[3] >> 4) & 0x0f;
+        if (channel_mask & (1 << (remote_num + 1))) {
+		dbginfo(&ati_remote->interface->dev,
+			"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
+			remote_num, data[1], data[2], channel_mask);
+		return;
+	}
+
+	/* Look up event code index in translation table */
+	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
+	if (index < 0) {
+		dev_warn(&ati_remote->interface->dev,
+			 "Unknown input from channel 0x%02x: data %02x,%02x\n",
+			 remote_num, data[1], data[2]);
+		return;
+	}
+	dbginfo(&ati_remote->interface->dev,
+		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
+		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
+
+	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code,
+			ati_remote_tbl[index].value);
+		input_sync(dev);
+
+		ati_remote->old_jiffies = jiffies;
+		return;
+	}
+
+	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
+		unsigned long now = jiffies;
+
+		/* Filter duplicate events which happen "too close" together. */
+		if (ati_remote->old_data[0] == data[1] &&
+		    ati_remote->old_data[1] == data[2] &&
+		    time_before(now, ati_remote->old_jiffies +
+				     msecs_to_jiffies(repeat_filter))) {
+			ati_remote->repeat_count++;
+		} else {
+			ati_remote->repeat_count = 0;
+			ati_remote->first_jiffies = now;
+		}
+
+		ati_remote->old_data[0] = data[1];
+		ati_remote->old_data[1] = data[2];
+		ati_remote->old_jiffies = now;
+
+		/* Ensure we skip at least the 4 first duplicate events (generated
+		 * by a single keypress), and continue skipping until repeat_delay
+		 * msecs have passed
+		 */
+		if (ati_remote->repeat_count > 0 &&
+		    (ati_remote->repeat_count < 5 ||
+		     time_before(now, ati_remote->first_jiffies +
+				      msecs_to_jiffies(repeat_delay))))
+			return;
+
+
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code, 1);
+		input_sync(dev);
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code, 0);
+		input_sync(dev);
+
+	} else {
+
+		/*
+		 * Other event kinds are from the directional control pad, and have an
+		 * acceleration factor applied to them.  Without this acceleration, the
+		 * control pad is mostly unusable.
+		 */
+		acc = ati_remote_compute_accel(ati_remote);
+
+		switch (ati_remote_tbl[index].kind) {
+		case KIND_ACCEL:
+			input_event(dev, ati_remote_tbl[index].type,
+				ati_remote_tbl[index].code,
+				ati_remote_tbl[index].value * acc);
+			break;
+		case KIND_LU:
+			input_report_rel(dev, REL_X, -acc);
+			input_report_rel(dev, REL_Y, -acc);
+			break;
+		case KIND_RU:
+			input_report_rel(dev, REL_X, acc);
+			input_report_rel(dev, REL_Y, -acc);
+			break;
+		case KIND_LD:
+			input_report_rel(dev, REL_X, -acc);
+			input_report_rel(dev, REL_Y, acc);
+			break;
+		case KIND_RD:
+			input_report_rel(dev, REL_X, acc);
+			input_report_rel(dev, REL_Y, acc);
+			break;
+		default:
+			dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
+				ati_remote_tbl[index].kind);
+		}
+		input_sync(dev);
+
+		ati_remote->old_jiffies = jiffies;
+		ati_remote->old_data[0] = data[1];
+		ati_remote->old_data[1] = data[2];
+	}
+}
+
+/*
+ *	ati_remote_irq_in
+ */
+static void ati_remote_irq_in(struct urb *urb)
+{
+	struct ati_remote *ati_remote = urb->context;
+	int retval;
+
+	switch (urb->status) {
+	case 0:			/* success */
+		ati_remote_input_report(urb);
+		break;
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
+			__func__);
+		return;
+	default:		/* error */
+		dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
+			__func__, urb->status);
+	}
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
+			__func__, retval);
+}
+
+/*
+ *	ati_remote_alloc_buffers
+ */
+static int ati_remote_alloc_buffers(struct usb_device *udev,
+				    struct ati_remote *ati_remote)
+{
+	ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
+					       &ati_remote->inbuf_dma);
+	if (!ati_remote->inbuf)
+		return -1;
+
+	ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
+					        &ati_remote->outbuf_dma);
+	if (!ati_remote->outbuf)
+		return -1;
+
+	ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ati_remote->irq_urb)
+		return -1;
+
+	ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ati_remote->out_urb)
+		return -1;
+
+	return 0;
+}
+
+/*
+ *	ati_remote_free_buffers
+ */
+static void ati_remote_free_buffers(struct ati_remote *ati_remote)
+{
+	usb_free_urb(ati_remote->irq_urb);
+	usb_free_urb(ati_remote->out_urb);
+
+	usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
+		ati_remote->inbuf, ati_remote->inbuf_dma);
+
+	usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
+		ati_remote->outbuf, ati_remote->outbuf_dma);
+}
+
+static void ati_remote_input_init(struct ati_remote *ati_remote)
+{
+	struct input_dev *idev = ati_remote->idev;
+	int i;
+
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+	idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+		BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
+	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
+		if (ati_remote_tbl[i].type == EV_KEY)
+			set_bit(ati_remote_tbl[i].code, idev->keybit);
+
+	input_set_drvdata(idev, ati_remote);
+
+	idev->open = ati_remote_open;
+	idev->close = ati_remote_close;
+
+	idev->name = ati_remote->name;
+	idev->phys = ati_remote->phys;
+
+	usb_to_input_id(ati_remote->udev, &idev->id);
+	idev->dev.parent = &ati_remote->udev->dev;
+}
+
+static int ati_remote_initialize(struct ati_remote *ati_remote)
+{
+	struct usb_device *udev = ati_remote->udev;
+	int pipe, maxp;
+
+	init_waitqueue_head(&ati_remote->wait);
+
+	/* Set up irq_urb */
+	pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+	usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
+			 maxp, ati_remote_irq_in, ati_remote,
+			 ati_remote->endpoint_in->bInterval);
+	ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
+	ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* Set up out_urb */
+	pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+	usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
+			 maxp, ati_remote_irq_out, ati_remote,
+			 ati_remote->endpoint_out->bInterval);
+	ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
+	ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* send initialization strings */
+	if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
+	    (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
+		dev_err(&ati_remote->interface->dev,
+			 "Initializing ati_remote hardware failed.\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ *	ati_remote_probe
+ */
+static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *iface_host = interface->cur_altsetting;
+	struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
+	struct ati_remote *ati_remote;
+	struct input_dev *input_dev;
+	int err = -ENOMEM;
+
+	if (iface_host->desc.bNumEndpoints != 2) {
+		err("%s: Unexpected desc.bNumEndpoints\n", __func__);
+		return -ENODEV;
+	}
+
+	endpoint_in = &iface_host->endpoint[0].desc;
+	endpoint_out = &iface_host->endpoint[1].desc;
+
+	if (!usb_endpoint_is_int_in(endpoint_in)) {
+		err("%s: Unexpected endpoint_in\n", __func__);
+		return -ENODEV;
+	}
+	if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
+		err("%s: endpoint_in message size==0? \n", __func__);
+		return -ENODEV;
+	}
+
+	ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ati_remote || !input_dev)
+		goto fail1;
+
+	/* Allocate URB buffers, URBs */
+	if (ati_remote_alloc_buffers(udev, ati_remote))
+		goto fail2;
+
+	ati_remote->endpoint_in = endpoint_in;
+	ati_remote->endpoint_out = endpoint_out;
+	ati_remote->udev = udev;
+	ati_remote->idev = input_dev;
+	ati_remote->interface = interface;
+
+	usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys));
+	strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys));
+
+	if (udev->manufacturer)
+		strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
+
+	if (udev->product)
+		snprintf(ati_remote->name, sizeof(ati_remote->name),
+			 "%s %s", ati_remote->name, udev->product);
+
+	if (!strlen(ati_remote->name))
+		snprintf(ati_remote->name, sizeof(ati_remote->name),
+			DRIVER_DESC "(%04x,%04x)",
+			le16_to_cpu(ati_remote->udev->descriptor.idVendor),
+			le16_to_cpu(ati_remote->udev->descriptor.idProduct));
+
+	ati_remote_input_init(ati_remote);
+
+	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
+	err = ati_remote_initialize(ati_remote);
+	if (err)
+		goto fail3;
+
+	/* Set up and register input device */
+	err = input_register_device(ati_remote->idev);
+	if (err)
+		goto fail3;
+
+	usb_set_intfdata(interface, ati_remote);
+	return 0;
+
+ fail3:	usb_kill_urb(ati_remote->irq_urb);
+	usb_kill_urb(ati_remote->out_urb);
+ fail2:	ati_remote_free_buffers(ati_remote);
+ fail1:	input_free_device(input_dev);
+	kfree(ati_remote);
+	return err;
+}
+
+/*
+ *	ati_remote_disconnect
+ */
+static void ati_remote_disconnect(struct usb_interface *interface)
+{
+	struct ati_remote *ati_remote;
+
+	ati_remote = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+	if (!ati_remote) {
+		dev_warn(&interface->dev, "%s - null device?\n", __func__);
+		return;
+	}
+
+	usb_kill_urb(ati_remote->irq_urb);
+	usb_kill_urb(ati_remote->out_urb);
+	input_unregister_device(ati_remote->idev);
+	ati_remote_free_buffers(ati_remote);
+	kfree(ati_remote);
+}
+
+/*
+ *	ati_remote_init
+ */
+static int __init ati_remote_init(void)
+{
+	int result;
+
+	result = usb_register(&ati_remote_driver);
+	if (result)
+		printk(KERN_ERR KBUILD_MODNAME
+		       ": usb_register error #%d\n", result);
+	else
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+		       DRIVER_DESC "\n");
+
+	return result;
+}
+
+/*
+ *	ati_remote_exit
+ */
+static void __exit ati_remote_exit(void)
+{
+	usb_deregister(&ati_remote_driver);
+}
+
+/*
+ *	module specification
+ */
+
+module_init(ati_remote_init);
+module_exit(ati_remote_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
-- 
1.7.4.4


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

* [PATCH 2/7] [media] ati_remote: migrate to the rc subsystem
  2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
  2011-08-06 22:18         ` [PATCH 1/7] [media] move ati_remote driver from input/misc to media/rc Anssi Hannula
@ 2011-08-06 22:18         ` Anssi Hannula
  2011-08-06 22:18         ` [PATCH 3/7] [media] ati_remote: parent input devices to usb interface Anssi Hannula
                           ` (4 subsequent siblings)
  6 siblings, 0 replies; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 22:18 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-media, linux-input, linux-kernel

Migrate the ATI/X10 RF remote driver to the rc subsystem, allowing the
use of its keymap handling capabilities.

The mouse handling is kept in-driver and now appears as a separate input
device which can be disabled with a new module option (autodetection
would be possible based on receiver, but it wouldn't account for cases
where a remote with mouse is used with a receiver that came with a
remote without mouse).

The remotes have 4-bit programmable IDs, so it would be possible to
support simultaneous use of multiple remotes with different keymaps with
each remote appearing as a separate input device; however,
implementation of that is left for a later date.

The driver previously transmitted all events as keydown/keyup
combinations. That behavior is kept (at least for now) to avoid the
current issue with rc-core where repeat events continue after a button
is released, since that would be a clear regression for this driver.

The keycode mangling algorithm is kept the same, so the new external
keymap has the same values as the old static table.

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
---
 drivers/media/rc/Kconfig              |    1 +
 drivers/media/rc/ati_remote.c         |  262 ++++++++++++++++++++-------------
 drivers/media/rc/keymaps/Makefile     |    1 +
 drivers/media/rc/keymaps/rc-ati-x10.c |  103 +++++++++++++
 include/media/rc-map.h                |    1 +
 5 files changed, 269 insertions(+), 99 deletions(-)
 create mode 100644 drivers/media/rc/keymaps/rc-ati-x10.c

diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 4a5b4a6..26937b2 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -100,6 +100,7 @@ config IR_LIRC_CODEC
 config RC_ATI_REMOTE
 	tristate "ATI / X10 USB RF remote control"
 	depends on USB_ARCH_HAS_HCD
+	depends on RC_CORE
 	select USB
 	help
 	   Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index bce5712..a1df21f 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -1,6 +1,7 @@
 /*
  *  USB ATI Remote support
  *
+ *                Copyright (c) 2011 Anssi Hannula <anssi.hannula@iki.fi>
  *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
  *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
  *
@@ -90,9 +91,11 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/usb/input.h>
 #include <linux/wait.h>
 #include <linux/jiffies.h>
+#include <media/rc-core.h>
 
 /*
  * Module and Version Information, Module Parameters
@@ -139,6 +142,10 @@ static int repeat_delay = REPEAT_DELAY;
 module_param(repeat_delay, int, 0644);
 MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec");
 
+static bool mouse = true;
+module_param(mouse, bool, 0444);
+MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes");
+
 #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
 #undef err
 #define err(format, arg...) printk(KERN_ERR format , ## arg)
@@ -167,6 +174,7 @@ static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
 
 struct ati_remote {
 	struct input_dev *idev;
+	struct rc_dev *rdev;
 	struct usb_device *udev;
 	struct usb_interface *interface;
 
@@ -186,11 +194,16 @@ struct ati_remote {
 
 	unsigned int repeat_count;
 
-	char name[NAME_BUFSIZE];
-	char phys[NAME_BUFSIZE];
+	char rc_name[NAME_BUFSIZE];
+	char rc_phys[NAME_BUFSIZE];
+	char mouse_name[NAME_BUFSIZE];
+	char mouse_phys[NAME_BUFSIZE];
 
 	wait_queue_head_t wait;
 	int send_flags;
+
+	int users; /* 0-2, users are rc and input */
+	struct mutex open_mutex;
 };
 
 /* "Kinds" of messages sent from the hardware to the driver. */
@@ -233,64 +246,11 @@ static const struct {
 	{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
 	{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
 
-	/* keyboard. */
-	{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
-	{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
-	{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
-	{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
-	{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
-	{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
-	{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
-	{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
-	{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
-	{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
-	{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
-	{KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
-	{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
-	{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
-	{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
-	{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
-
-	/* "special" keys */
-	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
-	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
-	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
-	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
-	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
-	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
-	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
-	{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
-	{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
-	{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
-	{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
-	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
-	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
-	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
-	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
-	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
-	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
-	{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
-	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
-	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
-	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
-	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
-	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
-	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
-	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
-	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
-	{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
-	{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
-	{KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
-	{KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
-	{KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
-	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
-
+	/* Non-mouse events are handled by rc-core */
 	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
 };
 
 /* Local function prototypes */
-static int ati_remote_open		(struct input_dev *inputdev);
-static void ati_remote_close		(struct input_dev *inputdev);
 static int ati_remote_sendpacket	(struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
 static void ati_remote_irq_out		(struct urb *urb);
 static void ati_remote_irq_in		(struct urb *urb);
@@ -326,29 +286,60 @@ static void ati_remote_dump(struct device *dev, unsigned char *data,
 /*
  *	ati_remote_open
  */
-static int ati_remote_open(struct input_dev *inputdev)
+static int ati_remote_open(struct ati_remote *ati_remote)
 {
-	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+	int err = 0;
+
+	mutex_lock(&ati_remote->open_mutex);
+
+	if (ati_remote->users++ != 0)
+		goto out; /* one was already active */
 
 	/* On first open, submit the read urb which was set up previously. */
 	ati_remote->irq_urb->dev = ati_remote->udev;
 	if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
 		dev_err(&ati_remote->interface->dev,
 			"%s: usb_submit_urb failed!\n", __func__);
-		return -EIO;
+		err = -EIO;
 	}
 
-	return 0;
+out:	mutex_unlock(&ati_remote->open_mutex);
+	return err;
 }
 
 /*
  *	ati_remote_close
  */
-static void ati_remote_close(struct input_dev *inputdev)
+static void ati_remote_close(struct ati_remote *ati_remote)
+{
+	mutex_lock(&ati_remote->open_mutex);
+	if (--ati_remote->users == 0)
+		usb_kill_urb(ati_remote->irq_urb);
+	mutex_unlock(&ati_remote->open_mutex);
+}
+
+static int ati_remote_input_open(struct input_dev *inputdev)
 {
 	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+	return ati_remote_open(ati_remote);
+}
 
-	usb_kill_urb(ati_remote->irq_urb);
+static void ati_remote_input_close(struct input_dev *inputdev)
+{
+	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+	ati_remote_close(ati_remote);
+}
+
+static int ati_remote_rc_open(struct rc_dev *rdev)
+{
+	struct ati_remote *ati_remote = rdev->priv;
+	return ati_remote_open(ati_remote);
+}
+
+static void ati_remote_rc_close(struct rc_dev *rdev)
+{
+	struct ati_remote *ati_remote = rdev->priv;
+	ati_remote_close(ati_remote);
 }
 
 /*
@@ -413,10 +404,8 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
 		/*
 		 * Decide if the table entry matches the remote input.
 		 */
-		if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
-		    ((((ati_remote_tbl[i].data1 >> 4) -
-		       (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
-		    (ati_remote_tbl[i].data2 == d2))
+		if (ati_remote_tbl[i].data1 == d1 &&
+		    ati_remote_tbl[i].data2 == d2)
 			return i;
 
 	}
@@ -468,8 +457,10 @@ static void ati_remote_input_report(struct urb *urb)
 	struct ati_remote *ati_remote = urb->context;
 	unsigned char *data= ati_remote->inbuf;
 	struct input_dev *dev = ati_remote->idev;
-	int index, acc;
+	int index = -1;
+	int acc;
 	int remote_num;
+	unsigned char scancode[2];
 
 	/* Deal with strange looking inputs */
 	if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
@@ -488,19 +479,26 @@ static void ati_remote_input_report(struct urb *urb)
 		return;
 	}
 
-	/* Look up event code index in translation table */
-	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
-	if (index < 0) {
-		dev_warn(&ati_remote->interface->dev,
-			 "Unknown input from channel 0x%02x: data %02x,%02x\n",
-			 remote_num, data[1], data[2]);
-		return;
-	}
-	dbginfo(&ati_remote->interface->dev,
-		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
-		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
+	scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f));
 
-	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
+	scancode[1] = data[2];
+
+	/* Look up event code index in mouse translation table. */
+	index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]);
+
+	if (index >= 0) {
+		dbginfo(&ati_remote->interface->dev,
+			"channel 0x%02x; mouse data %02x,%02x; index %d; keycode %d\n",
+			remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
+		if (!dev)
+			return; /* no mouse device */
+	} else
+		dbginfo(&ati_remote->interface->dev,
+			"channel 0x%02x; key data %02x,%02x, scancode %02x,%02x\n",
+			remote_num, data[1], data[2], scancode[0], scancode[1]);
+
+
+	if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) {
 		input_event(dev, ati_remote_tbl[index].type,
 			ati_remote_tbl[index].code,
 			ati_remote_tbl[index].value);
@@ -510,7 +508,7 @@ static void ati_remote_input_report(struct urb *urb)
 		return;
 	}
 
-	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
+	if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) {
 		unsigned long now = jiffies;
 
 		/* Filter duplicate events which happen "too close" together. */
@@ -538,6 +536,19 @@ static void ati_remote_input_report(struct urb *urb)
 				      msecs_to_jiffies(repeat_delay))))
 			return;
 
+		if (index < 0) {
+			/* Not a mouse event, hand it to rc-core. */
+			u32 rc_code = (scancode[0] << 8) | scancode[1];
+
+			/*
+			 * We don't use the rc-core repeat handling yet as
+			 * it would cause ghost repeats which would be a
+			 * regression for this driver.
+			 */
+			rc_keydown_notimeout(ati_remote->rdev, rc_code, 0);
+			rc_keyup(ati_remote->rdev);
+			return;
+		}
 
 		input_event(dev, ati_remote_tbl[index].type,
 			ati_remote_tbl[index].code, 1);
@@ -675,16 +686,37 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
 
 	input_set_drvdata(idev, ati_remote);
 
-	idev->open = ati_remote_open;
-	idev->close = ati_remote_close;
+	idev->open = ati_remote_input_open;
+	idev->close = ati_remote_input_close;
 
-	idev->name = ati_remote->name;
-	idev->phys = ati_remote->phys;
+	idev->name = ati_remote->mouse_name;
+	idev->phys = ati_remote->mouse_phys;
 
 	usb_to_input_id(ati_remote->udev, &idev->id);
 	idev->dev.parent = &ati_remote->udev->dev;
 }
 
+static void ati_remote_rc_init(struct ati_remote *ati_remote)
+{
+	struct rc_dev *rdev = ati_remote->rdev;
+
+	rdev->priv = ati_remote;
+	rdev->driver_type = RC_DRIVER_SCANCODE;
+	rdev->allowed_protos = RC_TYPE_OTHER;
+	rdev->driver_name = "ati_remote";
+
+	rdev->open = ati_remote_rc_open;
+	rdev->close = ati_remote_rc_close;
+
+	rdev->input_name = ati_remote->rc_name;
+	rdev->input_phys = ati_remote->rc_phys;
+
+	usb_to_input_id(ati_remote->udev, &rdev->input_id);
+	rdev->dev.parent = &ati_remote->udev->dev;
+
+	rdev->map_name = RC_MAP_ATI_X10;
+}
+
 static int ati_remote_initialize(struct ati_remote *ati_remote)
 {
 	struct usb_device *udev = ati_remote->udev;
@@ -735,6 +767,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
 	struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
 	struct ati_remote *ati_remote;
 	struct input_dev *input_dev;
+	struct rc_dev *rc_dev;
 	int err = -ENOMEM;
 
 	if (iface_host->desc.bNumEndpoints != 2) {
@@ -755,8 +788,8 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
 	}
 
 	ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!ati_remote || !input_dev)
+	rc_dev = rc_allocate_device();
+	if (!ati_remote || !rc_dev)
 		goto fail1;
 
 	/* Allocate URB buffers, URBs */
@@ -766,44 +799,73 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
 	ati_remote->endpoint_in = endpoint_in;
 	ati_remote->endpoint_out = endpoint_out;
 	ati_remote->udev = udev;
-	ati_remote->idev = input_dev;
+	ati_remote->rdev = rc_dev;
 	ati_remote->interface = interface;
 
-	usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys));
-	strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys));
+	usb_make_path(udev, ati_remote->rc_phys, sizeof(ati_remote->rc_phys));
+	strlcpy(ati_remote->mouse_phys, ati_remote->rc_phys,
+		sizeof(ati_remote->mouse_phys));
+
+	strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys));
+	strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys));
 
 	if (udev->manufacturer)
-		strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
+		strlcpy(ati_remote->rc_name, udev->manufacturer,
+			sizeof(ati_remote->rc_name));
 
 	if (udev->product)
-		snprintf(ati_remote->name, sizeof(ati_remote->name),
-			 "%s %s", ati_remote->name, udev->product);
+		snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name),
+			 "%s %s", ati_remote->rc_name, udev->product);
 
-	if (!strlen(ati_remote->name))
-		snprintf(ati_remote->name, sizeof(ati_remote->name),
+	if (!strlen(ati_remote->rc_name))
+		snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name),
 			DRIVER_DESC "(%04x,%04x)",
 			le16_to_cpu(ati_remote->udev->descriptor.idVendor),
 			le16_to_cpu(ati_remote->udev->descriptor.idProduct));
 
-	ati_remote_input_init(ati_remote);
+	snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name),
+		 "%s mouse", ati_remote->rc_name);
 
+	ati_remote_rc_init(ati_remote);
+	mutex_init(&ati_remote->open_mutex);
+	
 	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
 	err = ati_remote_initialize(ati_remote);
 	if (err)
 		goto fail3;
 
-	/* Set up and register input device */
-	err = input_register_device(ati_remote->idev);
+	/* Set up and register rc device */
+	err = rc_register_device(ati_remote->rdev);
 	if (err)
 		goto fail3;
 
+	/* use our delay for rc_dev */
+	ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay;
+	
+	/* Set up and register mouse input device */
+	if (mouse) {
+		input_dev = input_allocate_device();
+		if (!input_dev)
+			goto fail4;
+
+		ati_remote->idev = input_dev;
+		ati_remote_input_init(ati_remote);
+		err = input_register_device(input_dev);
+
+		if (err)
+			goto fail5;
+	}
+
 	usb_set_intfdata(interface, ati_remote);
 	return 0;
 
+ fail5:	input_free_device(input_dev);
+ fail4:	rc_unregister_device(rc_dev);
+	rc_dev = NULL;
  fail3:	usb_kill_urb(ati_remote->irq_urb);
 	usb_kill_urb(ati_remote->out_urb);
  fail2:	ati_remote_free_buffers(ati_remote);
- fail1:	input_free_device(input_dev);
+ fail1:	rc_free_device(rc_dev);
 	kfree(ati_remote);
 	return err;
 }
@@ -824,7 +886,9 @@ static void ati_remote_disconnect(struct usb_interface *interface)
 
 	usb_kill_urb(ati_remote->irq_urb);
 	usb_kill_urb(ati_remote->out_urb);
-	input_unregister_device(ati_remote->idev);
+	if (ati_remote->idev)
+		input_unregister_device(ati_remote->idev);
+	rc_unregister_device(ati_remote->rdev);
 	ati_remote_free_buffers(ati_remote);
 	kfree(ati_remote);
 }
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 85cac7d..3ca9265b7 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-apac-viewcomp.o \
 			rc-asus-pc39.o \
 			rc-ati-tv-wonder-hd-600.o \
+			rc-ati-x10.o \
 			rc-avermedia-a16d.o \
 			rc-avermedia.o \
 			rc-avermedia-cardbus.o \
diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c
new file mode 100644
index 0000000..c1a055e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-ati-x10.c
@@ -0,0 +1,103 @@
+/*
+ * ATI X10 RF remote keytable
+ *
+ * Copyright (C) 2011 Anssi Hannula <anssi.hannula@ıki.fi>
+ *
+ * This file is based on the static generic keytable previously found in
+ * ati_remote.c, which is
+ * Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
+ * Copyright (c) 2002 Vladimir Dergachev
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table ati_x10[] = {
+	{ 0xd20d, KEY_1 },
+	{ 0xd30e, KEY_2 },
+	{ 0xd40f, KEY_3 },
+	{ 0xd510, KEY_4 },
+	{ 0xd611, KEY_5 },
+	{ 0xd712, KEY_6 },
+	{ 0xd813, KEY_7 },
+	{ 0xd914, KEY_8 },
+	{ 0xda15, KEY_9 },
+	{ 0xdc17, KEY_0 },
+	{ 0xc500, KEY_A },
+	{ 0xc601, KEY_B },
+	{ 0xde19, KEY_C },
+	{ 0xe01b, KEY_D },
+	{ 0xe621, KEY_E },
+	{ 0xe823, KEY_F },
+
+	{ 0xdd18, KEY_KPENTER },    /* "check" */
+	{ 0xdb16, KEY_MENU },       /* "menu" */
+	{ 0xc702, KEY_POWER },      /* Power */
+	{ 0xc803, KEY_TV },         /* TV */
+	{ 0xc904, KEY_DVD },        /* DVD */
+	{ 0xca05, KEY_WWW },        /* WEB */
+	{ 0xcb06, KEY_BOOKMARKS },  /* "book" */
+	{ 0xcc07, KEY_EDIT },       /* "hand" */
+	{ 0xe11c, KEY_COFFEE },     /* "timer" */
+	{ 0xe520, KEY_FRONT },      /* "max" */
+	{ 0xe21d, KEY_LEFT },       /* left */
+	{ 0xe41f, KEY_RIGHT },      /* right */
+	{ 0xe722, KEY_DOWN },       /* down */
+	{ 0xdf1a, KEY_UP },         /* up */
+	{ 0xe31e, KEY_OK },         /* "OK" */
+	{ 0xce09, KEY_VOLUMEDOWN }, /* VOL + */
+	{ 0xcd08, KEY_VOLUMEUP },   /* VOL - */
+	{ 0xcf0a, KEY_MUTE },       /* MUTE  */
+	{ 0xd00b, KEY_CHANNELUP },  /* CH + */
+	{ 0xd10c, KEY_CHANNELDOWN },/* CH - */
+	{ 0xec27, KEY_RECORD },     /* ( o) red */
+	{ 0xea25, KEY_PLAY },       /* ( >) */
+	{ 0xe924, KEY_REWIND },     /* (<<) */
+	{ 0xeb26, KEY_FORWARD },    /* (>>) */
+	{ 0xed28, KEY_STOP },       /* ([]) */
+	{ 0xee29, KEY_PAUSE },      /* ('') */
+	{ 0xf02b, KEY_PREVIOUS },   /* (<-) */
+	{ 0xef2a, KEY_NEXT },       /* (>+) */
+	{ 0xf22d, KEY_INFO },       /* PLAYING */
+	{ 0xf32e, KEY_HOME },       /* TOP */
+	{ 0xf42f, KEY_END },        /* END */
+	{ 0xf530, KEY_SELECT },     /* SELECT */
+};
+
+static struct rc_map_list ati_x10_map = {
+	.map = {
+		.scan    = ati_x10,
+		.size    = ARRAY_SIZE(ati_x10),
+		.rc_type = RC_TYPE_OTHER,
+		.name    = RC_MAP_ATI_X10,
+	}
+};
+
+static int __init init_rc_map_ati_x10(void)
+{
+	return rc_map_register(&ati_x10_map);
+}
+
+static void __exit exit_rc_map_ati_x10(void)
+{
+	rc_map_unregister(&ati_x10_map);
+}
+
+module_init(init_rc_map_ati_x10)
+module_exit(exit_rc_map_ati_x10)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 9184751..09e4451 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -60,6 +60,7 @@ void rc_map_init(void);
 #define RC_MAP_APAC_VIEWCOMP             "rc-apac-viewcomp"
 #define RC_MAP_ASUS_PC39                 "rc-asus-pc39"
 #define RC_MAP_ATI_TV_WONDER_HD_600      "rc-ati-tv-wonder-hd-600"
+#define RC_MAP_ATI_X10                   "rc-ati-x10"
 #define RC_MAP_AVERMEDIA_A16D            "rc-avermedia-a16d"
 #define RC_MAP_AVERMEDIA_CARDBUS         "rc-avermedia-cardbus"
 #define RC_MAP_AVERMEDIA_DVBT            "rc-avermedia-dvbt"
-- 
1.7.4.4


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

* [PATCH 3/7] [media] ati_remote: parent input devices to usb interface
  2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
  2011-08-06 22:18         ` [PATCH 1/7] [media] move ati_remote driver from input/misc to media/rc Anssi Hannula
  2011-08-06 22:18         ` [PATCH 2/7] [media] ati_remote: migrate to the rc subsystem Anssi Hannula
@ 2011-08-06 22:18         ` Anssi Hannula
  2011-08-06 22:18         ` [PATCH 4/7] [media] ati_remote: fix check for a weird byte Anssi Hannula
                           ` (3 subsequent siblings)
  6 siblings, 0 replies; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 22:18 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-media, linux-input, linux-kernel

Parent the input devices to usb_interface instead of usb_device. This
fixes (at least) persistent input device nodes.

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
---
 drivers/media/rc/ati_remote.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index a1df21f..842dee4 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -693,7 +693,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
 	idev->phys = ati_remote->mouse_phys;
 
 	usb_to_input_id(ati_remote->udev, &idev->id);
-	idev->dev.parent = &ati_remote->udev->dev;
+	idev->dev.parent = &ati_remote->interface->dev;
 }
 
 static void ati_remote_rc_init(struct ati_remote *ati_remote)
@@ -712,7 +712,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
 	rdev->input_phys = ati_remote->rc_phys;
 
 	usb_to_input_id(ati_remote->udev, &rdev->input_id);
-	rdev->dev.parent = &ati_remote->udev->dev;
+	rdev->dev.parent = &ati_remote->interface->dev;
 
 	rdev->map_name = RC_MAP_ATI_X10;
 }
-- 
1.7.4.4


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

* [PATCH 4/7] [media] ati_remote: fix check for a weird byte
  2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
                           ` (2 preceding siblings ...)
  2011-08-06 22:18         ` [PATCH 3/7] [media] ati_remote: parent input devices to usb interface Anssi Hannula
@ 2011-08-06 22:18         ` Anssi Hannula
  2011-08-06 22:18         ` [PATCH 5/7] [media] ati_remote: add keymap for Medion X10 RF remote Anssi Hannula
                           ` (2 subsequent siblings)
  6 siblings, 0 replies; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 22:18 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-media, linux-input, linux-kernel

The ati_remote_dump() function tries to not print "Weird byte" warning
for 1-byte responses that contain 0xff or 0x00, but it doesn't work
properly as it simply falls back to the "Weird data" warning in the else
clause.

Fix that by adding an inner if clause.

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
---
 drivers/media/rc/ati_remote.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 842dee4..74cc6b1 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -273,9 +273,10 @@ static struct usb_driver ati_remote_driver = {
 static void ati_remote_dump(struct device *dev, unsigned char *data,
 			    unsigned int len)
 {
-	if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
-		dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
-	else if (len == 4)
+	if (len == 1) {
+		if (data[0] != (unsigned char)0xff && data[0] != 0x00)
+			dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
+	} else if (len == 4)
 		dev_warn(dev, "Weird key %02x %02x %02x %02x\n",
 		     data[0], data[1], data[2], data[3]);
 	else
-- 
1.7.4.4


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

* [PATCH 5/7] [media] ati_remote: add keymap for Medion X10 RF remote
  2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
                           ` (3 preceding siblings ...)
  2011-08-06 22:18         ` [PATCH 4/7] [media] ati_remote: fix check for a weird byte Anssi Hannula
@ 2011-08-06 22:18         ` Anssi Hannula
  2011-08-08  5:57           ` Dmitry Torokhov
  2011-08-06 22:18         ` [PATCH 6/7] [media] ati_remote: add support for SnapStream Firefly remote Anssi Hannula
  2011-08-06 22:18         ` [PATCH 7/7] [media] ati_remote: update Kconfig description Anssi Hannula
  6 siblings, 1 reply; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 22:18 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-media, linux-input, linux-kernel

Add keymap for the Medion X10 RF remote which uses the ati_remote
driver, and default to it based on the usb id.

The keymap is adapted from an earlier patch by
Jan Losinski <losinski@wh2.tu-dresden.de>:
https://lkml.org/lkml/2011/4/18/104
with KEY_PLAYPAUSE replaced by KEY_PAUSE.

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
---
 drivers/media/rc/ati_remote.c            |   17 +++--
 drivers/media/rc/keymaps/Makefile        |    1 +
 drivers/media/rc/keymaps/rc-medion-x10.c |  116 ++++++++++++++++++++++++++++++
 include/media/rc-map.h                   |    1 +
 4 files changed, 128 insertions(+), 7 deletions(-)
 create mode 100644 drivers/media/rc/keymaps/rc-medion-x10.c

diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 74cc6b1..4576462 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -151,11 +151,11 @@ MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes");
 #define err(format, arg...) printk(KERN_ERR format , ## arg)
 
 static struct usb_device_id ati_remote_table[] = {
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_MEDION_X10 },
 	{}	/* Terminating entry */
 };
 
@@ -714,8 +714,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
 
 	usb_to_input_id(ati_remote->udev, &rdev->input_id);
 	rdev->dev.parent = &ati_remote->interface->dev;
-
-	rdev->map_name = RC_MAP_ATI_X10;
 }
 
 static int ati_remote_initialize(struct ati_remote *ati_remote)
@@ -827,6 +825,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
 	snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name),
 		 "%s mouse", ati_remote->rc_name);
 
+	if (id->driver_info)
+		rc_dev->map_name = (const char *)id->driver_info;
+	else
+		rc_dev->map_name = RC_MAP_ATI_X10;
+
 	ati_remote_rc_init(ati_remote);
 	mutex_init(&ati_remote->open_mutex);
 	
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 3ca9265b7..c3d0f34 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-lirc.o \
 			rc-lme2510.o \
 			rc-manli.o \
+			rc-medion-x10.o \
 			rc-msi-digivox-ii.o \
 			rc-msi-digivox-iii.o \
 			rc-msi-tvanywhere.o \
diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c
new file mode 100644
index 0000000..ff62aab
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-medion-x10.c
@@ -0,0 +1,116 @@
+/*
+ * Medion X10 RF remote keytable
+ *
+ * Copyright (C) 2011 Anssi Hannula <anssi.hannula@ıki.fi>
+ *
+ * This file is based on a keytable provided by
+ * Jan Losinski <losinski@wh2.tu-dresden.de>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table medion_x10[] = {
+	{ 0xf12c, KEY_TV },    /* TV */
+	{ 0xf22d, KEY_VCR },   /* VCR */
+	{ 0xc904, KEY_DVD },   /* DVD */
+	{ 0xcb06, KEY_AUDIO }, /* MUSIC */
+
+	{ 0xf32e, KEY_RADIO },     /* RADIO */
+	{ 0xca05, KEY_DIRECTORY }, /* PHOTO */
+	{ 0xf42f, KEY_INFO },      /* TV-PREVIEW */
+	{ 0xf530, KEY_LIST },      /* CHANNEL-LST */
+
+	{ 0xe01b, KEY_SETUP }, /* SETUP */
+	{ 0xf631, KEY_VIDEO }, /* VIDEO DESKTOP */
+
+	{ 0xcd08, KEY_VOLUMEDOWN },  /* VOL - */
+	{ 0xce09, KEY_VOLUMEUP },    /* VOL + */
+	{ 0xd00b, KEY_CHANNELUP },   /* CHAN + */
+	{ 0xd10c, KEY_CHANNELDOWN }, /* CHAN - */
+	{ 0xc500, KEY_MUTE },        /* MUTE */
+
+	{ 0xf732, KEY_RED }, /* red */
+	{ 0xf833, KEY_GREEN }, /* green */
+	{ 0xf934, KEY_YELLOW }, /* yellow */
+	{ 0xfa35, KEY_BLUE }, /* blue */
+	{ 0xdb16, KEY_TEXT }, /* TXT */
+
+	{ 0xd20d, KEY_1 },
+	{ 0xd30e, KEY_2 },
+	{ 0xd40f, KEY_3 },
+	{ 0xd510, KEY_4 },
+	{ 0xd611, KEY_5 },
+	{ 0xd712, KEY_6 },
+	{ 0xd813, KEY_7 },
+	{ 0xd914, KEY_8 },
+	{ 0xda15, KEY_9 },
+	{ 0xdc17, KEY_0 },
+	{ 0xe11c, KEY_SEARCH }, /* TV/RAD, CH SRC */
+	{ 0xe520, KEY_DELETE }, /* DELETE */
+
+	{ 0xfb36, KEY_KEYBOARD }, /* RENAME */
+	{ 0xdd18, KEY_SCREEN },   /* SNAPSHOT */
+
+	{ 0xdf1a, KEY_UP },    /* up */
+	{ 0xe722, KEY_DOWN },  /* down */
+	{ 0xe21d, KEY_LEFT },  /* left */
+	{ 0xe41f, KEY_RIGHT }, /* right */
+	{ 0xe31e, KEY_OK },    /* OK */
+
+	{ 0xfc37, KEY_SELECT }, /* ACQUIRE IMAGE */
+	{ 0xfd38, KEY_EDIT },   /* EDIT IMAGE */
+
+	{ 0xe924, KEY_REWIND },   /* rewind  (<<) */
+	{ 0xea25, KEY_PLAY },     /* play    ( >) */
+	{ 0xeb26, KEY_FORWARD },  /* forward (>>) */
+	{ 0xec27, KEY_RECORD },   /* record  ( o) */
+	{ 0xed28, KEY_STOP },     /* stop    ([]) */
+	{ 0xee29, KEY_PAUSE },    /* pause   ('') */
+
+	{ 0xe621, KEY_PREVIOUS },        /* prev */
+	{ 0xfe39, KEY_SWITCHVIDEOMODE }, /* F SCR */
+	{ 0xe823, KEY_NEXT },            /* next */
+	{ 0xde19, KEY_MENU },            /* MENU */
+	{ 0xff3a, KEY_LANGUAGE },        /* AUDIO */
+
+	{ 0xc702, KEY_POWER }, /* POWER */
+};
+
+static struct rc_map_list medion_x10_map = {
+	.map = {
+		.scan    = medion_x10,
+		.size    = ARRAY_SIZE(medion_x10),
+		.rc_type = RC_TYPE_OTHER,
+		.name    = RC_MAP_MEDION_X10,
+	}
+};
+
+static int __init init_rc_map_medion_x10(void)
+{
+	return rc_map_register(&medion_x10_map);
+}
+
+static void __exit exit_rc_map_medion_x10(void)
+{
+	rc_map_unregister(&medion_x10_map);
+}
+
+module_init(init_rc_map_medion_x10)
+module_exit(exit_rc_map_medion_x10)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 09e4451..86e7e85 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -106,6 +106,7 @@ void rc_map_init(void);
 #define RC_MAP_LIRC                      "rc-lirc"
 #define RC_MAP_LME2510                   "rc-lme2510"
 #define RC_MAP_MANLI                     "rc-manli"
+#define RC_MAP_MEDION_X10                "rc-medion-x10"
 #define RC_MAP_MSI_DIGIVOX_II            "rc-msi-digivox-ii"
 #define RC_MAP_MSI_DIGIVOX_III           "rc-msi-digivox-iii"
 #define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
-- 
1.7.4.4


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

* [PATCH 6/7] [media] ati_remote: add support for SnapStream Firefly remote
  2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
                           ` (4 preceding siblings ...)
  2011-08-06 22:18         ` [PATCH 5/7] [media] ati_remote: add keymap for Medion X10 RF remote Anssi Hannula
@ 2011-08-06 22:18         ` Anssi Hannula
  2011-08-06 22:18         ` [PATCH 7/7] [media] ati_remote: update Kconfig description Anssi Hannula
  6 siblings, 0 replies; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 22:18 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-media, linux-input, linux-kernel

Add support for SnapStream Firefly remote control.

The protocol differs by having two toggle bits in the scancode. Since
one of the bits is otherwise unused, we can safely handle the bits
unconditionally.

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
---
 drivers/media/rc/ati_remote.c                    |   15 +++-
 drivers/media/rc/keymaps/Makefile                |    1 +
 drivers/media/rc/keymaps/rc-snapstream-firefly.c |  106 ++++++++++++++++++++++
 include/media/rc-map.h                           |    1 +
 4 files changed, 121 insertions(+), 2 deletions(-)
 create mode 100644 drivers/media/rc/keymaps/rc-snapstream-firefly.c

diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 4576462..9e03efa 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -107,6 +107,7 @@
 #define ATI_REMOTE_PRODUCT_ID		0x0004
 #define NVIDIA_REMOTE_PRODUCT_ID	0x0005
 #define MEDION_REMOTE_PRODUCT_ID	0x0006
+#define FIREFLY_REMOTE_PRODUCT_ID	0x0008
 
 #define DRIVER_VERSION	        "2.2.1"
 #define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
@@ -156,6 +157,7 @@ static struct usb_device_id ati_remote_table[] = {
 	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
 	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
 	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_MEDION_X10 },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_SNAPSTREAM_FIREFLY },
 	{}	/* Terminating entry */
 };
 
@@ -482,7 +484,15 @@ static void ati_remote_input_report(struct urb *urb)
 
 	scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f));
 
-	scancode[1] = data[2];
+	/*
+	 * Some devices (e.g. SnapStream Firefly) use 8080 as toggle code,
+	 * so we have to clear them. The first bit is a bit tricky as the
+	 * "non-toggled" state depends on remote_num, so we xor it with the
+	 * second bit which is only used for toggle.
+	 */
+	scancode[0] ^= (data[2] & 0x80);
+
+	scancode[1] = data[2] & ~0x80;
 
 	/* Look up event code index in mouse translation table. */
 	index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]);
@@ -546,7 +556,8 @@ static void ati_remote_input_report(struct urb *urb)
 			 * it would cause ghost repeats which would be a
 			 * regression for this driver.
 			 */
-			rc_keydown_notimeout(ati_remote->rdev, rc_code, 0);
+			rc_keydown_notimeout(ati_remote->rdev, rc_code,
+					     data[2]);
 			rc_keyup(ati_remote->rdev);
 			return;
 		}
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index c3d0f34..5ff4d10 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-hauppauge.o \
 			rc-rc6-mce.o \
 			rc-real-audio-220-32-keys.o \
+			rc-snapstream-firefly.o \
 			rc-streamzap.o \
 			rc-tbs-nec.o \
 			rc-technisat-usb2.o \
diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c
new file mode 100644
index 0000000..2df02e4
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c
@@ -0,0 +1,106 @@
+/*
+ * SnapStream Firefly X10 RF remote keytable
+ *
+ * Copyright (C) 2011 Anssi Hannula <anssi.hannula@ıki.fi>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table snapstream_firefly[] = {
+	{ 0xf12c, KEY_ZOOM },       /* Maximize */
+	{ 0xc702, KEY_CLOSE },
+	
+	{ 0xd20d, KEY_1 },
+	{ 0xd30e, KEY_2 },
+	{ 0xd40f, KEY_3 },
+	{ 0xd510, KEY_4 },
+	{ 0xd611, KEY_5 },
+	{ 0xd712, KEY_6 },
+	{ 0xd813, KEY_7 },
+	{ 0xd914, KEY_8 },
+	{ 0xda15, KEY_9 },
+	{ 0xdc17, KEY_0 },
+	{ 0xdb16, KEY_BACK },
+	{ 0xdd18, KEY_KPENTER },    /* ent */
+
+	{ 0xce09, KEY_VOLUMEUP },
+	{ 0xcd08, KEY_VOLUMEDOWN },
+	{ 0xcf0a, KEY_MUTE },
+	{ 0xd00b, KEY_CHANNELUP },
+	{ 0xd10c, KEY_CHANNELDOWN },
+	{ 0xc500, KEY_VENDOR },     /* firefly */
+
+	{ 0xf32e, KEY_INFO },
+	{ 0xf42f, KEY_OPTION },
+
+	{ 0xe21d, KEY_LEFT },
+	{ 0xe41f, KEY_RIGHT },
+	{ 0xe722, KEY_DOWN },
+	{ 0xdf1a, KEY_UP },
+	{ 0xe31e, KEY_OK },
+	
+	{ 0xe11c, KEY_MENU },
+	{ 0xe520, KEY_EXIT },
+	
+	{ 0xec27, KEY_RECORD },
+	{ 0xea25, KEY_PLAY },
+	{ 0xed28, KEY_STOP },
+	{ 0xe924, KEY_REWIND },
+	{ 0xeb26, KEY_FORWARD },
+	{ 0xee29, KEY_PAUSE },
+	{ 0xf02b, KEY_PREVIOUS },
+	{ 0xef2a, KEY_NEXT },
+
+	{ 0xcb06, KEY_AUDIO },      /* Music */
+	{ 0xca05, KEY_IMAGES },     /* Photos */
+	{ 0xc904, KEY_DVD },
+	{ 0xc803, KEY_TV },
+	{ 0xcc07, KEY_VIDEO },
+
+	{ 0xc601, KEY_HELP },
+	{ 0xf22d, KEY_MODE },       /* Mouse */
+
+	{ 0xde19, KEY_A },
+	{ 0xe01b, KEY_B },
+	{ 0xe621, KEY_C },
+	{ 0xe823, KEY_D },
+};
+
+static struct rc_map_list snapstream_firefly_map = {
+	.map = {
+		.scan    = snapstream_firefly,
+		.size    = ARRAY_SIZE(snapstream_firefly),
+		.rc_type = RC_TYPE_OTHER,
+		.name    = RC_MAP_SNAPSTREAM_FIREFLY,
+	}
+};
+
+static int __init init_rc_map_snapstream_firefly(void)
+{
+	return rc_map_register(&snapstream_firefly_map);
+}
+
+static void __exit exit_rc_map_snapstream_firefly(void)
+{
+	rc_map_unregister(&snapstream_firefly_map);
+}
+
+module_init(init_rc_map_snapstream_firefly)
+module_exit(exit_rc_map_snapstream_firefly)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 86e7e85..9bc16cf 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -131,6 +131,7 @@ void rc_map_init(void);
 #define RC_MAP_RC5_TV                    "rc-rc5-tv"
 #define RC_MAP_RC6_MCE                   "rc-rc6-mce"
 #define RC_MAP_REAL_AUDIO_220_32_KEYS    "rc-real-audio-220-32-keys"
+#define RC_MAP_SNAPSTREAM_FIREFLY        "rc-snapstream-firefly"
 #define RC_MAP_STREAMZAP                 "rc-streamzap"
 #define RC_MAP_TBS_NEC                   "rc-tbs-nec"
 #define RC_MAP_TECHNISAT_USB2            "rc-technisat-usb2"
-- 
1.7.4.4


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

* [PATCH 7/7] [media] ati_remote: update Kconfig description
  2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
                           ` (5 preceding siblings ...)
  2011-08-06 22:18         ` [PATCH 6/7] [media] ati_remote: add support for SnapStream Firefly remote Anssi Hannula
@ 2011-08-06 22:18         ` Anssi Hannula
  6 siblings, 0 replies; 18+ messages in thread
From: Anssi Hannula @ 2011-08-06 22:18 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-media, linux-input, linux-kernel

The ati_remote driver supports more remotes nowadays, update the
description to reflect that.

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
---
 drivers/media/rc/Kconfig |   12 +++++++-----
 1 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 26937b2..86c6abc 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -98,16 +98,18 @@ config IR_LIRC_CODEC
 	   the LIRC interface.
 
 config RC_ATI_REMOTE
-	tristate "ATI / X10 USB RF remote control"
+	tristate "ATI / X10 based USB RF remote controls"
 	depends on USB_ARCH_HAS_HCD
 	depends on RC_CORE
 	select USB
 	help
-	   Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
+	   Say Y here if you want to use an X10 based USB remote control.
 	   These are RF remotes with USB receivers.
-	   The ATI remote comes with many of ATI's All-In-Wonder video cards.
-	   The X10 "Lola" remote is available at:
-	      <http://www.x10.com/products/lola_sg1.htm>
+
+	   Such devices include the ATI remote that comes with many of ATI's
+	   All-In-Wonder video cards, the X10 "Lola" remote, NVIDIA RF remote,
+	   Medion RF remote, and SnapStream FireFly remote.
+
 	   This driver provides mouse pointer, left and right mouse buttons,
 	   and maps all the other remote buttons to keypress events.
 
-- 
1.7.4.4


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

* Re: [PATCH 5/7] [media] ati_remote: add keymap for Medion X10 RF remote
  2011-08-06 22:18         ` [PATCH 5/7] [media] ati_remote: add keymap for Medion X10 RF remote Anssi Hannula
@ 2011-08-08  5:57           ` Dmitry Torokhov
  2011-08-08 14:31             ` Anssi Hannula
  0 siblings, 1 reply; 18+ messages in thread
From: Dmitry Torokhov @ 2011-08-08  5:57 UTC (permalink / raw)
  To: Anssi Hannula; +Cc: linux-media, linux-input, linux-kernel

On Sun, Aug 07, 2011 at 01:18:11AM +0300, Anssi Hannula wrote:
> Add keymap for the Medion X10 RF remote which uses the ati_remote
> driver, and default to it based on the usb id.

Since rc-core supports loading custom keytmaps should we ass medion
keymap here?

I think we should keep the original keymap to avoid regressions, but new
keymaps should be offloaded to udev.

Thanks.

> 
> The keymap is adapted from an earlier patch by
> Jan Losinski <losinski@wh2.tu-dresden.de>:
> https://lkml.org/lkml/2011/4/18/104
> with KEY_PLAYPAUSE replaced by KEY_PAUSE.
> 
> Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
> ---
>  drivers/media/rc/ati_remote.c            |   17 +++--
>  drivers/media/rc/keymaps/Makefile        |    1 +
>  drivers/media/rc/keymaps/rc-medion-x10.c |  116 ++++++++++++++++++++++++++++++
>  include/media/rc-map.h                   |    1 +
>  4 files changed, 128 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/media/rc/keymaps/rc-medion-x10.c
> 
> diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
> index 74cc6b1..4576462 100644
> --- a/drivers/media/rc/ati_remote.c
> +++ b/drivers/media/rc/ati_remote.c
> @@ -151,11 +151,11 @@ MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes");
>  #define err(format, arg...) printk(KERN_ERR format , ## arg)
>  
>  static struct usb_device_id ati_remote_table[] = {
> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) },
> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) },
> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_MEDION_X10 },
>  	{}	/* Terminating entry */
>  };
>  
> @@ -714,8 +714,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
>  
>  	usb_to_input_id(ati_remote->udev, &rdev->input_id);
>  	rdev->dev.parent = &ati_remote->interface->dev;
> -
> -	rdev->map_name = RC_MAP_ATI_X10;
>  }
>  
>  static int ati_remote_initialize(struct ati_remote *ati_remote)
> @@ -827,6 +825,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
>  	snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name),
>  		 "%s mouse", ati_remote->rc_name);
>  
> +	if (id->driver_info)
> +		rc_dev->map_name = (const char *)id->driver_info;
> +	else
> +		rc_dev->map_name = RC_MAP_ATI_X10;
> +
>  	ati_remote_rc_init(ati_remote);
>  	mutex_init(&ati_remote->open_mutex);
>  	
> diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
> index 3ca9265b7..c3d0f34 100644
> --- a/drivers/media/rc/keymaps/Makefile
> +++ b/drivers/media/rc/keymaps/Makefile
> @@ -48,6 +48,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
>  			rc-lirc.o \
>  			rc-lme2510.o \
>  			rc-manli.o \
> +			rc-medion-x10.o \
>  			rc-msi-digivox-ii.o \
>  			rc-msi-digivox-iii.o \
>  			rc-msi-tvanywhere.o \
> diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c
> new file mode 100644
> index 0000000..ff62aab
> --- /dev/null
> +++ b/drivers/media/rc/keymaps/rc-medion-x10.c
> @@ -0,0 +1,116 @@
> +/*
> + * Medion X10 RF remote keytable
> + *
> + * Copyright (C) 2011 Anssi Hannula <anssi.hannula@ıki.fi>
> + *
> + * This file is based on a keytable provided by
> + * Jan Losinski <losinski@wh2.tu-dresden.de>
> + *
> + * 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; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#include <media/rc-map.h>
> +
> +static struct rc_map_table medion_x10[] = {
> +	{ 0xf12c, KEY_TV },    /* TV */
> +	{ 0xf22d, KEY_VCR },   /* VCR */
> +	{ 0xc904, KEY_DVD },   /* DVD */
> +	{ 0xcb06, KEY_AUDIO }, /* MUSIC */
> +
> +	{ 0xf32e, KEY_RADIO },     /* RADIO */
> +	{ 0xca05, KEY_DIRECTORY }, /* PHOTO */
> +	{ 0xf42f, KEY_INFO },      /* TV-PREVIEW */
> +	{ 0xf530, KEY_LIST },      /* CHANNEL-LST */
> +
> +	{ 0xe01b, KEY_SETUP }, /* SETUP */
> +	{ 0xf631, KEY_VIDEO }, /* VIDEO DESKTOP */
> +
> +	{ 0xcd08, KEY_VOLUMEDOWN },  /* VOL - */
> +	{ 0xce09, KEY_VOLUMEUP },    /* VOL + */
> +	{ 0xd00b, KEY_CHANNELUP },   /* CHAN + */
> +	{ 0xd10c, KEY_CHANNELDOWN }, /* CHAN - */
> +	{ 0xc500, KEY_MUTE },        /* MUTE */
> +
> +	{ 0xf732, KEY_RED }, /* red */
> +	{ 0xf833, KEY_GREEN }, /* green */
> +	{ 0xf934, KEY_YELLOW }, /* yellow */
> +	{ 0xfa35, KEY_BLUE }, /* blue */
> +	{ 0xdb16, KEY_TEXT }, /* TXT */
> +
> +	{ 0xd20d, KEY_1 },
> +	{ 0xd30e, KEY_2 },
> +	{ 0xd40f, KEY_3 },
> +	{ 0xd510, KEY_4 },
> +	{ 0xd611, KEY_5 },
> +	{ 0xd712, KEY_6 },
> +	{ 0xd813, KEY_7 },
> +	{ 0xd914, KEY_8 },
> +	{ 0xda15, KEY_9 },
> +	{ 0xdc17, KEY_0 },
> +	{ 0xe11c, KEY_SEARCH }, /* TV/RAD, CH SRC */
> +	{ 0xe520, KEY_DELETE }, /* DELETE */
> +
> +	{ 0xfb36, KEY_KEYBOARD }, /* RENAME */
> +	{ 0xdd18, KEY_SCREEN },   /* SNAPSHOT */
> +
> +	{ 0xdf1a, KEY_UP },    /* up */
> +	{ 0xe722, KEY_DOWN },  /* down */
> +	{ 0xe21d, KEY_LEFT },  /* left */
> +	{ 0xe41f, KEY_RIGHT }, /* right */
> +	{ 0xe31e, KEY_OK },    /* OK */
> +
> +	{ 0xfc37, KEY_SELECT }, /* ACQUIRE IMAGE */
> +	{ 0xfd38, KEY_EDIT },   /* EDIT IMAGE */
> +
> +	{ 0xe924, KEY_REWIND },   /* rewind  (<<) */
> +	{ 0xea25, KEY_PLAY },     /* play    ( >) */
> +	{ 0xeb26, KEY_FORWARD },  /* forward (>>) */
> +	{ 0xec27, KEY_RECORD },   /* record  ( o) */
> +	{ 0xed28, KEY_STOP },     /* stop    ([]) */
> +	{ 0xee29, KEY_PAUSE },    /* pause   ('') */
> +
> +	{ 0xe621, KEY_PREVIOUS },        /* prev */
> +	{ 0xfe39, KEY_SWITCHVIDEOMODE }, /* F SCR */
> +	{ 0xe823, KEY_NEXT },            /* next */
> +	{ 0xde19, KEY_MENU },            /* MENU */
> +	{ 0xff3a, KEY_LANGUAGE },        /* AUDIO */
> +
> +	{ 0xc702, KEY_POWER }, /* POWER */
> +};
> +
> +static struct rc_map_list medion_x10_map = {
> +	.map = {
> +		.scan    = medion_x10,
> +		.size    = ARRAY_SIZE(medion_x10),
> +		.rc_type = RC_TYPE_OTHER,
> +		.name    = RC_MAP_MEDION_X10,
> +	}
> +};
> +
> +static int __init init_rc_map_medion_x10(void)
> +{
> +	return rc_map_register(&medion_x10_map);
> +}
> +
> +static void __exit exit_rc_map_medion_x10(void)
> +{
> +	rc_map_unregister(&medion_x10_map);
> +}
> +
> +module_init(init_rc_map_medion_x10)
> +module_exit(exit_rc_map_medion_x10)
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
> index 09e4451..86e7e85 100644
> --- a/include/media/rc-map.h
> +++ b/include/media/rc-map.h
> @@ -106,6 +106,7 @@ void rc_map_init(void);
>  #define RC_MAP_LIRC                      "rc-lirc"
>  #define RC_MAP_LME2510                   "rc-lme2510"
>  #define RC_MAP_MANLI                     "rc-manli"
> +#define RC_MAP_MEDION_X10                "rc-medion-x10"
>  #define RC_MAP_MSI_DIGIVOX_II            "rc-msi-digivox-ii"
>  #define RC_MAP_MSI_DIGIVOX_III           "rc-msi-digivox-iii"
>  #define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
> -- 
> 1.7.4.4
> 

-- 
Dmitry

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

* Re: [PATCH 5/7] [media] ati_remote: add keymap for Medion X10 RF remote
  2011-08-08  5:57           ` Dmitry Torokhov
@ 2011-08-08 14:31             ` Anssi Hannula
  2011-08-08 15:57               ` Jarod Wilson
  0 siblings, 1 reply; 18+ messages in thread
From: Anssi Hannula @ 2011-08-08 14:31 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-media, linux-input, linux-kernel

On 08.08.2011 08:57, Dmitry Torokhov wrote:
> On Sun, Aug 07, 2011 at 01:18:11AM +0300, Anssi Hannula wrote:
>> Add keymap for the Medion X10 RF remote which uses the ati_remote
>> driver, and default to it based on the usb id.
> 
> Since rc-core supports loading custom keytmaps should we ass medion
> keymap here?
> 
> I think we should keep the original keymap to avoid regressions, but new
> keymaps should be offloaded to udev.

Well, I simply followed the convention, as all other remotes under
media/ have the default table in-kernel.

I'm not against putting it off-kernel, but in that case the same should
be done for all new media devices. Is that the plan?


> Thanks.
> 
>>
>> The keymap is adapted from an earlier patch by
>> Jan Losinski <losinski@wh2.tu-dresden.de>:
>> https://lkml.org/lkml/2011/4/18/104
>> with KEY_PLAYPAUSE replaced by KEY_PAUSE.
>>
>> Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
>> ---
>>  drivers/media/rc/ati_remote.c            |   17 +++--
>>  drivers/media/rc/keymaps/Makefile        |    1 +
>>  drivers/media/rc/keymaps/rc-medion-x10.c |  116 ++++++++++++++++++++++++++++++
>>  include/media/rc-map.h                   |    1 +
>>  4 files changed, 128 insertions(+), 7 deletions(-)
>>  create mode 100644 drivers/media/rc/keymaps/rc-medion-x10.c
>>
>> diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
>> index 74cc6b1..4576462 100644
>> --- a/drivers/media/rc/ati_remote.c
>> +++ b/drivers/media/rc/ati_remote.c
>> @@ -151,11 +151,11 @@ MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes");
>>  #define err(format, arg...) printk(KERN_ERR format , ## arg)
>>  
>>  static struct usb_device_id ati_remote_table[] = {
>> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
>> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) },
>> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
>> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) },
>> -	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
>> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
>> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
>> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
>> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_ATI_X10 },
>> +	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID),	.driver_info = (unsigned long)RC_MAP_MEDION_X10 },
>>  	{}	/* Terminating entry */
>>  };
>>  
>> @@ -714,8 +714,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
>>  
>>  	usb_to_input_id(ati_remote->udev, &rdev->input_id);
>>  	rdev->dev.parent = &ati_remote->interface->dev;
>> -
>> -	rdev->map_name = RC_MAP_ATI_X10;
>>  }
>>  
>>  static int ati_remote_initialize(struct ati_remote *ati_remote)
>> @@ -827,6 +825,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
>>  	snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name),
>>  		 "%s mouse", ati_remote->rc_name);
>>  
>> +	if (id->driver_info)
>> +		rc_dev->map_name = (const char *)id->driver_info;
>> +	else
>> +		rc_dev->map_name = RC_MAP_ATI_X10;
>> +
>>  	ati_remote_rc_init(ati_remote);
>>  	mutex_init(&ati_remote->open_mutex);
>>  	
>> diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
>> index 3ca9265b7..c3d0f34 100644
>> --- a/drivers/media/rc/keymaps/Makefile
>> +++ b/drivers/media/rc/keymaps/Makefile
>> @@ -48,6 +48,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
>>  			rc-lirc.o \
>>  			rc-lme2510.o \
>>  			rc-manli.o \
>> +			rc-medion-x10.o \
>>  			rc-msi-digivox-ii.o \
>>  			rc-msi-digivox-iii.o \
>>  			rc-msi-tvanywhere.o \
>> diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c
>> new file mode 100644
>> index 0000000..ff62aab
>> --- /dev/null
>> +++ b/drivers/media/rc/keymaps/rc-medion-x10.c
>> @@ -0,0 +1,116 @@
>> +/*
>> + * Medion X10 RF remote keytable
>> + *
>> + * Copyright (C) 2011 Anssi Hannula <anssi.hannula@ıki.fi>
>> + *
>> + * This file is based on a keytable provided by
>> + * Jan Losinski <losinski@wh2.tu-dresden.de>
>> + *
>> + * 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; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, write to the Free Software Foundation, Inc.,
>> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>> + */
>> +
>> +#include <media/rc-map.h>
>> +
>> +static struct rc_map_table medion_x10[] = {
>> +	{ 0xf12c, KEY_TV },    /* TV */
>> +	{ 0xf22d, KEY_VCR },   /* VCR */
>> +	{ 0xc904, KEY_DVD },   /* DVD */
>> +	{ 0xcb06, KEY_AUDIO }, /* MUSIC */
>> +
>> +	{ 0xf32e, KEY_RADIO },     /* RADIO */
>> +	{ 0xca05, KEY_DIRECTORY }, /* PHOTO */
>> +	{ 0xf42f, KEY_INFO },      /* TV-PREVIEW */
>> +	{ 0xf530, KEY_LIST },      /* CHANNEL-LST */
>> +
>> +	{ 0xe01b, KEY_SETUP }, /* SETUP */
>> +	{ 0xf631, KEY_VIDEO }, /* VIDEO DESKTOP */
>> +
>> +	{ 0xcd08, KEY_VOLUMEDOWN },  /* VOL - */
>> +	{ 0xce09, KEY_VOLUMEUP },    /* VOL + */
>> +	{ 0xd00b, KEY_CHANNELUP },   /* CHAN + */
>> +	{ 0xd10c, KEY_CHANNELDOWN }, /* CHAN - */
>> +	{ 0xc500, KEY_MUTE },        /* MUTE */
>> +
>> +	{ 0xf732, KEY_RED }, /* red */
>> +	{ 0xf833, KEY_GREEN }, /* green */
>> +	{ 0xf934, KEY_YELLOW }, /* yellow */
>> +	{ 0xfa35, KEY_BLUE }, /* blue */
>> +	{ 0xdb16, KEY_TEXT }, /* TXT */
>> +
>> +	{ 0xd20d, KEY_1 },
>> +	{ 0xd30e, KEY_2 },
>> +	{ 0xd40f, KEY_3 },
>> +	{ 0xd510, KEY_4 },
>> +	{ 0xd611, KEY_5 },
>> +	{ 0xd712, KEY_6 },
>> +	{ 0xd813, KEY_7 },
>> +	{ 0xd914, KEY_8 },
>> +	{ 0xda15, KEY_9 },
>> +	{ 0xdc17, KEY_0 },
>> +	{ 0xe11c, KEY_SEARCH }, /* TV/RAD, CH SRC */
>> +	{ 0xe520, KEY_DELETE }, /* DELETE */
>> +
>> +	{ 0xfb36, KEY_KEYBOARD }, /* RENAME */
>> +	{ 0xdd18, KEY_SCREEN },   /* SNAPSHOT */
>> +
>> +	{ 0xdf1a, KEY_UP },    /* up */
>> +	{ 0xe722, KEY_DOWN },  /* down */
>> +	{ 0xe21d, KEY_LEFT },  /* left */
>> +	{ 0xe41f, KEY_RIGHT }, /* right */
>> +	{ 0xe31e, KEY_OK },    /* OK */
>> +
>> +	{ 0xfc37, KEY_SELECT }, /* ACQUIRE IMAGE */
>> +	{ 0xfd38, KEY_EDIT },   /* EDIT IMAGE */
>> +
>> +	{ 0xe924, KEY_REWIND },   /* rewind  (<<) */
>> +	{ 0xea25, KEY_PLAY },     /* play    ( >) */
>> +	{ 0xeb26, KEY_FORWARD },  /* forward (>>) */
>> +	{ 0xec27, KEY_RECORD },   /* record  ( o) */
>> +	{ 0xed28, KEY_STOP },     /* stop    ([]) */
>> +	{ 0xee29, KEY_PAUSE },    /* pause   ('') */
>> +
>> +	{ 0xe621, KEY_PREVIOUS },        /* prev */
>> +	{ 0xfe39, KEY_SWITCHVIDEOMODE }, /* F SCR */
>> +	{ 0xe823, KEY_NEXT },            /* next */
>> +	{ 0xde19, KEY_MENU },            /* MENU */
>> +	{ 0xff3a, KEY_LANGUAGE },        /* AUDIO */
>> +
>> +	{ 0xc702, KEY_POWER }, /* POWER */
>> +};
>> +
>> +static struct rc_map_list medion_x10_map = {
>> +	.map = {
>> +		.scan    = medion_x10,
>> +		.size    = ARRAY_SIZE(medion_x10),
>> +		.rc_type = RC_TYPE_OTHER,
>> +		.name    = RC_MAP_MEDION_X10,
>> +	}
>> +};
>> +
>> +static int __init init_rc_map_medion_x10(void)
>> +{
>> +	return rc_map_register(&medion_x10_map);
>> +}
>> +
>> +static void __exit exit_rc_map_medion_x10(void)
>> +{
>> +	rc_map_unregister(&medion_x10_map);
>> +}
>> +
>> +module_init(init_rc_map_medion_x10)
>> +module_exit(exit_rc_map_medion_x10)
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
>> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
>> index 09e4451..86e7e85 100644
>> --- a/include/media/rc-map.h
>> +++ b/include/media/rc-map.h
>> @@ -106,6 +106,7 @@ void rc_map_init(void);
>>  #define RC_MAP_LIRC                      "rc-lirc"
>>  #define RC_MAP_LME2510                   "rc-lme2510"
>>  #define RC_MAP_MANLI                     "rc-manli"
>> +#define RC_MAP_MEDION_X10                "rc-medion-x10"
>>  #define RC_MAP_MSI_DIGIVOX_II            "rc-msi-digivox-ii"
>>  #define RC_MAP_MSI_DIGIVOX_III           "rc-msi-digivox-iii"
>>  #define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
>> -- 
>> 1.7.4.4
>>
> 


-- 
Anssi Hannula

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

* Re: [PATCH 5/7] [media] ati_remote: add keymap for Medion X10 RF remote
  2011-08-08 14:31             ` Anssi Hannula
@ 2011-08-08 15:57               ` Jarod Wilson
  0 siblings, 0 replies; 18+ messages in thread
From: Jarod Wilson @ 2011-08-08 15:57 UTC (permalink / raw)
  To: Anssi Hannula; +Cc: Dmitry Torokhov, linux-media, linux-input, linux-kernel

Anssi Hannula wrote:
> On 08.08.2011 08:57, Dmitry Torokhov wrote:
>> On Sun, Aug 07, 2011 at 01:18:11AM +0300, Anssi Hannula wrote:
>>> Add keymap for the Medion X10 RF remote which uses the ati_remote
>>> driver, and default to it based on the usb id.
>> Since rc-core supports loading custom keytmaps should we ass medion
>> keymap here?
>>
>> I think we should keep the original keymap to avoid regressions, but new
>> keymaps should be offloaded to udev.
>
> Well, I simply followed the convention, as all other remotes under
> media/ have the default table in-kernel.
>
> I'm not against putting it off-kernel, but in that case the same should
> be done for all new media devices. Is that the plan?

That's the long-term plan, but not every distro has a sufficiently new 
enough v4l-utils and ir-keytable with udev rules to load keymaps, so 
we've been adding default remotes in-kernel and userspace (effectively 
meaning duplicated keymap loads if the user does have ir-keytable with 
udev rules, but meh). I'd say add it for now, and when we get to the 
point of v4l-utils ubiquity, we can drop this along with all the other 
in-kernel rc keymaps.

-- 
Jarod Wilson
jarod@redhat.com



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

end of thread, other threads:[~2011-08-08 15:58 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-18 10:41 [PATCH 0/1] Input: ati_remote - extend keytable for medion remotes Jan Losinski
2011-04-18 10:45 ` [PATCH 1/1] " Jan Losinski
2011-05-19  8:54   ` Jan Losinski
2011-05-25 16:32   ` Dmitry Torokhov
2011-07-01 14:01     ` Steffen Barszus
2011-08-06 15:32     ` Steffen Barszus
2011-08-06 21:31     ` Anssi Hannula
2011-08-06 22:18       ` [PATCH 0/7] ati_remote: move to rc-core and other updates Anssi Hannula
2011-08-06 22:18         ` [PATCH 1/7] [media] move ati_remote driver from input/misc to media/rc Anssi Hannula
2011-08-06 22:18         ` [PATCH 2/7] [media] ati_remote: migrate to the rc subsystem Anssi Hannula
2011-08-06 22:18         ` [PATCH 3/7] [media] ati_remote: parent input devices to usb interface Anssi Hannula
2011-08-06 22:18         ` [PATCH 4/7] [media] ati_remote: fix check for a weird byte Anssi Hannula
2011-08-06 22:18         ` [PATCH 5/7] [media] ati_remote: add keymap for Medion X10 RF remote Anssi Hannula
2011-08-08  5:57           ` Dmitry Torokhov
2011-08-08 14:31             ` Anssi Hannula
2011-08-08 15:57               ` Jarod Wilson
2011-08-06 22:18         ` [PATCH 6/7] [media] ati_remote: add support for SnapStream Firefly remote Anssi Hannula
2011-08-06 22:18         ` [PATCH 7/7] [media] ati_remote: update Kconfig description Anssi Hannula

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