From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peter Stokes Subject: [PATCH] ati_remote2 loadable keymap support Date: Sat, 5 Apr 2008 19:30:10 +0100 Message-ID: <200804051930.10574.linux@dadeos.co.uk> Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_yU89HzrAl1YEQIm" Return-path: Received: from smtp1.wanadoo.co.uk ([193.252.22.158]:2376 "EHLO smtp1.freeserve.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753132AbYDESda (ORCPT ); Sat, 5 Apr 2008 14:33:30 -0400 Sender: linux-input-owner@vger.kernel.org List-Id: linux-input@vger.kernel.org To: linux-input@vger.kernel.org Cc: Ville =?iso-8859-1?q?Syrj=E4l=E4?= , Jiri Kosina , dmitry.torokhov@gmail.com --Boundary-00=_yU89HzrAl1YEQIm Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline The attached patch adds support for loadable key maps support to the=20 ati_remote2 driver. This patch is similar to the previous version that I originally posted on 1= 6th=20 =46ebruary 2008. As requested, I have removed the code that reconfigured th= is=20 driver to utilise the input core's built in soft auto repeat functionality.= =20 Those changes are pending further clarification on how buttons that should= =20 not be auto repeated (e.g. mouse buttons) can be excluded from the soft aut= o=20 repeat implementation. On Tuesday 04 March 2008 22:17:49 Ville Syrj=E4l=E4 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 generate= d=20 from any given physical key on the remote dependant upon which 'mode' the=20 remote is currently in should be dropped. Consequently I have left the=20 implementation in the attached patch. I feel that a valid way of thinking about this implementation is that the=20 hardware scancodes consist of the mode and key bytes combined. Given any su= ch=20 implementation it could be assumed that the device has 5 x 46 =3D 230 keys,= it=20 therefore seems entirely reasonable to me to provide a mechanism by which a= ny=20 of those keys can be remapped. On Tuesday 04 March 2008 20:38:22 Ville Syrj=E4l=E4 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= =20 user space. The primary purpose behind making these changes is to provide=20 full access to all of the keys within X windows, as such one is dependant=20 upon the X input system interfacing to the event device. The goal is to mak= e=20 this device behave as a regular keyboard, not requiring any special case co= de=20 in any application the user might wish to control using it.=20 I do not feel that my proposed code changes are particularly invasive. I wo= uld=20 accept that the static table outlining the default keycode mappings=20 represents a reasonable change. Whilst this table could be eliminated (and= =20 generated programmatically) I feel that it serves in some part towards=20 documenting the implementation. All of the changes proposed have no effect upon the operation of the driver= =20 out-of-the-box they merely provide a mechanism by which an end user can=20 configure their setup to function as they desire. Best regards Peter Stokes --Boundary-00=_yU89HzrAl1YEQIm Content-Type: text/x-diff; charset="iso-8859-1"; name="ati_remote2_keycode.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ati_remote2_keycode.patch" Signed-off-by: Peter Stokes --- 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 - * Copyright (C) 2007 Peter Stokes + * Copyright (C) 2007 Peter Stokes * * 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 #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; } --Boundary-00=_yU89HzrAl1YEQIm--