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