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