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