linux-old/drivers/acorn/char/keyb_arc.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/acorn/char/keyb_arc.c
   3 *
   4 *  Copyright (C) 2000 Russell King
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 *  Acorn keyboard driver for ARM Linux.
  11 *
  12 *  The Acorn keyboard appears to have a ***very*** buggy reset protocol -
  13 *  every reset behaves differently.  We try to get round this by attempting
  14 *  a few things...
  15 */
  16#include <linux/config.h>
  17#include <linux/sched.h>
  18#include <linux/interrupt.h>
  19#include <linux/tty.h>
  20#include <linux/tty_flip.h>
  21#include <linux/mm.h>
  22#include <linux/slab.h>
  23#include <linux/ptrace.h>
  24#include <linux/signal.h>
  25#include <linux/timer.h>
  26#include <linux/random.h>
  27#include <linux/ctype.h>
  28#include <linux/init.h>
  29#include <linux/kbd_ll.h>
  30#include <linux/kbd_kern.h>
  31#include <linux/delay.h>
  32
  33#include <asm/bitops.h>
  34#include <asm/keyboard.h>
  35#include <asm/irq.h>
  36#include <asm/hardware.h>
  37#include <asm/hardware/ioc.h>
  38
  39#include "../../char/busmouse.h"
  40
  41extern struct tasklet_struct keyboard_tasklet;
  42extern void kbd_reset_kdown(void);
  43
  44#define VERSION 108
  45
  46#define KBD_REPORT_ERR
  47#define KBD_REPORT_UNKN
  48
  49#include <asm/io.h>
  50#include <asm/system.h>
  51
  52static char kbd_txval[4];
  53static unsigned char kbd_txhead, kbd_txtail;
  54#define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3)
  55static int kbd_id = -1;
  56static DECLARE_WAIT_QUEUE_HEAD(kbd_waitq);
  57#ifdef CONFIG_KBDMOUSE
  58static int mousedev;
  59#endif
  60
  61/*
  62 * Protocol codes to send the keyboard.
  63 */
  64#define HRST 0xff       /* reset keyboard */
  65#define RAK1 0xfe       /* reset response */
  66#define RAK2 0xfd       /* reset response */
  67#define BACK 0x3f       /* Ack for first keyboard pair */
  68#define SMAK 0x33       /* Last data byte ack (key scanning + mouse movement scanning) */
  69#define MACK 0x32       /* Last data byte ack (mouse movement scanning) */
  70#define SACK 0x31       /* Last data byte ack (key scanning) */
  71#define NACK 0x30       /* Last data byte ack (no scanning, mouse data) */
  72#define RQMP 0x22       /* Request mouse data */
  73#define PRST 0x21       /* nothing */
  74#define RQID 0x20       /* Request ID */
  75
  76#define UP_FLAG 1
  77
  78#ifdef CONFIG_MAGIC_SYSRQ
  79unsigned char a5kkbd_sysrq_xlate[] = 
  80{
  81    27,    0,    0,    0,    0,    0,    0,    0,
  82     0,    0,    0,    0,    0,    0,    0,    0,
  83   '`',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
  84   '8',  '9',  '0',  '-',  '=',  '£',  127,    0,
  85     0,    0,    0,  '/',  '*',  '#',    9,  'q',
  86   'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',
  87   'p',  '[',  ']', '\\',  22,    23,   25,  '7',
  88   '8',  '9',  '-',    0,  'a',  's',  'd',  'f',
  89   'g',  'h',  'j',  'k',  'l',  ';', '\'',   13,
  90   '4',  '5',  '6',  '+',    0,    0,  'z',  'x',
  91   'c',  'v',  'b',  'n',  'm',  ',',  '.',  '/',
  92     0,    0,  '1',  '2',  '3',    0,    0,  ' ',
  93     0,    0,    0,    0,    0,  '0',  '.',   10,
  94     0,    0,    0,    0,    0,    0,    0,    0,
  95     0,    0,    0,    0,    0,    0,    0,    0,
  96     0,    0,    0,    0,    0,    0,    0,    0,
  97};
  98#endif
  99
 100/*
 101 * This array converts the scancode that we get from the keyboard to the
 102 * real rows/columns on the A5000 keyboard.  This might be keyboard specific...
 103 *
 104 * It is these values that we use to maintain the key down array.  That way, we
 105 * should pick up on the ghost key presses (which is what happens when you press
 106 * three keys, and the keyboard thinks you have pressed four!)
 107 *
 108 * Row 8 (0x80+c) is actually a column with one key per row.  It is isolated from
 109 * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc).
 110 *
 111 * Illegal scancodes are denoted by an 0xff (in other words, we don't know about
 112 * them, and can't process them for ghosts).  This does however, cause problems with
 113 * autorepeat processing...
 114 */
 115static unsigned char scancode_2_colrow[256] = {
 116  0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60,
 117  0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79,
 118  0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a,
 119  0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34,
 120  0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12,
 121  0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03,
 122  0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff,
 123};
 124
 125#define BITS_PER_SHORT (8*sizeof(unsigned short))
 126static unsigned short ghost_down[128/BITS_PER_SHORT];
 127
 128static void a5kkbd_key(unsigned int keycode, unsigned int up_flag)
 129{
 130        unsigned int real_keycode;
 131
 132        if (keycode > 0x72) {
 133#ifdef KBD_REPORT_UNKN
 134                printk ("kbd: unknown scancode 0x%04x\n", keycode);
 135#endif
 136                return;
 137        }
 138        if (keycode >= 0x70) {
 139#ifdef CONFIG_KBDMOUSE
 140                if (mousedev >= 0)
 141                        switch (keycode) {
 142                        case 0x70: /* Left mouse button */
 143                                busmouse_add_buttons(mousedev, 4, up_flag ? 4 : 0);
 144                                break;
 145
 146                        case 0x71: /* Middle mouse button */
 147                                busmouse_add_buttons(mousedev, 2, up_flag ? 2 : 0);
 148                                break;
 149
 150                        case 0x72:/* Right mouse button */
 151                                busmouse_add_buttons(mousedev, 1, up_flag ? 1 : 0);
 152                                break;
 153                        }
 154#endif
 155                return;
 156        }
 157
 158        /*
 159         * We have to work out if we accept this key press as a real key, or
 160         * if it is a ghost.  IE. If you press three keys, the keyboard will think
 161         * that you've pressed a fourth: (@ = key down, # = ghost)
 162         *
 163         *   0 1 2 3 4 5 6 7
 164         *   | | | | | | | |
 165         * 0-+-+-+-+-+-+-+-+-
 166         *   | | | | | | | |
 167         * 1-+-@-+-+-+-@-+-+-
 168         *   | | | | | | | |
 169         * 2-+-+-+-+-+-+-+-+-
 170         *   | | | | | | | |
 171         * 3-+-@-+-+-+-#-+-+-
 172         *   | | | | | | | |
 173         *
 174         * This is what happens when you have a matrix keyboard...
 175         */
 176
 177        real_keycode = scancode_2_colrow[keycode];
 178
 179        if ((real_keycode & 0x80) == 0) {
 180                int rr, kc = (real_keycode >> 4) & 7;
 181                int cc;
 182                unsigned short res, kdownkc;
 183
 184                kdownkc = ghost_down[kc] | (1 << (real_keycode & 15));
 185
 186                for (rr = 0; rr < 128/BITS_PER_SHORT; rr++)
 187                        if (rr != kc && (res = ghost_down[rr] & kdownkc)) {
 188                                /*
 189                                 * we have found a second row with at least one key pressed in the
 190                                 * same column.
 191                                 */
 192                                for (cc = 0; res; res >>= 1)
 193                                        cc += (res & 1);
 194                                if (cc > 1)
 195                                        return; /* ignore it */
 196                        }
 197                if (up_flag)
 198                        clear_bit (real_keycode, ghost_down);
 199                else
 200                        set_bit (real_keycode, ghost_down);
 201        }
 202
 203        handle_scancode(keycode, !up_flag);
 204}
 205
 206static inline void a5kkbd_sendbyte(unsigned char val)
 207{
 208        kbd_txval[kbd_txhead] = val;
 209        KBD_INCTXPTR(kbd_txhead);
 210        enable_irq(IRQ_KEYBOARDTX);
 211}
 212
 213static inline void a5kkbd_reset(void)
 214{
 215        int i;
 216
 217        for (i = 0; i < NR_SCANCODES/BITS_PER_SHORT; i++)
 218                ghost_down[i] = 0;
 219
 220        kbd_reset_kdown();
 221}
 222
 223void a5kkbd_leds(unsigned char leds)
 224{
 225        leds =  ((leds & (1<<VC_SCROLLOCK))?4:0) | ((leds & (1<<VC_NUMLOCK))?2:0) |
 226                ((leds & (1<<VC_CAPSLOCK))?1:0);
 227        a5kkbd_sendbyte(leds);
 228}
 229
 230/* Keyboard states:
 231 *  0 initial reset condition, receive HRST, send RRAK1
 232 *  1 Sent RAK1, wait for RAK1, send RRAK2
 233 *  2 Sent RAK2, wait for RAK2, send SMAK or RQID
 234 *  3 Sent RQID, expect KBID, send SMAK
 235 *  4 Sent SMAK, wait for anything
 236 *  5 Wait for second keyboard nibble for key pressed
 237 *  6 Wait for second keyboard nibble for key released
 238 *  7 Wait for second part of mouse data
 239 *
 240 * This function returns 1 when we successfully enter the IDLE state
 241 * (and hence need to do some keyboard processing).
 242 */
 243#define KBD_INITRST     0
 244#define KBD_RAK1        1
 245#define KBD_RAK2        2
 246#define KBD_ID          3
 247#define KBD_IDLE        4
 248#define KBD_KEYDOWN     5
 249#define KBD_KEYUP       6
 250#define KBD_MOUSE       7
 251
 252static int handle_rawcode(unsigned int keyval)
 253{
 254        static signed char kbd_mousedx = 0;
 255               signed char kbd_mousedy;
 256        static unsigned char kbd_state = KBD_INITRST;
 257        static unsigned char kbd_keyhigh = 0;
 258
 259        if (keyval == HRST && kbd_state != KBD_INITRST && kbd_state != KBD_ID) {
 260                a5kkbd_sendbyte (HRST);
 261                a5kkbd_reset ();
 262                kbd_state = KBD_INITRST;
 263        } else switch(kbd_state) {
 264        case KBD_INITRST:                       /* hard reset - sent HRST */
 265                if (keyval == HRST) {
 266                        a5kkbd_sendbyte (RAK1);
 267                        kbd_state = KBD_RAK1;
 268                } else if (keyval == RAK1) {
 269                        /* Some A5000 keyboards are very fussy and don't follow Acorn's
 270                         * specs - this appears to fix them, but them it might stop
 271                         * them from being initialised.
 272                         *  fix by Philip Blundell
 273                         */
 274                        printk(KERN_DEBUG "keyboard sent early RAK1 -- ignored\n");
 275                } else
 276                        goto kbd_wontreset;
 277                break;
 278
 279        case KBD_RAK1:                          /* sent RAK1 - expect RAK1 and send RAK2 */
 280                if (keyval == RAK1) {
 281                        a5kkbd_sendbyte (RAK2);
 282                        kbd_state = KBD_RAK2;
 283                } else
 284                        goto kbd_wontreset;
 285                break;
 286
 287        case KBD_RAK2:                          /* Sent RAK2 - expect RAK2 and send either RQID or SMAK */
 288                if (keyval == RAK2) {
 289                        if (kbd_id == -1) {
 290                                a5kkbd_sendbyte (NACK);
 291                                a5kkbd_sendbyte (RQID);
 292                                kbd_state = KBD_ID;
 293                        } else {
 294                                a5kkbd_sendbyte (SMAK);
 295                                kbd_state = KBD_IDLE;
 296                        }
 297                } else
 298                        goto kbd_wontreset;
 299                break;
 300
 301        case KBD_ID:                            /* Sent RQID - expect KBID */
 302                if (keyval == HRST) {
 303                        kbd_id = -2;
 304                        a5kkbd_reset ();
 305                        a5kkbd_sendbyte (HRST);
 306                        kbd_state = KBD_INITRST;
 307                        wake_up (&kbd_waitq);
 308                } else if ((keyval & 0xc0) == 0x80) {
 309                        kbd_id = keyval & 0x3f;
 310                        a5kkbd_sendbyte (SMAK);
 311                        kbd_state = KBD_IDLE;
 312                        wake_up (&kbd_waitq);
 313                }
 314                break;
 315
 316        case KBD_IDLE:                          /* Send SMAK, ready for any reply */
 317                switch (keyval & 0xf0) {
 318                default:        /* 0x00 - 0x7f */
 319                        kbd_mousedx = keyval & 0x40 ? keyval|0x80 : keyval;
 320                        kbd_state   = KBD_MOUSE;
 321                        a5kkbd_sendbyte (BACK);
 322                        break;
 323
 324                case 0x80:
 325                case 0x90:
 326                case 0xa0:
 327                case 0xb0:
 328                        if (kbd_id == -1)
 329                                kbd_id = keyval & 0x3f;
 330                        break;
 331
 332                case 0xc0:
 333                        kbd_keyhigh = keyval;
 334                        kbd_state   = KBD_KEYDOWN;
 335                        a5kkbd_sendbyte (BACK);
 336                        break;
 337
 338                case 0xd0:
 339                        kbd_keyhigh = keyval;
 340                        kbd_state   = KBD_KEYUP;
 341                        a5kkbd_sendbyte (BACK);
 342                        break;
 343
 344                case 0xe0:
 345                case 0xf0:
 346                        goto kbd_error;
 347                }
 348                break;
 349
 350        case KBD_KEYDOWN:
 351                if ((keyval & 0xf0) != 0xc0)
 352                        goto kbd_error;
 353                else {
 354                        kbd_state = KBD_IDLE;
 355                        a5kkbd_sendbyte (SMAK);
 356                        if (((kbd_keyhigh ^ keyval) & 0xf0) == 0)
 357                                a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), 0);
 358                }
 359                break;
 360
 361        case KBD_KEYUP:
 362                if ((keyval & 0xf0) != 0xd0)
 363                        goto kbd_error;
 364                else {
 365                        kbd_state = KBD_IDLE;
 366                        a5kkbd_sendbyte (SMAK);
 367                        if (((kbd_keyhigh ^ keyval) & 0xf0) == 0)
 368                                a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), UP_FLAG);
 369                }
 370                break;
 371
 372        case KBD_MOUSE:
 373                if (keyval & 0x80)
 374                        goto kbd_error;
 375                else {
 376                        kbd_state = KBD_IDLE;
 377                        a5kkbd_sendbyte (SMAK);
 378                        kbd_mousedy = (char)(keyval & 0x40 ? keyval | 0x80 : keyval);
 379#ifdef CONFIG_KBDMOUSE
 380                        if (mousedev >= 0)
 381                                busmouse_add_movement(mousedev, (int)kbd_mousedx, (int)kbd_mousedy);
 382#endif
 383                }
 384        }
 385        return kbd_state == KBD_IDLE ? 1 : 0;
 386
 387kbd_wontreset:
 388#ifdef KBD_REPORT_ERR
 389        printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n",
 390                kbd_state, keyval);
 391#endif
 392        mdelay(1);
 393        ioc_readb(IOC_KARTRX);
 394        a5kkbd_sendbyte (HRST);
 395        kbd_state = KBD_INITRST;
 396        return 0;
 397
 398kbd_error:
 399#ifdef KBD_REPORT_ERR
 400        printk ("kbd: keyboard out of sync - resetting\n");
 401#endif
 402        a5kkbd_sendbyte (HRST);
 403        kbd_state = KBD_INITRST;
 404        return 0;
 405}
 406
 407static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs)
 408{
 409        kbd_pt_regs = regs;
 410        if (handle_rawcode(ioc_readb(IOC_KARTRX)))
 411                tasklet_schedule(&keyboard_tasklet);
 412}
 413
 414static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs)
 415{
 416        ioc_writeb (kbd_txval[kbd_txtail], IOC_KARTTX);
 417        KBD_INCTXPTR(kbd_txtail);
 418        if (kbd_txtail == kbd_txhead)
 419                disable_irq(irq);
 420}
 421
 422static int a5kkbd_setkeycode(unsigned int scancode, unsigned int keycode)
 423{
 424        return -EINVAL;
 425}
 426
 427static int a5kkbd_getkeycode(unsigned int scancode)
 428{
 429        return -EINVAL;
 430}
 431
 432static int a5kkbd_translate(unsigned char scancode, unsigned char *keycode, char rawmode)
 433{
 434        *keycode = scancode;
 435        return 1;
 436}
 437
 438static char a5kkbd_unexpected_up(unsigned char keycode)
 439{
 440        return 0200;
 441}
 442
 443static int a5kkbd_rate(struct kbd_repeat *rep)
 444{
 445        return -EINVAL;
 446}
 447
 448#ifdef CONFIG_KBDMOUSE
 449static struct busmouse a5kkbd_mouse = {
 450        6, "kbdmouse", NULL, NULL, NULL, 7
 451};
 452#endif
 453
 454struct kbd_ops_struct a5k_kbd_ops = {
 455        k_setkeycode:           a5kkbd_setkeycode,
 456        k_getkeycode:           a5kkbd_getkeycode,
 457        k_translate:            a5kkbd_translate,
 458        k_unexpected_up:        a5kkbd_unexpected_up,
 459        k_leds:                 a5kkbd_leds,
 460        k_rate:                 a5kkbd_rate,
 461#ifdef CONFIG_MAGIC_SYSRQ
 462        k_sysrq_xlate:          a5kkbd_sysrq_xlate,
 463        k_sysrq_key:            13,
 464#endif
 465};
 466
 467void __init a5kkbd_init_hw (void)
 468{
 469        if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0)
 470                panic("Could not allocate keyboard transmit IRQ!");
 471        (void)ioc_readb(IOC_KARTRX);
 472        if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0)
 473                panic("Could not allocate keyboard receive IRQ!");
 474
 475        a5kkbd_sendbyte (HRST); /* send HRST (expect HRST) */
 476
 477        /* wait 1s for keyboard to initialise */
 478        interruptible_sleep_on_timeout(&kbd_waitq, HZ);
 479
 480#ifdef CONFIG_KBDMOUSE
 481        mousedev = register_busmouse(&a5kkbd_mouse);
 482        if (mousedev < 0)
 483                printk(KERN_ERR "Unable to register mouse driver\n");
 484#endif
 485
 486        printk (KERN_INFO "Keyboard driver v%d.%02d. (", VERSION/100, VERSION%100);
 487        if (kbd_id != -1)
 488              printk ("id=%d ", kbd_id);
 489        printk ("English)\n");
 490}
 491
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.