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
40 unsigned 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 
53 unsigned 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  */
75 static 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 
96 static 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 
162 static 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 : */
196 static 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 
q40kbd_setkeycode(unsigned int scancode,unsigned int keycode)216 int 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 
q40kbd_getkeycode(unsigned int scancode)227 int 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 
q40kbd_translate(unsigned char scancode,unsigned char * keycode,char raw_mode)242 int 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 
q40kbd_unexpected_up(unsigned char keycode)337 char 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 
347 static int keyup=0;
348 static int qprev=0;
349 
keyboard_interrupt(int irq,void * dev_id,struct pt_regs * regs)350 static 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 	  }
394 exit:
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 
q40kbd_read_input(void)403 static 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 
kbd_clear_input(void)419 static 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 
q40kbd_init_hw(void)430 int __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