From: Peter Stokes <linux@dadeos.co.uk>
To: linux-input@vger.kernel.org
Cc: "Ville Syrjälä" <syrjala@sci.fi>, "Jiri Kosina" <jkosina@suse.cz>,
dmitry.torokhov@gmail.com
Subject: [PATCH] ati_remote2 loadable keymap support
Date: Sat, 5 Apr 2008 19:30:10 +0100 [thread overview]
Message-ID: <200804051930.10574.linux@dadeos.co.uk> (raw)
[-- Attachment #1: Type: text/plain, Size: 2943 bytes --]
The attached patch adds support for loadable key maps support to the
ati_remote2 driver.
This patch is similar to the previous version that I originally posted on 16th
February 2008. As requested, I have removed the code that reconfigured this
driver to utilise the input core's built in soft auto repeat functionality.
Those changes are pending further clarification on how buttons that should
not be auto repeated (e.g. mouse buttons) can be excluded from the soft auto
repeat implementation.
On Tuesday 04 March 2008 22:17:49 Ville Syrjälä wrote:
> However, since that seems unlikely to happen, and the input core already
> has support for keymaps I'm fine with adding the set/getkeycode stuff.
> What I'd like to drop is the support for five different keymaps since
> AFAICS that could be handled in a more generic way in user space.
I do not agree that the opportunity to remap the resultant keycode generated
from any given physical key on the remote dependant upon which 'mode' the
remote is currently in should be dropped. Consequently I have left the
implementation in the attached patch.
I feel that a valid way of thinking about this implementation is that the
hardware scancodes consist of the mode and key bytes combined. Given any such
implementation it could be assumed that the device has 5 x 46 = 230 keys, it
therefore seems entirely reasonable to me to provide a mechanism by which any
of those keys can be remapped.
On Tuesday 04 March 2008 20:38:22 Ville Syrjälä wrote:
> I think you could implement the multiple keymaps thing rather trivially
> in user space by having a small daemon listening on the event device
> and loading a new keymap when a mode key is pressed. That would limit
> the changes to the driver, and it would not require any kernel changes
> when if you would need to adapt it to a device that uses a different
> driver.
I do not agree that it this functionality would be trivial to implement in
user space. The primary purpose behind making these changes is to provide
full access to all of the keys within X windows, as such one is dependant
upon the X input system interfacing to the event device. The goal is to make
this device behave as a regular keyboard, not requiring any special case code
in any application the user might wish to control using it.
I do not feel that my proposed code changes are particularly invasive. I would
accept that the static table outlining the default keycode mappings
represents a reasonable change. Whilst this table could be eliminated (and
generated programmatically) I feel that it serves in some part towards
documenting the implementation.
All of the changes proposed have no effect upon the operation of the driver
out-of-the-box they merely provide a mechanism by which an end user can
configure their setup to function as they desire.
Best regards
Peter Stokes
[-- Attachment #2: ati_remote2_keycode.patch --]
[-- Type: text/x-diff, Size: 13089 bytes --]
Signed-off-by: Peter Stokes <linux@dadeos.co.uk>
--- linux-2.6.24-orig/drivers/input/misc/ati_remote2.c 2008-01-24 22:58:37.000000000 +0000
+++ linux-2.6.24/drivers/input/misc/ati_remote2.c 2008-04-05 18:34:31.000000000 +0100
@@ -2,7 +2,7 @@
* ati_remote2 - ATI/Philips USB RF remote driver
*
* Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi>
- * Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.co.uk>
+ * Copyright (C) 2007 Peter Stokes <linux@dadeos.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -12,7 +12,7 @@
#include <linux/usb/input.h>
#define DRIVER_DESC "ATI/Philips USB RF remote driver"
-#define DRIVER_VERSION "0.2"
+#define DRIVER_VERSION "0.3"
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
@@ -27,7 +27,7 @@
* A remote's "channel" may be altered by pressing and holding the "PC" button for
* approximately 3 seconds, after which the button will slowly flash the count of the
* currently configured "channel", using the numeric keypad enter a number between 1 and
- * 16 and then the "PC" button again, the button will slowly flash the count of the
+ * 16 and then press the "PC" button again, the button will slowly flash the count of the
* newly configured "channel".
*/
@@ -45,61 +45,66 @@
};
MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
+
+static u8 ati_remote2_modes[] = {
+ 0x01, /* AUX1 */
+ 0x02, /* AUX2 */
+ 0x04, /* AUX3 */
+ 0x08, /* AUX4 */
+ 0x10, /* PC */
+};
+
static struct {
- int hw_code;
- int key_code;
-} ati_remote2_key_table[] = {
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
- { 0x0c, KEY_POWER },
- { 0x0d, KEY_MUTE },
- { 0x10, KEY_VOLUMEUP },
- { 0x11, KEY_VOLUMEDOWN },
- { 0x20, KEY_CHANNELUP },
- { 0x21, KEY_CHANNELDOWN },
- { 0x28, KEY_FORWARD },
- { 0x29, KEY_REWIND },
- { 0x2c, KEY_PLAY },
- { 0x30, KEY_PAUSE },
- { 0x31, KEY_STOP },
- { 0x37, KEY_RECORD },
- { 0x38, KEY_DVD },
- { 0x39, KEY_TV },
- { 0x54, KEY_MENU },
- { 0x58, KEY_UP },
- { 0x59, KEY_DOWN },
- { 0x5a, KEY_LEFT },
- { 0x5b, KEY_RIGHT },
- { 0x5c, KEY_OK },
- { 0x78, KEY_A },
- { 0x79, KEY_B },
- { 0x7a, KEY_C },
- { 0x7b, KEY_D },
- { 0x7c, KEY_E },
- { 0x7d, KEY_F },
- { 0x82, KEY_ENTER },
- { 0x8e, KEY_VENDOR },
- { 0x96, KEY_COFFEE },
- { 0xa9, BTN_LEFT },
- { 0xaa, BTN_RIGHT },
- { 0xbe, KEY_QUESTION },
- { 0xd5, KEY_FRONT },
- { 0xd0, KEY_EDIT },
- { 0xf9, KEY_INFO },
- { (0x00 << 8) | 0x3f, KEY_PROG1 },
- { (0x01 << 8) | 0x3f, KEY_PROG2 },
- { (0x02 << 8) | 0x3f, KEY_PROG3 },
- { (0x03 << 8) | 0x3f, KEY_PROG4 },
- { (0x04 << 8) | 0x3f, KEY_PC },
- { 0, KEY_RESERVED }
+ u8 hwcode;
+ u16 keycode[ARRAY_SIZE(ati_remote2_modes)];
+} ati_remote2_keycodes[] = {
+/* hwcode AUX1 AUX2 AUX3 AUX4 PC */
+ { 0x00, { KEY_0, KEY_0, KEY_0, KEY_0, KEY_0 } },
+ { 0x01, { KEY_1, KEY_1, KEY_1, KEY_1, KEY_1 } },
+ { 0x02, { KEY_2, KEY_2, KEY_2, KEY_2, KEY_2 } },
+ { 0x03, { KEY_3, KEY_3, KEY_3, KEY_3, KEY_3 } },
+ { 0x04, { KEY_4, KEY_4, KEY_4, KEY_4, KEY_4 } },
+ { 0x05, { KEY_5, KEY_5, KEY_5, KEY_5, KEY_5 } },
+ { 0x06, { KEY_6, KEY_6, KEY_6, KEY_6, KEY_6 } },
+ { 0x07, { KEY_7, KEY_7, KEY_7, KEY_7, KEY_7 } },
+ { 0x08, { KEY_8, KEY_8, KEY_8, KEY_8, KEY_8 } },
+ { 0x09, { KEY_9, KEY_9, KEY_9, KEY_9, KEY_9 } },
+ { 0x0c, { KEY_POWER, KEY_POWER, KEY_POWER, KEY_POWER, KEY_POWER } },
+ { 0x0d, { KEY_MUTE, KEY_MUTE, KEY_MUTE, KEY_MUTE, KEY_MUTE } },
+ { 0x10, { KEY_VOLUMEUP, KEY_VOLUMEUP, KEY_VOLUMEUP, KEY_VOLUMEUP, KEY_VOLUMEUP } },
+ { 0x11, { KEY_VOLUMEDOWN, KEY_VOLUMEDOWN, KEY_VOLUMEDOWN, KEY_VOLUMEDOWN, KEY_VOLUMEDOWN } },
+ { 0x20, { KEY_CHANNELUP, KEY_CHANNELUP, KEY_CHANNELUP, KEY_CHANNELUP, KEY_CHANNELUP } },
+ { 0x21, { KEY_CHANNELDOWN, KEY_CHANNELDOWN, KEY_CHANNELDOWN, KEY_CHANNELDOWN, KEY_CHANNELDOWN } },
+ { 0x28, { KEY_FORWARD, KEY_FORWARD, KEY_FORWARD, KEY_FORWARD, KEY_FORWARD } },
+ { 0x29, { KEY_REWIND, KEY_REWIND, KEY_REWIND, KEY_REWIND, KEY_REWIND } },
+ { 0x2c, { KEY_PLAY, KEY_PLAY, KEY_PLAY, KEY_PLAY, KEY_PLAY } },
+ { 0x30, { KEY_PAUSE, KEY_PAUSE, KEY_PAUSE, KEY_PAUSE, KEY_PAUSE } },
+ { 0x31, { KEY_STOP, KEY_STOP, KEY_STOP, KEY_STOP, KEY_STOP } },
+ { 0x37, { KEY_RECORD, KEY_RECORD, KEY_RECORD, KEY_RECORD, KEY_RECORD } },
+ { 0x38, { KEY_DVD, KEY_DVD, KEY_DVD, KEY_DVD, KEY_DVD } },
+ { 0x39, { KEY_TV, KEY_TV, KEY_TV, KEY_TV, KEY_TV } },
+ { 0x3F, { KEY_PROG1, KEY_PROG2, KEY_PROG3, KEY_PROG4, KEY_PC } },
+ { 0x54, { KEY_MENU, KEY_MENU, KEY_MENU, KEY_MENU, KEY_MENU } },
+ { 0x58, { KEY_UP, KEY_UP, KEY_UP, KEY_UP, KEY_UP } },
+ { 0x59, { KEY_DOWN, KEY_DOWN, KEY_DOWN, KEY_DOWN, KEY_DOWN } },
+ { 0x5a, { KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT } },
+ { 0x5b, { KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT } },
+ { 0x5c, { KEY_OK, KEY_OK, KEY_OK, KEY_OK, KEY_OK } },
+ { 0x78, { KEY_A, KEY_A, KEY_A, KEY_A, KEY_A } },
+ { 0x79, { KEY_B, KEY_B, KEY_B, KEY_B, KEY_B } },
+ { 0x7a, { KEY_C, KEY_C, KEY_C, KEY_C, KEY_C } },
+ { 0x7b, { KEY_D, KEY_D, KEY_D, KEY_D, KEY_D } },
+ { 0x7c, { KEY_E, KEY_E, KEY_E, KEY_E, KEY_E } },
+ { 0x7d, { KEY_F, KEY_F, KEY_F, KEY_F, KEY_F } },
+ { 0x82, { KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER } },
+ { 0x8e, { KEY_VENDOR, KEY_VENDOR, KEY_VENDOR, KEY_VENDOR, KEY_VENDOR } },
+ { 0x96, { KEY_COFFEE, KEY_COFFEE, KEY_COFFEE, KEY_COFFEE, KEY_COFFEE } },
+ { 0xa9, { BTN_LEFT, BTN_LEFT, BTN_LEFT, BTN_LEFT, BTN_LEFT } },
+ { 0xaa, { BTN_RIGHT, BTN_RIGHT, BTN_RIGHT, BTN_RIGHT, BTN_RIGHT, } },
+ { 0xbe, { KEY_QUESTION, KEY_QUESTION, KEY_QUESTION, KEY_QUESTION, KEY_QUESTION, } },
+ { 0xd0, { KEY_EDIT, KEY_EDIT, KEY_EDIT, KEY_EDIT, KEY_EDIT } },
+ { 0xd5, { KEY_FRONT, KEY_FRONT, KEY_FRONT, KEY_FRONT, KEY_FRONT } },
+ { 0xf9, { KEY_INFO, KEY_INFO, KEY_INFO, KEY_INFO, KEY_INFO } }
};
struct ati_remote2 {
@@ -117,6 +122,8 @@
char name[64];
char phys[64];
+
+ u32 keycode[ARRAY_SIZE(ati_remote2_keycodes)][ARRAY_SIZE(ati_remote2_modes)];
};
static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
@@ -159,11 +166,84 @@
usb_kill_urb(ar2->urb[1]);
}
+static int ati_remote2_lookup(u8 hwcode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ati_remote2_keycodes); i++)
+ if (ati_remote2_keycodes[i].hwcode == hwcode)
+ return i;
+
+ return -1;
+}
+
+static int ati_remote2_getkeycode(struct input_dev *idev,
+ int scancode, int *keycode)
+{
+ struct ati_remote2 *ar2 = input_get_drvdata(idev);
+ int index, mode;
+
+ if (((scancode >> 8) & mode_mask) != (scancode >> 8))
+ return -EINVAL;
+
+ index = ati_remote2_lookup(scancode & 0xFF);
+ if (index == -1)
+ return -EINVAL;
+
+ for (mode = 0; mode < ARRAY_SIZE(ati_remote2_modes); mode++) {
+ if ((1 << mode) & (scancode >> 8)) {
+ *keycode = ar2->keycode[index][mode];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int ati_remote2_setkeycode(struct input_dev *idev,
+ int scancode, int keycode)
+{
+ struct ati_remote2 *ar2 = input_get_drvdata(idev);
+ int old_keycode = -1;
+ int index, mode;
+
+ if (((scancode >> 8) & mode_mask) != (scancode >> 8))
+ return -EINVAL;
+
+ index = ati_remote2_lookup(scancode & 0xFF);
+ if (index == -1)
+ return -EINVAL;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ for (mode = 0; mode < ARRAY_SIZE(ati_remote2_modes); mode++) {
+ if ((1 << mode) & (scancode >> 8)) {
+ old_keycode = ar2->keycode[index][mode];
+ ar2->keycode[index][mode] = keycode;
+ }
+ }
+
+ set_bit(keycode, idev->keybit);
+
+ for (index = 0; index < ARRAY_SIZE(ati_remote2_keycodes); index++) {
+ for (mode = 0; mode < ARRAY_SIZE(ati_remote2_modes); mode++) {
+ if (ar2->keycode[index][mode] == old_keycode)
+ return 0;
+ }
+ }
+
+ clear_bit(old_keycode, idev->keybit);
+
+ return 0;
+}
+
+
static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
{
struct input_dev *idev = ar2->idev;
u8 *data = ar2->buf[0];
- int channel, mode;
+ u8 channel, mode;
channel = data[0] >> 4;
@@ -187,22 +267,12 @@
input_sync(idev);
}
-static int ati_remote2_lookup(unsigned int hw_code)
-{
- int i;
-
- for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
- if (ati_remote2_key_table[i].hw_code == hw_code)
- return i;
-
- return -1;
-}
-
static void ati_remote2_input_key(struct ati_remote2 *ar2)
{
struct input_dev *idev = ar2->idev;
u8 *data = ar2->buf[1];
- int channel, mode, hw_code, index;
+ u8 channel, mode;
+ int index;
channel = data[0] >> 4;
@@ -218,12 +288,10 @@
return;
}
- hw_code = data[2];
- /*
- * Mode keys (AUX1-AUX4, PC) all generate the same code byte.
- * Use the mode byte to figure out which one was pressed.
- */
- if (hw_code == 0x3f) {
+ if (!((1 << mode) & mode_mask))
+ return;
+
+ if (data[2] == 0x3f) {
/*
* For some incomprehensible reason the mouse pad generates
* events which look identical to the events from the last
@@ -236,14 +304,9 @@
if (data[1] == 0)
ar2->mode = mode;
-
- hw_code |= mode << 8;
}
- if (!((1 << mode) & mode_mask))
- return;
-
- index = ati_remote2_lookup(hw_code);
+ index = ati_remote2_lookup(data[2]);
if (index < 0) {
dev_err(&ar2->intf[1]->dev,
"Unknown code byte (%02x %02x %02x %02x)\n",
@@ -260,8 +323,7 @@
case 2: /* repeat */
/* No repeat for mouse buttons. */
- if (ati_remote2_key_table[index].key_code == BTN_LEFT ||
- ati_remote2_key_table[index].key_code == BTN_RIGHT)
+ if (data[2] == 0xa9 || data[2] == 0xaa)
return;
if (!time_after_eq(jiffies, ar2->jiffies))
@@ -276,7 +338,7 @@
return;
}
- input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]);
+ input_event(idev, EV_KEY, ar2->keycode[index][mode], data[1]);
input_sync(idev);
}
@@ -334,10 +396,11 @@
"%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
}
+
static int ati_remote2_input_init(struct ati_remote2 *ar2)
{
struct input_dev *idev;
- int i, retval;
+ int index, mode, retval;
idev = input_allocate_device();
if (!idev)
@@ -347,11 +410,15 @@
input_set_drvdata(idev, ar2);
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
- idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
- BIT_MASK(BTN_RIGHT);
+ idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
- for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
- set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
+
+ for (index = 0; index < ARRAY_SIZE(ati_remote2_keycodes); index++) {
+ for (mode = 0; mode < ARRAY_SIZE(ati_remote2_modes); mode++) {
+ ar2->keycode[index][mode] = ati_remote2_keycodes[index].keycode[mode];
+ set_bit(ar2->keycode[index][mode], idev->keybit);
+ }
+ }
idev->rep[REP_DELAY] = 250;
idev->rep[REP_PERIOD] = 33;
@@ -359,6 +426,9 @@
idev->open = ati_remote2_open;
idev->close = ati_remote2_close;
+ idev->getkeycode = ati_remote2_getkeycode;
+ idev->setkeycode = ati_remote2_setkeycode;
+
idev->name = ar2->name;
idev->phys = ar2->phys;
@@ -532,6 +602,9 @@
else
printk(KERN_INFO "ati_remote2: " DRIVER_DESC " " DRIVER_VERSION "\n");
+ mode_mask &= 0x1F;
+ channel_mask &= 0xFFFF;
+
return r;
}
next reply other threads:[~2008-04-05 18:33 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-04-05 18:30 Peter Stokes [this message]
2008-04-08 20:18 ` [PATCH] ati_remote2 loadable keymap support Ville Syrjälä
2008-04-17 19:00 ` Dmitry Torokhov
2008-04-18 20:49 ` Peter Stokes
2008-04-18 19:42 ` Peter Stokes
2008-06-03 18:45 ` Ville Syrjälä
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200804051930.10574.linux@dadeos.co.uk \
--to=linux@dadeos.co.uk \
--cc=dmitry.torokhov@gmail.com \
--cc=jkosina@suse.cz \
--cc=linux-input@vger.kernel.org \
--cc=syrjala@sci.fi \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).