diff options
| author | Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de> | 2007-05-01 16:32:38 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-04 20:59:05 -0400 |
| commit | c04cb856e20a8bf68762d60737b84328c1ab5900 (patch) | |
| tree | c8046787b2fa708b0a5a0972444bac9df67fadff /arch/m68k/atari | |
| parent | 3130d905ba86d5f2636b2f45d5beefe82cb03df6 (diff) | |
m68k: Atari keyboard and mouse support.
Atari keyboard and mouse support.
(reformating and Kconfig fixes by Roman Zippel)
Signed-off-by: Michael Schmitz <schmitz@debian.org>
Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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 8cb6236b39..2cb86191f0 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 0000000000..1c29603b16 --- /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 | } | ||
