- Kai Germaschewski: ymfpci cleanups and resource leak fixes
[davej-history.git] / drivers / char / q40_keyb.c
blob22c981b79aa1438ed826d3895830888be6dd39be
1 /*
2 * linux/drivers/char/q40_keyb.c
4 */
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>
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>
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>
34 /* Some configuration switches are present in the include file... */
36 #define KBD_REPORT_ERR
38 /* Simple translation table for the SysRq keys */
40 #define SYSRQ_KEY 0x54
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
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 */
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 */
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*/
99 static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
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).
109 * For 1-88 keycode equals scancode.
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
129 #define E1_PAUSE 119
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.
138 #define SC_LIM 89
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
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.
160 #define RGN1 124
161 #define RGN2 125
162 #define RGN3 126
163 #define RGN4 127
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 */
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
184 * My OmniKey generates e0 4c for the "OMNI" key and the
185 * right alt key does nada. [kkoller@nyx10.cs.du.edu]
187 #define E0_OK 124
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]
194 #define E0_MSLW 125
195 #define E0_MSRW 126
196 #define E0_MSTM 127
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 */
218 static unsigned int prev_scancode = 0; /* remember E0, E1 */
220 int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode)
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;
231 int q40kbd_getkeycode(unsigned int scancode)
233 return
234 (scancode < SC_LIM || scancode > 255) ? -EINVAL :
235 (scancode < 128) ? high_keys[scancode - SC_LIM] :
236 e0_keys[scancode - 128];
240 #define disable_keyboard()
241 #define enable_keyboard()
246 int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
247 char raw_mode)
249 if (scancode == 0xe0 || scancode == 0xe1) {
250 prev_scancode = scancode;
251 return 0;
254 if (prev_scancode) {
256 * usually it will be 0xe0, but a Pause key generates
257 * e1 1d 45 e1 9d c5 when pressed, and nothing when released
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;
274 } else {
275 prev_scancode = 0;
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.
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
289 if (scancode == 0x2a || scancode == 0x36)
290 return 0;
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;
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. */
314 *keycode = high_keys[scancode - SC_LIM];
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
323 return 0;
325 } else
326 *keycode = scancode;
327 return 1;
330 char q40kbd_unexpected_up(unsigned char keycode)
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;
340 static int keyup=0;
341 static int qprev=0;
343 static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
345 unsigned char status;
347 spin_lock(&kbd_controller_lock);
348 kbd_pt_regs = regs;
350 status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
351 if (status )
353 unsigned char scancode,qcode;
355 qcode = master_inb(KEYCODE_REG);
357 if (qcode != 0xf0)
359 if (qcode == 0xe0)
361 qprev=0xe0;
362 handle_scancode(qprev , 1);
363 goto exit;
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)
374 printk("unknown scancode %x\n",qcode);
375 goto exit;
377 if (scancode==0xff) /* SySrq */
378 scancode=SYSRQ_KEY;
380 handle_scancode(scancode, ! keyup );
381 keyup=0;
382 tasklet_schedule(&keyboard_tasklet);
384 else
385 keyup=1;
387 exit:
388 spin_unlock(&kbd_controller_lock);
389 master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */
393 #define KBD_NO_DATA (-1) /* No data */
394 #define KBD_BAD_DATA (-2) /* Parity or other error */
396 static int __init kbd_read_input(void)
398 int retval = KBD_NO_DATA;
399 unsigned char status;
401 status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
402 if (status) {
403 unsigned char data = master_inb(KEYCODE_REG);
405 retval = data;
406 master_outb(-1,KEYBOARD_UNLOCK_REG);
408 return retval;
411 extern void q40kbd_leds(unsigned char leds)
412 { /* nothing can be done */ }
414 static void __init kbd_clear_input(void)
416 int maxread = 100; /* Random number */
418 do {
419 if (kbd_read_input() == KBD_NO_DATA)
420 break;
421 } while (--maxread);
425 void __init q40kbd_init_hw(void)
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();
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);