Hi,
Here is the keyboard autorepeat patch. It should apply to 2.3.99pre* kernels.
I'm not going to say it's SMP safe - it probably isn't. Maybe you guys can
help get it into a state where its reasonable to go into the mainsteam kernel.
The following patch:
1. Cleans up unnecessary initialisers.
2. Cleans up some formatting.
3. Adds keyboard soft-autorepeat (but retains the original behaviour for
Xfree via the VC RAW keyboard mode).
4. Adds an extra function - kbd_reset_down() so that low level keyboard
drivers can inform this layer that the key down arrays should be cleared.
The keyboard rate can be altered by the "DEFAULT_REPEAT_*" macros, however
please note that they are set rather high at the moment.
Todo:
1. Set sensible defaults.
2. Make repeat settings run-time configurable.
If anyone would like to fix either of the above two points, please contact
me.
I'm CC'ing linux-kernel for comment/other interest only. I do not intend
this patch to go into the Linux kernel at this time. New versions of this
can usually be found contained within the ARM patches at:
ftp.arm.linux.org.uk:/pub/armlinux/source/kernel-patches
If you wish to use a different version, you will have to dig out the relevent
hunks from those patches, but you're on your own there.
diff -urN linux-orig/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- linux-orig/drivers/char/keyboard.c Fri Feb 18 20:52:54 2000
+++ linux/drivers/char/keyboard.c Fri Feb 18 21:05:20 2000
@@ -21,6 +21,10 @@
*
* 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
* 30-07-98: Dead keys redone, aeb@cwi.nl.
+ *
+ * 04-04-1998: Added keyboard autorepeat support (some keyboards don't
+ * autorepeat, and some keyboard changers interfere with keyboard
+ * autorepeat settings). - Russell King (rmk@arm.uk.linux.org)
*/
#include <linux/config.h>
@@ -30,6 +34,7 @@
#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/string.h>
+#include <linux/timer.h>
#include <linux/random.h>
#include <linux/init.h>
@@ -61,6 +66,14 @@
#define KBD_DEFLOCK 0
#endif
+/*
+ * Default autorepeat settings.
+ * DEFAULT_REPEAT_TIMEOUT is the timeout from the keypress to the first repeat
+ * DEFAULT_REPEAT_INTERVAL is the timeout between successive repeats
+ */
+#define DEFAULT_REPEAT_TIMEOUT HZ*300/1000
+#define DEFAULT_REPEAT_INTERVAL HZ*30/1000
+
void (*kbd_ledfunc)(unsigned int led) = NULL;
EXPORT_SYMBOL(handle_scancode);
EXPORT_SYMBOL(kbd_ledfunc);
@@ -83,25 +96,29 @@
*/
/* shift state counters.. */
-static unsigned char k_down[NR_SHIFT] = {0, };
+static unsigned char k_down[NR_SHIFT];
/* keyboard key bitmap */
-static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
+static unsigned long key_down[256/BITS_PER_LONG];
-static int dead_key_next = 0;
+static int dead_key_next;
/*
* In order to retrieve the shift_state (for the mouse server), either
* the variable must be global, or a new procedure must be created to
* return the value. I chose the former way.
*/
-int shift_state = 0;
+int shift_state;
static int npadch = -1; /* -1 or number assembled on pad */
-static unsigned char diacr = 0;
-static char rep = 0; /* flag telling character repeat */
+static unsigned char diacr;
+static char rep; /* flag telling character repeat */
+static int kbd_repeatkeycode= -1;
+static int kbd_repeattimeout = DEFAULT_REPEAT_TIMEOUT;
+static int kbd_repeatinterval= DEFAULT_REPEAT_INTERVAL;
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct tty_struct **ttytab;
static struct kbd_struct * kbd = kbd_table;
-static struct tty_struct * tty = NULL;
+static struct tty_struct * tty;
+static void kbd_processkeycode(unsigned char scancode, char up_flag, int autorepeat);
void compute_shiftstate(void);
typedef void (*k_hand)(unsigned char value, char up_flag);
@@ -169,7 +186,8 @@
* string, and in both cases we might assume that it is
* in utf-8 already.
*/
-void to_utf8(ushort c) {
+void to_utf8(ushort c)
+{
if (c < 0x80)
put_queue(c); /* 0******* */
else if (c < 0x800) {
@@ -188,17 +206,23 @@
* Translation of escaped scancodes to keycodes.
* This is now user-settable (for machines were it makes sense).
*/
-
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- return kbd_setkeycode(scancode, keycode);
+ return kbd_setkeycode(scancode, keycode);
}
int getkeycode(unsigned int scancode)
{
- return kbd_getkeycode(scancode);
+ return kbd_getkeycode(scancode);
}
+static void key_callback(unsigned long nr);
+
+static struct timer_list key_autorepeat_timer =
+{
+ NULL, NULL, 0, 0, key_callback
+};
+
void handle_scancode(unsigned char scancode, int down)
{
unsigned char keycode;
@@ -207,14 +231,12 @@
pm_access(pm_kbd);
- do_poke_blanked_console = 1;
- tasklet_schedule(&console_tasklet);
add_keyboard_randomness(scancode | up_flag);
tty = ttytab? ttytab[fg_console]: NULL;
if (tty && (!tty->driver_data)) {
/*
- * We touch the tty structure via the the ttytab array
+ * We touch the tty structure via the ttytab array
* without knowing whether or not tty is open, which
* is inherently dangerous. We currently rely on that
* fact that console_open sets tty->driver_data when
@@ -243,12 +265,33 @@
* return the keycode if in MEDIUMRAW mode.
*/
+ kbd_processkeycode(keycode, up_flag, 0);
+}
+
+static void
+kbd_processkeycode(unsigned char keycode, char up_flag, int autorepeat)
+{
+ char raw_mode = (kbd->kbdmode == VC_RAW);
+
if (up_flag) {
rep = 0;
if(!test_and_clear_bit(keycode, key_down))
up_flag = kbd_unexpected_up(keycode);
- } else
+ } else {
rep = test_and_set_bit(keycode, key_down);
+ /* If the keyboard autorepeated for us, ignore it.
+ * We do our own autorepeat processing.
+ */
+ if (rep && !autorepeat)
+ return;
+ }
+
+ if (kbd_repeatkeycode == keycode || !up_flag || raw_mode) {
+ kbd_repeatkeycode = -1;
+ del_timer(&key_autorepeat_timer);
+ }
+ do_poke_blanked_console = 1;
+ tasklet_schedule(&console_tasklet);
#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */
if (keycode == SYSRQ_KEY) {
@@ -262,6 +305,23 @@
}
#endif
+ /*
+ * Calculate the next time when we have to do some autorepeat
+ * processing. Note that we do not do autorepeat processing
+ * while in raw mode but we do do autorepeat processing in
+ * medium raw mode.
+ */
+ if (!up_flag && !raw_mode) {
+ kbd_repeatkeycode = keycode;
+ if (vc_kbd_mode(kbd, VC_REPEAT)) {
+ if (rep)
+ key_autorepeat_timer.expires = jiffies + kbd_repeatinterval;
+ else
+ key_autorepeat_timer.expires = jiffies + kbd_repeattimeout;
+ add_timer(&key_autorepeat_timer);
+ }
+ }
+
if (kbd->kbdmode == VC_MEDIUMRAW) {
/* soon keycodes will require more than one byte */
put_queue(keycode + up_flag);
@@ -330,6 +390,23 @@
#endif
}
}
+ rep = 0;
+}
+
+/*
+ * This clears the key down arrays when the keyboard is reset. On
+ * keyboard reset, this must be called before any keycodes are
+ * received.
+ */
+void kbd_reset_kdown(void)
+{
+ int i;
+
+ for (i = 0; i < NR_SHIFT; i++)
+ k_down[i] = 0;
+ for (i = 0; i < SIZE(key_down); i++)
+ key_down[i] = 0;
+ shift_state = 0;
}
@@ -518,7 +595,7 @@
{
}
-static void do_null()
+static void do_null(void)
{
compute_shiftstate();
}
@@ -633,8 +710,8 @@
static void do_pad(unsigned char value, char up_flag)
{
- static const char *pad_chars = "0123456789+-*/\015,.?()";
- static const char *app_map = "pqrstuvwxylSRQMnnmPQ";
+ static const char *pad_chars = "0123456789+-*/\015,.?()#";
+ static const char *app_map = "pqrstuvwxylSRQMnnmPQS";
if (up_flag)
return; /* no action, if this is a key release */
@@ -735,9 +812,10 @@
}
}
-/* called after returning from RAW mode or when changing consoles -
- recompute k_down[] and shift_state from key_down[] */
-/* maybe called when keymap is undefined, so that shiftkey release is seen */
+/* Called after returning from RAW mode or when changing consoles -
+ * recompute k_down[] and shift_state from key_down[]
+ * Maybe called when keymap is undefined so that shift key release is seen
+ */
void compute_shiftstate(void)
{
int i, j, k, sym, val;
@@ -816,19 +894,22 @@
}
/*
- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
- * or (ii) whatever pattern of lights people want to show using KDSETLED,
- * or (iii) specified bits of specified words in kernel memory.
+ * The leds display either
+ * (i) the status of NumLock, CapsLock, ScrollLock, or
+ * (ii) whatever pattern of lights people want to show using KDSETLED, or
+ * (iii) specified bits of specified words in kernel memory.
*/
static unsigned char ledstate = 0xff; /* undefined */
static unsigned char ledioctl;
-unsigned char getledstate(void) {
+unsigned char getledstate(void)
+{
return ledstate;
}
-void setledstate(struct kbd_struct *kbd, unsigned int led) {
+void setledstate(struct kbd_struct *kbd, unsigned int led)
+{
if (!(led & ~7)) {
ledioctl = led;
kbd->ledmode = LED_SHOW_IOCTL;
@@ -844,7 +925,8 @@
} ledptrs[3];
void register_leds(int console, unsigned int led,
- unsigned int *addr, unsigned int mask) {
+ unsigned int *addr, unsigned int mask)
+{
struct kbd_struct *kbd = kbd_table + console;
if (led < 3) {
ledptrs[led].addr = addr;
@@ -855,7 +937,8 @@
kbd->ledmode = LED_SHOW_FLAGS;
}
-static inline unsigned char getleds(void){
+static inline unsigned char getleds(void)
+{
struct kbd_struct *kbd = kbd_table + fg_console;
unsigned char leds;
@@ -902,6 +985,19 @@
{
unsigned char leds = getleds();
+ if (rep && kbd_repeatkeycode != -1) {
+ tty = ttytab? ttytab[fg_console]: NULL;
+ kbd = kbd_table + fg_console;
+
+ /* This prevents the kbd_key routine from being called
+ * twice, once by this BH, and once by the interrupt
+ * routine.
+ */
+ kbd_disable_irq();
+ kbd_processkeycode(kbd_repeatkeycode, 0, 1);
+ kbd_enable_irq();
+ }
+
if (leds != ledstate) {
ledstate = leds;
kbd_leds(leds);
@@ -912,6 +1008,12 @@
EXPORT_SYMBOL(keyboard_tasklet);
DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
+static void key_callback(unsigned long nr)
+{
+ rep = 1;
+ tasklet_schedule(&keyboard_tasklet);
+}
+
int __init kbd_init(void)
{
int i;
@@ -934,7 +1036,7 @@
tasklet_enable(&keyboard_tasklet);
tasklet_schedule(&keyboard_tasklet);
-
+
pm_kbd = pm_register(PM_SYS_DEV, PM_SYS_KBC, NULL);
return 0;
_____
|_____| ------------------------------------------------- ---+---+-
| | Russell King rmk@arm.linux.org.uk --- ---
| | | | http://www.arm.linux.org.uk/~rmk/aboutme.html / / |
| +-+-+ --- -+-
/ | THE developer of ARM Linux |+| /|\
/ | | | --- |
+-+-+ ------------------------------------------------- /\\\ |
-
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/
This archive was generated by hypermail 2b29 : Fri Mar 31 2000 - 21:00:17 EST