diff options
Diffstat (limited to 'drivers/tc/lk201.c')
-rw-r--r-- | drivers/tc/lk201.c | 439 |
1 files changed, 0 insertions, 439 deletions
diff --git a/drivers/tc/lk201.c b/drivers/tc/lk201.c deleted file mode 100644 index a90c255f079d..000000000000 --- a/drivers/tc/lk201.c +++ /dev/null | |||
@@ -1,439 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * This file is subject to the terms and conditions of the GNU General Public | ||
4 | * License. See the file "COPYING" in the main directory of this archive | ||
5 | * for more details. | ||
6 | * | ||
7 | * Copyright (C) 1999-2002 Harald Koerfgen <hkoerfg@web.de> | ||
8 | * Copyright (C) 2001, 2002, 2003, 2004 Maciej W. Rozycki | ||
9 | */ | ||
10 | |||
11 | |||
12 | #include <linux/errno.h> | ||
13 | #include <linux/tty.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/kbd_ll.h> | ||
18 | #include <linux/kbd_kern.h> | ||
19 | #include <linux/vt_kern.h> | ||
20 | |||
21 | #include <asm/keyboard.h> | ||
22 | #include <asm/dec/tc.h> | ||
23 | #include <asm/dec/machtype.h> | ||
24 | #include <asm/dec/serial.h> | ||
25 | |||
26 | #include "lk201.h" | ||
27 | |||
28 | /* | ||
29 | * Only handle DECstations that have an LK201 interface. | ||
30 | * Maxine uses LK501 at the Access.Bus and various DECsystems | ||
31 | * have no keyboard interface at all. | ||
32 | */ | ||
33 | #define LK_IFACE (mips_machtype == MACH_DS23100 || \ | ||
34 | mips_machtype == MACH_DS5000_200 || \ | ||
35 | mips_machtype == MACH_DS5000_1XX || \ | ||
36 | mips_machtype == MACH_DS5000_2X0) | ||
37 | /* | ||
38 | * These use the Z8530 SCC. Others use the DZ11. | ||
39 | */ | ||
40 | #define LK_IFACE_ZS (mips_machtype == MACH_DS5000_1XX || \ | ||
41 | mips_machtype == MACH_DS5000_2X0) | ||
42 | |||
43 | /* Simple translation table for the SysRq keys */ | ||
44 | |||
45 | #ifdef CONFIG_MAGIC_SYSRQ | ||
46 | /* | ||
47 | * Actually no translation at all, at least until we figure out | ||
48 | * how to define SysRq for LK201 and friends. --macro | ||
49 | */ | ||
50 | unsigned char lk201_sysrq_xlate[128]; | ||
51 | unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate; | ||
52 | |||
53 | unsigned char kbd_sysrq_key = -1; | ||
54 | #endif | ||
55 | |||
56 | #define KEYB_LINE 3 | ||
57 | |||
58 | static int __init lk201_init(void *); | ||
59 | static void __init lk201_info(void *); | ||
60 | static void lk201_rx_char(unsigned char, unsigned char); | ||
61 | |||
62 | static struct dec_serial_hook lk201_hook = { | ||
63 | .init_channel = lk201_init, | ||
64 | .init_info = lk201_info, | ||
65 | .rx_char = NULL, | ||
66 | .poll_rx_char = NULL, | ||
67 | .poll_tx_char = NULL, | ||
68 | .cflags = B4800 | CS8 | CSTOPB | CLOCAL, | ||
69 | }; | ||
70 | |||
71 | /* | ||
72 | * This is used during keyboard initialisation | ||
73 | */ | ||
74 | static unsigned char lk201_reset_string[] = { | ||
75 | LK_CMD_SET_DEFAULTS, | ||
76 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 1), | ||
77 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 2), | ||
78 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 3), | ||
79 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 4), | ||
80 | LK_CMD_MODE(LK_MODE_DOWN_UP, 5), | ||
81 | LK_CMD_MODE(LK_MODE_DOWN_UP, 6), | ||
82 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 7), | ||
83 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 8), | ||
84 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 9), | ||
85 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 10), | ||
86 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 11), | ||
87 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 12), | ||
88 | LK_CMD_MODE(LK_MODE_DOWN, 13), | ||
89 | LK_CMD_MODE(LK_MODE_RPT_DOWN, 14), | ||
90 | LK_CMD_DIS_KEYCLK, | ||
91 | LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4), | ||
92 | }; | ||
93 | |||
94 | static void *lk201_handle; | ||
95 | |||
96 | static int lk201_send(unsigned char ch) | ||
97 | { | ||
98 | if (lk201_hook.poll_tx_char(lk201_handle, ch)) { | ||
99 | printk(KERN_ERR "lk201: transmit timeout\n"); | ||
100 | return -EIO; | ||
101 | } | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static inline int lk201_get_id(void) | ||
106 | { | ||
107 | return lk201_send(LK_CMD_REQ_ID); | ||
108 | } | ||
109 | |||
110 | static int lk201_reset(void) | ||
111 | { | ||
112 | int i, r; | ||
113 | |||
114 | for (i = 0; i < sizeof(lk201_reset_string); i++) { | ||
115 | r = lk201_send(lk201_reset_string[i]); | ||
116 | if (r < 0) | ||
117 | return r; | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static void lk201_report(unsigned char id[6]) | ||
123 | { | ||
124 | char *report = "lk201: keyboard attached, "; | ||
125 | |||
126 | switch (id[2]) { | ||
127 | case LK_STAT_PWRUP_OK: | ||
128 | printk(KERN_INFO "%sself-test OK\n", report); | ||
129 | break; | ||
130 | case LK_STAT_PWRUP_KDOWN: | ||
131 | /* The keyboard will resend the power-up ID | ||
132 | after all keys are released, so we don't | ||
133 | bother handling the error specially. Still | ||
134 | there may be a short-circuit inside. | ||
135 | */ | ||
136 | printk(KERN_ERR "%skey down (stuck?), code: 0x%02x\n", | ||
137 | report, id[3]); | ||
138 | break; | ||
139 | case LK_STAT_PWRUP_ERROR: | ||
140 | printk(KERN_ERR "%sself-test failure\n", report); | ||
141 | break; | ||
142 | default: | ||
143 | printk(KERN_ERR "%sunknown error: 0x%02x\n", | ||
144 | report, id[2]); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | static void lk201_id(unsigned char id[6]) | ||
149 | { | ||
150 | /* | ||
151 | * Report whether there is an LK201 or an LK401 | ||
152 | * The LK401 has ALT keys... | ||
153 | */ | ||
154 | switch (id[4]) { | ||
155 | case 1: | ||
156 | printk(KERN_INFO "lk201: LK201 detected\n"); | ||
157 | break; | ||
158 | case 2: | ||
159 | printk(KERN_INFO "lk201: LK401 detected\n"); | ||
160 | break; | ||
161 | case 3: | ||
162 | printk(KERN_INFO "lk201: LK443 detected\n"); | ||
163 | break; | ||
164 | case 4: | ||
165 | printk(KERN_INFO "lk201: LK421 detected\n"); | ||
166 | break; | ||
167 | default: | ||
168 | printk(KERN_WARNING | ||
169 | "lk201: unknown keyboard detected, ID %d\n", id[4]); | ||
170 | printk(KERN_WARNING "lk201: ... please report to " | ||
171 | "<linux-mips@linux-mips.org>\n"); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | #define DEFAULT_KEYB_REP_DELAY (250/5) /* [5ms] */ | ||
176 | #define DEFAULT_KEYB_REP_RATE 30 /* [cps] */ | ||
177 | |||
178 | static struct kbd_repeat kbdrate = { | ||
179 | DEFAULT_KEYB_REP_DELAY, | ||
180 | DEFAULT_KEYB_REP_RATE | ||
181 | }; | ||
182 | |||
183 | static void parse_kbd_rate(struct kbd_repeat *r) | ||
184 | { | ||
185 | if (r->delay <= 0) | ||
186 | r->delay = kbdrate.delay; | ||
187 | if (r->rate <= 0) | ||
188 | r->rate = kbdrate.rate; | ||
189 | |||
190 | if (r->delay < 5) | ||
191 | r->delay = 5; | ||
192 | if (r->delay > 630) | ||
193 | r->delay = 630; | ||
194 | if (r->rate < 12) | ||
195 | r->rate = 12; | ||
196 | if (r->rate > 127) | ||
197 | r->rate = 127; | ||
198 | if (r->rate == 125) | ||
199 | r->rate = 124; | ||
200 | } | ||
201 | |||
202 | static int write_kbd_rate(struct kbd_repeat *rep) | ||
203 | { | ||
204 | int delay, rate; | ||
205 | int i; | ||
206 | |||
207 | delay = rep->delay / 5; | ||
208 | rate = rep->rate; | ||
209 | for (i = 0; i < 4; i++) { | ||
210 | if (lk201_hook.poll_tx_char(lk201_handle, | ||
211 | LK_CMD_RPT_RATE(i))) | ||
212 | return 1; | ||
213 | if (lk201_hook.poll_tx_char(lk201_handle, | ||
214 | LK_PARAM_DELAY(delay))) | ||
215 | return 1; | ||
216 | if (lk201_hook.poll_tx_char(lk201_handle, | ||
217 | LK_PARAM_RATE(rate))) | ||
218 | return 1; | ||
219 | } | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static int lk201_kbd_rate(struct kbd_repeat *rep) | ||
224 | { | ||
225 | if (rep == NULL) | ||
226 | return -EINVAL; | ||
227 | |||
228 | parse_kbd_rate(rep); | ||
229 | |||
230 | if (write_kbd_rate(rep)) { | ||
231 | memcpy(rep, &kbdrate, sizeof(struct kbd_repeat)); | ||
232 | return -EIO; | ||
233 | } | ||
234 | |||
235 | memcpy(&kbdrate, rep, sizeof(struct kbd_repeat)); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static void lk201_kd_mksound(unsigned int hz, unsigned int ticks) | ||
241 | { | ||
242 | if (!ticks) | ||
243 | return; | ||
244 | |||
245 | /* | ||
246 | * Can't set frequency and we "approximate" | ||
247 | * duration by volume. ;-) | ||
248 | */ | ||
249 | ticks /= HZ / 32; | ||
250 | if (ticks > 7) | ||
251 | ticks = 7; | ||
252 | ticks = 7 - ticks; | ||
253 | |||
254 | if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_ENB_BELL)) | ||
255 | return; | ||
256 | if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_VOLUME(ticks))) | ||
257 | return; | ||
258 | if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_BELL)) | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | void kbd_leds(unsigned char leds) | ||
263 | { | ||
264 | unsigned char l = 0; | ||
265 | |||
266 | if (!lk201_handle) /* FIXME */ | ||
267 | return; | ||
268 | |||
269 | /* FIXME -- Only Hold and Lock LEDs for now. --macro */ | ||
270 | if (leds & LED_SCR) | ||
271 | l |= LK_LED_HOLD; | ||
272 | if (leds & LED_CAP) | ||
273 | l |= LK_LED_LOCK; | ||
274 | |||
275 | if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_ON)) | ||
276 | return; | ||
277 | if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(l))) | ||
278 | return; | ||
279 | if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_OFF)) | ||
280 | return; | ||
281 | if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(~l))) | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | int kbd_setkeycode(unsigned int scancode, unsigned int keycode) | ||
286 | { | ||
287 | return -EINVAL; | ||
288 | } | ||
289 | |||
290 | int kbd_getkeycode(unsigned int scancode) | ||
291 | { | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | |||
295 | int kbd_translate(unsigned char scancode, unsigned char *keycode, | ||
296 | char raw_mode) | ||
297 | { | ||
298 | *keycode = scancode; | ||
299 | return 1; | ||
300 | } | ||
301 | |||
302 | char kbd_unexpected_up(unsigned char keycode) | ||
303 | { | ||
304 | return 0x80; | ||
305 | } | ||
306 | |||
307 | static void lk201_rx_char(unsigned char ch, unsigned char fl) | ||
308 | { | ||
309 | static unsigned char id[6]; | ||
310 | static int id_i; | ||
311 | |||
312 | static int shift_state = 0; | ||
313 | static int prev_scancode; | ||
314 | unsigned char c = scancodeRemap[ch]; | ||
315 | |||
316 | if (fl != TTY_NORMAL && fl != TTY_OVERRUN) { | ||
317 | printk(KERN_ERR "lk201: keyboard receive error: 0x%02x\n", fl); | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | /* Assume this is a power-up ID. */ | ||
322 | if (ch == LK_STAT_PWRUP_ID && !id_i) { | ||
323 | id[id_i++] = ch; | ||
324 | return; | ||
325 | } | ||
326 | |||
327 | /* Handle the power-up sequence. */ | ||
328 | if (id_i) { | ||
329 | id[id_i++] = ch; | ||
330 | if (id_i == 4) { | ||
331 | /* OK, the power-up concluded. */ | ||
332 | lk201_report(id); | ||
333 | if (id[2] == LK_STAT_PWRUP_OK) | ||
334 | lk201_get_id(); | ||
335 | else { | ||
336 | id_i = 0; | ||
337 | printk(KERN_ERR "lk201: keyboard power-up " | ||
338 | "error, skipping initialization\n"); | ||
339 | } | ||
340 | } else if (id_i == 6) { | ||
341 | /* We got the ID; report it and start operation. */ | ||
342 | id_i = 0; | ||
343 | lk201_id(id); | ||
344 | lk201_reset(); | ||
345 | } | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | /* Everything else is a scancode/status response. */ | ||
350 | id_i = 0; | ||
351 | switch (ch) { | ||
352 | case LK_STAT_RESUME_ERR: | ||
353 | case LK_STAT_ERROR: | ||
354 | case LK_STAT_INHIBIT_ACK: | ||
355 | case LK_STAT_TEST_ACK: | ||
356 | case LK_STAT_MODE_KEYDOWN: | ||
357 | case LK_STAT_MODE_ACK: | ||
358 | break; | ||
359 | case LK_KEY_LOCK: | ||
360 | shift_state ^= LK_LOCK; | ||
361 | handle_scancode(c, (shift_state & LK_LOCK) ? 1 : 0); | ||
362 | break; | ||
363 | case LK_KEY_SHIFT: | ||
364 | shift_state ^= LK_SHIFT; | ||
365 | handle_scancode(c, (shift_state & LK_SHIFT) ? 1 : 0); | ||
366 | break; | ||
367 | case LK_KEY_CTRL: | ||
368 | shift_state ^= LK_CTRL; | ||
369 | handle_scancode(c, (shift_state & LK_CTRL) ? 1 : 0); | ||
370 | break; | ||
371 | case LK_KEY_COMP: | ||
372 | shift_state ^= LK_COMP; | ||
373 | handle_scancode(c, (shift_state & LK_COMP) ? 1 : 0); | ||
374 | break; | ||
375 | case LK_KEY_RELEASE: | ||
376 | if (shift_state & LK_SHIFT) | ||
377 | handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0); | ||
378 | if (shift_state & LK_CTRL) | ||
379 | handle_scancode(scancodeRemap[LK_KEY_CTRL], 0); | ||
380 | if (shift_state & LK_COMP) | ||
381 | handle_scancode(scancodeRemap[LK_KEY_COMP], 0); | ||
382 | if (shift_state & LK_LOCK) | ||
383 | handle_scancode(scancodeRemap[LK_KEY_LOCK], 0); | ||
384 | shift_state = 0; | ||
385 | break; | ||
386 | case LK_KEY_REPEAT: | ||
387 | handle_scancode(prev_scancode, 1); | ||
388 | break; | ||
389 | default: | ||
390 | prev_scancode = c; | ||
391 | handle_scancode(c, 1); | ||
392 | break; | ||
393 | } | ||
394 | tasklet_schedule(&keyboard_tasklet); | ||
395 | } | ||
396 | |||
397 | static void __init lk201_info(void *handle) | ||
398 | { | ||
399 | } | ||
400 | |||
401 | static int __init lk201_init(void *handle) | ||
402 | { | ||
403 | /* First install handlers. */ | ||
404 | lk201_handle = handle; | ||
405 | kbd_rate = lk201_kbd_rate; | ||
406 | kd_mksound = lk201_kd_mksound; | ||
407 | |||
408 | lk201_hook.rx_char = lk201_rx_char; | ||
409 | |||
410 | /* Then just issue a reset -- the handlers will do the rest. */ | ||
411 | lk201_send(LK_CMD_POWER_UP); | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | void __init kbd_init_hw(void) | ||
417 | { | ||
418 | /* Maxine uses LK501 at the Access.Bus. */ | ||
419 | if (!LK_IFACE) | ||
420 | return; | ||
421 | |||
422 | printk(KERN_INFO "lk201: DECstation LK keyboard driver v0.05.\n"); | ||
423 | |||
424 | if (LK_IFACE_ZS) { | ||
425 | /* | ||
426 | * kbd_init_hw() is being called before | ||
427 | * rs_init() so just register the kbd hook | ||
428 | * and let zs_init do the rest :-) | ||
429 | */ | ||
430 | if (!register_dec_serial_hook(KEYB_LINE, &lk201_hook)) | ||
431 | unregister_dec_serial_hook(KEYB_LINE); | ||
432 | } else { | ||
433 | /* | ||
434 | * TODO: modify dz.c to allow similar hooks | ||
435 | * for LK201 handling on DS2100, DS3100, and DS5000/200 | ||
436 | */ | ||
437 | printk(KERN_ERR "lk201: support for DZ11 not yet ready.\n"); | ||
438 | } | ||
439 | } | ||