~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/char/q40_keyb.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.