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