mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Patch for PC keyboard driver's autorepeat-rate handling
@ 2002-08-22 15:59 Alan Stern
  2002-08-22 17:31 ` Alan Cox
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Stern @ 2002-08-22 15:59 UTC (permalink / raw)
  To: Dave Jones, Alan Cox, James Simmons; +Cc: linux-kernel

This patch fixes several mistakes in the PC keyboard driver's
autorepeat-rate handling.  It applies as-is to both the current 2.4.x
and 2.5.x Linux kernels.

I don't know why nobody has addressed this problem earlier.  Hasn't
anyone noticed that Rik Faith's kbdrate program no longer works
properly?  The error is not in the program; it's in the kernel's
handling of the KDKBDREP ioctl.  This patch fixes the following three
mistakes:

	The .rate member of struct kbd_repeat is actually a repeat
	_period_ measured in msec; the driver interprets it as a
	repeat _rate_ in characters per second.

	The driver returns the _prior_ values of the rate and delay
	settings rather than the _current_ values.

	The driver looks for an exact match for the rate and delay
	values rather than using the closest match.

Note that the first two issues above are mentioned explicitly in
include/linux/kd.h, in the region defining the KDKBDREP ioctl.

Not all the repeat rates supported by the PC hardware are recognized
by the driver.  I decided not to change that, since many of the rates
are only imperceptibly different.  If anybody thinks that implementing
the full set would be worthwhile, it will be easy enough to do so.

Incidentally, does anybody know why drivers/char/pc_keyb.c hasn't been
moved to the arch/i386 part of the directory tree?

Alan Stern


--- drivers/char/pc_keyb.c.orig	Wed Aug 21 15:36:13 2002
+++ drivers/char/pc_keyb.c	Thu Aug 22 11:12:05 2002
@@ -13,6 +13,9 @@
  * Code fixes to handle mouse ACKs properly.
  * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
  *
+ * Fix the keyboard autorepeat rate handling.
+ * Alan Stern <stern@rowland.org> 2002-08-21.
+ *
  */

 #include <linux/config.h>
@@ -578,7 +581,7 @@
 }

 #define DEFAULT_KEYB_REP_DELAY	250
-#define DEFAULT_KEYB_REP_RATE	30	/* cps */
+#define DEFAULT_KEYB_REP_RATE	33	/* msec: = 30 cps */

 static struct kbd_repeat kbdrate={
 	DEFAULT_KEYB_REP_DELAY,
@@ -587,48 +590,48 @@

 static unsigned char parse_kbd_rate(struct kbd_repeat *r)
 {
-	static struct r2v{
-		int rate;
-		unsigned char val;
-	} kbd_rates[]={	{5,0x14},
-			{7,0x10},
-			{10,0x0c},
-			{15,0x08},
-			{20,0x04},
-			{25,0x02},
-			{30,0x00}
-	};
-	static struct d2v{
-		int delay;
-		unsigned char val;
-	} kbd_delays[]={{250,0},
-			{500,1},
-			{750,2},
-			{1000,3}
+#if 0	/* Here is the complete list of repeat periods in msec. */
+		{	 33,  38,  42,  46,  50,  54,  58,  63,
+			 67,  75,  83,  92, 100, 108, 117, 125,
+			133, 150, 167, 183, 200, 217, 234, 250,
+			267, 300, 334, 367, 400, 434, 467, 500};
+#endif
+	static struct r2v {
+		int period;
+		int val;
+	} kbd_rates[] = {	{33,0},		/* 30 cps */
+				{42,2},		/* 24 */
+				{50,4},		/* 20 */
+				{67,8},		/* 15 */
+				{100,12},	/* 10 */
+				{133,16},	/* 7.5 */
+				{200,20},	/* 5 */
+				{500,31},	/* 2 */
 	};
-	int rate=0,delay=0;
+	static int kbd_delays[4] = {250, 500, 750, 1000};
+	int rval=0, dval=0, i;
+
 	if (r != NULL){
-		int i,new_rate=30,new_delay=250;
 		if (r->rate <= 0)
 			r->rate=kbdrate.rate;
 		if (r->delay <= 0)
 			r->delay=kbdrate.delay;
-		for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++)
-			if (kbd_rates[i].rate == r->rate){
-				new_rate=kbd_rates[i].rate;
-				rate=kbd_rates[i].val;
+
+		/* Find the closest matches */
+
+		for (i = 0; i < sizeof(kbd_rates)/sizeof(struct r2v)-1; i++) {
+			if ((kbd_rates[i].period+kbd_rates[i+1].period)/2 >= r->rate)
 				break;
-			}
-		for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++)
-			if (kbd_delays[i].delay == r->delay){
-				new_delay=kbd_delays[i].delay;
-				delay=kbd_delays[i].val;
+		}
+		r->rate = kbd_rates[i].period;
+		rval = kbd_rates[i].val;
+		for (dval=0; dval < sizeof(kbd_delays)/sizeof(int)-1; dval++) {
+			if ((kbd_delays[dval]+kbd_delays[dval+1])/2 >= r->delay)
 				break;
-			}
-		r->rate=new_rate;
-		r->delay=new_delay;
+		}
+		r->delay = kbd_delays[dval];
 	}
-	return (delay << 5) | rate;
+	return (dval << 5) | rval;
 }

 static int write_kbd_rate(unsigned char r)
@@ -644,13 +647,13 @@
 {
 	if (rep == NULL)
 		return -EINVAL;
-	else{
+	if (rep->rate < 0 && rep->delay < 0) {
+		*rep = kbdrate;
+		return 0;
+	} else {
 		unsigned char r=parse_kbd_rate(rep);
-		struct kbd_repeat old_rep;
-		memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat));
-		if (write_kbd_rate(r)){
-			memcpy(&kbdrate,rep,sizeof(struct kbd_repeat));
-			memcpy(rep,&old_rep,sizeof(struct kbd_repeat));
+		if (write_kbd_rate(r)) {
+			kbdrate = *rep;
 			return 0;
 		}
 	}



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2002-08-22 20:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-08-22 15:59 Patch for PC keyboard driver's autorepeat-rate handling Alan Stern
2002-08-22 17:31 ` Alan Cox
2002-08-22 19:37   ` Andries Brouwer
2002-08-22 20:16     ` Alan Cox
2002-08-22 20:39       ` Andries Brouwer
2002-08-22 20:57     ` Alan Stern

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®