summaryrefslogtreecommitdiff
path: root/arch/ppc/boot/lib/kbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/boot/lib/kbd.c')
-rw-r--r--arch/ppc/boot/lib/kbd.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/arch/ppc/boot/lib/kbd.c b/arch/ppc/boot/lib/kbd.c
new file mode 100644
index 000000000000..3931727434de
--- /dev/null
+++ b/arch/ppc/boot/lib/kbd.c
@@ -0,0 +1,248 @@
+#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);
+}