2 * linux/drivers/char/q40_keyb.c 6 #include <linux/config.h> 8 #include <linux/spinlock.h> 9 #include <linux/sched.h> 10 #include <linux/interrupt.h> 11 #include <linux/tty.h> 13 #include <linux/signal.h> 14 #include <linux/ioport.h> 15 #include <linux/init.h> 16 #include <linux/kbd_ll.h> 17 #include <linux/delay.h> 18 #include <linux/sysrq.h> 19 #include <linux/random.h> 20 #include <linux/poll.h> 21 #include <linux/miscdevice.h> 22 #include <linux/malloc.h> 24 #include <asm/keyboard.h> 25 #include <asm/bitops.h> 27 #include <asm/uaccess.h> 28 #include <asm/q40_master.h> 30 #include <asm/q40ints.h> 32 /* Some configuration switches are present in the include file... */ 34 #define KBD_REPORT_ERR 36 /* Simple translation table for the SysRq keys */ 38 #define SYSRQ_KEY 0x54 40 #ifdef CONFIG_MAGIC_SYSRQ 41 unsigned char q40kbd_sysrq_xlate
[128] = 42 "\000\0331234567890-=\177\t"/* 0x00 - 0x0f */ 43 "qwertyuiop[]\r\000as"/* 0x10 - 0x1f */ 44 "dfghjkl;'`\000\\zxcv"/* 0x20 - 0x2f */ 45 "bnm,./\000*\000 \000\201\202\203\204\205"/* 0x30 - 0x3f */ 46 "\206\207\210\211\212\000\000789-456+1"/* 0x40 - 0x4f */ 47 "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000"/* 0x50 - 0x5f */ 48 "\r\000/";/* 0x60 - 0x6f */ 51 /* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/ 52 /* 0x00 means not a valid entry or no conversion known */ 54 unsigned static char q40cl
[256] = 55 {/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */ 56 0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00,/* 0x00 - 0x0f */ 57 0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00,/* 0x10 - 0x1f */ 58 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 ???*/ 59 0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00,/* 0x30 - 0x3f */ 60 0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00,/* 0x40 - 0x4f */ 61 0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00,/* 0x50 - 0x5f*/ 62 0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,/* 0x60 - 0x6f */ 63 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00,/* 0x70 - 0x7f */ 64 0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0x80 - 0x8f 0x84/0x37 is SySrq*/ 65 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0x90 - 0x9f */ 66 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xa0 - 0xaf */ 67 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xb0 - 0xbf */ 68 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xc0 - 0xcf */ 69 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xd0 - 0xdf */ 70 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xe0 - 0xef */ 71 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xf0 - 0xff */ 74 /* another table, AT 0xe0 codes to PC 0xe0 codes, 75 0xff special entry for SysRq - DROPPED right now */ 76 static unsigned char q40ecl
[]= 77 {/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */ 78 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0x00 - 0x0f*/ 79 0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0x10 - 0x1f */ 80 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0x20 - 0x2f*/ 81 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0x30 - 0x3f*/ 82 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00,/* 0x40 - 0x4f*/ 83 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,/* 0x50 - 0x5f*/ 84 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,/* 0x60 - 0x6f*/ 85 0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00,/* 0x70 - 0x7f*/ 86 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0x80 - 0x8f*/ 87 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0x90 - 0x9f*/ 88 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xa0 - 0xaf*/ 89 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xb0 - 0xbf*/ 90 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xc0 - 0xcf*/ 91 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xd0 - 0xdf*/ 92 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* 0xe0 - 0xef*/ 93 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00/* 0xf0 - 0xff*/ 97 spinlock_t kbd_controller_lock
= SPIN_LOCK_UNLOCKED
; 101 * Translation of escaped scancodes to keycodes. 102 * This is now user-settable. 103 * The keycodes 1-88,96-111,119 are fairly standard, and 104 * should probably not be changed - changing might confuse X. 105 * X also interprets scancode 0x5d (KEY_Begin). 107 * For 1-88 keycode equals scancode. 110 #define E0_KPENTER 96 112 #define E0_KPSLASH 98 115 #define E0_BREAK 101/* (control-pause) */ 130 * The keycodes below are randomly located in 89-95,112-118,120-127. 131 * They could be thrown away (and all occurrences below replaced by 0), 132 * but that would force many users to use the `setkeycodes' utility, where 133 * they needed not before. It does not matter that there are duplicates, as 134 * long as no duplication occurs for any single keyboard. 138 #define FOCUS_PF1 85/* actual code! */ 146 #define FOCUS_PF9 120 147 #define FOCUS_PF10 121 148 #define FOCUS_PF11 122 149 #define FOCUS_PF12 123 152 /* tfj@olivia.ping.dk: 153 * The four keys are located over the numeric keypad, and are 154 * labelled A1-A4. It's an rc930 keyboard, from 155 * Regnecentralen/RC International, Now ICL. 156 * Scancodes: 59, 5a, 5b, 5c. 163 static unsigned char high_keys
[128- SC_LIM
] = { 164 RGN1
, RGN2
, RGN3
, RGN4
,0,0,0,/* 0x59-0x5f */ 165 0,0,0,0,0,0,0,0,/* 0x60-0x67 */ 166 0,0,0,0,0, FOCUS_PF11
,0, FOCUS_PF12
,/* 0x68-0x6f */ 167 0,0,0, FOCUS_PF2
, FOCUS_PF9
,0,0, FOCUS_PF3
,/* 0x70-0x77 */ 168 FOCUS_PF4
, FOCUS_PF5
, FOCUS_PF6
, FOCUS_PF7
,/* 0x78-0x7b */ 169 FOCUS_PF8
, JAP_86
, FOCUS_PF10
,0/* 0x7c-0x7f */ 180 #define E0_KPMINPLUS 118 182 * My OmniKey generates e0 4c for the "OMNI" key and the 183 * right alt key does nada. [kkoller@nyx10.cs.du.edu] 187 * New microsoft keyboard is rumoured to have 188 * e0 5b (left window button), e0 5c (right window button), 189 * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] 190 * [or: Windows_L, Windows_R, TaskMan] 196 /* this can be changed using setkeys : */ 197 static unsigned char e0_keys
[128] = { 198 0,0,0,0,0,0,0,0,/* 0x00-0x07 */ 199 0,0,0,0,0,0,0,0,/* 0x08-0x0f */ 200 0,0,0,0,0,0,0,0,/* 0x10-0x17 */ 201 0,0,0,0, E0_KPENTER
, E0_RCTRL
,0,0,/* 0x18-0x1f */ 202 0,0,0,0,0,0,0,0,/* 0x20-0x27 */ 203 0,0,0,0,0,0,0,0,/* 0x28-0x2f */ 204 0,0,0,0,0, E0_KPSLASH
,0, E0_PRSCR
,/* 0x30-0x37 */ 205 E0_RALT
,0,0,0,0, E0_F13
, E0_F14
, E0_HELP
,/* 0x38-0x3f */ 206 E0_DO
, E0_F17
,0,0,0,0, E0_BREAK
, E0_HOME
,/* 0x40-0x47 */ 207 E0_UP
, E0_PGUP
,0, E0_LEFT
, E0_OK
, E0_RIGHT
, E0_KPMINPLUS
, E0_END
,/* 0x48-0x4f */ 208 E0_DOWN
, E0_PGDN
, E0_INS
, E0_DEL
,0,0,0,0,/* 0x50-0x57 */ 209 0,0,0, E0_MSLW
, E0_MSRW
, E0_MSTM
,0,0,/* 0x58-0x5f */ 210 0,0,0,0,0,0,0,0,/* 0x60-0x67 */ 211 0,0,0,0,0,0,0, E0_MACRO
,/* 0x68-0x6f */ 212 0,0,0,0,0,0,0,0,/* 0x70-0x77 */ 213 0,0,0,0,0,0,0,0/* 0x78-0x7f */ 216 static unsigned int prev_scancode
=0;/* remember E0, E1 */ 218 intq40kbd_setkeycode(unsigned int scancode
,unsigned int keycode
) 220 if(scancode
< SC_LIM
|| scancode
>255|| keycode
>127) 223 high_keys
[scancode
- SC_LIM
] = keycode
; 225 e0_keys
[scancode
-128] = keycode
; 229 intq40kbd_getkeycode(unsigned int scancode
) 232 (scancode
< SC_LIM
|| scancode
>255) ? -EINVAL
: 233 (scancode
<128) ? high_keys
[scancode
- SC_LIM
] : 234 e0_keys
[scancode
-128]; 238 #define disable_keyboard() 239 #define enable_keyboard() 244 intq40kbd_translate(unsigned char scancode
,unsigned char*keycode
, 247 if(scancode
==0xe0|| scancode
==0xe1) { 248 prev_scancode
= scancode
; 254 * usually it will be 0xe0, but a Pause key generates 255 * e1 1d 45 e1 9d c5 when pressed, and nothing when released 257 if(prev_scancode
!=0xe0) { 258 if(prev_scancode
==0xe1&& scancode
==0x1d) { 259 prev_scancode
=0x100; 261 }else if(prev_scancode
==0x100&& scancode
==0x45) { 265 #ifdef KBD_REPORT_UNKN 267 printk(KERN_INFO
"keyboard: unknown e1 escape sequence\n"); 275 * The keyboard maintains its own internal caps lock and 276 * num lock statuses. In caps lock mode E0 AA precedes make 277 * code and E0 2A follows break code. In num lock mode, 278 * E0 2A precedes make code and E0 AA follows break code. 279 * We do our own book-keeping, so we will just ignore these. 282 * For my keyboard there is no caps lock mode, but there are 283 * both Shift-L and Shift-R modes. The former mode generates 284 * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. 285 * So, we should also ignore the latter. - aeb@cwi.nl 287 if(scancode
==0x2a|| scancode
==0x36) 290 if(e0_keys
[scancode
]) 291 *keycode
= e0_keys
[scancode
]; 293 #ifdef KBD_REPORT_UNKN 295 printk(KERN_INFO
"keyboard: unknown scancode e0 %02x\n", 301 }else if(scancode
>= SC_LIM
) { 302 /* This happens with the FOCUS 9000 keyboard 303 Its keys PF1..PF12 are reported to generate 304 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f 305 Moreover, unless repeated, they do not generate 306 key-down events, so we have to zero up_flag below */ 307 /* Also, Japanese 86/106 keyboards are reported to 308 generate 0x73 and 0x7d for \ - and \ | respectively. */ 309 /* Also, some Brazilian keyboard is reported to produce 310 0x73 and 0x7e for \ ? and KP-dot, respectively. */ 312 *keycode
= high_keys
[scancode
- SC_LIM
]; 316 #ifdef KBD_REPORT_UNKN 317 printk(KERN_INFO
"keyboard: unrecognized scancode (%02x)" 318 " - ignored\n", scancode
); 328 charq40kbd_unexpected_up(unsigned char keycode
) 330 /* unexpected, but this can happen: maybe this was a key release for a 331 FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ 332 if(keycode
>= SC_LIM
|| keycode
==85) 341 static voidkeyboard_interrupt(int irq
,void*dev_id
,struct pt_regs
*regs
) 344 unsigned char status
; 347 spin_lock_irqsave(&kbd_controller_lock
, flags
); 350 status
= IRQ_KEYB_MASK
&master_inb(INTERRUPT_REG
); 353 unsigned char scancode
,qcode
; 355 qcode
=master_inb(KEYCODE_REG
); 362 handle_scancode(qprev
,1); 366 scancode
=qprev
? q40ecl
[qcode
] : q40cl
[qcode
]; 368 /* next line is last resort to hanlde some oddities */ 369 if(qprev
&& !scancode
) scancode
=q40cl
[qcode
]; 374 printk("unknown scancode %x\n",qcode
); 377 if(scancode
==0xff)/* SySrq */ 380 handle_scancode(scancode
, ! keyup
); 382 mark_bh(KEYBOARD_BH
); 389 spin_unlock_irqrestore(&kbd_controller_lock
, flags
); 390 master_outb(-1,KEYBOARD_UNLOCK_REG
);/* keyb ints reenabled herewith */ 397 #ifdef CONFIG_MAGIC_SYSRQ 398 intkbd_is_sysrq(unsigned char keycode
) 400 return( keycode
== SYSRQ_KEY
); 402 #endif/* CONFIG_MAGIC_SYSRQ */ 407 #define KBD_NO_DATA (-1)/* No data */ 408 #define KBD_BAD_DATA (-2)/* Parity or other error */ 410 static int __init
kbd_read_input(void) 412 int retval
= KBD_NO_DATA
; 413 unsigned char status
; 415 status
= IRQ_KEYB_MASK
&master_inb(INTERRUPT_REG
); 417 unsigned char data
=master_inb(KEYCODE_REG
); 420 master_outb(-1,KEYBOARD_UNLOCK_REG
); 425 externvoidq40kbd_leds(unsigned char leds
) 426 {/* nothing can be done */} 428 static void __init
kbd_clear_input(void) 430 int maxread
=100;/* Random number */ 433 if(kbd_read_input() == KBD_NO_DATA
) 439 void __init
q40kbd_init_hw(void) 442 /* Get the keyboard controller registers (incomplete decode) */ 443 request_region(0x60,16,"keyboard"); 445 /* Flush any pending input. */ 448 /* Ok, finally allocate the IRQ, and off we go.. */ 449 request_irq(Q40_IRQ_KEYBOARD
, keyboard_interrupt
,0,"keyboard", NULL
); 450 master_outb(-1,KEYBOARD_UNLOCK_REG
); 451 master_outb(1,KEY_IRQ_ENABLE_REG
);