dm355evm input driver
Subsystems (2)
PATCH 5/6 dm355evm input driver
From: David Brownell <[email protected]>
Simple input driver support for the events reported by the MSP430 firmware on the DM355 EVM. Verified using the remote included with the kit; docs weren't quite right. Some of the keycode selections might need improvement; I'm hoping I implemented the remapping support right, so there's at least a runtime workaround.
Keys on the remote seem to repeat undesirably. Someone might want to see what's up with that, and fix it; it might just be an issue of tracking RC5 state and using the toggle.
---
Depends on the patch for the parent MFD driver, and won't work without the patch making GPIO IRQs work on dm355.
NOTE: not suitable for mainline until the dm355evm board support (and parent MFD driver) is in the merge queue.
drivers/input/keyboard/Kconfig | 8 drivers/input/keyboard/Makefile | 1 drivers/input/keyboard/dm355evm_keys.c | 303 +++++++++++++++++++++++++++++++ 3 files changed, 312 insertions(+)
drivers/input/keyboard/Kconfig +8 -0
@@ -356,4 +356,12 @@ config KEYBOARD_SH_KEYSC To compile this driver as a module, choose M here: the module will be called sh_keysc. + +config KEYBOARD_DM355EVM + tristate "TI DaVinci DM355 EVM Keypad and IR Remote" + depends on MFD_DM355EVM_MSP + help + Supports the pushbuttons and IR remote used with + the DM355 EVM board. + endif
drivers/input/keyboard/Makefile +1 -0
@@ -31,3 +31,4 @@ obj-$(CONFIG_KEYBOARD_HP7XX) += jornada obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o +obj-$(CONFIG_KEYBOARD_DM355EVM) += dm355evm_keys.o
drivers/input/keyboard/dm355evm_keys.c new file +303 -0
303 lines not on this page · raw message
Hi Dave,
only one comment below.
drivers/input/keyboard/dm355evm_keys.c line 203
Quoted 13 lines · David Brownell
drivers/input/keyboard/dm355evm_keys.c new file +13
-0+static int __devinit dm355evm_keys_probe (struct platform_device *pdev) +{ +struct dm355evm_keys *keys; +int status = -ENOMEM ; +struct input_dev *input; +int i; + +/* allocate instance struct */ + keys =kzalloc (sizeof *keys,GFP_KERNEL ); +if (!keys) + goto fail0; +platform_set_drvdata (pdev, keys); + keys->pdev = pdev;
you could be holding only the device pointer.
keys->dev = &pdev->dev;
then, if you really happen to need the pdev pointer you can use
to_platform_device(keys->dev);
Signature · 1 line
balbi
Quoted 10 lines · Felipe Balbi
Quoted 2 lines
+ platform_set_drvdata(pdev, keys);
+ keys->pdev = pdev;you could be holding only the device pointer.
keys->dev =
&pdev->dev;then, if you really happen to need the pdev pointer you can use
to_platform_device(keys->dev);
True, that would be a bit simpler; the device handle is what's normally needed, e.g. for dev_dbg(). I'd take an update patch; but for now I'll avoid a re-test cycle. :)
- Dave
Quoted 3 lines · David Brownell
True, that would be a bit simpler; the device handle is what's normally needed, e.g. for
dev_dbg(). I'd take an update patch; but for now I'll avoid a re-test cycle. :)
Sure, I'm in the testing your patches right now. Will send you an update patch soonish ;-)
Great work btw :-D everything looks great.
Signature · 1 line
balbi
Quoted 8 lines · David Brownell
Quoted 7 lines · Felipe Balbi
Quoted 2 lines
+ platform_set_drvdata(pdev, keys);
+ keys->pdev = pdev;you could be holding only the device pointer.
keys->dev =
&pdev->dev;
Quoted 7 lines
Quoted 3 lines
then, if you really happen to need the pdev pointer you can use
to_platform_device(keys->dev);True, that would be a bit simpler; the device handle is what's normally needed, e.g. for
dev_dbg(). I'd take an update patch; but for now I'll avoid a re-test cycle. :)
Here's an update patch for your input driver:
================ cut here ===================
drivers/input/keyboard/dm355evm_keys.c +7 -5
@@ -33,7 +33,7 @@struct dm355evm_keys {struct work_struct work;struct input_dev *input; -struct platform_device *pdev; +struct device *dev;int irq; };
@@ -128,7 +128,7 @@ static void dm355evm_keys_work(struct work_struct *work) status =dm355evm_msp_read (DM355EVM_MSP_INPUT_HIGH );if (status <0 ) { -dev_dbg (&keys->pdev->dev,"input high err %d\n" , +dev_dbg (keys->dev,"input high err %d\n" , status);break ; }
@@ -136,7 +136,7 @@ static void dm355evm_keys_work(struct work_struct *work) status =dm355evm_msp_read (DM355EVM_MSP_INPUT_LOW );if (status <0 ) { -dev_dbg (&keys->pdev->dev,"input low err %d\n" , +dev_dbg (keys->dev,"input low err %d\n" , status);break ; }
@@ -155,7 +155,7 @@ static void dm355evm_keys_work(struct work_struct *work) keycode = dm355evm_keys[i].keycode;break ; } -dev_dbg (&keys->pdev->dev, +dev_dbg (keys->dev,"input event 0x%04x--> keycode %d\n" , event, keycode);
@@ -200,7 +200,7 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)if (!keys) goto fail0;platform_set_drvdata (pdev, keys); - keys->pdev = pdev; + keys->dev = &pdev->dev;/* ... and input dev ... */ input =input_allocate_device ();
@@ -257,6 +257,7 @@ fail1: fail0:kfree (keys);dev_err (&pdev->dev,"can't register, err %d\n" , status); +return status; }
@@ -267,6 +268,7 @@ static int __devexit dm355evm_keys_remove(struct platform_device *pdev)free_irq (keys->irq, keys);input_unregister_device (keys->input);kfree (keys); +return 0 ; }
Signature · 5 lines
balbi -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 1 line · Felipe Balbi
Here's an update patch for your input driver:
Looks good, thanks. If someone commits the original patch, this one has my ack. Else I'll merge this into the next version I send.
- Dave
I have a question for the Input folk, see below ...
Quoted 21 lines · David Brownell
From: David Brownell <[email protected]>
Simple input driver support for the events reported by the MSP430 firmware on the DM355 EVM. Verified using the remote included with the kit; docs weren't quite right. Some of the keycode selections might need improvement; I'm hoping I implemented the remapping support right, so there's at least a runtime workaround.
Keys on the remote seem to repeat undesirably. Someone might want to see what's up with that, and fix it; it might just be an issue of tracking RC5 state and using the toggle.
Signed-off-by David Brownell <[email protected]>---
Depends on the patch for the parent MFD driver, and won't work without the patch making GPIO IRQs work on dm355.NOTE: not suitable for mainline until the dm355evm board support (and parent MFD driver) is in the merge queue.
Quoted 6 lines
drivers/input/keyboard/Kconfig | 8 drivers/input/keyboard/Makefile | 1 drivers/input/keyboard/dm355evm_keys.c | 303 +++++++++++++++++++++++++++++++ 3 files changed, 312 insertions(+)...
It seems this RC5 coding is used by a fair number of devices. Is this the first one to get Linux support?
I kind of get the impression that some more generic support for this might be useful at some point. Along the lines of a module to map (and remap?) RC5 codes to what Linux uses.
Maybe the *next* remote control driver can worry about that. :)
- Dave
Quoted 42 lines
drivers/input/keyboard/dm355evm_keys.c new file +42
-0+/* +* IR buttons ... codes assigned to match the universal remote +* provided with the EVM (Philips PM4S) using DVD code 0020. +* +* These event codes match firmware documentation, but other +* remote controls could easily send more RC5-encoded events. +* The PM4S manual was used in several cases to help select +* a keycode reflecting the intended usage. +* +* RC5 codes are 14 bits, with two start bits (0x3 prefix) +* and a toggle bit (masked out below). +*/ + { 0x300c, KEY_POWER, }, /* NOTE: docs omit this */ + { 0x3000, KEY_NUMERIC_0, }, + { 0x3001, KEY_NUMERIC_1, }, + { 0x3002, KEY_NUMERIC_2, }, + { 0x3003, KEY_NUMERIC_3, }, + { 0x3004, KEY_NUMERIC_4, }, + { 0x3005, KEY_NUMERIC_5, }, + { 0x3006, KEY_NUMERIC_6, }, + { 0x3007, KEY_NUMERIC_7, }, + { 0x3008, KEY_NUMERIC_8, }, + { 0x3009, KEY_NUMERIC_9, }, + { 0x3022, KEY_ENTER, }, + { 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */ + { 0x300f, KEY_SELECT, }, /* "info" */ + { 0x3020, KEY_CHANNELUP, }, /* "up" */ + { 0x302e, KEY_MENU, }, /* "in/out" */ + { 0x3011, KEY_VOLUMEDOWN, }, /* "left" */ + { 0x300d, KEY_MUTE, }, /* "ok" */ + { 0x3010, KEY_VOLUMEUP, }, /* "right" */ + { 0x301e, KEY_SUBTITLE, }, /* "cc" */ + { 0x3021, KEY_CHANNELDOWN, }, /* "down" */ + { 0x3022, KEY_PREVIOUS, }, + { 0x3026, KEY_SLEEP, }, + { 0x3172, KEY_REWIND, }, /* NOTE: docs wrongly say 0x30ca */ + { 0x3175, KEY_PLAY, }, + { 0x3174, KEY_FASTFORWARD, }, + { 0x3177, KEY_RECORD, }, + { 0x3176, KEY_STOP, }, + { 0x3169, KEY_PAUSE, }, +};
Dmitry Torokhov
maintainerHi David,
Quoted 13 lines · David Brownell
From: David Brownell <[email protected]>
Simple input driver support for the events reported by the MSP430 firmware on the DM355 EVM. Verified using the remote included with the kit; docs weren't quite right. Some of the keycode selections might need improvement; I'm hoping I implemented the remapping support right, so there's at least a runtime workaround.
Keys on the remote seem to repeat undesirably. Someone might want to see what's up with that, and fix it; it might just be an issue of tracking RC5 state and using the toggle.
Quoted 8 lines
Signed-off-by David Brownell <[email protected]>---
Depends on the patch for the parent MFD driver, and won't work without the patch making GPIO IRQs work on dm355.NOTE: not suitable for mainline until the dm355evm board support (and parent MFD driver) is in the merge queue.
It looks like the MFD driver was merged so we need to start wokring on this one :)
drivers/input/keyboard/dm355evm_keys.c line 166
Quoted 9 lines
drivers/input/keyboard/dm355evm_keys.c new file +9
-0+dev_dbg (&keys->pdev->dev, +"input event 0x%04x--> keycode %d\n" , + event, keycode); + +/* Report press + release ... we can't tell if +* this is an autorepeat, and we need to guess +* about the release. +*/ +input_report_key (keys->input, keycode,1 );
input_sync() is also needed here.
drivers/input/keyboard/dm355evm_keys.c line 177
Quoted 11 lines
drivers/input/keyboard/dm355evm_keys.c new file +11
-0+input_report_key (keys->input, keycode,0 ); + } +input_sync (keys->input); +} + +static int dm355evm_setkeycode (struct input_dev *dev,int index,int keycode) +{ +if (index >=ARRAY_SIZE (dm355evm_keys)) +return -EINVAL ; + + dm355evm_keys[index].keycode = keycode;
You also need to alter dev->keybit to indicate that device may generate new keycode, otherwise input core will drop event intead of passing it on. Also I prefer devices that support remapping to keep their copy of keymap so in unlikely case there are 2 devices in the system they can have separate keymaps.
Quoted 38 lines
drivers/input/keyboard/dm355evm_keys.c new file +38
-0+return 0 ; +} + +static int dm355evm_getkeycode (struct input_dev *dev,int index,int *keycode) +{ +if (index >=ARRAY_SIZE (dm355evm_keys)) +return -EINVAL ; + +return dm355evm_keys[index].keycode; +} + +/*----------------------------------------------------------------------*/ + +static int __devinit dm355evm_keys_probe (struct platform_device *pdev) +{ +struct dm355evm_keys *keys; +int status = -ENOMEM ; +struct input_dev *input; +int i; + +/* allocate instance struct */ + keys =kzalloc (sizeof *keys,GFP_KERNEL ); +if (!keys) + goto fail0; +platform_set_drvdata (pdev, keys); + keys->pdev = pdev; + +/* ... and input dev ... */ + input =input_allocate_device (); +if (!input) + goto fail0; + keys->input = input; +input_set_drvdata (input, keys); + + input->name ="DM355 EVM Controls" ; + input->phys ="dm355evm/input0" ; + input->dev.parent = &pdev->dev; +
drivers/input/keyboard/dm355evm_keys.c line 225
Quoted 10 lines
drivers/input/keyboard/dm355evm_keys.c new file +10
-0+ input->id.bustype =BUS_I2C ; + input->id.product =0x0355 ; + input->id.version =dm355evm_msp_read (DM355EVM_MSP_FIRMREV ); + + input->evbit[0 ] =BIT (EV_KEY ); +for (i =0 ; i <ARRAY_SIZE (dm355evm_keys); i++) +set_bit (dm355evm_keys[i].keycode, input->keybit); + + input->keycodemax =ARRAY_SIZE (dm355evm_keys); + input->keycodesize =sizeof (dm355evm_keys[0 ]);
You don't need to setup keycodesize and keycodemax since you provide your own get and set keycode helpers.
Quoted 15 lines
drivers/input/keyboard/dm355evm_keys.c new file +15
-0+ input->keycode = dm355evm_keys; + input->setkeycode = dm355evm_setkeycode; + input->getkeycode = dm355evm_getkeycode; + +/* set up "threaded IRQ handler" */ + status =platform_get_irq (pdev,0 ); +if (status <0 ) + goto fail1; + keys->irq = status; +INIT_WORK (&keys->work, dm355evm_keys_work); + +/* REVISIT: flush the event queue? */ + +/* register */ + status =input_register_device (input);
drivers/input/keyboard/dm355evm_keys.c line 250
Quoted 10 lines
drivers/input/keyboard/dm355evm_keys.c new file +10
-0+if (status <0 ) + goto fail1; + +/* start reporting events */ + status =request_irq (keys->irq, dm355evm_keys_irq, +IRQF_TRIGGER_FALLING , +dev_name (&pdev->dev), keys); +if (status <0 ) { +input_unregister_device (input); + goto fail1;
You should not call input_free_device() after input_unregister_device(). Either jump to "fail0" or do "input = NULL;".
Quoted 12 lines
drivers/input/keyboard/dm355evm_keys.c new file +12
-0+ } + +return 0 ; + +fail1: +input_free_device (input); +fail0: +kfree (keys); +dev_err (&pdev->dev,"can't register, err %d\n" , status); +return status; +} +
Signature · 1 line
Dmitry
Quoted 10 lines · Dmitry Torokhov
...
Quoted 6 lines
Depends on the patch for the parent MFD driver, and won't work without the patch making GPIO IRQs work on dm355.
NOTE: not suitable for mainline until the dm355evm board support (and parent MFD driver) is in the merge queue.
It looks like the MFD driver was merged so we need to start wokring on this one :)
Much to my surprise! :)
Quoted 12 lines
drivers/input/keyboard/dm355evm_keys.c line 166
Quoted 9 lines
drivers/input/keyboard/dm355evm_keys.c new file +9
-0+dev_dbg (&keys->pdev->dev, +"input event 0x%04x--> keycode %d\n" , + event, keycode); + +/* Report press + release ... we can't tell if +* this is an autorepeat, and we need to guess +* about the release. +*/ +input_report_key (keys->input, keycode,1 );
input_sync()is also needed here.
Quoted 3 lines
drivers/input/keyboard/dm355evm_keys.c line 169
Quoted 3 lines
drivers/input/keyboard/dm355evm_keys.c new file +3
-0+input_report_key (keys->input, keycode,0 ); + } +input_sync (keys->input);
If so, then the existing input_sync() needs to move up a few lines too ... I had thought that the "sync" was like with a filesystem, where lots of events could be batched, but evidently not.
Quoted 4 lines
Quoted 4 lines
drivers/input/keyboard/dm355evm_keys.c new file +4
-0+} + +static int dm355evm_setkeycode (struct input_dev *dev,int index,int keycode) +{
Quoted 8 lines
drivers/input/keyboard/dm355evm_keys.c line 177
Quoted 4 lines
drivers/input/keyboard/dm355evm_keys.c new file +4
-0+if (index >=ARRAY_SIZE (dm355evm_keys)) +return -EINVAL ; + + dm355evm_keys[index].keycode = keycode;You also need to alter
dev->keybitto indicate that device may generate new keycode, otherwise input core will drop event intead of passing it on.
Should something then be scrubbing out dev->keybit to indicate the *old* key code is no longer reported? (After verifying that no other button reports it.)
Quoted 3 lines
Also I prefer devices that support remapping to keep their copy of keymap so in unlikely case there are 2 devices in the system they can have separate keymaps.
That's physically impossible in this case.
Quoted 9 lines
drivers/input/keyboard/dm355evm_keys.c line 225
Quoted 6 lines
drivers/input/keyboard/dm355evm_keys.c new file +6
-0+ input->evbit[0 ] =BIT (EV_KEY ); +for (i =0 ; i <ARRAY_SIZE (dm355evm_keys); i++) +set_bit (dm355evm_keys[i].keycode, input->keybit); + + input->keycodemax =ARRAY_SIZE (dm355evm_keys); + input->keycodesize =sizeof (dm355evm_keys[0 ]);You don't need to setup keycodesize and keycodemax since you provide your own get and set keycode helpers.
... which I'm presuming is the right thing to do. It's a bit surprising to see that the input core will then have no way to tell what keycodes are valid other than querying all possible codes!
Quoted 10 lines
drivers/input/keyboard/dm355evm_keys.c line 250
Quoted 7 lines
drivers/input/keyboard/dm355evm_keys.c new file +7
-0+/* start reporting events */ + status =request_irq (keys->irq, dm355evm_keys_irq, +IRQF_TRIGGER_FALLING , +dev_name (&pdev->dev), keys); +if (status <0 ) { +input_unregister_device (input); + goto fail1;You should not call
input_free_device()afterinput_unregister_device(). Either jump to "fail0" or do "input = NULL;".
"goto fail0" seems much simpler. :)
Dmitry Torokhov
maintainerQuoted 27 lines · David Brownell
Quoted 10 lines · Dmitry Torokhov
...
Quoted 6 lines
Depends on the patch for the parent MFD driver, and won't work without the patch making GPIO IRQs work on dm355.
NOTE: not suitable for mainline until the dm355evm board support (and parent MFD driver) is in the merge queue.
It looks like the MFD driver was merged so we need to start wokring on this one :)
Much to my surprise! :)
Quoted 12 lines
drivers/input/keyboard/dm355evm_keys.c line 166
Quoted 9 lines
drivers/input/keyboard/dm355evm_keys.c new file +9
-0+dev_dbg (&keys->pdev->dev, +"input event 0x%04x--> keycode %d\n" , + event, keycode); + +/* Report press + release ... we can't tell if +* this is an autorepeat, and we need to guess +* about the release. +*/ +input_report_key (keys->input, keycode,1 );
input_sync()is also needed here.
Quoted 9 lines
Quoted 3 lines
drivers/input/keyboard/dm355evm_keys.c line 169
Quoted 3 lines
drivers/input/keyboard/dm355evm_keys.c new file +3
-0+input_report_key (keys->input, keycode,0 ); + } +input_sync (keys->input);If so, then the existing
input_sync()needs to move up a few lines too ... I had thought that the "sync" was like with a filesystem, where lots of events could be batched, but evidently not.
It is and they can. The idea is that userspace accumulates input events until it gets the sync event which signals that as full as possible hardware state was transmitted. The problem with keys is that if userspace really does accumulate events the 2 down/up in succession will cancel each other. There are really 2 separate states - button pressed and button released which should be accompanied with its own sync. But if you were reposting several buttons at once they could all "share" the same sync event. Does it make any sense to you?
Quoted 14 lines
Quoted 13 lines
drivers/input/keyboard/dm355evm_keys.c line 177
Quoted 9 lines
drivers/input/keyboard/dm355evm_keys.c new file +8
-0+} + +static int dm355evm_setkeycode (struct input_dev *dev,int index,int keycode) +{ +if (index >=ARRAY_SIZE (dm355evm_keys)) +return -EINVAL ; + + dm355evm_keys[index].keycode = keycode;You also need to alter
dev->keybitto indicate that device may generate new keycode, otherwise input core will drop event intead of passing it on.
Quoted 4 lines
Should something then be scrubbing out
dev->keybitto indicate the *old* key code is no longer reported? (After verifying that no other button reports it.)
Yes, that is responsibility of the setkeycode method as well.
Quoted 7 lines
Quoted 4 lines
Also I prefer devices that support remapping to keep their copy of keymap so in unlikely case there are 2 devices in the system they can have separate keymaps.
That's physically impossible in this case.
Ah, OK.
Quoted 11 lines
Quoted 10 lines
drivers/input/keyboard/dm355evm_keys.c line 225
Quoted 7 lines
drivers/input/keyboard/dm355evm_keys.c new file +6
-0+ input->evbit[0 ] =BIT (EV_KEY ); +for (i =0 ; i <ARRAY_SIZE (dm355evm_keys); i++) +set_bit (dm355evm_keys[i].keycode, input->keybit); + + input->keycodemax =ARRAY_SIZE (dm355evm_keys); + input->keycodesize =sizeof (dm355evm_keys[0 ]);You don't need to setup keycodesize and keycodemax since you provide your own get and set keycode helpers.
Quoted 5 lines
... which I'm presuming is the right thing to do. It's a bit surprising to see that the input core will then have no way to tell what keycodes are valid other than querying all possible codes!
It knows keycodes but not scancodes (or their equivalent). Given that many (most?) keympas are sparse input core does not really know whether a value is a valid scancode or not even if it is within the range of input->keycodemax. COnsider HID - its 'scancodes' are 64 bits ;)
Quoted 12 lines
Quoted 11 lines
drivers/input/keyboard/dm355evm_keys.c line 250
Quoted 8 lines
drivers/input/keyboard/dm355evm_keys.c new file +7
-0+/* start reporting events */ + status =request_irq (keys->irq, dm355evm_keys_irq, +IRQF_TRIGGER_FALLING , +dev_name (&pdev->dev), keys); +if (status <0 ) { +input_unregister_device (input); + goto fail1;You should not call
input_free_device()afterinput_unregister_device(). Either jump to "fail0" or do "input = NULL;".
Quoted 2 lines
"goto fail0" seems much simpler. :)
So you will be sending an update, right?
Thanks!
Signature · 1 line
Dmitry
Quoted 18 lines · Dmitry Torokhov
Quoted 8 lines
Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ /* Report press + release ... we can't tell if + * this is an autorepeat, and we need to guess + * about the release. + */ + input_report_key(keys->input, keycode, 1);
input_sync()is also needed here.Quoted 9 lines
Quoted 3 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ input_report_key(keys->input, keycode, 0); + } + input_sync(keys->input);If so, then the existing
input_sync()needs to move up a few lines too ... I had thought that the "sync" was like with a filesystem, where lots of events could be batched, but evidently not.
Quoted 8 lines
It is and they can. The idea is that userspace accumulates input events until it gets the sync event which signals that as full as possible hardware state was transmitted. The problem with keys is that if userspace really does accumulate events the 2 down/up in succession will cancel each other. There are really 2 separate states - button pressed and button released which should be accompanied with its own sync. But if you were reposting several buttons at once they could all "share" the same sync event. Does it make any sense to you?
Yes. But now I seem to observe a LOT more events. I suppose that's partly due to the fuzzy semantics of these events: they don't encode "down" or "up".
Quoted 1 line
So you will be sending an update, right?
Appended is a patchlet addressing your feedback. What I'll do is submit this to the DaVinci tree, and send you an all-in-one patch.
- Dave
======= SNIP!
From: David Brownell <[email protected]>
Address feedback from Dmitry:
- input_sync() per event
- maintain dev->keybit when remapping keys
- since we handle remapping, keycodemax and keycodesize aren't used
- on probe error, don't input_free_device() unless it registered
Also:
- avoid reporting excess events
- more bad-parameter paranoia in the remapping code
The excess event issue is basically that we don't have a way to distinguish "button press" events from "button release" ones or autorepeat events, so we should try being a bit smarter about synthesizing them.
--- drivers/input/keyboard/dm355evm_keys.c | 49 ++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-)
drivers/input/keyboard/dm355evm_keys.c +39 -10
@@ -28,6 +28,8 @@* using a work_struct. The IRQ is active low, but we use it through * the GPIO controller so we can trigger on falling edges. * +* Note that physically there can only be one of these devices. +* * This driver was tested with firmware revision A4. */ struct dm355evm_keys {
@@ -120,6 +122,8 @@ static void dm355evm_keys_work(struct wo* Reading INPUT_LOW decrements the count. */ for (;;) { +static u16 last_event; +u16 event;int keycode;int i;
@@ -142,6 +146,23 @@ static void dm355evm_keys_work(struct woif (event ==0xdead )break ; +/* Press and release a button: two events, same code. +* Press and hold (autorepeat), then release: N events +* (N > 2), same code. For RC5 buttons the toggle bits +* distinguish (for example) "1-autorepeat" from "1 1"; +* but PCB buttons don't support that bit. +* +* So we must synthesize release events. We do that by +* mapping events to a press/release event pair; then +* to avoid adding extra events, skip the second event +* of each pair. +*/ +if (event == last_event) { + last_event =0 ; +continue ; + } + last_event = event; +/* ignore the RC5 toggle bit */ event &= ~0x0800 ;
@@ -157,28 +178,38 @@ static void dm355evm_keys_work(struct wo"input event 0x%04x--> keycode %d\n" , event, keycode); -/* Report press + release ... we can't tell if -* this is an autorepeat, and we need to guess -* about the release. -*/ +/* report press + release */ input_report_key (keys->input, keycode,1 ); +input_sync (keys->input);input_report_key (keys->input, keycode,0 ); +input_sync (keys->input); } -input_sync (keys->input); }static int dm355evm_setkeycode (struct input_dev *dev,int index,int keycode) { -if (index >=ARRAY_SIZE (dm355evm_keys)) +u16 old_keycode; +unsigned i; + +if (((unsigned )index) >=ARRAY_SIZE (dm355evm_keys))return -EINVAL ; + old_keycode = dm355evm_keys[index].keycode; dm355evm_keys[index].keycode = keycode; +set_bit (keycode, dev->keybit); + +for (i =0 ; i <ARRAY_SIZE (dm355evm_keys); i++) { +if (dm355evm_keys[index].keycode == old_keycode) + goto done; + } +clear_bit (old_keycode, dev->keybit); +done:return 0 ; }static int dm355evm_getkeycode (struct input_dev *dev,int index,int *keycode) { -if (index >=ARRAY_SIZE (dm355evm_keys)) +if (((unsigned )index) >=ARRAY_SIZE (dm355evm_keys))return -EINVAL ;return dm355evm_keys[index].keycode;
@@ -219,8 +250,6 @@ static int __devinit dm355evm_keys_probefor (i =0 ; i <ARRAY_SIZE (dm355evm_keys); i++)set_bit (dm355evm_keys[i].keycode, input->keybit); - input->keycodemax =ARRAY_SIZE (dm355evm_keys); - input->keycodesize =sizeof (dm355evm_keys[0 ]); input->keycode = dm355evm_keys; input->setkeycode = dm355evm_setkeycode; input->getkeycode = dm355evm_getkeycode;
@@ -237,7 +266,7 @@ static int __devinit dm355evm_keys_probe/* register */ status =input_register_device (input);if (status <0 ) - goto fail1; + goto fail0;/* start reporting events */ status = request_irq(keys->irq, dm355evm_keys_irq,