Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / arch / ppc / boot / lib / kbd.c
blob3931727434de1f64491684fcf08e2b1368a8ceec
1 #include <linux/keyboard.h>
3 #include "defkeymap.c" /* yeah I know it's bad -- Cort */
6 unsigned char shfts, ctls, alts, caps;
8 #define KBDATAP 0x60 /* kbd data port */
9 #define KBSTATUSPORT 0x61 /* kbd status */
10 #define KBSTATP 0x64 /* kbd status port */
11 #define KBINRDY 0x01
12 #define KBOUTRDY 0x02
14 extern unsigned char inb(int port);
15 extern void outb(int port, char val);
16 extern void puts(const char *);
17 extern void puthex(unsigned long val);
18 extern void udelay(long x);
20 static int kbd(int noblock)
22 unsigned char dt, brk, val;
23 unsigned code;
24 loop:
25 if (noblock) {
26 if ((inb(KBSTATP) & KBINRDY) == 0)
27 return (-1);
28 } else while((inb(KBSTATP) & KBINRDY) == 0) ;
30 dt = inb(KBDATAP);
32 brk = dt & 0x80; /* brk == 1 on key release */
33 dt = dt & 0x7f; /* keycode */
35 if (shfts)
36 code = shift_map[dt];
37 else if (ctls)
38 code = ctrl_map[dt];
39 else
40 code = plain_map[dt];
42 val = KVAL(code);
43 switch (KTYP(code) & 0x0f) {
44 case KT_LATIN:
45 if (brk)
46 break;
47 if (alts)
48 val |= 0x80;
49 if (val == 0x7f) /* map delete to backspace */
50 val = '\b';
51 return val;
53 case KT_LETTER:
54 if (brk)
55 break;
56 if (caps)
57 val -= 'a'-'A';
58 return val;
60 case KT_SPEC:
61 if (brk)
62 break;
63 if (val == KVAL(K_CAPS))
64 caps = !caps;
65 else if (val == KVAL(K_ENTER)) {
66 enter: /* Wait for key up */
67 while (1) {
68 while((inb(KBSTATP) & KBINRDY) == 0) ;
69 dt = inb(KBDATAP);
70 if (dt & 0x80) /* key up */ break;
72 return 10;
74 break;
76 case KT_PAD:
77 if (brk)
78 break;
79 if (val < 10)
80 return val;
81 if (val == KVAL(K_PENTER))
82 goto enter;
83 break;
85 case KT_SHIFT:
86 switch (val) {
87 case KG_SHIFT:
88 case KG_SHIFTL:
89 case KG_SHIFTR:
90 shfts = brk ? 0 : 1;
91 break;
92 case KG_ALT:
93 case KG_ALTGR:
94 alts = brk ? 0 : 1;
95 break;
96 case KG_CTRL:
97 case KG_CTRLL:
98 case KG_CTRLR:
99 ctls = brk ? 0 : 1;
100 break;
102 break;
104 case KT_LOCK:
105 switch (val) {
106 case KG_SHIFT:
107 case KG_SHIFTL:
108 case KG_SHIFTR:
109 if (brk)
110 shfts = !shfts;
111 break;
112 case KG_ALT:
113 case KG_ALTGR:
114 if (brk)
115 alts = !alts;
116 break;
117 case KG_CTRL:
118 case KG_CTRLL:
119 case KG_CTRLR:
120 if (brk)
121 ctls = !ctls;
122 break;
124 break;
126 if (brk) return (-1); /* Ignore initial 'key up' codes */
127 goto loop;
130 static int __kbdreset(void)
132 unsigned char c;
133 int i, t;
135 /* flush input queue */
136 t = 2000;
137 while ((inb(KBSTATP) & KBINRDY))
139 (void)inb(KBDATAP);
140 if (--t == 0)
141 return 1;
143 /* Send self-test */
144 t = 20000;
145 while (inb(KBSTATP) & KBOUTRDY)
146 if (--t == 0)
147 return 2;
148 outb(KBSTATP,0xAA);
149 t = 200000;
150 while ((inb(KBSTATP) & KBINRDY) == 0) /* wait input ready */
151 if (--t == 0)
152 return 3;
153 if ((c = inb(KBDATAP)) != 0x55)
155 puts("Keyboard self test failed - result:");
156 puthex(c);
157 puts("\n");
159 /* Enable interrupts and keyboard controller */
160 t = 20000;
161 while (inb(KBSTATP) & KBOUTRDY)
162 if (--t == 0) return 4;
163 outb(KBSTATP,0x60);
164 t = 20000;
165 while (inb(KBSTATP) & KBOUTRDY)
166 if (--t == 0) return 5;
167 outb(KBDATAP,0x45);
168 for (i = 0; i < 10000; i++) udelay(1);
170 t = 20000;
171 while (inb(KBSTATP) & KBOUTRDY)
172 if (--t == 0) return 6;
173 outb(KBSTATP,0x20);
174 t = 200000;
175 while ((inb(KBSTATP) & KBINRDY) == 0) /* wait input ready */
176 if (--t == 0) return 7;
177 if (! (inb(KBDATAP) & 0x40)) {
179 * Quote from PS/2 System Reference Manual:
181 * "Address hex 0060 and address hex 0064 should be
182 * written only when the input-buffer-full bit and
183 * output-buffer-full bit in the Controller Status
184 * register are set 0." (KBINRDY and KBOUTRDY)
186 t = 200000;
187 while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
188 if (--t == 0) return 8;
189 outb(KBDATAP,0xF0);
190 t = 200000;
191 while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
192 if (--t == 0) return 9;
193 outb(KBDATAP,0x01);
195 t = 20000;
196 while (inb(KBSTATP) & KBOUTRDY)
197 if (--t == 0) return 10;
198 outb(KBSTATP,0xAE);
199 return 0;
202 static void kbdreset(void)
204 int ret = __kbdreset();
206 if (ret) {
207 puts("__kbdreset failed: ");
208 puthex(ret);
209 puts("\n");
213 /* We have to actually read the keyboard when CRT_tstc is called,
214 * since the pending data might be a key release code, and therefore
215 * not valid data. In this case, kbd() will return -1, even though there's
216 * data to be read. Of course, we might actually read a valid key press,
217 * in which case it gets queued into key_pending for use by CRT_getc.
220 static int kbd_reset = 0;
222 static int key_pending = -1;
224 int CRT_getc(void)
226 int c;
227 if (!kbd_reset) {kbdreset(); kbd_reset++; }
229 if (key_pending != -1) {
230 c = key_pending;
231 key_pending = -1;
232 return c;
233 } else {
234 while ((c = kbd(0)) == 0) ;
235 return c;
239 int CRT_tstc(void)
241 if (!kbd_reset) {kbdreset(); kbd_reset++; }
243 while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) {
244 key_pending = kbd(1);
247 return (key_pending != -1);