public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Torokhov <dtor_core@ameritech.net>
To: linux-input@atrey.karlin.mff.cuni.cz
Cc: Vojtech Pavlik <vojtech@suse.cz>, Andrew Morton <akpm@osdl.org>,
	LKML <linux-kernel@vger.kernel.org>
Subject: [RFT/PATCH] atkbd - speed up setting leds/repeat state
Date: Mon, 31 Oct 2005 02:24:02 -0500	[thread overview]
Message-ID: <200510310224.03010.dtor_core@ameritech.net> (raw)

Input: atkbd - speed up setting leds/repeat state

Changing led state is pretty slow operation; when there are multiple
requests coming at a high rate they may interfere with normal typing.
Try optimize (skip) changing hardware state when multiple requests
are coming back-to-back.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/input/keyboard/atkbd.c |   99 ++++++++++++++++++++++++++++-------------
 1 files changed, 68 insertions(+), 31 deletions(-)

Index: work/drivers/input/keyboard/atkbd.c
===================================================================
--- work.orig/drivers/input/keyboard/atkbd.c
+++ work/drivers/input/keyboard/atkbd.c
@@ -166,6 +166,9 @@ static unsigned char atkbd_unxlate_table
 
 #define ATKBD_SPECIAL		248
 
+#define ATKBD_LED_EVENT_BIT	0
+#define ATKBD_REP_EVENT_BIT	1
+
 static struct {
 	unsigned char keycode;
 	unsigned char set2;
@@ -211,6 +214,10 @@ struct atkbd {
 	unsigned char err_xl;
 	unsigned int last;
 	unsigned long time;
+
+	struct work_struct event_work;
+	struct semaphore event_sem;
+	unsigned long event_mask;
 };
 
 static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
@@ -424,58 +431,86 @@ out:
 }
 
 /*
- * Event callback from the input module. Events that change the state of
- * the hardware are processed here.
+ * atkbd_event_work() is used to complete processing of events that
+ * can not be processed by input_event() which is often called from
+ * interrupt context.
  */
 
-static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static void atkbd_event_work(void *data)
 {
-	struct atkbd *atkbd = dev->private;
 	const short period[32] =
 		{ 33,  37,  42,  46,  50,  54,  58,  63,  67,  75,  83,  92, 100, 109, 116, 125,
 		 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
 	const short delay[4] =
 		{ 250, 500, 750, 1000 };
+
+	struct atkbd *atkbd = data;
+	struct input_dev *dev = atkbd->dev;
 	unsigned char param[2];
 	int i, j;
 
+	down(&atkbd->event_sem);
+
+	if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) {
+		param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
+			 | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
+			 | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
+		ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
+
+		if (atkbd->extra) {
+			param[0] = 0;
+			param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
+				 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
+				 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
+				 | (test_bit(LED_MISC,    dev->led) ? 0x10 : 0)
+				 | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
+			ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
+		}
+	}
+
+	if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) {
+		i = j = 0;
+		while (i < 31 && period[i] < dev->rep[REP_PERIOD])
+			i++;
+		while (j < 3 && delay[j] < dev->rep[REP_DELAY])
+			j++;
+		dev->rep[REP_PERIOD] = period[i];
+		dev->rep[REP_DELAY] = delay[j];
+		param[0] = i | (j << 5);
+		ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
+	}
+
+	up(&atkbd->event_sem);
+}
+
+/*
+ * Event callback from the input module. Events that change the state of
+ * the hardware are processed here. If action can not be performed in
+ * interrupt context it is offloaded to atkbd_event_work.
+ */
+
+static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct atkbd *atkbd = dev->private;
+
 	if (!atkbd->write)
 		return -1;
 
 	switch (type) {
 
 		case EV_LED:
-
-			param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
-			         | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
-			         | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
-		        ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
-
-			if (atkbd->extra) {
-				param[0] = 0;
-				param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
-					 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
-					 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
-				         | (test_bit(LED_MISC,    dev->led) ? 0x10 : 0)
-				         | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
-				ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
-			}
-
+			set_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask);
+			wmb();
+			schedule_work(&atkbd->event_work);
 			return 0;
 
 		case EV_REP:
 
-			if (atkbd->softrepeat) return 0;
-
-			i = j = 0;
-			while (i < 31 && period[i] < dev->rep[REP_PERIOD])
-				i++;
-			while (j < 3 && delay[j] < dev->rep[REP_DELAY])
-				j++;
-			dev->rep[REP_PERIOD] = period[i];
-			dev->rep[REP_DELAY] = delay[j];
-			param[0] = i | (j << 5);
-			ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
+			if (!atkbd->softrepeat) {
+				set_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask);
+				wmb();
+				schedule_work(&atkbd->event_work);
+			}
 
 			return 0;
 	}
@@ -810,6 +845,8 @@ static int atkbd_connect(struct serio *s
 
 	atkbd->dev = dev;
 	ps2_init(&atkbd->ps2dev, serio);
+	INIT_WORK(&atkbd->event_work, atkbd_event_work, atkbd);
+	init_MUTEX(&atkbd->event_sem);
 
 	switch (serio->id.type) {
 

             reply	other threads:[~2005-10-31  7:24 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-10-31  7:24 Dmitry Torokhov [this message]
2005-10-31 12:47 ` [RFT/PATCH] atkbd - speed up setting leds/repeat state Vojtech Pavlik
2005-10-31 14:05   ` Dmitry Torokhov
2005-10-31 14:42     ` Vojtech Pavlik

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=200510310224.03010.dtor_core@ameritech.net \
    --to=dtor_core@ameritech.net \
    --cc=akpm@osdl.org \
    --cc=linux-input@atrey.karlin.mff.cuni.cz \
    --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