#include #include "defkeymap.c" /* yeah I know it's bad -- Cort */ unsigned char shfts, ctls, alts, caps; #define KBDATAP 0x60 /* kbd data port */ #define KBSTATUSPORT 0x61 /* kbd status */ #define KBSTATP 0x64 /* kbd status port */ #define KBINRDY 0x01 #define KBOUTRDY 0x02 extern unsigned char inb(int port); extern void outb(int port, char val); extern void puts(const char *); extern void puthex(unsigned long val); extern void udelay(long x); static int kbd(int noblock) { unsigned char dt, brk, val; unsigned code; loop: if (noblock) { if ((inb(KBSTATP) & KBINRDY) == 0) return (-1); } else while((inb(KBSTATP) & KBINRDY) == 0) ; dt = inb(KBDATAP); brk = dt & 0x80; /* brk == 1 on key release */ dt = dt & 0x7f; /* keycode */ if (shfts) code = shift_map[dt]; else if (ctls) code = ctrl_map[dt]; else code = plain_map[dt]; val = KVAL(code); switch (KTYP(code) & 0x0f) { case KT_LATIN: if (brk) break; if (alts) val |= 0x80; if (val == 0x7f) /* map delete to backspace */ val = '\b'; return val; case KT_LETTER: if (brk) break; if (caps) val -= 'a'-'A'; return val; case KT_SPEC: if (brk) break; if (val == KVAL(K_CAPS)) caps = !caps; else if (val == KVAL(K_ENTER)) { enter: /* Wait for key up */ while (1) { while((inb(KBSTATP) & KBINRDY) == 0) ; dt = inb(KBDATAP); if (dt & 0x80) /* key up */ break; } return 10; } break; case KT_PAD: if (brk) break; if (val < 10) return val; if (val == KVAL(K_PENTER)) goto enter; break; case KT_SHIFT: switch (val) { case KG_SHIFT: case KG_SHIFTL: case KG_SHIFTR: shfts = brk ? 0 : 1; break; case KG_ALT: case KG_ALTGR: alts = brk ? 0 : 1; break; case KG_CTRL: case KG_CTRLL: case KG_CTRLR: ctls = brk ? 0 : 1; break; } break; case KT_LOCK: switch (val) { case KG_SHIFT: case KG_SHIFTL: case KG_SHIFTR: if (brk) shfts = !shfts; break; case KG_ALT: case KG_ALTGR: if (brk) alts = !alts; break; case KG_CTRL: case KG_CTRLL: case KG_CTRLR: if (brk) ctls = !ctls; break; } break; } if (brk) return (-1); /* Ignore initial 'key up' codes */ goto loop; } static int __kbdreset(void) { unsigned char c; int i, t; /* flush input queue */ t = 2000; while ((inb(KBSTATP) & KBINRDY)) { (void)inb(KBDATAP); if (--t == 0) return 1; } /* Send self-test */ t = 20000; while (inb(KBSTATP) & KBOUTRDY) if (--t == 0) return 2; outb(KBSTATP,0xAA); t = 200000; while ((inb(KBSTATP) & KBINRDY) == 0) /* wait input ready */ if (--t == 0) return 3; if ((c = inb(KBDATAP)) != 0x55) { puts("Keyboard self test failed - result:"); puthex(c); puts("\n"); } /* Enable interrupts and keyboard controller */ t = 20000; while (inb(KBSTATP) & KBOUTRDY) if (--t == 0) return 4; outb(KBSTATP,0x60); t = 20000; while (inb(KBSTATP) & KBOUTRDY) if (--t == 0) return 5; outb(KBDATAP,0x45); for (i = 0; i < 10000; i++) udelay(1); t = 20000; while (inb(KBSTATP) & KBOUTRDY) if (--t == 0) return 6; outb(KBSTATP,0x20); t = 200000; while ((inb(KBSTATP) & KBINRDY) == 0) /* wait input ready */ if (--t == 0) return 7; if (! (inb(KBDATAP) & 0x40)) { /* * Quote from PS/2 System Reference Manual: * * "Address hex 0060 and address hex 0064 should be * written only when the input-buffer-full bit and * output-buffer-full bit in the Controller Status * register are set 0." (KBINRDY and KBOUTRDY) */ t = 200000; while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) if (--t == 0) return 8; outb(KBDATAP,0xF0); t = 200000; while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) if (--t == 0) return 9; outb(KBDATAP,0x01); } t = 20000; while (inb(KBSTATP) & KBOUTRDY) if (--t == 0) return 10; outb(KBSTATP,0xAE); return 0; } static void kbdreset(void) { int ret = __kbdreset(); if (ret) { puts("__kbdreset failed: "); puthex(ret); puts("\n"); } } /* We have to actually read the keyboard when CRT_tstc is called, * since the pending data might be a key release code, and therefore * not valid data. In this case, kbd() will return -1, even though there's * data to be read. Of course, we might actually read a valid key press, * in which case it gets queued into key_pending for use by CRT_getc. */ static int kbd_reset = 0; static int key_pending = -1; int CRT_getc(void) { int c; if (!kbd_reset) {kbdreset(); kbd_reset++; } if (key_pending != -1) { c = key_pending; key_pending = -1; return c; } else { while ((c = kbd(0)) == 0) ; return c; } } int CRT_tstc(void) { if (!kbd_reset) {kbdreset(); kbd_reset++; } while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) { key_pending = kbd(1); } return (key_pending != -1); }