aboutsummaryrefslogtreecommitdiffstats
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 @@
1#include <linux/keyboard.h>
2
3#include "defkeymap.c" /* yeah I know it's bad -- Cort */
4
5
6unsigned char shfts, ctls, alts, caps;
7
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
13
14extern unsigned char inb(int port);
15extern void outb(int port, char val);
16extern void puts(const char *);
17extern void puthex(unsigned long val);
18extern void udelay(long x);
19
20static int kbd(int noblock)
21{
22 unsigned char dt, brk, val;
23 unsigned code;
24loop:
25 if (noblock) {
26 if ((inb(KBSTATP) & KBINRDY) == 0)
27 return (-1);
28 } else while((inb(KBSTATP) & KBINRDY) == 0) ;
29
30 dt = inb(KBDATAP);
31
32 brk = dt & 0x80; /* brk == 1 on key release */
33 dt = dt & 0x7f; /* keycode */
34
35 if (shfts)
36 code = shift_map[dt];
37 else if (ctls)
38 code = ctrl_map[dt];
39 else
40 code = plain_map[dt];
41
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;
52
53 case KT_LETTER:
54 if (brk)
55 break;
56 if (caps)
57 val -= 'a'-'A';
58 return val;
59
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)) {
66enter: /* Wait for key up */
67 while (1) {
68 while((inb(KBSTATP) & KBINRDY) == 0) ;
69 dt = inb(KBDATAP);
70 if (dt & 0x80) /* key up */ break;
71 }
72 return 10;
73 }
74 break;
75
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;
84
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;
101 }
102 break;
103
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;
123 }
124 break;
125 }
126 if (brk) return (-1); /* Ignore initial 'key up' codes */
127 goto loop;
128}
129
130static int __kbdreset(void)
131{
132 unsigned char c;
133 int i, t;
134
135 /* flush input queue */
136 t = 2000;
137 while ((inb(KBSTATP) & KBINRDY))
138 {
139 (void)inb(KBDATAP);
140 if (--t == 0)
141 return 1;
142 }
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)
154 {
155 puts("Keyboard self test failed - result:");
156 puthex(c);
157 puts("\n");
158 }
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);
169
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)) {
178 /*
179 * Quote from PS/2 System Reference Manual:
180 *
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)
185 */
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);
194 }
195 t = 20000;
196 while (inb(KBSTATP) & KBOUTRDY)
197 if (--t == 0) return 10;
198 outb(KBSTATP,0xAE);
199 return 0;
200}
201
202static void kbdreset(void)
203{
204 int ret = __kbdreset();
205
206 if (ret) {
207 puts("__kbdreset failed: ");
208 puthex(ret);
209 puts("\n");
210 }
211}
212
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.
218 */
219
220static int kbd_reset = 0;
221
222static int key_pending = -1;
223
224int CRT_getc(void)
225{
226 int c;
227 if (!kbd_reset) {kbdreset(); kbd_reset++; }
228
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;
236 }
237}
238
239int CRT_tstc(void)
240{
241 if (!kbd_reset) {kbdreset(); kbd_reset++; }
242
243 while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) {
244 key_pending = kbd(1);
245 }
246
247 return (key_pending != -1);
248}