From: "Ville Syrjälä" <syrjala@sci.fi>
To: Peter Stokes <linux@dadeos.co.uk>
Cc: linux-input@vger.kernel.org, Jiri Kosina <jkosina@suse.cz>,
dmitry.torokhov@gmail.com
Subject: Re: [PATCH] ati_remote2 loadable keymap support
Date: Tue, 8 Apr 2008 23:18:26 +0300 [thread overview]
Message-ID: <20080408201826.GG16619@sci.fi> (raw)
In-Reply-To: <200804051930.10574.linux@dadeos.co.uk>
On Sat, Apr 05, 2008 at 07:30:10PM +0100, Peter Stokes wrote:
> 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.
Userspace keymap handling would not require any special case code in
many applications. It would just need a small daemon that would react
to the mode keys and reload the keymap. Getting such a thing
packaged/distributed might be a bigger challenge though, so if you
really want to have it in the kernel driver I can live with 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.
It does increase the module size though.
> 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
>
>
> 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>
2008?
> *
> * 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".
> */
Unrelated change. I saw a couple of other unrelated changes too (just
changing the whitespace) further down.
>
> @@ -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 */
> +};
It seems you only use this table to get the number of modes. A define
would suffice.
> 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 */
checkpatch.pl doesn't like these long lines.
> 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)];
Somehow it would seem more natural to me if you would swap the array
dimensions. But that's a minor issue and you can leave it like this if
you prefer.
> };
>
> 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;
> + }
> + }
Is there a reason you using the high bits like a mask? IIRC the hardware
mode byte isn't a mask. So something like this should do:
mode = scancode >> 8;
if (mode < 0 || mode > MAX_MODE)
return -EINVAL;
index = ati_remote2_lookup(scancode & 0xff);
if (index < 0)
return -EINVAL;
I'm not sure if mode_mask should affect the keymap handling at all since both
can be changed runtime.
> +
> + 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;
> +
Same comments as above.
> + index = ati_remote2_lookup(scancode & 0xFF);
> + if (index == -1)
> + return -EINVAL;
> +
> + if (keycode < 0 || keycode > KEY_MAX)
Are KEY_RESERVED/KEY_MAX valid here?
> + 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;
> + }
> + }
Because of using the scancode high bits as a mask this could leave some
bits set even though they are no longer in the map.
> +
> + 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;
Moving this test before updating ar2->mode could leave the driver
unaware of the actual mode it's in. I think it could leave to key
events getting through from the mouse at least when mode_mask is
suitably changed runtime. Was there a reason for this change?
> -
> - 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;
> +
As I said these can be changed runtime, so masking them should happen
every time they are used. A nicer solution would be to actually
reject invalid values.
> return r;
> }
>
--
Ville Syrjälä
syrjala@sci.fi
http://www.sci.fi/~syrjala/
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2008-04-08 20:18 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-04-05 18:30 [PATCH] ati_remote2 loadable keymap support Peter Stokes
2008-04-08 20:18 ` Ville Syrjälä [this message]
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=20080408201826.GG16619@sci.fi \
--to=syrjala@sci.fi \
--cc=dmitry.torokhov@gmail.com \
--cc=jkosina@suse.cz \
--cc=linux-input@vger.kernel.org \
--cc=linux@dadeos.co.uk \
/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).