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 put_queue(d);
589 return ch;
590 }
591
592 static void do_cons(unsigned char value, char up_flag)
593 {
594 if (up_flag)
595 return;
596 want_console = value;
597 }
598
599 static void do_fn(unsigned char value, char up_flag)
600 {
601 if (up_flag)
602 return;
603 if (value < SIZE(func_table))
604 puts_queue(func_table[value]);
605 else
606 printk("do_fn called with value=%d\n", value);
607 }
608
609 static void do_pad(unsigned char value, char up_flag)
610 {
611 static char *pad_chars = "0123456789+-*/\015,.?";
612 static char *app_map = "pqrstuvwxylSRQMnn?";
613
614 if (up_flag)
615 return;
616
617
618 if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
619 applkey(app_map[value], 1);
620 return;
621 }
622
623 if (!vc_kbd_led(kbd,VC_NUMLOCK))
624 switch (value) {
625 case KVAL(K_PCOMMA):
626 case KVAL(K_PDOT):
627 do_fn(KVAL(K_REMOVE), 0);
628 return;
629 case KVAL(K_P0):
630 do_fn(KVAL(K_INSERT), 0);
631 return;
632 case KVAL(K_P1):
633 do_fn(KVAL(K_SELECT), 0);
634 return;
635 case KVAL(K_P2):
636 do_cur(KVAL(K_DOWN), 0);
637 return;
638 case KVAL(K_P3):
639 do_fn(KVAL(K_PGDN), 0);
640 return;
641 case KVAL(K_P4):
642 do_cur(KVAL(K_LEFT), 0);
643 return;
644 case KVAL(K_P6):
645 do_cur(KVAL(K_RIGHT), 0);
646 return;
647 case KVAL(K_P7):
648 do_fn(KVAL(K_FIND), 0);
649 return;
650 case KVAL(K_P8):
651 do_cur(KVAL(K_UP), 0);
652 return;
653 case KVAL(K_P9):
654 do_fn(KVAL(K_PGUP), 0);
655 return;
656 case KVAL(K_P5):
657 applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
658 return;
659 }
660
661 put_queue(pad_chars[value]);
662 if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
663 put_queue(10);
664 }
665
666 static void do_cur(unsigned char value, char up_flag)
667 {
668 static char *cur_chars = "BDCA";
669 if (up_flag)
670 return;
671
672 applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
673 }
674
675 static void do_shift(unsigned char value, char up_flag)
676 {
677 int old_state = shift_state;
678
679 if (rep)
680 return;
681
682
683 if (value == KVAL(K_CAPSSHIFT)) {
684 value = KVAL(K_SHIFT);
685 clr_vc_kbd_led(kbd, VC_CAPSLOCK);
686 }
687
688 if (up_flag) {
689
690
691 if (k_down[value])
692 k_down[value]--;
693 } else
694 k_down[value]++;
695
696 if (k_down[value])
697 shift_state |= (1 << value);
698 else
699 shift_state &= ~ (1 << value);
700
701
702 if (up_flag && shift_state != old_state && npadch != -1) {
703 put_queue(npadch);
704 npadch = -1;
705 }
706 }
707
708
709
710 void compute_shiftstate(void)
711 {
712 int i, j, k, sym, val;
713
714 shift_state = 0;
715 for(i=0; i < SIZE(k_down); i++)
716 k_down[i] = 0;
717
718 for(i=0; i < SIZE(key_down); i++)
719 if(key_down[i]) {
720 k = (i<<5);
721 for(j=0; j<32; j++,k++)
722 if(test_bit(k, key_down)) {
723 sym = key_map[0][k];
724 if(KTYP(sym) == KT_SHIFT) {
725 val = KVAL(sym);
726 k_down[val]++;
727 shift_state |= (1<<val);
728 }
729 }
730 }
731 }
732
733 static void do_meta(unsigned char value, char up_flag)
734 {
735 if (up_flag)
736 return;
737
738 if (vc_kbd_mode(kbd, VC_META)) {
739 put_queue('\033');
740 put_queue(value);
741 } else
742 put_queue(value | 0x80);
743 }
744
745 static void do_ascii(unsigned char value, char up_flag)
746 {
747 if (up_flag)
748 return;
749
750 if (npadch == -1)
751 npadch = value;
752 else
753 npadch = (npadch * 10 + value) % 1000;
754 }
755
756 static void do_lock(unsigned char value, char up_flag)
757 {
758 if (up_flag || rep)
759 return;
760 chg_vc_kbd_lock(kbd, value);
761 }
762
763
764
765
766
767
768 static int send_data(unsigned char data)
769 {
770 int retries = 3;
771 int i;
772
773 do {
774 kb_wait();
775 acknowledge = 0;
776 resend = 0;
777 outb_p(data, 0x60);
778 for(i=0; i<0x20000; i++) {
779 inb_p(0x64);
780 if (acknowledge)
781 return 1;
782 if (resend)
783 break;
784 }
785 if (!resend)
786 return 0;
787 } while (retries-- > 0);
788 return 0;
789 }
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804 static void kbd_bh(void * unused)
805 {
806 static unsigned char old_leds = 0xff;
807 unsigned char leds = kbd_table[fg_console].ledstate;
808
809 if (leds != old_leds) {
810 old_leds = leds;
811 if (!send_data(0xed) || !send_data(leds))
812 send_data(0xf4);
813 }
814 if (want_console >= 0) {
815 if (want_console != fg_console) {
816 last_console = fg_console;
817 change_console(want_console);
818 }
819 want_console = -1;
820 }
821 if (got_break) {
822 if (tty && !I_IGNBRK(tty)) {
823 if (I_BRKINT(tty)) {
824 flush_input(tty);
825 flush_output(tty);
826 if (tty->pgrp > 0)
827 kill_pg(tty->pgrp, SIGINT, 1);
828 } else {
829 cli();
830 if (LEFT(&tty->read_q) >= 2) {
831 set_bit(tty->read_q.head,
832 &tty->readq_flags);
833 put_queue(TTY_BREAK);
834 put_queue(0);
835 }
836 sti();
837 }
838 }
839 got_break = 0;
840 }
841 do_keyboard_interrupt();
842 cli();
843 if ((inb_p(0x64) & kbd_read_mask) == 0x01)
844 fake_keyboard_interrupt();
845 sti();
846 }
847
848 long no_idt[2] = {0, 0};
849
850
851
852
853
854
855 void hard_reset_now(void)
856 {
857 int i, j;
858 extern unsigned long pg0[1024];
859
860 sti();
861
862 pg0[0] = 7;
863 *((unsigned short *)0x472) = 0x1234;
864 for (;;) {
865 for (i=0; i<100; i++) {
866 kb_wait();
867 for(j = 0; j < 100000 ; j++)
868 ;
869 outb(0xfe,0x64);
870 }
871 __asm__("\tlidt _no_idt");
872 }
873 }
874
875 unsigned long kbd_init(unsigned long kmem_start)
876 {
877 int i;
878 struct kbd_struct * kbd;
879
880 kbd = kbd_table + 0;
881 for (i = 0 ; i < NR_CONSOLES ; i++,kbd++) {
882 kbd->ledstate = KBD_DEFLEDS;
883 kbd->default_ledstate = KBD_DEFLEDS;
884 kbd->lockstate = KBD_DEFLOCK;
885 kbd->modeflags = KBD_DEFMODE;
886 }
887
888 bh_base[KEYBOARD_BH].routine = kbd_bh;
889 request_irq(KEYBOARD_IRQ,keyboard_interrupt);
890 mark_bh(KEYBOARD_BH);
891 return kmem_start;
892 }