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