* [PATCH] atkbd: add basic debounce support
@ 2015-07-13 7:36 Gavin Li
2015-07-13 17:20 ` Dmitry Torokhov
0 siblings, 1 reply; 3+ messages in thread
From: Gavin Li @ 2015-07-13 7:36 UTC (permalink / raw)
To: Dmitry Torokhov, linux-input; +Cc: Gavin Li
From: Gavin Li <git@thegavinli.com>
For physically quirky or otherwise poor keyboards.
---
drivers/input/keyboard/atkbd.c | 69 +++++++++++++++++++++++++++++++++---------
1 file changed, 54 insertions(+), 15 deletions(-)
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 387c51f..b1ff62d 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -28,6 +28,7 @@
#include <linux/libps2.h>
#include <linux/mutex.h>
#include <linux/dmi.h>
+#include <linux/timekeeping.h>
#define DRIVER_DESC "AT and PS/2 keyboard driver"
@@ -67,6 +68,10 @@ static bool atkbd_terminal;
module_param_named(terminal, atkbd_terminal, bool, 0);
MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
+static int atkbd_debounce;
+module_param_named(debounce, atkbd_debounce, int, 0);
+MODULE_PARM_DESC(debounce, "Milliseconds to debounce successive keys");
+
/*
* Scancode to keycode tables. These are just the default setting, and
* are loadable via a userland utility.
@@ -218,6 +223,7 @@ struct atkbd {
bool softraw;
bool scroll;
bool enabled;
+ ktime_t debounce_ktime;
/* Accessed only from interrupt */
unsigned char emul;
@@ -227,6 +233,9 @@ struct atkbd {
unsigned int last;
unsigned long time;
unsigned long err_count;
+ bool is_debouncing;
+ unsigned short last_debounce_code;
+ ktime_t last_debounce_expiration;
struct delayed_work event_work;
unsigned long event_jiffies;
@@ -375,7 +384,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
struct atkbd *atkbd = serio_get_drvdata(serio);
struct input_dev *dev = atkbd->dev;
unsigned int code = data;
- int scroll = 0, hscroll = 0, click = -1;
+ int scroll = 0, hscroll = 0, keypress = 0, click = -1;
int value;
unsigned short keycode;
@@ -456,23 +465,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
keycode = atkbd->keycode[code];
- if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
- if (keycode != ATKBD_KEY_NULL)
- input_event(dev, EV_MSC, MSC_SCAN, code);
-
switch (keycode) {
case ATKBD_KEY_NULL:
- break;
case ATKBD_KEY_UNKNOWN:
- dev_warn(&serio->dev,
- "Unknown key %s (%s set %d, code %#x on %s).\n",
- atkbd->release ? "released" : "pressed",
- atkbd->translated ? "translated" : "raw",
- atkbd->set, code, serio->phys);
- dev_warn(&serio->dev,
- "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
- code & 0x80 ? "e0" : "", code & 0x7f);
- input_sync(dev);
break;
case ATKBD_SCR_1:
scroll = 1;
@@ -496,6 +491,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
hscroll = 1;
break;
default:
+ keypress = 1;
if (atkbd->release) {
value = 0;
atkbd->last = 0;
@@ -507,7 +503,49 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd->last = code;
atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
}
+ }
+
+ if (keypress) {
+ if (atkbd->is_debouncing && code == atkbd->last_debounce_code) {
+ /* ignore debounced release/repeat event */
+ if (value == 0) {
+ atkbd->is_debouncing = false;
+ atkbd->release = false;
+ }
+ goto out;
+ }
+ if (!atkbd->is_debouncing && value == 1) {
+ ktime_t now = ktime_get();
+ if (code == atkbd->last_debounce_code &&
+ ktime_before(now, atkbd->last_debounce_expiration)) {
+ /* debounce the press event */
+ dev_dbg(&serio->dev, "Debounced scan code %#x.\n", code);
+ atkbd->is_debouncing = !test_bit(code, atkbd->force_release_mask);
+ goto out;
+ } else {
+ atkbd->last_debounce_code = code;
+ atkbd->last_debounce_expiration = ktime_add(now, atkbd->debounce_ktime);
+ }
+ }
+ }
+
+ if (keycode != ATKBD_KEY_NULL)
+ if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
+ input_event(dev, EV_MSC, MSC_SCAN, code);
+
+ if (keycode == ATKBD_KEY_UNKNOWN) {
+ dev_warn(&serio->dev,
+ "Unknown key %s (%s set %d, code %#x on %s).\n",
+ atkbd->release ? "released" : "pressed",
+ atkbd->translated ? "translated" : "raw",
+ atkbd->set, code, serio->phys);
+ dev_warn(&serio->dev,
+ "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
+ code & 0x80 ? "e0" : "", code & 0x7f);
+ input_sync(dev);
+ }
+ if (keypress) {
input_event(dev, EV_KEY, keycode, value);
input_sync(dev);
@@ -1161,6 +1199,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd->softraw = atkbd_softraw;
atkbd->softrepeat = atkbd_softrepeat;
atkbd->scroll = atkbd_scroll;
+ atkbd->debounce_ktime = ms_to_ktime(max(atkbd_debounce, 0));
if (atkbd->softrepeat)
atkbd->softraw = true;
--
2.4.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] atkbd: add basic debounce support
2015-07-13 7:36 [PATCH] atkbd: add basic debounce support Gavin Li
@ 2015-07-13 17:20 ` Dmitry Torokhov
2015-07-14 6:04 ` Gavin Li
0 siblings, 1 reply; 3+ messages in thread
From: Dmitry Torokhov @ 2015-07-13 17:20 UTC (permalink / raw)
To: Gavin Li; +Cc: linux-input, Gavin Li
Hi Gavin,
On Mon, Jul 13, 2015 at 12:36:12AM -0700, Gavin Li wrote:
> From: Gavin Li <git@thegavinli.com>
>
> For physically quirky or otherwise poor keyboards.
It would be nice to know what keyboards have this issue? It is
widespread problem or just a single unit misbehaving?
Thanks.
> ---
> drivers/input/keyboard/atkbd.c | 69 +++++++++++++++++++++++++++++++++---------
> 1 file changed, 54 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
> index 387c51f..b1ff62d 100644
> --- a/drivers/input/keyboard/atkbd.c
> +++ b/drivers/input/keyboard/atkbd.c
> @@ -28,6 +28,7 @@
> #include <linux/libps2.h>
> #include <linux/mutex.h>
> #include <linux/dmi.h>
> +#include <linux/timekeeping.h>
>
> #define DRIVER_DESC "AT and PS/2 keyboard driver"
>
> @@ -67,6 +68,10 @@ static bool atkbd_terminal;
> module_param_named(terminal, atkbd_terminal, bool, 0);
> MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
>
> +static int atkbd_debounce;
> +module_param_named(debounce, atkbd_debounce, int, 0);
> +MODULE_PARM_DESC(debounce, "Milliseconds to debounce successive keys");
> +
> /*
> * Scancode to keycode tables. These are just the default setting, and
> * are loadable via a userland utility.
> @@ -218,6 +223,7 @@ struct atkbd {
> bool softraw;
> bool scroll;
> bool enabled;
> + ktime_t debounce_ktime;
>
> /* Accessed only from interrupt */
> unsigned char emul;
> @@ -227,6 +233,9 @@ struct atkbd {
> unsigned int last;
> unsigned long time;
> unsigned long err_count;
> + bool is_debouncing;
> + unsigned short last_debounce_code;
> + ktime_t last_debounce_expiration;
>
> struct delayed_work event_work;
> unsigned long event_jiffies;
> @@ -375,7 +384,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
> struct atkbd *atkbd = serio_get_drvdata(serio);
> struct input_dev *dev = atkbd->dev;
> unsigned int code = data;
> - int scroll = 0, hscroll = 0, click = -1;
> + int scroll = 0, hscroll = 0, keypress = 0, click = -1;
> int value;
> unsigned short keycode;
>
> @@ -456,23 +465,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
>
> keycode = atkbd->keycode[code];
>
> - if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
> - if (keycode != ATKBD_KEY_NULL)
> - input_event(dev, EV_MSC, MSC_SCAN, code);
> -
> switch (keycode) {
> case ATKBD_KEY_NULL:
> - break;
> case ATKBD_KEY_UNKNOWN:
> - dev_warn(&serio->dev,
> - "Unknown key %s (%s set %d, code %#x on %s).\n",
> - atkbd->release ? "released" : "pressed",
> - atkbd->translated ? "translated" : "raw",
> - atkbd->set, code, serio->phys);
> - dev_warn(&serio->dev,
> - "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
> - code & 0x80 ? "e0" : "", code & 0x7f);
> - input_sync(dev);
> break;
> case ATKBD_SCR_1:
> scroll = 1;
> @@ -496,6 +491,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
> hscroll = 1;
> break;
> default:
> + keypress = 1;
> if (atkbd->release) {
> value = 0;
> atkbd->last = 0;
> @@ -507,7 +503,49 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
> atkbd->last = code;
> atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
> }
> + }
> +
> + if (keypress) {
> + if (atkbd->is_debouncing && code == atkbd->last_debounce_code) {
> + /* ignore debounced release/repeat event */
> + if (value == 0) {
> + atkbd->is_debouncing = false;
> + atkbd->release = false;
> + }
> + goto out;
> + }
> + if (!atkbd->is_debouncing && value == 1) {
> + ktime_t now = ktime_get();
> + if (code == atkbd->last_debounce_code &&
> + ktime_before(now, atkbd->last_debounce_expiration)) {
> + /* debounce the press event */
> + dev_dbg(&serio->dev, "Debounced scan code %#x.\n", code);
> + atkbd->is_debouncing = !test_bit(code, atkbd->force_release_mask);
> + goto out;
> + } else {
> + atkbd->last_debounce_code = code;
> + atkbd->last_debounce_expiration = ktime_add(now, atkbd->debounce_ktime);
> + }
> + }
> + }
> +
> + if (keycode != ATKBD_KEY_NULL)
> + if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
> + input_event(dev, EV_MSC, MSC_SCAN, code);
> +
> + if (keycode == ATKBD_KEY_UNKNOWN) {
> + dev_warn(&serio->dev,
> + "Unknown key %s (%s set %d, code %#x on %s).\n",
> + atkbd->release ? "released" : "pressed",
> + atkbd->translated ? "translated" : "raw",
> + atkbd->set, code, serio->phys);
> + dev_warn(&serio->dev,
> + "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
> + code & 0x80 ? "e0" : "", code & 0x7f);
> + input_sync(dev);
> + }
>
> + if (keypress) {
> input_event(dev, EV_KEY, keycode, value);
> input_sync(dev);
>
> @@ -1161,6 +1199,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
> atkbd->softraw = atkbd_softraw;
> atkbd->softrepeat = atkbd_softrepeat;
> atkbd->scroll = atkbd_scroll;
> + atkbd->debounce_ktime = ms_to_ktime(max(atkbd_debounce, 0));
>
> if (atkbd->softrepeat)
> atkbd->softraw = true;
> --
> 2.4.5
>
--
Dmitry
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] atkbd: add basic debounce support
2015-07-13 17:20 ` Dmitry Torokhov
@ 2015-07-14 6:04 ` Gavin Li
0 siblings, 0 replies; 3+ messages in thread
From: Gavin Li @ 2015-07-14 6:04 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, Gavin Li
Hello Dmitry,
I implemented this patch because my personal keyboard was misbehaving,
but I believe it's likely that someone else out there is having the
same issue.
Gavin
On Mon, Jul 13, 2015 at 10:20 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> Hi Gavin,
>
> On Mon, Jul 13, 2015 at 12:36:12AM -0700, Gavin Li wrote:
>> From: Gavin Li <git@thegavinli.com>
>>
>> For physically quirky or otherwise poor keyboards.
>
> It would be nice to know what keyboards have this issue? It is
> widespread problem or just a single unit misbehaving?
>
> Thanks.
>
>> ---
>> drivers/input/keyboard/atkbd.c | 69 +++++++++++++++++++++++++++++++++---------
>> 1 file changed, 54 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
>> index 387c51f..b1ff62d 100644
>> --- a/drivers/input/keyboard/atkbd.c
>> +++ b/drivers/input/keyboard/atkbd.c
>> @@ -28,6 +28,7 @@
>> #include <linux/libps2.h>
>> #include <linux/mutex.h>
>> #include <linux/dmi.h>
>> +#include <linux/timekeeping.h>
>>
>> #define DRIVER_DESC "AT and PS/2 keyboard driver"
>>
>> @@ -67,6 +68,10 @@ static bool atkbd_terminal;
>> module_param_named(terminal, atkbd_terminal, bool, 0);
>> MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
>>
>> +static int atkbd_debounce;
>> +module_param_named(debounce, atkbd_debounce, int, 0);
>> +MODULE_PARM_DESC(debounce, "Milliseconds to debounce successive keys");
>> +
>> /*
>> * Scancode to keycode tables. These are just the default setting, and
>> * are loadable via a userland utility.
>> @@ -218,6 +223,7 @@ struct atkbd {
>> bool softraw;
>> bool scroll;
>> bool enabled;
>> + ktime_t debounce_ktime;
>>
>> /* Accessed only from interrupt */
>> unsigned char emul;
>> @@ -227,6 +233,9 @@ struct atkbd {
>> unsigned int last;
>> unsigned long time;
>> unsigned long err_count;
>> + bool is_debouncing;
>> + unsigned short last_debounce_code;
>> + ktime_t last_debounce_expiration;
>>
>> struct delayed_work event_work;
>> unsigned long event_jiffies;
>> @@ -375,7 +384,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
>> struct atkbd *atkbd = serio_get_drvdata(serio);
>> struct input_dev *dev = atkbd->dev;
>> unsigned int code = data;
>> - int scroll = 0, hscroll = 0, click = -1;
>> + int scroll = 0, hscroll = 0, keypress = 0, click = -1;
>> int value;
>> unsigned short keycode;
>>
>> @@ -456,23 +465,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
>>
>> keycode = atkbd->keycode[code];
>>
>> - if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
>> - if (keycode != ATKBD_KEY_NULL)
>> - input_event(dev, EV_MSC, MSC_SCAN, code);
>> -
>> switch (keycode) {
>> case ATKBD_KEY_NULL:
>> - break;
>> case ATKBD_KEY_UNKNOWN:
>> - dev_warn(&serio->dev,
>> - "Unknown key %s (%s set %d, code %#x on %s).\n",
>> - atkbd->release ? "released" : "pressed",
>> - atkbd->translated ? "translated" : "raw",
>> - atkbd->set, code, serio->phys);
>> - dev_warn(&serio->dev,
>> - "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
>> - code & 0x80 ? "e0" : "", code & 0x7f);
>> - input_sync(dev);
>> break;
>> case ATKBD_SCR_1:
>> scroll = 1;
>> @@ -496,6 +491,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
>> hscroll = 1;
>> break;
>> default:
>> + keypress = 1;
>> if (atkbd->release) {
>> value = 0;
>> atkbd->last = 0;
>> @@ -507,7 +503,49 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
>> atkbd->last = code;
>> atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
>> }
>> + }
>> +
>> + if (keypress) {
>> + if (atkbd->is_debouncing && code == atkbd->last_debounce_code) {
>> + /* ignore debounced release/repeat event */
>> + if (value == 0) {
>> + atkbd->is_debouncing = false;
>> + atkbd->release = false;
>> + }
>> + goto out;
>> + }
>> + if (!atkbd->is_debouncing && value == 1) {
>> + ktime_t now = ktime_get();
>> + if (code == atkbd->last_debounce_code &&
>> + ktime_before(now, atkbd->last_debounce_expiration)) {
>> + /* debounce the press event */
>> + dev_dbg(&serio->dev, "Debounced scan code %#x.\n", code);
>> + atkbd->is_debouncing = !test_bit(code, atkbd->force_release_mask);
>> + goto out;
>> + } else {
>> + atkbd->last_debounce_code = code;
>> + atkbd->last_debounce_expiration = ktime_add(now, atkbd->debounce_ktime);
>> + }
>> + }
>> + }
>> +
>> + if (keycode != ATKBD_KEY_NULL)
>> + if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
>> + input_event(dev, EV_MSC, MSC_SCAN, code);
>> +
>> + if (keycode == ATKBD_KEY_UNKNOWN) {
>> + dev_warn(&serio->dev,
>> + "Unknown key %s (%s set %d, code %#x on %s).\n",
>> + atkbd->release ? "released" : "pressed",
>> + atkbd->translated ? "translated" : "raw",
>> + atkbd->set, code, serio->phys);
>> + dev_warn(&serio->dev,
>> + "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
>> + code & 0x80 ? "e0" : "", code & 0x7f);
>> + input_sync(dev);
>> + }
>>
>> + if (keypress) {
>> input_event(dev, EV_KEY, keycode, value);
>> input_sync(dev);
>>
>> @@ -1161,6 +1199,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
>> atkbd->softraw = atkbd_softraw;
>> atkbd->softrepeat = atkbd_softrepeat;
>> atkbd->scroll = atkbd_scroll;
>> + atkbd->debounce_ktime = ms_to_ktime(max(atkbd_debounce, 0));
>>
>> if (atkbd->softrepeat)
>> atkbd->softraw = true;
>> --
>> 2.4.5
>>
>
> --
> Dmitry
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2015-07-14 6:04 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-13 7:36 [PATCH] atkbd: add basic debounce support Gavin Li
2015-07-13 17:20 ` Dmitry Torokhov
2015-07-14 6:04 ` Gavin Li
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.