linux-old/drivers/char/q40_keyb.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/char/q40_keyb.c
   3 *
   4 */
   5
   6#include <linux/config.h>
   7
   8#include <linux/spinlock.h>
   9#include <linux/sched.h>
  10#include <linux/interrupt.h>
  11#include <linux/tty.h>
  12#include <linux/mm.h>
  13#include <linux/keyboard.h>
  14#include <linux/signal.h>
  15#include <linux/ioport.h>
  16#include <linux/init.h>
  17#include <linux/kbd_ll.h>
  18#include <linux/kbd_kern.h>
  19#include <linux/delay.h>
  20#include <linux/sysrq.h>
  21#include <linux/random.h>
  22#include <linux/poll.h>
  23#include <linux/miscdevice.h>
  24#include <linux/slab.h>
  25
  26#include <asm/keyboard.h>
  27#include <asm/bitops.h>
  28#include <asm/io.h>
  29#include <asm/uaccess.h>
  30#include <asm/q40_master.h>
  31#include <asm/irq.h>
  32#include <asm/q40ints.h>
  33
  34
  35/* Simple translation table for the SysRq keys */
  36
  37#define SYSRQ_KEY 0x54
  38
  39#ifdef CONFIG_MAGIC_SYSRQ
  40unsigned char q40kbd_sysrq_xlate[128] =
  41        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
  42        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
  43        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
  44        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
  45        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
  46        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
  47        "\r\000/";                                      /* 0x60 - 0x6f */
  48#endif
  49
  50/* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/
  51/* 0x00 means not a valid entry or no conversion known                    */
  52
  53unsigned static char q40cl[256] =
  54{/* 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   a,   b,   c,   d,   e,   f, */
  55 0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00,     /* 0x00 - 0x0f */
  56 0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00,     /* 0x10 - 0x1f */
  57 0x00,0x2e,0x2d,0x20,0x12,0x05,0x04,0x00,0x21,0x39,0x2f,0x21,0x14,0x13,0x06,0x00,     /* 0x20 - 0x2f  'f' is at 0x2b, what is 0x28 ???*/
  58 0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00,     /* 0x30 - 0x3f */
  59 0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00,     /* 0x40 - 0x4f */
  60 0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00,     /* 0x50 - 0x5f*/
  61 0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,     /* 0x60 - 0x6f */
  62 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00,     /* 0x70 - 0x7f */
  63 0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x80 - 0x8f  0x84/0x37 is SySrq*/
  64 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x90 - 0x9f */
  65 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xa0 - 0xaf */
  66 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xb0 - 0xbf */
  67 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xc0 - 0xcf */
  68 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xd0 - 0xdf */
  69 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xe0 - 0xef */
  70 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xf0 - 0xff */
  71};
  72
  73/* another table, AT 0xe0 codes to PC 0xe0 codes, 
  74   0xff special entry for SysRq - DROPPED right now  */
  75static unsigned char q40ecl[]=
  76{/* 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   a,   b,   c,   d,   e,   f, */
  77 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x00 - 0x0f*/
  78 0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x10 - 0x1f */
  79 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x20 - 0x2f*/
  80 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x30 - 0x3f*/
  81 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00,     /* 0x40 - 0x4f*/
  82 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,     /* 0x50 - 0x5f*/
  83 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,     /* 0x60 - 0x6f*/
  84 0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00,     /* 0x70 - 0x7f*/
  85 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x80 - 0x8f*/
  86 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x90 - 0x9f*/
  87 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xa0 - 0xaf*/
  88 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xb0 - 0xbf*/
  89 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xc0 - 0xcf*/
  90 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xd0 - 0xdf*/
  91 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xe0 - 0xef*/
  92 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00      /* 0xf0 - 0xff*/
  93};
  94
  95
  96static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
  97
  98
  99/*
 100 * Translation of escaped scancodes to keycodes.
 101 * This is now user-settable.
 102 * The keycodes 1-88,96-111,119 are fairly standard, and
 103 * should probably not be changed - changing might confuse X.
 104 * X also interprets scancode 0x5d (KEY_Begin).
 105 *
 106 * For 1-88 keycode equals scancode.
 107 */
 108
 109#define E0_KPENTER 96
 110#define E0_RCTRL   97
 111#define E0_KPSLASH 98
 112#define E0_PRSCR   99
 113#define E0_RALT    100
 114#define E0_BREAK   101  /* (control-pause) */
 115#define E0_HOME    102
 116#define E0_UP      103
 117#define E0_PGUP    104
 118#define E0_LEFT    105
 119#define E0_RIGHT   106
 120#define E0_END     107
 121#define E0_DOWN    108
 122#define E0_PGDN    109
 123#define E0_INS     110
 124#define E0_DEL     111
 125
 126#define E1_PAUSE   119
 127
 128/*
 129 * The keycodes below are randomly located in 89-95,112-118,120-127.
 130 * They could be thrown away (and all occurrences below replaced by 0),
 131 * but that would force many users to use the `setkeycodes' utility, where
 132 * they needed not before. It does not matter that there are duplicates, as
 133 * long as no duplication occurs for any single keyboard.
 134 */
 135#define SC_LIM 89
 136
 137#define FOCUS_PF1 85           /* actual code! */
 138#define FOCUS_PF2 89
 139#define FOCUS_PF3 90
 140#define FOCUS_PF4 91
 141#define FOCUS_PF5 92
 142#define FOCUS_PF6 93
 143#define FOCUS_PF7 94
 144#define FOCUS_PF8 95
 145#define FOCUS_PF9 120
 146#define FOCUS_PF10 121
 147#define FOCUS_PF11 122
 148#define FOCUS_PF12 123
 149
 150#define JAP_86     124
 151/* tfj@olivia.ping.dk:
 152 * The four keys are located over the numeric keypad, and are
 153 * labelled A1-A4. It's an rc930 keyboard, from
 154 * Regnecentralen/RC International, Now ICL.
 155 * Scancodes: 59, 5a, 5b, 5c.
 156 */
 157#define RGN1 124
 158#define RGN2 125
 159#define RGN3 126
 160#define RGN4 127
 161
 162static unsigned char high_keys[128 - SC_LIM] = {
 163  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
 164  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
 165  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
 166  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
 167  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
 168  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
 169};
 170
 171/* BTC */
 172#define E0_MACRO   112
 173/* LK450 */
 174#define E0_F13     113
 175#define E0_F14     114
 176#define E0_HELP    115
 177#define E0_DO      116
 178#define E0_F17     117
 179#define E0_KPMINPLUS 118
 180/*
 181 * My OmniKey generates e0 4c for  the "OMNI" key and the
 182 * right alt key does nada. [kkoller@nyx10.cs.du.edu]
 183 */
 184#define E0_OK   124
 185/*
 186 * New microsoft keyboard is rumoured to have
 187 * e0 5b (left window button), e0 5c (right window button),
 188 * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
 189 * [or: Windows_L, Windows_R, TaskMan]
 190 */
 191#define E0_MSLW 125
 192#define E0_MSRW 126
 193#define E0_MSTM 127
 194
 195/* this can be changed using setkeys : */
 196static unsigned char e0_keys[128] = {
 197  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x00-0x07 */
 198  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x08-0x0f */
 199  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x10-0x17 */
 200  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,             /* 0x18-0x1f */
 201  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x20-0x27 */
 202  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x28-0x2f */
 203  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,             /* 0x30-0x37 */
 204  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,       /* 0x38-0x3f */
 205  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,       /* 0x40-0x47 */
 206  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
 207  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,       /* 0x50-0x57 */
 208  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,           /* 0x58-0x5f */
 209  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x60-0x67 */
 210  0, 0, 0, 0, 0, 0, 0, E0_MACRO,                      /* 0x68-0x6f */
 211  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x70-0x77 */
 212  0, 0, 0, 0, 0, 0, 0, 0                              /* 0x78-0x7f */
 213};
 214
 215
 216int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode)
 217{
 218        if (scancode < SC_LIM || scancode > 255 || keycode > 127)
 219          return -EINVAL;
 220        if (scancode < 128)
 221          high_keys[scancode - SC_LIM] = keycode;
 222        else
 223          e0_keys[scancode - 128] = keycode;
 224        return 0;
 225}
 226
 227int q40kbd_getkeycode(unsigned int scancode)
 228{
 229        return
 230          (scancode < SC_LIM || scancode > 255) ? -EINVAL :
 231          (scancode < 128) ? high_keys[scancode - SC_LIM] :
 232            e0_keys[scancode - 128];
 233}
 234
 235
 236#define disable_keyboard()      
 237#define enable_keyboard()       
 238
 239
 240
 241
 242int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
 243                    char raw_mode)
 244{
 245        static int prev_scancode;
 246
 247        /* special prefix scancodes.. */
 248        if (scancode == 0xe0 || scancode == 0xe1) {
 249                prev_scancode = scancode;
 250                return 0;
 251        }
 252
 253        /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
 254        if (scancode == 0x00 || scancode == 0xff) {
 255                prev_scancode = 0;
 256                return 0;
 257        }
 258
 259        scancode &= 0x7f;
 260
 261        if (prev_scancode) {
 262          /*
 263           * usually it will be 0xe0, but a Pause key generates
 264           * e1 1d 45 e1 9d c5 when pressed, and nothing when released
 265           */
 266          if (prev_scancode != 0xe0) {
 267              if (prev_scancode == 0xe1 && scancode == 0x1d) {
 268                  prev_scancode = 0x100;
 269                  return 0;
 270              } else if (prev_scancode == 0x100 && scancode == 0x45) {
 271                  *keycode = E1_PAUSE;
 272                  prev_scancode = 0;
 273              } else {
 274#ifdef KBD_REPORT_UNKN
 275                  if (!raw_mode)
 276                    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
 277#endif
 278                  prev_scancode = 0;
 279                  return 0;
 280              }
 281          } else {
 282              prev_scancode = 0;
 283              /*
 284               *  The keyboard maintains its own internal caps lock and
 285               *  num lock statuses. In caps lock mode E0 AA precedes make
 286               *  code and E0 2A follows break code. In num lock mode,
 287               *  E0 2A precedes make code and E0 AA follows break code.
 288               *  We do our own book-keeping, so we will just ignore these.
 289               */
 290              /*
 291               *  For my keyboard there is no caps lock mode, but there are
 292               *  both Shift-L and Shift-R modes. The former mode generates
 293               *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
 294               *  So, we should also ignore the latter. - aeb@cwi.nl
 295               */
 296              if (scancode == 0x2a || scancode == 0x36)
 297                return 0;
 298
 299              if (e0_keys[scancode])
 300                *keycode = e0_keys[scancode];
 301              else {
 302#ifdef KBD_REPORT_UNKN
 303                  if (!raw_mode)
 304                    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
 305                           scancode);
 306#endif
 307                  return 0;
 308              }
 309          }
 310        } else if (scancode >= SC_LIM) {
 311            /* This happens with the FOCUS 9000 keyboard
 312               Its keys PF1..PF12 are reported to generate
 313               55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
 314               Moreover, unless repeated, they do not generate
 315               key-down events, so we have to zero up_flag below */
 316            /* Also, Japanese 86/106 keyboards are reported to
 317               generate 0x73 and 0x7d for \ - and \ | respectively. */
 318            /* Also, some Brazilian keyboard is reported to produce
 319               0x73 and 0x7e for \ ? and KP-dot, respectively. */
 320
 321          *keycode = high_keys[scancode - SC_LIM];
 322
 323          if (!*keycode) {
 324              if (!raw_mode) {
 325#ifdef KBD_REPORT_UNKN
 326                  printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
 327                         " - ignored\n", scancode);
 328#endif
 329              }
 330              return 0;
 331          }
 332        } else
 333          *keycode = scancode;
 334        return 1;
 335}
 336
 337char q40kbd_unexpected_up(unsigned char keycode)
 338{
 339        /* unexpected, but this can happen: maybe this was a key release for a
 340           FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
 341        if (keycode >= SC_LIM || keycode == 85)
 342            return 0;
 343        else
 344            return 0200;
 345}
 346
 347static int keyup=0;
 348static int qprev=0;
 349
 350static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 351{
 352        unsigned char status;
 353
 354        spin_lock(&kbd_controller_lock);
 355        kbd_pt_regs = regs;
 356
 357        status = Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
 358        if (status ) 
 359          {
 360            unsigned char scancode,qcode;
 361            
 362            qcode = master_inb(KEYCODE_REG);
 363            
 364            if (qcode != 0xf0)
 365              {
 366                if (qcode == 0xe0)
 367                  {
 368                    qprev=0xe0;
 369                    handle_scancode(qprev , 1);
 370                    goto exit;
 371                  }
 372                
 373                scancode=qprev ? q40ecl[qcode] : q40cl[qcode];
 374#if 0
 375/* next line is last resort to hanlde some oddities */
 376                if (qprev && !scancode) scancode=q40cl[qcode];
 377#endif
 378                qprev=0;
 379                if (!scancode)
 380                  {
 381                    printk("unknown scancode %x\n",qcode);
 382                    goto exit;
 383                  }
 384                if (scancode==0xff)  /* SySrq */
 385                  scancode=SYSRQ_KEY;
 386
 387                handle_scancode(scancode, ! keyup );
 388                keyup=0;
 389                tasklet_schedule(&keyboard_tasklet);
 390              }
 391            else
 392              keyup=1;
 393          }
 394exit:
 395        spin_unlock(&kbd_controller_lock);
 396        master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */
 397}
 398
 399
 400#define KBD_NO_DATA     (-1)    /* No data */
 401#define KBD_BAD_DATA    (-2)    /* Parity or other error */
 402
 403static int __init q40kbd_read_input(void)
 404{
 405        int retval = KBD_NO_DATA;
 406        unsigned char status;
 407
 408        status = Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
 409        if (status) {
 410                unsigned char data = master_inb(KEYCODE_REG);
 411
 412                retval = data;
 413                master_outb(-1,KEYBOARD_UNLOCK_REG);
 414        }
 415        return retval;
 416}
 417
 418
 419static void __init kbd_clear_input(void)
 420{
 421        int maxread = 100;      /* Random number */
 422
 423        do {
 424                if (q40kbd_read_input() == KBD_NO_DATA)
 425                        break;
 426        } while (--maxread);
 427}
 428
 429
 430int __init q40kbd_init_hw(void)
 431{
 432
 433        /* Flush any pending input. */
 434        kbd_clear_input();
 435
 436        /* Ok, finally allocate the IRQ, and off we go.. */
 437        request_irq(Q40_IRQ_KEYBOARD, keyboard_interrupt, 0, "keyboard", NULL);
 438        master_outb(-1,KEYBOARD_UNLOCK_REG);
 439        master_outb(1,KEY_IRQ_ENABLE_REG);
 440
 441        return 0;
 442}
 443
 444
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.