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