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