X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fkeyboard.c;h=dddd022c3a611c5ce5c7363fa32d22ceb35b0b47;hb=refs%2Fheads%2Fvserver;hp=010bff6e144995208b5263319e4eefbe0c41d5c6;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 010bff6e1..dddd022c3 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -14,7 +14,7 @@ * `Sticky' modifier keys, 951006. * * 11-11-96: SAK should now work in the raw mode (Martin Mares) - * + * * Modified to provide 'generic' keyboard support by Hamish Macdonald * Merge with the m68k keyboard driver and split-off of the PC low-level * parts by Geert Uytterhoeven, May 1997 @@ -24,22 +24,22 @@ * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) */ -#include #include #include #include #include #include #include -#include #include #include +#include #include #include #include #include #include +#include static void kbd_disconnect(struct input_handle *handle); extern void ctrl_alt_del(void); @@ -52,13 +52,12 @@ extern void ctrl_alt_del(void); /* * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. - * This seems a good reason to start with NumLock off. On PC9800 and HIL keyboards - * of PARISC machines however there is no NumLock key and everyone expects the keypad + * This seems a good reason to start with NumLock off. On HIL keyboards + * of PARISC machines however there is no NumLock key and everyone expects the keypad * to be used for numbers. */ -#if defined(CONFIG_X86_PC9800) || \ - defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) +#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) #define KBD_DEFLEDS (1 << VC_NUMLOCK) #else #define KBD_DEFLEDS 0 @@ -76,21 +75,21 @@ void compute_shiftstate(void); k_self, k_fn, k_spec, k_pad,\ k_dead, k_cons, k_cur, k_shift,\ k_meta, k_ascii, k_lock, k_lowercase,\ - k_slock, k_dead2, k_ignore, k_ignore + k_slock, k_dead2, k_brl, k_ignore -typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, - char up_flag, struct pt_regs *regs); +typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, + char up_flag); static k_handler_fn K_HANDLERS; static k_handler_fn *k_handler[16] = { K_HANDLERS }; #define FN_HANDLERS\ - fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ - fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ - fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ - fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ - fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num + fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ + fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ + fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ + fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ + fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num -typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs); +typedef void (fn_handler_fn)(struct vc_data *vc); static fn_handler_fn FN_HANDLERS; static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; @@ -102,16 +101,19 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; const int max_vals[] = { 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, - 255, NR_LOCK - 1, 255 + 255, NR_LOCK - 1, 255, NR_BRL - 1 }; const int NR_TYPES = ARRAY_SIZE(max_vals); struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct kbd_struct *kbd = kbd_table; -static struct kbd_struct kbd0; -int spawnpid, spawnsig; +struct vt_spawn_console vt_spawn_con = { + .lock = SPIN_LOCK_UNLOCKED, + .pid = NULL, + .sig = 0, +}; /* * Variables exported for vt.c @@ -124,11 +126,11 @@ int shift_state = 0; */ static struct input_handler kbd_handler; -static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ +static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static int dead_key_next; static int npadch = -1; /* -1 or number assembled on pad */ -static unsigned char diacr; +static unsigned int diacr; static char rep; /* flag telling character repeat */ static unsigned char ledstate = 0xff; /* undefined */ @@ -143,7 +145,7 @@ static struct ledptr { /* Simple translation table for the SysRq keys */ #ifdef CONFIG_MAGIC_SYSRQ -unsigned char kbd_sysrq_xlate[128] = +unsigned char kbd_sysrq_xlate[KEY_MAX + 1] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ @@ -152,6 +154,7 @@ unsigned char kbd_sysrq_xlate[128] = "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ "\r\000/"; /* 0x60 - 0x6f */ static int sysrq_down; +static int sysrq_alt_use; #endif static int sysrq_alt; @@ -161,13 +164,13 @@ static int sysrq_alt; */ int getkeycode(unsigned int scancode) { - struct list_head * node; + struct list_head *node; struct input_dev *dev = NULL; - list_for_each(node,&kbd_handler.h_list) { - struct input_handle * handle = to_handle_h(node); - if (handle->dev->keycodesize) { - dev = handle->dev; + list_for_each(node, &kbd_handler.h_list) { + struct input_handle *handle = to_handle_h(node); + if (handle->dev->keycodesize) { + dev = handle->dev; break; } } @@ -175,7 +178,7 @@ int getkeycode(unsigned int scancode) if (!dev) return -ENODEV; - if (scancode < 0 || scancode >= dev->keycodemax) + if (scancode >= dev->keycodemax) return -EINVAL; return INPUT_KEYCODE(dev, scancode); @@ -183,22 +186,26 @@ int getkeycode(unsigned int scancode) int setkeycode(unsigned int scancode, unsigned int keycode) { - struct list_head * node; + struct list_head *node; struct input_dev *dev = NULL; - int i, oldkey; + unsigned int i, oldkey; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); - if (handle->dev->keycodesize) { - dev = handle->dev; - break; + if (handle->dev->keycodesize) { + dev = handle->dev; + break; } } if (!dev) return -ENODEV; - if (scancode < 0 || scancode >= dev->keycodemax) + if (scancode >= dev->keycodemax) + return -EINVAL; + if (keycode < 0 || keycode > KEY_MAX) + return -EINVAL; + if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) return -EINVAL; oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode); @@ -214,42 +221,41 @@ int setkeycode(unsigned int scancode, unsigned int keycode) } /* - * Making beeps and bells. + * Making beeps and bells. */ static void kd_nosound(unsigned long ignored) { - struct list_head * node; + struct list_head *node; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) - input_event(handle->dev, EV_SND, SND_TONE, 0); + input_inject_event(handle, EV_SND, SND_TONE, 0); if (test_bit(SND_BELL, handle->dev->sndbit)) - input_event(handle->dev, EV_SND, SND_BELL, 0); + input_inject_event(handle, EV_SND, SND_BELL, 0); } } } -static struct timer_list kd_mksound_timer = - TIMER_INITIALIZER(kd_nosound, 0, 0); +static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); void kd_mksound(unsigned int hz, unsigned int ticks) { - struct list_head * node; + struct list_head *node; del_timer(&kd_mksound_timer); if (hz) { - list_for_each_prev(node,&kbd_handler.h_list) { + list_for_each_prev(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) { - input_event(handle->dev, EV_SND, SND_TONE, hz); + input_inject_event(handle, EV_SND, SND_TONE, hz); break; } if (test_bit(SND_BELL, handle->dev->sndbit)) { - input_event(handle->dev, EV_SND, SND_BELL, 1); + input_inject_event(handle, EV_SND, SND_BELL, 1); break; } } @@ -270,15 +276,15 @@ int kbd_rate(struct kbd_repeat *rep) unsigned int d = 0; unsigned int p = 0; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); struct input_dev *dev = handle->dev; if (test_bit(EV_REP, dev->evbit)) { if (rep->delay > 0) - input_event(dev, EV_REP, REP_DELAY, rep->delay); + input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); if (rep->period > 0) - input_event(dev, EV_REP, REP_PERIOD, rep->period); + input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); d = dev->rep[REP_DELAY]; p = dev->rep[REP_PERIOD]; } @@ -331,35 +337,35 @@ static void applkey(struct vc_data *vc, int key, char mode) * in utf-8 already. UTF-8 is defined for words of up to 31 bits, * but we need only 16 bits here */ -void to_utf8(struct vc_data *vc, ushort c) +static void to_utf8(struct vc_data *vc, ushort c) { if (c < 0x80) /* 0******* */ put_queue(vc, c); - else if (c < 0x800) { + else if (c < 0x800) { /* 110***** 10****** */ - put_queue(vc, 0xc0 | (c >> 6)); + put_queue(vc, 0xc0 | (c >> 6)); put_queue(vc, 0x80 | (c & 0x3f)); - } else { + } else { /* 1110**** 10****** 10****** */ put_queue(vc, 0xe0 | (c >> 12)); put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); put_queue(vc, 0x80 | (c & 0x3f)); - } + } } -/* +/* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is * undefined, so that shiftkey release is seen */ void compute_shiftstate(void) { - int i, j, k, sym, val; + unsigned int i, j, k, sym, val; shift_state = 0; memset(shift_down, 0, sizeof(shift_down)); - + for (i = 0; i < ARRAY_SIZE(key_down); i++) { if (!key_down[i]) @@ -393,32 +399,43 @@ void compute_shiftstate(void) * Otherwise, conclude that DIACR was not combining after all, * queue it and return CH. */ -unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) +static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) { - int d = diacr; - int i; + unsigned int d = diacr; + unsigned int i; diacr = 0; - for (i = 0; i < accent_table_size; i++) { - if (accent_table[i].diacr == d && accent_table[i].base == ch) - return accent_table[i].result; + if ((d & ~0xff) == BRL_UC_ROW) { + if ((ch & ~0xff) == BRL_UC_ROW) + return d | ch; + } else { + for (i = 0; i < accent_table_size; i++) + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; } - if (ch == ' ' || ch == d) + if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) return d; - put_queue(vc, d); + if (kbd->kbdmode == VC_UNICODE) + to_utf8(vc, d); + else if (d < 0x100) + put_queue(vc, d); + return ch; } /* * Special function handlers */ -static void fn_enter(struct vc_data *vc, struct pt_regs *regs) +static void fn_enter(struct vc_data *vc) { if (diacr) { - put_queue(vc, diacr); + if (kbd->kbdmode == VC_UNICODE) + to_utf8(vc, diacr); + else if (diacr < 0x100) + put_queue(vc, diacr); diacr = 0; } put_queue(vc, 13); @@ -426,27 +443,28 @@ static void fn_enter(struct vc_data *vc, struct pt_regs *regs) put_queue(vc, 10); } -static void fn_caps_toggle(struct vc_data *vc, struct pt_regs *regs) +static void fn_caps_toggle(struct vc_data *vc) { if (rep) return; chg_vc_kbd_led(kbd, VC_CAPSLOCK); } -static void fn_caps_on(struct vc_data *vc, struct pt_regs *regs) +static void fn_caps_on(struct vc_data *vc) { if (rep) return; set_vc_kbd_led(kbd, VC_CAPSLOCK); } -static void fn_show_ptregs(struct vc_data *vc, struct pt_regs *regs) +static void fn_show_ptregs(struct vc_data *vc) { + struct pt_regs *regs = get_irq_regs(); if (regs) show_regs(regs); } -static void fn_hold(struct vc_data *vc, struct pt_regs *regs) +static void fn_hold(struct vc_data *vc) { struct tty_struct *tty = vc->vc_tty; @@ -464,12 +482,12 @@ static void fn_hold(struct vc_data *vc, struct pt_regs *regs) stop_tty(tty); } -static void fn_num(struct vc_data *vc, struct pt_regs *regs) +static void fn_num(struct vc_data *vc) { if (vc_kbd_mode(kbd,VC_APPLIC)) applkey(vc, 'P', 1); else - fn_bare_num(vc, regs); + fn_bare_num(vc); } /* @@ -478,19 +496,19 @@ static void fn_num(struct vc_data *vc, struct pt_regs *regs) * Bind this to NumLock if you prefer that the NumLock key always * changes the NumLock flag. */ -static void fn_bare_num(struct vc_data *vc, struct pt_regs *regs) +static void fn_bare_num(struct vc_data *vc) { if (!rep) chg_vc_kbd_led(kbd, VC_NUMLOCK); } -static void fn_lastcons(struct vc_data *vc, struct pt_regs *regs) +static void fn_lastcons(struct vc_data *vc) { /* switch to the last used console, ChN */ set_console(last_console); } -static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs) +static void fn_dec_console(struct vc_data *vc) { int i, cur = fg_console; @@ -498,16 +516,16 @@ static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs) if (want_console != -1) cur = want_console; - for (i = cur-1; i != cur; i--) { + for (i = cur - 1; i != cur; i--) { if (i == -1) - i = MAX_NR_CONSOLES-1; + i = MAX_NR_CONSOLES - 1; if (vc_cons_allocated(i)) break; } set_console(i); } -static void fn_inc_console(struct vc_data *vc, struct pt_regs *regs) +static void fn_inc_console(struct vc_data *vc) { int i, cur = fg_console; @@ -524,7 +542,7 @@ static void fn_inc_console(struct vc_data *vc, struct pt_regs *regs) set_console(i); } -static void fn_send_intr(struct vc_data *vc, struct pt_regs *regs) +static void fn_send_intr(struct vc_data *vc) { struct tty_struct *tty = vc->vc_tty; @@ -534,44 +552,48 @@ static void fn_send_intr(struct vc_data *vc, struct pt_regs *regs) con_schedule_flip(tty); } -static void fn_scroll_forw(struct vc_data *vc, struct pt_regs *regs) +static void fn_scroll_forw(struct vc_data *vc) { - scrollfront(0); + scrollfront(vc, 0); } -static void fn_scroll_back(struct vc_data *vc, struct pt_regs *regs) +static void fn_scroll_back(struct vc_data *vc) { - scrollback(0); + scrollback(vc, 0); } -static void fn_show_mem(struct vc_data *vc, struct pt_regs *regs) +static void fn_show_mem(struct vc_data *vc) { show_mem(); } -static void fn_show_state(struct vc_data *vc, struct pt_regs *regs) +static void fn_show_state(struct vc_data *vc) { show_state(); } -static void fn_boot_it(struct vc_data *vc, struct pt_regs *regs) +static void fn_boot_it(struct vc_data *vc) { ctrl_alt_del(); } -static void fn_compose(struct vc_data *vc, struct pt_regs *regs) +static void fn_compose(struct vc_data *vc) { dead_key_next = 1; } -static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) +static void fn_spawn_con(struct vc_data *vc) { - if (spawnpid) - if(kill_proc(spawnpid, spawnsig, 1)) - spawnpid = 0; + spin_lock(&vt_spawn_con.lock); + if (vt_spawn_con.pid) + if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { + put_pid(vt_spawn_con.pid); + vt_spawn_con.pid = NULL; + } + spin_unlock(&vt_spawn_con.lock); } -static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) +static void fn_SAK(struct vc_data *vc) { struct tty_struct *tty = vc->vc_tty; @@ -581,10 +603,10 @@ static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) */ if (tty) do_SAK(tty); - reset_vc(fg_console); + reset_vc(vc); } -static void fn_null(struct vc_data *vc, struct pt_regs *regs) +static void fn_null(struct vc_data *vc) { compute_shiftstate(); } @@ -592,29 +614,29 @@ static void fn_null(struct vc_data *vc, struct pt_regs *regs) /* * Special key handlers */ -static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) { } -static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; if (value >= ARRAY_SIZE(fn_handler)) return; - if ((kbd->kbdmode == VC_RAW || - kbd->kbdmode == VC_MEDIUMRAW) && + if ((kbd->kbdmode == VC_RAW || + kbd->kbdmode == VC_MEDIUMRAW) && value != KVAL(K_SAK)) return; /* SAK is allowed even in raw mode */ - fn_handler[value](vc, regs); + fn_handler[value](vc); } -static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) { printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); } -static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) { if (up_flag) return; /* no action, if this is a key release */ @@ -627,7 +649,10 @@ static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct diacr = value; return; } - put_queue(vc, value); + if (kbd->kbdmode == VC_UNICODE) + to_utf8(vc, value); + else if (value < 0x100) + put_queue(vc, value); } /* @@ -635,31 +660,41 @@ static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct * dead keys modifying the same character. Very useful * for Vietnamese. */ -static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) { if (up_flag) return; diacr = (diacr ? handle_diacr(vc, value) : value); } +static void k_self(struct vc_data *vc, unsigned char value, char up_flag) +{ + k_unicode(vc, value, up_flag); +} + +static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) +{ + k_deadunicode(vc, value, up_flag); +} + /* * Obsolete - for backwards compatibility only */ -static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) { - static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; + static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; value = ret_diacr[value]; - k_dead2(vc, value, up_flag, regs); + k_deadunicode(vc, value, up_flag); } -static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; set_console(value); } -static void k_fn(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) { unsigned v; @@ -673,19 +708,19 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag, struct p printk(KERN_ERR "k_fn called with value=%d\n", value); } -static void k_cur(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) { - static const char *cur_chars = "BDCA"; + static const char cur_chars[] = "BDCA"; if (up_flag) return; applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE)); } -static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) { - static const char *pad_chars = "0123456789+-*/\015,.?()#"; - static const char *app_map = "pqrstuvwxylSRQMnnmPQS"; + 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 */ @@ -700,34 +735,34 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct switch (value) { case KVAL(K_PCOMMA): case KVAL(K_PDOT): - k_fn(vc, KVAL(K_REMOVE), 0, regs); + k_fn(vc, KVAL(K_REMOVE), 0); return; case KVAL(K_P0): - k_fn(vc, KVAL(K_INSERT), 0, regs); + k_fn(vc, KVAL(K_INSERT), 0); return; case KVAL(K_P1): - k_fn(vc, KVAL(K_SELECT), 0, regs); + k_fn(vc, KVAL(K_SELECT), 0); return; case KVAL(K_P2): - k_cur(vc, KVAL(K_DOWN), 0, regs); + k_cur(vc, KVAL(K_DOWN), 0); return; case KVAL(K_P3): - k_fn(vc, KVAL(K_PGDN), 0, regs); + k_fn(vc, KVAL(K_PGDN), 0); return; case KVAL(K_P4): - k_cur(vc, KVAL(K_LEFT), 0, regs); + k_cur(vc, KVAL(K_LEFT), 0); return; case KVAL(K_P6): - k_cur(vc, KVAL(K_RIGHT), 0, regs); + k_cur(vc, KVAL(K_RIGHT), 0); return; case KVAL(K_P7): - k_fn(vc, KVAL(K_FIND), 0, regs); + k_fn(vc, KVAL(K_FIND), 0); return; case KVAL(K_P8): - k_cur(vc, KVAL(K_UP), 0, regs); + k_cur(vc, KVAL(K_UP), 0); return; case KVAL(K_P9): - k_fn(vc, KVAL(K_PGUP), 0, regs); + k_fn(vc, KVAL(K_PGUP), 0); return; case KVAL(K_P5): applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); @@ -739,7 +774,7 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct put_queue(vc, 10); } -static void k_shift(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) { int old_state = shift_state; @@ -780,7 +815,7 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag, struc } } -static void k_meta(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; @@ -792,7 +827,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag, struct put_queue(vc, value | 0x80); } -static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) { int base; @@ -814,16 +849,16 @@ static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag, struc npadch = npadch * base + value; } -static void k_lock(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag || rep) return; chg_vc_kbd_lock(kbd, value); } -static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) { - k_shift(vc, value, up_flag, regs); + k_shift(vc, value, up_flag); if (up_flag || rep) return; chg_vc_kbd_slock(kbd, value); @@ -834,6 +869,80 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc } } +/* by default, 300ms interval for combination release */ +static unsigned brl_timeout = 300; +MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)"); +module_param(brl_timeout, uint, 0644); + +static unsigned brl_nbchords = 1; +MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)"); +module_param(brl_nbchords, uint, 0644); + +static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag) +{ + static unsigned long chords; + static unsigned committed; + + if (!brl_nbchords) + k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag); + else { + committed |= pattern; + chords++; + if (chords == brl_nbchords) { + k_unicode(vc, BRL_UC_ROW | committed, up_flag); + chords = 0; + committed = 0; + } + } +} + +static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) +{ + static unsigned pressed,committing; + static unsigned long releasestart; + + if (kbd->kbdmode != VC_UNICODE) { + if (!up_flag) + printk("keyboard mode must be unicode for braille patterns\n"); + return; + } + + if (!value) { + k_unicode(vc, BRL_UC_ROW, up_flag); + return; + } + + if (value > 8) + return; + + if (up_flag) { + if (brl_timeout) { + if (!committing || + jiffies - releasestart > (brl_timeout * HZ) / 1000) { + committing = pressed; + releasestart = jiffies; + } + pressed &= ~(1 << (value - 1)); + if (!pressed) { + if (committing) { + k_brlcommit(vc, committing, 0); + committing = 0; + } + } + } else { + if (committing) { + k_brlcommit(vc, committing, 0); + committing = 0; + } + pressed &= ~(1 << (value - 1)); + } + } else { + pressed |= 1 << (value - 1); + if (!brl_timeout) + committing = pressed; + } +} + /* * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, * or (ii) whatever pattern of lights people want to show using KDSETLED, @@ -854,18 +963,6 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) set_leds(); } -void register_leds(struct kbd_struct *kbd, unsigned int led, - unsigned int *addr, unsigned int mask) -{ - if (led < 3) { - ledptrs[led].addr = addr; - ledptrs[led].mask = mask; - ledptrs[led].valid = 1; - kbd->ledmode = LED_SHOW_MEM; - } else - kbd->ledmode = LED_SHOW_FLAGS; -} - static inline unsigned char getleds(void) { struct kbd_struct *kbd = kbd_table + fg_console; @@ -900,21 +997,21 @@ static inline unsigned char getleds(void) * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. * This allows for easy and efficient race-condition prevention - * for kbd_refresh_leds => input_event(dev, EV_LED, ...) => ... + * for kbd_start => input_inject_event(dev, EV_LED, ...) => ... */ static void kbd_bh(unsigned long dummy) { - struct list_head * node; + struct list_head *node; unsigned char leds = getleds(); if (leds != ledstate) { - list_for_each(node,&kbd_handler.h_list) { - struct input_handle * handle = to_handle_h(node); - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_sync(handle->dev); + list_for_each(node, &kbd_handler.h_list) { + struct input_handle *handle = to_handle_h(node); + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); } } @@ -923,33 +1020,22 @@ static void kbd_bh(unsigned long dummy) DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -/* - * This allows a newly plugged keyboard to pick the LED state. - */ -void kbd_refresh_leds(struct input_handle *handle) -{ - unsigned char leds = ledstate; - - tasklet_disable(&keyboard_tasklet); - if (leds != 0xff) { - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_sync(handle->dev); - } - tasklet_enable(&keyboard_tasklet); -} +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ + defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ + defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ + (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SH_MPC1211) +#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ + ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) -static unsigned short x86_keycodes[256] = +static const unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92, - 284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339, + 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339, 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, 103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361, @@ -963,44 +1049,63 @@ static unsigned short x86_keycodes[256] = extern int mac_hid_mouse_emulate_buttons(int, int, int); #endif /* CONFIG_MAC_EMUMOUSEBTN */ -#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) +#ifdef CONFIG_SPARC static int sparc_l1_a_state = 0; extern void sun_do_break(void); #endif -static int emulate_raw(struct vc_data *vc, unsigned int keycode, +static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { - if (keycode > 255 || !x86_keycodes[keycode]) - return -1; + int code; switch (keycode) { case KEY_PAUSE: put_queue(vc, 0xe1); put_queue(vc, 0x1d | up_flag); put_queue(vc, 0x45 | up_flag); - return 0; - case KEY_HANGUEL: - if (!up_flag) put_queue(vc, 0xf1); - return 0; + break; + + case KEY_HANGEUL: + if (!up_flag) + put_queue(vc, 0xf2); + break; + case KEY_HANJA: - if (!up_flag) put_queue(vc, 0xf2); - return 0; - } + if (!up_flag) + put_queue(vc, 0xf1); + break; - if (keycode == KEY_SYSRQ && sysrq_alt) { - put_queue(vc, 0x54 | up_flag); - return 0; - } + case KEY_SYSRQ: + /* + * Real AT keyboards (that's what we're trying + * to emulate here emit 0xe0 0x2a 0xe0 0x37 when + * pressing PrtSc/SysRq alone, but simply 0x54 + * when pressing Alt+PrtSc/SysRq. + */ + if (sysrq_alt) { + put_queue(vc, 0x54 | up_flag); + } else { + put_queue(vc, 0xe0); + put_queue(vc, 0x2a | up_flag); + put_queue(vc, 0xe0); + put_queue(vc, 0x37 | up_flag); + } + break; + + default: + if (keycode > 255) + return -1; - if (x86_keycodes[keycode] & 0x100) - put_queue(vc, 0xe0); + code = x86_keycodes[keycode]; + if (!code) + return -1; - put_queue(vc, (x86_keycodes[keycode] & 0x7f) | up_flag); + if (code & 0x100) + put_queue(vc, 0xe0); + put_queue(vc, (code & 0x7f) | up_flag); - if (keycode == KEY_SYSRQ) { - put_queue(vc, 0xe0); - put_queue(vc, 0x37 | up_flag); + break; } return 0; @@ -1008,6 +1113,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, #else +#define HW_RAW(dev) 0 + #warning "Cannot generate rawmode keyboard for your architecture yet." static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) @@ -1020,7 +1127,15 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u } #endif -void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) +static void kbd_rawcode(unsigned char data) +{ + struct vc_data *vc = vc_cons[fg_console].d; + kbd = kbd_table + fg_console; + if (kbd->kbdmode == VC_RAW) + put_queue(vc, data); +} + +static void kbd_keycode(unsigned int keycode, int down, int hw_raw) { struct vc_data *vc = vc_cons[fg_console].d; unsigned short keysym, *key_map; @@ -1028,9 +1143,6 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) struct tty_struct *tty; int shift_final; - if (down != 2) - add_keyboard_randomness((keycode << 1) ^ down); - tty = vc->vc_tty; if (tty && (!tty->driver_data)) { @@ -1041,8 +1153,8 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) kbd = kbd_table + fg_console; if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) - sysrq_alt = down; -#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) + sysrq_alt = down ? keycode : 0; +#ifdef CONFIG_SPARC if (keycode == KEY_STOP) sparc_l1_a_state = down; #endif @@ -1054,22 +1166,27 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) return; #endif /* CONFIG_MAC_EMUMOUSEBTN */ - if ((raw_mode = (kbd->kbdmode == VC_RAW))) + if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { - sysrq_down = down; + if (!sysrq_down) { + sysrq_down = down; + sysrq_alt_use = sysrq_alt; + } return; } + if (sysrq_down && !down && keycode == sysrq_alt_use) + sysrq_down = 0; if (sysrq_down && down && !rep) { - handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); + handle_sysrq(kbd_sysrq_xlate[keycode], tty); return; } #endif -#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) +#ifdef CONFIG_SPARC if (keycode == KEY_A && sparc_l1_a_state) { sparc_l1_a_state = 0; sun_do_break(); @@ -1101,11 +1218,12 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) else clear_bit(keycode, key_down); - if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && - (!L_ECHO(tty) && tty->driver->chars_in_buffer(tty))))) { + if (rep && + (!vc_kbd_mode(kbd, VC_REPEAT) || + (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) { /* * Don't repeat a key if the input buffers are not empty and the - * characters get aren't echoed locally. This makes key repeat + * characters get aren't echoed locally. This makes key repeat * usable with slow applications and under heavy loads. */ return; @@ -1120,11 +1238,19 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) return; } - keysym = key_map[keycode]; + if (keycode > NR_KEYS) + if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) + keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1); + else + return; + else + keysym = key_map[keycode]; + type = KTYP(keysym); if (type < 0xf0) { - if (down && !raw_mode) to_utf8(vc, keysym); + if (down && !raw_mode) + to_utf8(vc, keysym); return; } @@ -1142,54 +1268,53 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) } } - (*k_handler[type])(vc, keysym & 0xff, !down, regs); + (*k_handler[type])(vc, keysym & 0xff, !down); if (type != KT_SLOCK) kbd->slockstate = 0; } -static void kbd_event(struct input_handle *handle, unsigned int event_type, - unsigned int keycode, int down) +static void kbd_event(struct input_handle *handle, unsigned int event_type, + unsigned int event_code, int value) { - if (event_type != EV_KEY) - return; - kbd_keycode(keycode, down, handle->dev->regs); + if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) + kbd_rawcode(value); + if (event_type == EV_KEY) + kbd_keycode(event_code, value, HW_RAW(handle->dev)); tasklet_schedule(&keyboard_tasklet); do_poke_blanked_console = 1; schedule_console_callback(); } -static char kbd_name[] = "kbd"; - /* * When a keyboard (or other input device) is found, the kbd_connect * function is called. The function then looks at the device, and if it * likes it, it can open it and get events from it. In this (kbd_connect) * function, we should decide which VT to bind that keyboard to initially. */ -static struct input_handle *kbd_connect(struct input_handler *handler, +static struct input_handle *kbd_connect(struct input_handler *handler, struct input_dev *dev, - struct input_device_id *id) + const struct input_device_id *id) { struct input_handle *handle; int i; for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) break; + if (test_bit(i, dev->keybit)) + break; - if ((i == BTN_MISC) && !test_bit(EV_SND, dev->evbit)) + if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) return NULL; - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) return NULL; - memset(handle, 0, sizeof(struct input_handle)); handle->dev = dev; handle->handler = handler; - handle->name = kbd_name; + handle->name = "kbd"; input_open_device(handle); - kbd_refresh_leds(handle); return handle; } @@ -1200,16 +1325,34 @@ static void kbd_disconnect(struct input_handle *handle) kfree(handle); } -static struct input_device_id kbd_ids[] = { +/* + * Start keyboard handler on the new keyboard by refreshing LED state to + * match the rest of the system. + */ +static void kbd_start(struct input_handle *handle) +{ + unsigned char leds = ledstate; + + tasklet_disable(&keyboard_tasklet); + if (leds != 0xff) { + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); + } + tasklet_enable(&keyboard_tasklet); +} + +static const struct input_device_id kbd_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_KEY) }, }, - + { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_SND) }, - }, + }, { }, /* Terminating entry */ }; @@ -1220,6 +1363,7 @@ static struct input_handler kbd_handler = { .event = kbd_event, .connect = kbd_connect, .disconnect = kbd_disconnect, + .start = kbd_start, .name = "kbd", .id_table = kbd_ids, }; @@ -1227,18 +1371,21 @@ static struct input_handler kbd_handler = { int __init kbd_init(void) { int i; + int error; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + kbd_table[i].ledflagstate = KBD_DEFLEDS; + kbd_table[i].default_ledflagstate = KBD_DEFLEDS; + kbd_table[i].ledmode = LED_SHOW_FLAGS; + kbd_table[i].lockstate = KBD_DEFLOCK; + kbd_table[i].slockstate = 0; + kbd_table[i].modeflags = KBD_DEFMODE; + kbd_table[i].kbdmode = VC_UNICODE; + } - kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; - kbd0.ledmode = LED_SHOW_FLAGS; - kbd0.lockstate = KBD_DEFLOCK; - kbd0.slockstate = 0; - kbd0.modeflags = KBD_DEFMODE; - kbd0.kbdmode = VC_XLATE; - - for (i = 0 ; i < MAX_NR_CONSOLES ; i++) - kbd_table[i] = kbd0; - - input_register_handler(&kbd_handler); + error = input_register_handler(&kbd_handler); + if (error) + return error; tasklet_enable(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet);