diff options
Diffstat (limited to 'arch/m68k/atari')
-rw-r--r-- | arch/m68k/atari/Makefile | 1 | ||||
-rw-r--r-- | arch/m68k/atari/atakeyb.c | 730 |
2 files changed, 731 insertions, 0 deletions
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile index 8cb6236b39db..2cb86191f0aa 100644 --- a/arch/m68k/atari/Makefile +++ b/arch/m68k/atari/Makefile | |||
@@ -8,3 +8,4 @@ obj-y := config.o time.o debug.o ataints.o stdma.o \ | |||
8 | ifeq ($(CONFIG_PCI),y) | 8 | ifeq ($(CONFIG_PCI),y) |
9 | obj-$(CONFIG_HADES) += hades-pci.o | 9 | obj-$(CONFIG_HADES) += hades-pci.o |
10 | endif | 10 | endif |
11 | obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o | ||
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c new file mode 100644 index 000000000000..1c29603b16b3 --- /dev/null +++ b/arch/m68k/atari/atakeyb.c | |||
@@ -0,0 +1,730 @@ | |||
1 | /* | ||
2 | * linux/atari/atakeyb.c | ||
3 | * | ||
4 | * Atari Keyboard driver for 680x0 Linux | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * Atari support by Robert de Vries | ||
13 | * enhanced by Bjoern Brauel and Roman Hodek | ||
14 | */ | ||
15 | |||
16 | #include <linux/sched.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/keyboard.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/kd.h> | ||
24 | #include <linux/random.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/kbd_kern.h> | ||
27 | |||
28 | #include <asm/atariints.h> | ||
29 | #include <asm/atarihw.h> | ||
30 | #include <asm/atarikb.h> | ||
31 | #include <asm/atari_joystick.h> | ||
32 | #include <asm/irq.h> | ||
33 | |||
34 | static void atakeyb_rep(unsigned long ignore); | ||
35 | extern unsigned int keymap_count; | ||
36 | |||
37 | /* Hook for MIDI serial driver */ | ||
38 | void (*atari_MIDI_interrupt_hook) (void); | ||
39 | /* Hook for mouse driver */ | ||
40 | void (*atari_mouse_interrupt_hook) (char *); | ||
41 | /* Hook for keyboard inputdev driver */ | ||
42 | void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); | ||
43 | /* Hook for mouse inputdev driver */ | ||
44 | void (*atari_input_mouse_interrupt_hook) (char *); | ||
45 | |||
46 | /* variables for IKBD self test: */ | ||
47 | |||
48 | /* state: 0: off; >0: in progress; >1: 0xf1 received */ | ||
49 | static volatile int ikbd_self_test; | ||
50 | /* timestamp when last received a char */ | ||
51 | static volatile unsigned long self_test_last_rcv; | ||
52 | /* bitmap of keys reported as broken */ | ||
53 | static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, }; | ||
54 | |||
55 | #define BREAK_MASK (0x80) | ||
56 | |||
57 | /* | ||
58 | * ++roman: The following changes were applied manually: | ||
59 | * | ||
60 | * - The Alt (= Meta) key works in combination with Shift and | ||
61 | * Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends | ||
62 | * Meta-Ctrl-A (0x81) ... | ||
63 | * | ||
64 | * - The parentheses on the keypad send '(' and ')' with all | ||
65 | * modifiers (as would do e.g. keypad '+'), but they cannot be used as | ||
66 | * application keys (i.e. sending Esc O c). | ||
67 | * | ||
68 | * - HELP and UNDO are mapped to be F21 and F24, resp, that send the | ||
69 | * codes "\E[M" and "\E[P". (This is better than the old mapping to | ||
70 | * F11 and F12, because these codes are on Shift+F1/2 anyway.) This | ||
71 | * way, applications that allow their own keyboard mappings | ||
72 | * (e.g. tcsh, X Windows) can be configured to use them in the way | ||
73 | * the label suggests (providing help or undoing). | ||
74 | * | ||
75 | * - Console switching is done with Alt+Fx (consoles 1..10) and | ||
76 | * Shift+Alt+Fx (consoles 11..20). | ||
77 | * | ||
78 | * - The misc. special function implemented in the kernel are mapped | ||
79 | * to the following key combinations: | ||
80 | * | ||
81 | * ClrHome -> Home/Find | ||
82 | * Shift + ClrHome -> End/Select | ||
83 | * Shift + Up -> Page Up | ||
84 | * Shift + Down -> Page Down | ||
85 | * Alt + Help -> show system status | ||
86 | * Shift + Help -> show memory info | ||
87 | * Ctrl + Help -> show registers | ||
88 | * Ctrl + Alt + Del -> Reboot | ||
89 | * Alt + Undo -> switch to last console | ||
90 | * Shift + Undo -> send interrupt | ||
91 | * Alt + Insert -> stop/start output (same as ^S/^Q) | ||
92 | * Alt + Up -> Scroll back console (if implemented) | ||
93 | * Alt + Down -> Scroll forward console (if implemented) | ||
94 | * Alt + CapsLock -> NumLock | ||
95 | * | ||
96 | * ++Andreas: | ||
97 | * | ||
98 | * - Help mapped to K_HELP | ||
99 | * - Undo mapped to K_UNDO (= K_F246) | ||
100 | * - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR] | ||
101 | */ | ||
102 | |||
103 | static u_short ataplain_map[NR_KEYS] __initdata = { | ||
104 | 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, | ||
105 | 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009, | ||
106 | 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, | ||
107 | 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, | ||
108 | 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, | ||
109 | 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, | ||
110 | 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200, | ||
111 | 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, | ||
112 | 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, | ||
113 | 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, | ||
114 | 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, | ||
115 | 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, | ||
116 | 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, | ||
117 | 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, | ||
118 | 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, | ||
119 | 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 | ||
120 | }; | ||
121 | |||
122 | typedef enum kb_state_t { | ||
123 | KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC | ||
124 | } KB_STATE_T; | ||
125 | |||
126 | #define IS_SYNC_CODE(sc) ((sc) >= 0x04 && (sc) <= 0xfb) | ||
127 | |||
128 | typedef struct keyboard_state { | ||
129 | unsigned char buf[6]; | ||
130 | int len; | ||
131 | KB_STATE_T state; | ||
132 | } KEYBOARD_STATE; | ||
133 | |||
134 | KEYBOARD_STATE kb_state; | ||
135 | |||
136 | #define DEFAULT_KEYB_REP_DELAY (HZ/4) | ||
137 | #define DEFAULT_KEYB_REP_RATE (HZ/25) | ||
138 | |||
139 | /* These could be settable by some ioctl() in future... */ | ||
140 | static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY; | ||
141 | static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE; | ||
142 | |||
143 | static unsigned char rep_scancode; | ||
144 | static struct timer_list atakeyb_rep_timer = { | ||
145 | .function = atakeyb_rep, | ||
146 | }; | ||
147 | |||
148 | static void atakeyb_rep(unsigned long ignore) | ||
149 | { | ||
150 | /* Disable keyboard for the time we call handle_scancode(), else a race | ||
151 | * in the keyboard tty queue may happen */ | ||
152 | atari_disable_irq(IRQ_MFP_ACIA); | ||
153 | del_timer(&atakeyb_rep_timer); | ||
154 | |||
155 | /* A keyboard int may have come in before we disabled the irq, so | ||
156 | * double-check whether rep_scancode is still != 0 */ | ||
157 | if (rep_scancode) { | ||
158 | init_timer(&atakeyb_rep_timer); | ||
159 | atakeyb_rep_timer.expires = jiffies + key_repeat_rate; | ||
160 | add_timer(&atakeyb_rep_timer); | ||
161 | |||
162 | //handle_scancode(rep_scancode, 1); | ||
163 | if (atari_input_keyboard_interrupt_hook) | ||
164 | atari_input_keyboard_interrupt_hook(rep_scancode, 1); | ||
165 | } | ||
166 | |||
167 | atari_enable_irq(IRQ_MFP_ACIA); | ||
168 | } | ||
169 | |||
170 | |||
171 | /* ++roman: If a keyboard overrun happened, we can't tell in general how much | ||
172 | * bytes have been lost and in which state of the packet structure we are now. | ||
173 | * This usually causes keyboards bytes to be interpreted as mouse movements | ||
174 | * and vice versa, which is very annoying. It seems better to throw away some | ||
175 | * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I | ||
176 | * introduced the RESYNC state for IKBD data. In this state, the bytes up to | ||
177 | * one that really looks like a key event (0x04..0xf2) or the start of a mouse | ||
178 | * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least | ||
179 | * speeds up the resynchronization of the event structure, even if maybe a | ||
180 | * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03, | ||
181 | * it's really hard to decide whether they're mouse or keyboard bytes. Since | ||
182 | * overruns usually occur when moving the Atari mouse rapidly, they're seen as | ||
183 | * mouse bytes here. If this is wrong, only a make code of the keyboard gets | ||
184 | * lost, which isn't too bad. Loosing a break code would be disastrous, | ||
185 | * because then the keyboard repeat strikes... | ||
186 | */ | ||
187 | |||
188 | static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy) | ||
189 | { | ||
190 | u_char acia_stat; | ||
191 | int scancode; | ||
192 | int break_flag; | ||
193 | |||
194 | repeat: | ||
195 | if (acia.mid_ctrl & ACIA_IRQ) | ||
196 | if (atari_MIDI_interrupt_hook) | ||
197 | atari_MIDI_interrupt_hook(); | ||
198 | acia_stat = acia.key_ctrl; | ||
199 | /* check out if the interrupt came from this ACIA */ | ||
200 | if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ)) | ||
201 | return IRQ_HANDLED; | ||
202 | |||
203 | if (acia_stat & ACIA_OVRN) { | ||
204 | /* a very fast typist or a slow system, give a warning */ | ||
205 | /* ...happens often if interrupts were disabled for too long */ | ||
206 | printk(KERN_DEBUG "Keyboard overrun\n"); | ||
207 | scancode = acia.key_data; | ||
208 | /* Turn off autorepeating in case a break code has been lost */ | ||
209 | del_timer(&atakeyb_rep_timer); | ||
210 | rep_scancode = 0; | ||
211 | if (ikbd_self_test) | ||
212 | /* During self test, don't do resyncing, just process the code */ | ||
213 | goto interpret_scancode; | ||
214 | else if (IS_SYNC_CODE(scancode)) { | ||
215 | /* This code seem already to be the start of a new packet or a | ||
216 | * single scancode */ | ||
217 | kb_state.state = KEYBOARD; | ||
218 | goto interpret_scancode; | ||
219 | } else { | ||
220 | /* Go to RESYNC state and skip this byte */ | ||
221 | kb_state.state = RESYNC; | ||
222 | kb_state.len = 1; /* skip max. 1 another byte */ | ||
223 | goto repeat; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | if (acia_stat & ACIA_RDRF) { | ||
228 | /* received a character */ | ||
229 | scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ | ||
230 | tasklet_schedule(&keyboard_tasklet); | ||
231 | interpret_scancode: | ||
232 | switch (kb_state.state) { | ||
233 | case KEYBOARD: | ||
234 | switch (scancode) { | ||
235 | case 0xF7: | ||
236 | kb_state.state = AMOUSE; | ||
237 | kb_state.len = 0; | ||
238 | break; | ||
239 | |||
240 | case 0xF8: | ||
241 | case 0xF9: | ||
242 | case 0xFA: | ||
243 | case 0xFB: | ||
244 | kb_state.state = RMOUSE; | ||
245 | kb_state.len = 1; | ||
246 | kb_state.buf[0] = scancode; | ||
247 | break; | ||
248 | |||
249 | case 0xFC: | ||
250 | kb_state.state = CLOCK; | ||
251 | kb_state.len = 0; | ||
252 | break; | ||
253 | |||
254 | case 0xFE: | ||
255 | case 0xFF: | ||
256 | kb_state.state = JOYSTICK; | ||
257 | kb_state.len = 1; | ||
258 | kb_state.buf[0] = scancode; | ||
259 | break; | ||
260 | |||
261 | case 0xF1: | ||
262 | /* during self-test, note that 0xf1 received */ | ||
263 | if (ikbd_self_test) { | ||
264 | ++ikbd_self_test; | ||
265 | self_test_last_rcv = jiffies; | ||
266 | break; | ||
267 | } | ||
268 | /* FALL THROUGH */ | ||
269 | |||
270 | default: | ||
271 | break_flag = scancode & BREAK_MASK; | ||
272 | scancode &= ~BREAK_MASK; | ||
273 | if (ikbd_self_test) { | ||
274 | /* Scancodes sent during the self-test stand for broken | ||
275 | * keys (keys being down). The code *should* be a break | ||
276 | * code, but nevertheless some AT keyboard interfaces send | ||
277 | * make codes instead. Therefore, simply ignore | ||
278 | * break_flag... | ||
279 | */ | ||
280 | int keyval = plain_map[scancode], keytyp; | ||
281 | |||
282 | set_bit(scancode, broken_keys); | ||
283 | self_test_last_rcv = jiffies; | ||
284 | keyval = plain_map[scancode]; | ||
285 | keytyp = KTYP(keyval) - 0xf0; | ||
286 | keyval = KVAL(keyval); | ||
287 | |||
288 | printk(KERN_WARNING "Key with scancode %d ", scancode); | ||
289 | if (keytyp == KT_LATIN || keytyp == KT_LETTER) { | ||
290 | if (keyval < ' ') | ||
291 | printk("('^%c') ", keyval + '@'); | ||
292 | else | ||
293 | printk("('%c') ", keyval); | ||
294 | } | ||
295 | printk("is broken -- will be ignored.\n"); | ||
296 | break; | ||
297 | } else if (test_bit(scancode, broken_keys)) | ||
298 | break; | ||
299 | |||
300 | #if 0 // FIXME; hangs at boot | ||
301 | if (break_flag) { | ||
302 | del_timer(&atakeyb_rep_timer); | ||
303 | rep_scancode = 0; | ||
304 | } else { | ||
305 | del_timer(&atakeyb_rep_timer); | ||
306 | rep_scancode = scancode; | ||
307 | atakeyb_rep_timer.expires = jiffies + key_repeat_delay; | ||
308 | add_timer(&atakeyb_rep_timer); | ||
309 | } | ||
310 | #endif | ||
311 | |||
312 | // handle_scancode(scancode, !break_flag); | ||
313 | if (atari_input_keyboard_interrupt_hook) | ||
314 | atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag); | ||
315 | break; | ||
316 | } | ||
317 | break; | ||
318 | |||
319 | case AMOUSE: | ||
320 | kb_state.buf[kb_state.len++] = scancode; | ||
321 | if (kb_state.len == 5) { | ||
322 | kb_state.state = KEYBOARD; | ||
323 | /* not yet used */ | ||
324 | /* wake up someone waiting for this */ | ||
325 | } | ||
326 | break; | ||
327 | |||
328 | case RMOUSE: | ||
329 | kb_state.buf[kb_state.len++] = scancode; | ||
330 | if (kb_state.len == 3) { | ||
331 | kb_state.state = KEYBOARD; | ||
332 | if (atari_mouse_interrupt_hook) | ||
333 | atari_mouse_interrupt_hook(kb_state.buf); | ||
334 | } | ||
335 | break; | ||
336 | |||
337 | case JOYSTICK: | ||
338 | kb_state.buf[1] = scancode; | ||
339 | kb_state.state = KEYBOARD; | ||
340 | #ifdef FIXED_ATARI_JOYSTICK | ||
341 | atari_joystick_interrupt(kb_state.buf); | ||
342 | #endif | ||
343 | break; | ||
344 | |||
345 | case CLOCK: | ||
346 | kb_state.buf[kb_state.len++] = scancode; | ||
347 | if (kb_state.len == 6) { | ||
348 | kb_state.state = KEYBOARD; | ||
349 | /* wake up someone waiting for this. | ||
350 | But will this ever be used, as Linux keeps its own time. | ||
351 | Perhaps for synchronization purposes? */ | ||
352 | /* wake_up_interruptible(&clock_wait); */ | ||
353 | } | ||
354 | break; | ||
355 | |||
356 | case RESYNC: | ||
357 | if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) { | ||
358 | kb_state.state = KEYBOARD; | ||
359 | goto interpret_scancode; | ||
360 | } | ||
361 | kb_state.len--; | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | #if 0 | ||
367 | if (acia_stat & ACIA_CTS) | ||
368 | /* cannot happen */; | ||
369 | #endif | ||
370 | |||
371 | if (acia_stat & (ACIA_FE | ACIA_PE)) { | ||
372 | printk("Error in keyboard communication\n"); | ||
373 | } | ||
374 | |||
375 | /* handle_scancode() can take a lot of time, so check again if | ||
376 | * some character arrived | ||
377 | */ | ||
378 | goto repeat; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * I write to the keyboard without using interrupts, I poll instead. | ||
383 | * This takes for the maximum length string allowed (7) at 7812.5 baud | ||
384 | * 8 data 1 start 1 stop bit: 9.0 ms | ||
385 | * If this takes too long for normal operation, interrupt driven writing | ||
386 | * is the solution. (I made a feeble attempt in that direction but I | ||
387 | * kept it simple for now.) | ||
388 | */ | ||
389 | void ikbd_write(const char *str, int len) | ||
390 | { | ||
391 | u_char acia_stat; | ||
392 | |||
393 | if ((len < 1) || (len > 7)) | ||
394 | panic("ikbd: maximum string length exceeded"); | ||
395 | while (len) { | ||
396 | acia_stat = acia.key_ctrl; | ||
397 | if (acia_stat & ACIA_TDRE) { | ||
398 | acia.key_data = *str++; | ||
399 | len--; | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | |||
404 | /* Reset (without touching the clock) */ | ||
405 | void ikbd_reset(void) | ||
406 | { | ||
407 | static const char cmd[2] = { 0x80, 0x01 }; | ||
408 | |||
409 | ikbd_write(cmd, 2); | ||
410 | |||
411 | /* | ||
412 | * if all's well code 0xF1 is returned, else the break codes of | ||
413 | * all keys making contact | ||
414 | */ | ||
415 | } | ||
416 | |||
417 | /* Set mouse button action */ | ||
418 | void ikbd_mouse_button_action(int mode) | ||
419 | { | ||
420 | char cmd[2] = { 0x07, mode }; | ||
421 | |||
422 | ikbd_write(cmd, 2); | ||
423 | } | ||
424 | |||
425 | /* Set relative mouse position reporting */ | ||
426 | void ikbd_mouse_rel_pos(void) | ||
427 | { | ||
428 | static const char cmd[1] = { 0x08 }; | ||
429 | |||
430 | ikbd_write(cmd, 1); | ||
431 | } | ||
432 | |||
433 | /* Set absolute mouse position reporting */ | ||
434 | void ikbd_mouse_abs_pos(int xmax, int ymax) | ||
435 | { | ||
436 | char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF }; | ||
437 | |||
438 | ikbd_write(cmd, 5); | ||
439 | } | ||
440 | |||
441 | /* Set mouse keycode mode */ | ||
442 | void ikbd_mouse_kbd_mode(int dx, int dy) | ||
443 | { | ||
444 | char cmd[3] = { 0x0A, dx, dy }; | ||
445 | |||
446 | ikbd_write(cmd, 3); | ||
447 | } | ||
448 | |||
449 | /* Set mouse threshold */ | ||
450 | void ikbd_mouse_thresh(int x, int y) | ||
451 | { | ||
452 | char cmd[3] = { 0x0B, x, y }; | ||
453 | |||
454 | ikbd_write(cmd, 3); | ||
455 | } | ||
456 | |||
457 | /* Set mouse scale */ | ||
458 | void ikbd_mouse_scale(int x, int y) | ||
459 | { | ||
460 | char cmd[3] = { 0x0C, x, y }; | ||
461 | |||
462 | ikbd_write(cmd, 3); | ||
463 | } | ||
464 | |||
465 | /* Interrogate mouse position */ | ||
466 | void ikbd_mouse_pos_get(int *x, int *y) | ||
467 | { | ||
468 | static const char cmd[1] = { 0x0D }; | ||
469 | |||
470 | ikbd_write(cmd, 1); | ||
471 | |||
472 | /* wait for returning bytes */ | ||
473 | } | ||
474 | |||
475 | /* Load mouse position */ | ||
476 | void ikbd_mouse_pos_set(int x, int y) | ||
477 | { | ||
478 | char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF }; | ||
479 | |||
480 | ikbd_write(cmd, 6); | ||
481 | } | ||
482 | |||
483 | /* Set Y=0 at bottom */ | ||
484 | void ikbd_mouse_y0_bot(void) | ||
485 | { | ||
486 | static const char cmd[1] = { 0x0F }; | ||
487 | |||
488 | ikbd_write(cmd, 1); | ||
489 | } | ||
490 | |||
491 | /* Set Y=0 at top */ | ||
492 | void ikbd_mouse_y0_top(void) | ||
493 | { | ||
494 | static const char cmd[1] = { 0x10 }; | ||
495 | |||
496 | ikbd_write(cmd, 1); | ||
497 | } | ||
498 | |||
499 | /* Resume */ | ||
500 | void ikbd_resume(void) | ||
501 | { | ||
502 | static const char cmd[1] = { 0x11 }; | ||
503 | |||
504 | ikbd_write(cmd, 1); | ||
505 | } | ||
506 | |||
507 | /* Disable mouse */ | ||
508 | void ikbd_mouse_disable(void) | ||
509 | { | ||
510 | static const char cmd[1] = { 0x12 }; | ||
511 | |||
512 | ikbd_write(cmd, 1); | ||
513 | } | ||
514 | |||
515 | /* Pause output */ | ||
516 | void ikbd_pause(void) | ||
517 | { | ||
518 | static const char cmd[1] = { 0x13 }; | ||
519 | |||
520 | ikbd_write(cmd, 1); | ||
521 | } | ||
522 | |||
523 | /* Set joystick event reporting */ | ||
524 | void ikbd_joystick_event_on(void) | ||
525 | { | ||
526 | static const char cmd[1] = { 0x14 }; | ||
527 | |||
528 | ikbd_write(cmd, 1); | ||
529 | } | ||
530 | |||
531 | /* Set joystick interrogation mode */ | ||
532 | void ikbd_joystick_event_off(void) | ||
533 | { | ||
534 | static const char cmd[1] = { 0x15 }; | ||
535 | |||
536 | ikbd_write(cmd, 1); | ||
537 | } | ||
538 | |||
539 | /* Joystick interrogation */ | ||
540 | void ikbd_joystick_get_state(void) | ||
541 | { | ||
542 | static const char cmd[1] = { 0x16 }; | ||
543 | |||
544 | ikbd_write(cmd, 1); | ||
545 | } | ||
546 | |||
547 | #if 0 | ||
548 | /* This disables all other ikbd activities !!!! */ | ||
549 | /* Set joystick monitoring */ | ||
550 | void ikbd_joystick_monitor(int rate) | ||
551 | { | ||
552 | static const char cmd[2] = { 0x17, rate }; | ||
553 | |||
554 | ikbd_write(cmd, 2); | ||
555 | |||
556 | kb_state.state = JOYSTICK_MONITOR; | ||
557 | } | ||
558 | #endif | ||
559 | |||
560 | /* some joystick routines not in yet (0x18-0x19) */ | ||
561 | |||
562 | /* Disable joysticks */ | ||
563 | void ikbd_joystick_disable(void) | ||
564 | { | ||
565 | static const char cmd[1] = { 0x1A }; | ||
566 | |||
567 | ikbd_write(cmd, 1); | ||
568 | } | ||
569 | |||
570 | /* Time-of-day clock set */ | ||
571 | void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second) | ||
572 | { | ||
573 | char cmd[7] = { 0x1B, year, month, day, hour, minute, second }; | ||
574 | |||
575 | ikbd_write(cmd, 7); | ||
576 | } | ||
577 | |||
578 | /* Interrogate time-of-day clock */ | ||
579 | void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second) | ||
580 | { | ||
581 | static const char cmd[1] = { 0x1C }; | ||
582 | |||
583 | ikbd_write(cmd, 1); | ||
584 | } | ||
585 | |||
586 | /* Memory load */ | ||
587 | void ikbd_mem_write(int address, int size, char *data) | ||
588 | { | ||
589 | panic("Attempt to write data into keyboard memory"); | ||
590 | } | ||
591 | |||
592 | /* Memory read */ | ||
593 | void ikbd_mem_read(int address, char data[6]) | ||
594 | { | ||
595 | char cmd[3] = { 0x21, address>>8, address&0xFF }; | ||
596 | |||
597 | ikbd_write(cmd, 3); | ||
598 | |||
599 | /* receive data and put it in data */ | ||
600 | } | ||
601 | |||
602 | /* Controller execute */ | ||
603 | void ikbd_exec(int address) | ||
604 | { | ||
605 | char cmd[3] = { 0x22, address>>8, address&0xFF }; | ||
606 | |||
607 | ikbd_write(cmd, 3); | ||
608 | } | ||
609 | |||
610 | /* Status inquiries (0x87-0x9A) not yet implemented */ | ||
611 | |||
612 | /* Set the state of the caps lock led. */ | ||
613 | void atari_kbd_leds(unsigned int leds) | ||
614 | { | ||
615 | char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0}; | ||
616 | |||
617 | ikbd_write(cmd, 6); | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * The original code sometimes left the interrupt line of | ||
622 | * the ACIAs low forever. I hope, it is fixed now. | ||
623 | * | ||
624 | * Martin Rogge, 20 Aug 1995 | ||
625 | */ | ||
626 | |||
627 | static int atari_keyb_done = 0; | ||
628 | |||
629 | int __init atari_keyb_init(void) | ||
630 | { | ||
631 | if (atari_keyb_done) | ||
632 | return 0; | ||
633 | |||
634 | /* setup key map */ | ||
635 | memcpy(key_maps[0], ataplain_map, sizeof(plain_map)); | ||
636 | |||
637 | kb_state.state = KEYBOARD; | ||
638 | kb_state.len = 0; | ||
639 | |||
640 | request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW, | ||
641 | "keyboard/mouse/MIDI", atari_keyboard_interrupt); | ||
642 | |||
643 | atari_turnoff_irq(IRQ_MFP_ACIA); | ||
644 | do { | ||
645 | /* reset IKBD ACIA */ | ||
646 | acia.key_ctrl = ACIA_RESET | | ||
647 | (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0; | ||
648 | (void)acia.key_ctrl; | ||
649 | (void)acia.key_data; | ||
650 | |||
651 | /* reset MIDI ACIA */ | ||
652 | acia.mid_ctrl = ACIA_RESET | | ||
653 | (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; | ||
654 | (void)acia.mid_ctrl; | ||
655 | (void)acia.mid_data; | ||
656 | |||
657 | /* divide 500kHz by 64 gives 7812.5 baud */ | ||
658 | /* 8 data no parity 1 start 1 stop bit */ | ||
659 | /* receive interrupt enabled */ | ||
660 | /* RTS low (except if switch selected), transmit interrupt disabled */ | ||
661 | acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) | | ||
662 | ((atari_switches & ATARI_SWITCH_IKBD) ? | ||
663 | ACIA_RHTID : ACIA_RLTID); | ||
664 | |||
665 | acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | | ||
666 | (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; | ||
667 | |||
668 | /* make sure the interrupt line is up */ | ||
669 | } while ((mfp.par_dt_reg & 0x10) == 0); | ||
670 | |||
671 | /* enable ACIA Interrupts */ | ||
672 | mfp.active_edge &= ~0x10; | ||
673 | atari_turnon_irq(IRQ_MFP_ACIA); | ||
674 | |||
675 | ikbd_self_test = 1; | ||
676 | ikbd_reset(); | ||
677 | /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's | ||
678 | * self-test is finished */ | ||
679 | self_test_last_rcv = jiffies; | ||
680 | while (time_before(jiffies, self_test_last_rcv + HZ/4)) | ||
681 | barrier(); | ||
682 | /* if not incremented: no 0xf1 received */ | ||
683 | if (ikbd_self_test == 1) | ||
684 | printk(KERN_ERR "WARNING: keyboard self test failed!\n"); | ||
685 | ikbd_self_test = 0; | ||
686 | |||
687 | ikbd_mouse_disable(); | ||
688 | ikbd_joystick_disable(); | ||
689 | |||
690 | #ifdef FIXED_ATARI_JOYSTICK | ||
691 | atari_joystick_init(); | ||
692 | #endif | ||
693 | |||
694 | // flag init done | ||
695 | atari_keyb_done = 1; | ||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | |||
700 | int atari_kbdrate(struct kbd_repeat *k) | ||
701 | { | ||
702 | if (k->delay > 0) { | ||
703 | /* convert from msec to jiffies */ | ||
704 | key_repeat_delay = (k->delay * HZ + 500) / 1000; | ||
705 | if (key_repeat_delay < 1) | ||
706 | key_repeat_delay = 1; | ||
707 | } | ||
708 | if (k->period > 0) { | ||
709 | key_repeat_rate = (k->period * HZ + 500) / 1000; | ||
710 | if (key_repeat_rate < 1) | ||
711 | key_repeat_rate = 1; | ||
712 | } | ||
713 | |||
714 | k->delay = key_repeat_delay * 1000 / HZ; | ||
715 | k->period = key_repeat_rate * 1000 / HZ; | ||
716 | |||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) | ||
721 | { | ||
722 | #ifdef CONFIG_MAGIC_SYSRQ | ||
723 | /* ALT+HELP pressed? */ | ||
724 | if ((keycode == 98) && ((shift_state & 0xff) == 8)) | ||
725 | *keycodep = 0xff; | ||
726 | else | ||
727 | #endif | ||
728 | *keycodep = keycode; | ||
729 | return 1; | ||
730 | } | ||