Re: Toshiba kbd patch - latest

Andrei Pitis (pink@roedu.net)
Tue, 14 Dec 1999 03:08:47 +0200 (EET)


Hi everybody,

Here is my latest version. It dinamically computes the mean value
of the kbd delay, correctly takes care of the 0xE0 prefix and prefixed
keys, and has no more side effects that would affect normal keyboards,
IMHO.

Linus: your call: either to put it as is or to make it configurable.
Either way is fine with me, thanks.

Best regards,
Andrei

--- linux-2.3.39/drivers/char/pc_keyb.c Tue Dec 7 01:10:31 1999
+++ pc_keyb.c Tue Dec 14 03:02:05 1999
@@ -413,6 +413,124 @@
}

/*
+ * Made initially for a Toshiba Satellite 2595XDVD, useful for
+ * other Toshiba laptops and not only, apparently. Under some
+ * circumstances, these keyboards behave like ignoring the
+ * kbd repeat _delay_. This happens in conjunction with shift
+ * keys (ctrl, alt, shift) and leads to undesirable repeat
+ * of a key even if pressed briefly. Fixed it by ignoring any
+ * subsequent occurence of the second identical make code within
+ * the kbd delay, which is dynamically computed. Takes into account
+ * keys with 0xE0. It adapts to the kbd delay, computing it from
+ * normal kbd repeats, which are defined to be those of no less
+ * than MIN_KBD_DELAY (100ms).
+ *
+ * Andrei Pitis <pink@roedu.net> Dec 1999
+ */
+
+/* Minimum KBD delay is considered to be 100 ms. */
+#define MIN_KBD_DELAY (HZ / 10)
+
+/* E0_PREFIX_BIT is to be ORed into every scancode that was preceeded
+ by an 0xE0 prefix. It is to be temporarily storeed into prev_scancode
+ shifted left by E0_STORE_SHL. */
+#define E0_PREFIX_BIT 0x100
+#define E0_STORE_SHL 16
+
+/* PULSE_BIT is ORed into the prev_scancode in the beginning of each
+ repeat sequence. Used to detect the "delay" - i.e. the time between
+ the first and the second consecutive identical make codes. */
+#define PULSE_BIT 0x200
+
+#define KEYUP_BIT 0x80
+#define SCANCODE_MASK 0xFF
+
+
+static void handle_delay(unsigned int scancode)
+{
+ /* State variables. */
+ static unsigned int prev_scancode = 0;
+ static unsigned long stop_jiffies = 0;
+
+ /* Some reasonable start values for the mean delay. */
+ static unsigned int kbd_delay_sum = MIN_KBD_DELAY;
+ static unsigned int kbd_n_repeats = 1;
+
+ unsigned int different_bits = 0;
+
+ /* Just remember that we've got the E0 prefix, will take care
+ of it next time. Use the high word of prev_scancode. */
+ if (scancode == 0xE0)
+ {
+ prev_scancode |= (E0_PREFIX_BIT << E0_STORE_SHL);
+ return;
+ }
+
+ /* Mark the E0 prefix as a bit in scancode. */
+ scancode |= (prev_scancode >> E0_STORE_SHL) & E0_PREFIX_BIT;
+ prev_scancode &= ~(E0_PREFIX_BIT << E0_STORE_SHL);
+
+ /* Compute different_bits of scancode and prev_scancode,
+ including the E0_PREFIX_BIT. */
+ different_bits = ((scancode ^ prev_scancode) &
+ (SCANCODE_MASK | E0_PREFIX_BIT));
+
+ /* True if the scancodes are different. */
+ if (different_bits)
+ {
+ /* Any make code triggers the delay and updates prev_scancode. */
+ if (!(scancode & KEYUP_BIT))
+ {
+ stop_jiffies = jiffies;
+ prev_scancode = scancode | PULSE_BIT;
+ }
+ /* True if this is the break code of the prev_scancode, i.e. if
+ only the KEYUP_BIT is different. Reset the delay. */
+ else if (different_bits == KEYUP_BIT)
+ stop_jiffies = prev_scancode = 0;
+ }
+ else /* Same make code. */
+ {
+ int delta_jiffies = jiffies - stop_jiffies;
+
+ /* True only for the second scancode in a row, i.e. the
+ first repetition of a scancode. */
+ if (prev_scancode & PULSE_BIT)
+ {
+ /* Reset the bit. */
+ prev_scancode &= ~PULSE_BIT;
+
+ /* Dynamically update the kbd repeat delay. */
+ if (delta_jiffies >= MIN_KBD_DELAY)
+ {
+ /* Reset it from time to time, to keep it dynamic,
+ in case the hard kbd repeat rate is changed. */
+ if (kbd_n_repeats > 400)
+ kbd_delay_sum = kbd_n_repeats = 0;
+
+ kbd_delay_sum += delta_jiffies;
+ kbd_n_repeats++;
+ }
+ else
+ printk(KERN_INFO
+ "KBD glitch (delay %d ms) at %d ms: [%03X]\n",
+ ((kbd_delay_sum / kbd_n_repeats) * 1000) / HZ,
+ (delta_jiffies * 1000) / HZ, scancode);
+ }
+
+ /* Reject scancode if within mean delay. Apply a correction of
+ -1 since kbd interrups are asynchronous wrt timer interrupts. */
+ if (delta_jiffies < kbd_delay_sum / kbd_n_repeats - 1)
+ return;
+ }
+
+ /* Handle the scancode, do not forget the E0 prefix. */
+ if (scancode & E0_PREFIX_BIT) handle_scancode(0xE0, 0);
+ handle_scancode(scancode & SCANCODE_MASK, !(scancode & KEYUP_BIT));
+}
+
+
+/*
* This reads the keyboard status port, and does the
* appropriate action.
*
@@ -433,7 +551,7 @@
} else {
#ifdef CONFIG_VT
if (do_acknowledge(scancode))
- handle_scancode(scancode, !(scancode & 0x80));
+ handle_delay(scancode);
#endif
mark_bh(KEYBOARD_BH);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/