]>
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 <[email protected]> | |
8 | * Copyright (C) 2001, 2002, 2003, 2004 Maciej W. Rozycki | |
9 | */ | |
10 | ||
1da177e4 LT |
11 | |
12 | #include <linux/errno.h> | |
1da177e4 LT |
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 | "<[email protected]>\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 | } |