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