diff options
Diffstat (limited to 'drivers/char/keyboard.c')
-rw-r--r-- | drivers/char/keyboard.c | 118 |
1 files changed, 101 insertions, 17 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 8b603b2d1c42..935670a3cd98 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -74,7 +74,7 @@ void compute_shiftstate(void); | |||
74 | k_self, k_fn, k_spec, k_pad,\ | 74 | k_self, k_fn, k_spec, k_pad,\ |
75 | k_dead, k_cons, k_cur, k_shift,\ | 75 | k_dead, k_cons, k_cur, k_shift,\ |
76 | k_meta, k_ascii, k_lock, k_lowercase,\ | 76 | k_meta, k_ascii, k_lock, k_lowercase,\ |
77 | k_slock, k_dead2, k_ignore, k_ignore | 77 | k_slock, k_dead2, k_brl, k_ignore |
78 | 78 | ||
79 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, | 79 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, |
80 | char up_flag, struct pt_regs *regs); | 80 | char up_flag, struct pt_regs *regs); |
@@ -100,7 +100,7 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; | |||
100 | const int max_vals[] = { | 100 | const int max_vals[] = { |
101 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, | 101 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, |
102 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, | 102 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, |
103 | 255, NR_LOCK - 1, 255 | 103 | 255, NR_LOCK - 1, 255, NR_BRL - 1 |
104 | }; | 104 | }; |
105 | 105 | ||
106 | const int NR_TYPES = ARRAY_SIZE(max_vals); | 106 | const int NR_TYPES = ARRAY_SIZE(max_vals); |
@@ -126,7 +126,7 @@ static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ | |||
126 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ | 126 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ |
127 | static int dead_key_next; | 127 | static int dead_key_next; |
128 | static int npadch = -1; /* -1 or number assembled on pad */ | 128 | static int npadch = -1; /* -1 or number assembled on pad */ |
129 | static unsigned char diacr; | 129 | static unsigned int diacr; |
130 | static char rep; /* flag telling character repeat */ | 130 | static char rep; /* flag telling character repeat */ |
131 | 131 | ||
132 | static unsigned char ledstate = 0xff; /* undefined */ | 132 | static unsigned char ledstate = 0xff; /* undefined */ |
@@ -394,22 +394,30 @@ void compute_shiftstate(void) | |||
394 | * Otherwise, conclude that DIACR was not combining after all, | 394 | * Otherwise, conclude that DIACR was not combining after all, |
395 | * queue it and return CH. | 395 | * queue it and return CH. |
396 | */ | 396 | */ |
397 | static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) | 397 | static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) |
398 | { | 398 | { |
399 | int d = diacr; | 399 | unsigned int d = diacr; |
400 | unsigned int i; | 400 | unsigned int i; |
401 | 401 | ||
402 | diacr = 0; | 402 | diacr = 0; |
403 | 403 | ||
404 | for (i = 0; i < accent_table_size; i++) { | 404 | if ((d & ~0xff) == BRL_UC_ROW) { |
405 | if (accent_table[i].diacr == d && accent_table[i].base == ch) | 405 | if ((ch & ~0xff) == BRL_UC_ROW) |
406 | return accent_table[i].result; | 406 | return d | ch; |
407 | } else { | ||
408 | for (i = 0; i < accent_table_size; i++) | ||
409 | if (accent_table[i].diacr == d && accent_table[i].base == ch) | ||
410 | return accent_table[i].result; | ||
407 | } | 411 | } |
408 | 412 | ||
409 | if (ch == ' ' || ch == d) | 413 | if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) |
410 | return d; | 414 | return d; |
411 | 415 | ||
412 | put_queue(vc, d); | 416 | if (kbd->kbdmode == VC_UNICODE) |
417 | to_utf8(vc, d); | ||
418 | else if (d < 0x100) | ||
419 | put_queue(vc, d); | ||
420 | |||
413 | return ch; | 421 | return ch; |
414 | } | 422 | } |
415 | 423 | ||
@@ -419,7 +427,10 @@ static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) | |||
419 | static void fn_enter(struct vc_data *vc, struct pt_regs *regs) | 427 | static void fn_enter(struct vc_data *vc, struct pt_regs *regs) |
420 | { | 428 | { |
421 | if (diacr) { | 429 | if (diacr) { |
422 | put_queue(vc, diacr); | 430 | if (kbd->kbdmode == VC_UNICODE) |
431 | to_utf8(vc, diacr); | ||
432 | else if (diacr < 0x100) | ||
433 | put_queue(vc, diacr); | ||
423 | diacr = 0; | 434 | diacr = 0; |
424 | } | 435 | } |
425 | put_queue(vc, 13); | 436 | put_queue(vc, 13); |
@@ -615,7 +626,7 @@ static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag, s | |||
615 | printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); | 626 | printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); |
616 | } | 627 | } |
617 | 628 | ||
618 | static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | 629 | static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs) |
619 | { | 630 | { |
620 | if (up_flag) | 631 | if (up_flag) |
621 | return; /* no action, if this is a key release */ | 632 | return; /* no action, if this is a key release */ |
@@ -628,7 +639,10 @@ static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct | |||
628 | diacr = value; | 639 | diacr = value; |
629 | return; | 640 | return; |
630 | } | 641 | } |
631 | put_queue(vc, value); | 642 | if (kbd->kbdmode == VC_UNICODE) |
643 | to_utf8(vc, value); | ||
644 | else if (value < 0x100) | ||
645 | put_queue(vc, value); | ||
632 | } | 646 | } |
633 | 647 | ||
634 | /* | 648 | /* |
@@ -636,13 +650,23 @@ static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct | |||
636 | * dead keys modifying the same character. Very useful | 650 | * dead keys modifying the same character. Very useful |
637 | * for Vietnamese. | 651 | * for Vietnamese. |
638 | */ | 652 | */ |
639 | static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | 653 | static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs) |
640 | { | 654 | { |
641 | if (up_flag) | 655 | if (up_flag) |
642 | return; | 656 | return; |
643 | diacr = (diacr ? handle_diacr(vc, value) : value); | 657 | diacr = (diacr ? handle_diacr(vc, value) : value); |
644 | } | 658 | } |
645 | 659 | ||
660 | static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | ||
661 | { | ||
662 | k_unicode(vc, value, up_flag, regs); | ||
663 | } | ||
664 | |||
665 | static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | ||
666 | { | ||
667 | k_deadunicode(vc, value, up_flag, regs); | ||
668 | } | ||
669 | |||
646 | /* | 670 | /* |
647 | * Obsolete - for backwards compatibility only | 671 | * Obsolete - for backwards compatibility only |
648 | */ | 672 | */ |
@@ -650,7 +674,7 @@ static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct | |||
650 | { | 674 | { |
651 | static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; | 675 | static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; |
652 | value = ret_diacr[value]; | 676 | value = ret_diacr[value]; |
653 | k_dead2(vc, value, up_flag, regs); | 677 | k_deadunicode(vc, value, up_flag, regs); |
654 | } | 678 | } |
655 | 679 | ||
656 | static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | 680 | static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) |
@@ -835,6 +859,62 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc | |||
835 | } | 859 | } |
836 | } | 860 | } |
837 | 861 | ||
862 | /* by default, 300ms interval for combination release */ | ||
863 | static long brl_timeout = 300; | ||
864 | MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for combination on first release, < 0 for dead characters)"); | ||
865 | module_param(brl_timeout, long, 0644); | ||
866 | static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | ||
867 | { | ||
868 | static unsigned pressed,committing; | ||
869 | static unsigned long releasestart; | ||
870 | |||
871 | if (kbd->kbdmode != VC_UNICODE) { | ||
872 | if (!up_flag) | ||
873 | printk("keyboard mode must be unicode for braille patterns\n"); | ||
874 | return; | ||
875 | } | ||
876 | |||
877 | if (!value) { | ||
878 | k_unicode(vc, BRL_UC_ROW, up_flag, regs); | ||
879 | return; | ||
880 | } | ||
881 | |||
882 | if (value > 8) | ||
883 | return; | ||
884 | |||
885 | if (brl_timeout < 0) { | ||
886 | k_deadunicode(vc, BRL_UC_ROW | (1 << (value - 1)), up_flag, regs); | ||
887 | return; | ||
888 | } | ||
889 | |||
890 | if (up_flag) { | ||
891 | if (brl_timeout) { | ||
892 | if (!committing || | ||
893 | jiffies - releasestart > (brl_timeout * HZ) / 1000) { | ||
894 | committing = pressed; | ||
895 | releasestart = jiffies; | ||
896 | } | ||
897 | pressed &= ~(1 << (value - 1)); | ||
898 | if (!pressed) { | ||
899 | if (committing) { | ||
900 | k_unicode(vc, BRL_UC_ROW | committing, 0, regs); | ||
901 | committing = 0; | ||
902 | } | ||
903 | } | ||
904 | } else { | ||
905 | if (committing) { | ||
906 | k_unicode(vc, BRL_UC_ROW | committing, 0, regs); | ||
907 | committing = 0; | ||
908 | } | ||
909 | pressed &= ~(1 << (value - 1)); | ||
910 | } | ||
911 | } else { | ||
912 | pressed |= 1 << (value - 1); | ||
913 | if (!brl_timeout) | ||
914 | committing = pressed; | ||
915 | } | ||
916 | } | ||
917 | |||
838 | /* | 918 | /* |
839 | * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, | 919 | * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, |
840 | * or (ii) whatever pattern of lights people want to show using KDSETLED, | 920 | * or (ii) whatever pattern of lights people want to show using KDSETLED, |
@@ -1125,9 +1205,13 @@ static void kbd_keycode(unsigned int keycode, int down, | |||
1125 | } | 1205 | } |
1126 | 1206 | ||
1127 | if (keycode > NR_KEYS) | 1207 | if (keycode > NR_KEYS) |
1128 | return; | 1208 | if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) |
1209 | keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1); | ||
1210 | else | ||
1211 | return; | ||
1212 | else | ||
1213 | keysym = key_map[keycode]; | ||
1129 | 1214 | ||
1130 | keysym = key_map[keycode]; | ||
1131 | type = KTYP(keysym); | 1215 | type = KTYP(keysym); |
1132 | 1216 | ||
1133 | if (type < 0xf0) { | 1217 | if (type < 0xf0) { |