This source file includes following definitions.
- kb_wait
- send_cmd
- keyboard_interrupt
- put_queue
- puts_queue
- applkey
- enter
- caps_toggle
- caps_on
- show_ptregs
- hold
- num
- lastcons
- send_intr
- scrll_forw
- scrll_back
- boot_it
- compose
- do_spec
- do_self
- do_dead
- handle_diacr
- do_cons
- do_fn
- do_pad
- do_cur
- do_shift
- compute_shiftstate
- do_meta
- do_ascii
- do_lock
- send_data
- kbd_bh
- hard_reset_now
- kbd_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #define KEYBOARD_IRQ 1
15
16 #include <linux/sched.h>
17 #include <linux/tty.h>
18 #include <linux/mm.h>
19 #include <linux/ptrace.h>
20 #include <linux/keyboard.h>
21 #include <linux/interrupt.h>
22 #include <linux/config.h>
23 #include <linux/signal.h>
24 #include <linux/string.h>
25
26 #include <asm/bitops.h>
27
28 #include "diacr.h"
29
30 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
31
32 #ifndef KBD_DEFFLAGS
33
34 #ifdef CONFIG_KBD_META
35 #define KBD_META (1 << VC_META)
36 #else
37 #define KBD_META 0
38 #endif
39
40 #ifdef CONFIG_KBD_NUML
41 #define KBD_NUML (1 << VC_NUMLOCK)
42 #else
43 #define KBD_NUML 0
44 #endif
45
46 #define KBD_DEFFLAGS (KBD_NUML | (1 << VC_REPEAT) | KBD_META)
47 #endif
48
49
50
51
52
53
54
55 #define REALLY_SLOW_IO
56 #define SLOW_IO_BY_JUMPING
57 #include <asm/io.h>
58 #include <asm/system.h>
59
60 extern void do_keyboard_interrupt(void);
61 extern void ctrl_alt_del(void);
62 extern void change_console(unsigned int new_console);
63 extern void scrollback(int);
64 extern void scrollfront(int);
65
66 #define fake_keyboard_interrupt() \
67 __asm__ __volatile__("int $0x21")
68
69 unsigned char kbd_read_mask = 0x01;
70
71
72
73
74
75
76
77
78 static unsigned char k_down[NR_SHIFT] = {0, };
79
80 static unsigned long key_down[8] = { 0, };
81
82 static int want_console = -1;
83 static int last_console = 0;
84 static int dead_key_next = 0;
85 static int shift_state = 0;
86 static int npadch = -1;
87 static unsigned char diacr = 0;
88 static char rep = 0;
89 struct kbd_struct kbd_table[NR_CONSOLES];
90 static struct kbd_struct * kbd = kbd_table;
91 static struct tty_struct * tty = NULL;
92
93 static volatile unsigned char acknowledge = 0;
94 static volatile unsigned char resend = 0;
95
96 typedef void (*k_hand)(unsigned char value, char up_flag);
97
98 static void do_self(unsigned char value, char up_flag);
99 static void do_fn(unsigned char value, char up_flag);
100 static void do_spec(unsigned char value, char up_flag);
101 static void do_pad(unsigned char value, char up_flag);
102 static void do_dead(unsigned char value, char up_flag);
103 static void do_cons(unsigned char value, char up_flag);
104 static void do_cur(unsigned char value, char up_flag);
105 static void do_shift(unsigned char value, char up_flag);
106 static void do_meta(unsigned char value, char up_flag);
107 static void do_ascii(unsigned char value, char up_flag);
108 static void do_lock(unsigned char value, char up_flag);
109
110 static k_hand key_handler[] = {
111 do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
112 do_meta, do_ascii, do_lock
113 };
114
115
116 const int max_vals[] = {
117 255, NR_FUNC - 1, 14, 17, 4, 255, 3, NR_SHIFT,
118 255, 9, 3
119 };
120
121 const int NR_TYPES = SIZE(max_vals);
122
123 static void put_queue(int);
124 static unsigned char handle_diacr(unsigned char);
125
126
127 static struct pt_regs * pt_regs;
128
129 static inline void kb_wait(void)
130 {
131 int i;
132
133 for (i=0; i<0x10000; i++)
134 if ((inb_p(0x64) & 0x02) == 0)
135 break;
136 }
137
138 static inline void send_cmd(unsigned char c)
139 {
140 kb_wait();
141 outb(c,0x64);
142 }
143
144
145
146
147
148 #define E0_BASE 96
149
150 #define E0_KPENTER (E0_BASE+0)
151 #define E0_RCTRL (E0_BASE+1)
152 #define E0_KPSLASH (E0_BASE+2)
153 #define E0_PRSCR (E0_BASE+3)
154 #define E0_RALT (E0_BASE+4)
155 #define E0_BREAK (E0_BASE+5)
156 #define E0_HOME (E0_BASE+6)
157 #define E0_UP (E0_BASE+7)
158 #define E0_PGUP (E0_BASE+8)
159 #define E0_LEFT (E0_BASE+9)
160 #define E0_RIGHT (E0_BASE+10)
161 #define E0_END (E0_BASE+11)
162 #define E0_DOWN (E0_BASE+12)
163 #define E0_PGDN (E0_BASE+13)
164 #define E0_INS (E0_BASE+14)
165 #define E0_DEL (E0_BASE+15)
166
167 #define E0_MACRO (E0_BASE+16)
168
169 #define E0_F13 (E0_BASE+17)
170 #define E0_F14 (E0_BASE+18)
171 #define E0_HELP (E0_BASE+19)
172 #define E0_DO (E0_BASE+20)
173 #define E0_F17 (E0_BASE+21)
174 #define E0_KPMINPLUS (E0_BASE+22)
175
176 #define E1_PAUSE (E0_BASE+23)
177
178 static unsigned char e0_keys[128] = {
179 0, 0, 0, 0, 0, 0, 0, 0,
180 0, 0, 0, 0, 0, 0, 0, 0,
181 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,
183 0, 0, 0, 0, 0, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0,
185 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,
186 E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,
187 E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,
188 E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, E0_KPMINPLUS, E0_END,
189 E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,
190 0, 0, 0, 0, 0, 0, 0, 0,
191 0, 0, 0, 0, 0, 0, 0, 0,
192 0, 0, 0, 0, 0, 0, 0, E0_MACRO,
193 0, 0, 0, 0, 0, 0, 0, 0,
194 0, 0, 0, 0, 0, 0, 0, 0
195 };
196
197 static void keyboard_interrupt(int int_pt_regs)
198 {
199 unsigned char scancode;
200 static unsigned int prev_scancode = 0;
201 char up_flag;
202 char raw_mode;
203
204 pt_regs = (struct pt_regs *) int_pt_regs;
205 send_cmd(0xAD);
206 kb_wait();
207 if ((inb_p(0x64) & kbd_read_mask) != 0x01)
208 goto end_kbd_intr;
209 scancode = inb(0x60);
210 mark_bh(KEYBOARD_BH);
211 if (scancode == 0xfa) {
212 acknowledge = 1;
213 goto end_kbd_intr;
214 } else if (scancode == 0xfe) {
215 resend = 1;
216 goto end_kbd_intr;
217 }
218 tty = TTY_TABLE(0);
219 kbd = kbd_table + fg_console;
220 if ((raw_mode = vc_kbd_flag(kbd,VC_RAW))) {
221 put_queue(scancode);
222
223
224
225 }
226 if (scancode == 0xe0 || scancode == 0xe1) {
227 prev_scancode = scancode;
228 goto end_kbd_intr;
229 }
230
231
232
233
234 up_flag = (scancode & 0200);
235 scancode &= 0x7f;
236
237 if (prev_scancode) {
238
239
240
241
242 if (prev_scancode != 0xe0) {
243 if (prev_scancode == 0xe1 && scancode == 0x1d) {
244 prev_scancode = 0x100;
245 goto end_kbd_intr;
246 } else if (prev_scancode == 0x100 && scancode == 0x45) {
247 scancode = E1_PAUSE;
248 prev_scancode = 0;
249 } else {
250 printk("keyboard: unknown e1 escape sequence\n");
251 prev_scancode = 0;
252 goto end_kbd_intr;
253 }
254 } else {
255 prev_scancode = 0;
256
257
258
259
260
261
262
263
264
265
266
267
268
269 if (scancode == 0x2a || scancode == 0x36)
270 goto end_kbd_intr;
271
272 if (e0_keys[scancode])
273 scancode = e0_keys[scancode];
274 else if (!raw_mode) {
275 printk("keyboard: unknown scancode e0 %02x\n", scancode);
276 goto end_kbd_intr;
277 }
278 }
279 } else if (scancode >= E0_BASE && !raw_mode) {
280 printk("keyboard: scancode (%02x) not in range 00 - %2x\n",
281 scancode, E0_BASE - 1);
282 goto end_kbd_intr;
283 }
284
285
286
287
288
289
290
291
292
293 if (up_flag) {
294 clear_bit(scancode, key_down);
295 rep = 0;
296 } else
297 rep = set_bit(scancode, key_down);
298
299 if (raw_mode)
300 goto end_kbd_intr;
301
302 if (vc_kbd_flag(kbd, VC_MEDIUMRAW)) {
303 put_queue(scancode + up_flag);
304 goto end_kbd_intr;
305 }
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320 if (!rep ||
321 (vc_kbd_flag(kbd,VC_REPEAT) && tty &&
322 (L_ECHO(tty) || (EMPTY(&tty->secondary) && EMPTY(&tty->read_q)))))
323 {
324 u_short key_code;
325
326 key_code = key_map[shift_state][scancode];
327 (*key_handler[key_code >> 8])(key_code & 0xff, up_flag);
328 }
329
330 end_kbd_intr:
331 send_cmd(0xAE);
332 }
333
334 static void put_queue(int ch)
335 {
336 struct tty_queue *qp;
337
338 wake_up(&keypress_wait);
339 if (!tty)
340 return;
341 qp = &tty->read_q;
342
343 if (LEFT(qp)) {
344 qp->buf[qp->head] = ch;
345 INC(qp->head);
346 wake_up_interruptible(&qp->proc_list);
347 }
348 }
349
350 static void puts_queue(char *cp)
351 {
352 struct tty_queue *qp;
353 char ch;
354
355
356 wake_up_interruptible(&keypress_wait);
357 if (!tty)
358 return;
359 qp = &tty->read_q;
360
361 while ((ch = *(cp++)) != 0) {
362 if (LEFT(qp)) {
363 qp->buf[qp->head] = ch;
364 INC(qp->head);
365 }
366 }
367 wake_up_interruptible(&qp->proc_list);
368 }
369
370 static void applkey(int key, char mode)
371 {
372 static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
373
374 buf[1] = (mode ? 'O' : '[');
375 buf[2] = key;
376 puts_queue(buf);
377 }
378
379 static void enter(void)
380 {
381 put_queue(13);
382 if (vc_kbd_flag(kbd,VC_CRLF))
383 put_queue(10);
384 }
385
386 static void caps_toggle(void)
387 {
388 if (rep)
389 return;
390 chg_vc_kbd_flag(kbd,VC_CAPSLOCK);
391 }
392
393 static void caps_on(void)
394 {
395 if (rep)
396 return;
397 set_vc_kbd_flag(kbd,VC_CAPSLOCK);
398 }
399
400 static void show_ptregs(void)
401 {
402 if (!pt_regs)
403 return;
404 printk("\n");
405 printk("EIP: %04x:%08lx",0xffff & pt_regs->cs,pt_regs->eip);
406 if (pt_regs->cs & 3)
407 printk(" ESP: %04x:%08lx",0xffff & pt_regs->ss,pt_regs->esp);
408 printk(" EFLAGS: %08lx\n",pt_regs->eflags);
409 printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
410 pt_regs->orig_eax,pt_regs->ebx,pt_regs->ecx,pt_regs->edx);
411 printk("ESI: %08lx EDI: %08lx EBP: %08lx",
412 pt_regs->esi, pt_regs->edi, pt_regs->ebp);
413 printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n",
414 0xffff & pt_regs->ds,0xffff & pt_regs->es,
415 0xffff & pt_regs->fs,0xffff & pt_regs->gs);
416 }
417
418 static void hold(void)
419 {
420 if (rep || !tty)
421 return;
422 if (vc_kbd_flag(kbd, VC_SCROLLOCK))
423
424 put_queue(START_CHAR(tty));
425 else
426
427 put_queue(STOP_CHAR(tty));
428 chg_vc_kbd_flag(kbd,VC_SCROLLOCK);
429 }
430
431 static void num(void)
432 {
433 #if 0
434 if (k_down[KG_CTRL]) {
435
436 chg_vc_kbd_flag(kbd,VC_PAUSE);
437 return;
438 }
439 #endif
440 if (vc_kbd_flag(kbd,VC_APPLIC)) {
441 applkey('P', 1);
442 return;
443 }
444 if (!rep)
445 chg_vc_kbd_flag(kbd,VC_NUMLOCK);
446 }
447
448 static void lastcons(void)
449 {
450
451 want_console = last_console;
452 }
453
454 static void send_intr(void)
455 {
456 if (tty)
457 put_queue(INTR_CHAR(tty));
458 }
459
460 static void scrll_forw(void)
461 {
462 scrollfront(0);
463 }
464
465 static void scrll_back(void)
466 {
467 scrollback(0);
468 }
469
470 static void boot_it(void)
471 {
472 ctrl_alt_del();
473 }
474
475 static void compose(void)
476 {
477 dead_key_next = 1;
478 }
479
480 static void do_spec(unsigned char value, char up_flag)
481 {
482 typedef void (*fnp)(void);
483 fnp fn_table[] = {
484 NULL, enter, show_ptregs, show_mem,
485 show_state, send_intr, lastcons, caps_toggle,
486 num, hold, scrll_forw, scrll_back,
487 boot_it, caps_on, compose
488 };
489
490 if (up_flag)
491 return;
492 if (value >= SIZE(fn_table))
493 return;
494 if (!fn_table[value])
495 return;
496 fn_table[value]();
497 }
498
499 static void do_self(unsigned char value, char up_flag)
500 {
501 if (up_flag)
502 return;
503
504 if (diacr)
505 value = handle_diacr(value);
506
507 if (dead_key_next) {
508 dead_key_next = 0;
509 diacr = value;
510 return;
511 }
512
513
514 if (vc_kbd_flag(kbd,VC_CAPSLOCK))
515 if ((value >= 'a' && value <= 'z')
516 || (value >= 224 && value <= 254)) {
517 value -= 32;
518 }
519
520 put_queue(value);
521 }
522
523 #define A_GRAVE '`'
524 #define A_ACUTE '\''
525 #define A_CFLEX '^'
526 #define A_TILDE '~'
527 #define A_DIAER '"'
528 static unsigned char ret_diacr[] =
529 {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
530
531
532
533
534 static void do_dead(unsigned char value, char up_flag)
535 {
536 if (up_flag)
537 return;
538
539 value = ret_diacr[value];
540 if (diacr == value) {
541 diacr = 0;
542 put_queue(value);
543 return;
544 }
545 diacr = value;
546 }
547
548
549
550
551
552 unsigned char handle_diacr(unsigned char ch)
553 {
554 int d = diacr;
555 int i;
556
557 diacr = 0;
558 if (ch == ' ')
559 return d;
560
561 for (i = 0; i < accent_table_size; i++)
562 if(accent_table[i].diacr == d && accent_table[i].base == ch)
563 return accent_table[i].result;
564
565 put_queue(d);
566 return ch;
567 }
568
569 static void do_cons(unsigned char value, char up_flag)
570 {
571 if (up_flag)
572 return;
573 want_console = value;
574 }
575
576 static void do_fn(unsigned char value, char up_flag)
577 {
578 if (up_flag)
579 return;
580 if (value < SIZE(func_table))
581 puts_queue(func_table[value]);
582 else
583 printk("do_fn called with value=%d\n", value);
584 }
585
586 static void do_pad(unsigned char value, char up_flag)
587 {
588 static char *pad_chars = "0123456789+-*/\015,.?";
589 static char *app_map = "pqrstuvwxylSRQMnn?";
590
591 if (up_flag)
592 return;
593
594
595 if (vc_kbd_flag(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
596 applkey(app_map[value], 1);
597 return;
598 }
599
600 if (!vc_kbd_flag(kbd,VC_NUMLOCK))
601 switch (value) {
602 case KVAL(K_PCOMMA):
603 case KVAL(K_PDOT):
604 do_fn(KVAL(K_REMOVE), 0);
605 return;
606 case KVAL(K_P0):
607 do_fn(KVAL(K_INSERT), 0);
608 return;
609 case KVAL(K_P1):
610 do_fn(KVAL(K_SELECT), 0);
611 return;
612 case KVAL(K_P2):
613 do_cur(KVAL(K_DOWN), 0);
614 return;
615 case KVAL(K_P3):
616 do_fn(KVAL(K_PGDN), 0);
617 return;
618 case KVAL(K_P4):
619 do_cur(KVAL(K_LEFT), 0);
620 return;
621 case KVAL(K_P6):
622 do_cur(KVAL(K_RIGHT), 0);
623 return;
624 case KVAL(K_P7):
625 do_fn(KVAL(K_FIND), 0);
626 return;
627 case KVAL(K_P8):
628 do_cur(KVAL(K_UP), 0);
629 return;
630 case KVAL(K_P9):
631 do_fn(KVAL(K_PGUP), 0);
632 return;
633 case KVAL(K_P5):
634 applkey('G', vc_kbd_flag(kbd, VC_APPLIC));
635 return;
636 }
637
638 put_queue(pad_chars[value]);
639 if (value == KVAL(K_PENTER) && vc_kbd_flag(kbd, VC_CRLF))
640 put_queue(10);
641 }
642
643 static void do_cur(unsigned char value, char up_flag)
644 {
645 static char *cur_chars = "BDCA";
646 if (up_flag)
647 return;
648
649 applkey(cur_chars[value], vc_kbd_flag(kbd,VC_CKMODE));
650 }
651
652 static void do_shift(unsigned char value, char up_flag)
653 {
654 int old_state = shift_state;
655
656 if (rep)
657 return;
658
659
660 if (value == KVAL(K_CAPSSHIFT)) {
661 value = KVAL(K_SHIFT);
662 clr_vc_kbd_flag(kbd, VC_CAPSLOCK);
663 }
664
665 if (up_flag) {
666
667
668 if (k_down[value])
669 k_down[value]--;
670 } else
671 k_down[value]++;
672
673 if (k_down[value])
674 shift_state |= (1 << value);
675 else
676 shift_state &= ~ (1 << value);
677
678
679 if (up_flag && shift_state != old_state && npadch != -1) {
680 put_queue(npadch);
681 npadch = -1;
682 }
683 }
684
685
686
687 void compute_shiftstate(void)
688 {
689 int i, j, k, sym, val;
690
691 shift_state = 0;
692 for(i=0; i < SIZE(k_down); i++)
693 k_down[i] = 0;
694
695 for(i=0; i < SIZE(key_down); i++)
696 if(key_down[i]) {
697 k = (i<<5);
698 for(j=0; j<32; j++,k++)
699 if(test_bit(k, key_down)) {
700 sym = key_map[0][k];
701 if(KTYP(sym) == KT_SHIFT) {
702 val = KVAL(sym);
703 k_down[val]++;
704 shift_state |= (1<<val);
705 }
706 }
707 }
708 }
709
710 static void do_meta(unsigned char value, char up_flag)
711 {
712 if (up_flag)
713 return;
714
715 if (vc_kbd_flag(kbd, VC_META)) {
716 put_queue('\033');
717 put_queue(value);
718 } else
719 put_queue(value | 0x80);
720 }
721
722 static void do_ascii(unsigned char value, char up_flag)
723 {
724 if (up_flag)
725 return;
726
727 if (npadch == -1)
728 npadch = value;
729 else
730 npadch = (npadch * 10 + value) % 1000;
731 }
732
733
734
735 static void do_lock(unsigned char value, char up_flag)
736 {
737 if (up_flag || rep)
738 return;
739 switch (value) {
740 case KVAL(K_SHIFTLOCK):
741 chg_vc_kbd_flag(kbd, VC_SHIFTLOCK);
742 do_shift(KG_SHIFT, !vc_kbd_flag(kbd, VC_SHIFTLOCK));
743 break;
744 case KVAL(K_CTRLLOCK):
745 chg_vc_kbd_flag(kbd, VC_CTRLLOCK);
746 do_shift(KG_CTRL, !vc_kbd_flag(kbd, VC_CTRLLOCK));
747 break;
748 case KVAL(K_ALTLOCK):
749 chg_vc_kbd_flag(kbd, VC_ALTLOCK);
750 do_shift(KG_ALT, !vc_kbd_flag(kbd, VC_ALTLOCK));
751 break;
752 case KVAL(K_ALTGRLOCK):
753 chg_vc_kbd_flag(kbd, VC_ALTGRLOCK);
754 do_shift(KG_ALTGR, !vc_kbd_flag(kbd, VC_ALTGRLOCK));
755 break;
756 }
757 }
758
759
760
761
762
763
764 static int send_data(unsigned char data)
765 {
766 int retries = 3;
767 int i;
768
769 do {
770 kb_wait();
771 acknowledge = 0;
772 resend = 0;
773 outb_p(data, 0x60);
774 for(i=0; i<0x20000; i++) {
775 inb_p(0x64);
776 if (acknowledge)
777 return 1;
778 if (resend)
779 break;
780 }
781 if (!resend)
782 return 0;
783 } while (retries-- > 0);
784 return 0;
785 }
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800 static void kbd_bh(void * unused)
801 {
802 static unsigned char old_leds = 0xff;
803 unsigned char leds = kbd_table[fg_console].flags & LED_MASK;
804
805 if (leds != old_leds) {
806 old_leds = leds;
807 if (!send_data(0xed) || !send_data(leds))
808 send_data(0xf4);
809 }
810 if (want_console >= 0) {
811 if (want_console != fg_console) {
812 last_console = fg_console;
813 change_console(want_console);
814 }
815 want_console = -1;
816 }
817 do_keyboard_interrupt();
818 cli();
819 if ((inb_p(0x64) & kbd_read_mask) == 0x01)
820 fake_keyboard_interrupt();
821 sti();
822 }
823
824 long no_idt[2] = {0, 0};
825
826
827
828
829
830
831 void hard_reset_now(void)
832 {
833 int i, j;
834 extern unsigned long pg0[1024];
835
836 sti();
837
838 pg0[0] = 7;
839 *((unsigned short *)0x472) = 0x1234;
840 for (;;) {
841 for (i=0; i<100; i++) {
842 kb_wait();
843 for(j = 0; j < 100000 ; j++)
844 ;
845 outb(0xfe,0x64);
846 }
847 __asm__("\tlidt _no_idt");
848 }
849 }
850
851 unsigned long kbd_init(unsigned long kmem_start)
852 {
853 int i;
854 struct kbd_struct * kbd;
855
856 kbd = kbd_table + 0;
857 for (i = 0 ; i < NR_CONSOLES ; i++,kbd++) {
858 kbd->flags = KBD_DEFFLAGS;
859 kbd->default_flags = KBD_DEFFLAGS;
860 }
861
862 bh_base[KEYBOARD_BH].routine = kbd_bh;
863 request_irq(KEYBOARD_IRQ,keyboard_interrupt);
864 mark_bh(KEYBOARD_BH);
865 return kmem_start;
866 }