| #include <linux/keyboard.h> | |
| #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); | |
| } |