diff options
Diffstat (limited to 'arch/ppc/boot/lib/kbd.c')
-rw-r--r-- | arch/ppc/boot/lib/kbd.c | 248 |
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 | |||
6 | unsigned 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 | |||
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); | ||
19 | |||
20 | static int kbd(int noblock) | ||
21 | { | ||
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) ; | ||
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)) { | ||
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; | ||
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 | |||
130 | static 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 | |||
202 | static 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 | |||
220 | static int kbd_reset = 0; | ||
221 | |||
222 | static int key_pending = -1; | ||
223 | |||
224 | int 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 | |||
239 | int 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 | } | ||