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