linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pavel Machek <pavel@ucw.cz>
To: kernel list <linux-kernel@vger.kernel.org>,
	jikos@suse.cz, vojtech@suse.cz, linux-input@vger.kernel.org,
	dmitry.torokhov@gmail.com
Subject: [rfd] saving old mice -- button glitching/debouncing
Date: Sat, 15 Dec 2018 00:24:37 +0100	[thread overview]
Message-ID: <20181214232437.GA8310@amd> (raw)

[-- Attachment #1: Type: text/plain, Size: 6821 bytes --]


I believe I have hardware problem, but I'm kind of hoping software
could help me...?

Mouse wheel on my machine started glitching on my machine, generating
double-clicks when I click it once. Which unfortunately is quite
annoying: texts are pasted twice, two tabs are closed instead of one,
....

Event: time 1544733054.903129, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90003
Event: time 1544733054.903129, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
Event: time 1544733054.903129, -------------- EV_SYN ------------
            1544733054.967251, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90003
Event: time 1544733054.967251, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
Event: time 1544733054.967251, -------------- EV_SYN ------------
Event: time 1544733054.975144, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90003
Event: time 1544733054.975144, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
Event: time 1544733054.975144, -------------- EV_SYN ------------
     : time 1544733065.127190, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90003
Event: time 1544733065.127190, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
Event: time 1544733065.127190, -------------- EV_SYN ------------

Now, I could just buy a new mouse, but it seems that most optical mice
die like this... so maybe it would be nice to have an option to
debounce the buttons, so that the useful life of mice is extended a
bit?

(So... I have two mice with that fault -- cheap to replace, but button
in thinkpad X220 started doing that, too. That one will not be so
cheap to fix :-( ).

It is possible that some X versions already do something like this.

Patch is obviously not ready; but:

a) would it be useful to people

b) would it be acceptable if done properly? (cmd line option to
enable, avoiding duplicate/wrong events?)

Thanks,
								Pavel
Signed-off-by: Pavel Machek <pavel@ucw.cz>

diff --git a/drivers/input/input.c b/drivers/input/input.c
index 3304aaa..ce0d081 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -40,6 +40,11 @@ static DEFINE_IDA(input_ida);
 static LIST_HEAD(input_dev_list);
 static LIST_HEAD(input_handler_list);
 
+static void input_repeat_key(struct timer_list *t);
+static void input_debounce_key(struct timer_list *t);
+
+static int debounce = 20;
+
 /*
  * input_mutex protects access to both input_dev_list and input_handler_list.
  * This also causes input_[un]register_device and input_[un]register_handler
@@ -77,6 +82,7 @@ static void input_start_autorepeat(struct input_dev *dev, int code)
 	if (test_bit(EV_REP, dev->evbit) &&
 	    dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
 	    dev->timer.function) {
+		dev->timer.function = input_repeat_key;
 		dev->repeat_key = code;
 		mod_timer(&dev->timer,
 			  jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
@@ -88,18 +94,42 @@ static void input_stop_autorepeat(struct input_dev *dev)
 	del_timer(&dev->timer);
 }
 
+static void input_start_debounce(struct input_dev *dev, int code)
+{
+	dev->timer.function = input_debounce_key;
+	dev->debounce_key = code;
+	mod_timer(&dev->timer,
+		  jiffies + msecs_to_jiffies(debounce));
+}
+
+static void input_stop_debounce(struct input_dev *dev)
+{
+	del_timer(&dev->timer);
+	dev->debounce_key = -1;
+}
+
 /*
  * Pass event first through all filters and then, if event has not been
  * filtered out, through all open handles. This function is called with
  * dev->event_lock held and interrupts disabled.
  */
-static unsigned int input_to_handler(struct input_handle *handle,
+static unsigned int input_to_handler(struct input_dev *dev, struct input_handle *handle,
 			struct input_value *vals, unsigned int count)
 {
 	struct input_handler *handler = handle->handler;
 	struct input_value *end = vals;
 	struct input_value *v;
 
+	if (!test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit) && debounce)
+		for (v = vals; v != vals + count; v++) {
+			if (v->type == EV_KEY && v->value == 0 && dev->debounce_key == -1) {
+				input_start_debounce(dev, v->code);
+				v->code = -2;
+			}
+			if (v->type == EV_KEY && v->value == 1 && dev->debounce_key == v->code)
+				input_stop_debounce(dev);
+		}
+
 	if (handler->filter) {
 		for (v = vals; v != vals + count; v++) {
 			if (handler->filter(handle, v->type, v->code, v->value))
@@ -117,8 +147,9 @@ static unsigned int input_to_handler(struct input_handle *handle,
 	if (handler->events)
 		handler->events(handle, vals, count);
 	else if (handler->event)
-		for (v = vals; v != vals + count; v++)
+		for (v = vals; v != vals + count; v++) {
 			handler->event(handle, v->type, v->code, v->value);
+		}
 
 	return count;
 }
@@ -141,11 +172,11 @@ static void input_pass_values(struct input_dev *dev,
 
 	handle = rcu_dereference(dev->grab);
 	if (handle) {
-		count = input_to_handler(handle, vals, count);
+		count = input_to_handler(dev, handle, vals, count);
 	} else {
 		list_for_each_entry_rcu(handle, &dev->h_list, d_node)
 			if (handle->open) {
-				count = input_to_handler(handle, vals, count);
+				count = input_to_handler(dev, handle, vals, count);
 				if (!count)
 					break;
 			}
@@ -203,6 +234,27 @@ static void input_repeat_key(struct timer_list *t)
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
+/*
+ * Generate software autorepeat event. Note that we take
+ * dev->event_lock here to avoid racing with input_event
+ * which may cause keys get "stuck".
+ */
+static void input_debounce_key(struct timer_list *t)
+{
+	struct input_dev *dev = from_timer(dev, t, timer);
+	unsigned long flags;
+
+	struct input_value vals[] =  {
+		{ EV_KEY, dev->debounce_key, 0 },
+		input_value_sync
+	};
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	input_pass_values(dev, vals, ARRAY_SIZE(vals));
+	input_stop_debounce(dev);
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
 #define INPUT_IGNORE_EVENT	0
 #define INPUT_PASS_TO_HANDLERS	1
 #define INPUT_PASS_TO_DEVICE	2
@@ -2109,6 +2161,8 @@ int input_register_device(struct input_dev *dev)
 	/* Every input device generates EV_SYN/SYN_REPORT events. */
 	__set_bit(EV_SYN, dev->evbit);
 
+	dev->debounce_key = -1;
+
 	/* KEY_RESERVED is not supposed to be transmitted to userspace. */
 	__clear_bit(KEY_RESERVED, dev->keybit);
 
diff --git a/include/linux/input.h b/include/linux/input.h
index 7c7516e..b2458b2 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -150,6 +150,7 @@ struct input_dev {
 
 	struct ff_device *ff;
 
+	int debounce_key;
 	unsigned int repeat_key;
 	struct timer_list timer;
 


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

             reply	other threads:[~2018-12-14 23:24 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-14 23:24 Pavel Machek [this message]
2018-12-15  0:19 ` [rfd] saving old mice -- button glitching/debouncing Dmitry Torokhov
2018-12-15  8:55 ` Vojtech Pavlik
2018-12-15  9:47   ` Pavel Machek
2018-12-15 10:12     ` Vojtech Pavlik
2018-12-15 10:29       ` Pavel Machek
2018-12-18 15:26 ` kbuild test robot

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=20181214232437.GA8310@amd \
    --to=pavel@ucw.cz \
    --cc=dmitry.torokhov@gmail.com \
    --cc=jikos@suse.cz \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=vojtech@suse.cz \
    /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).