1/*
2 *  linux/drivers/acorn/char/keyb_ps2.c
3 *
4 *  Copyright (C) 2000 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 *  Keyboard driver for RiscPC ARM Linux.
11 *
12 *  Note!!! This driver talks directly to the keyboard.
13 */
14#include <linux/config.h>
15#include <linux/sched.h>
16#include <linux/interrupt.h>
17#include <linux/tty.h>
18#include <linux/tty_flip.h>
19#include <linux/mm.h>
20#include <linux/slab.h>
21#include <linux/ptrace.h>
22#include <linux/signal.h>
23#include <linux/timer.h>
24#include <linux/random.h>
25#include <linux/ctype.h>
26#include <linux/kbd_ll.h>
27#include <linux/delay.h>
28#include <linux/init.h>
29
30#include <asm/bitops.h>
31#include <asm/irq.h>
32#include <asm/hardware.h>
33#include <asm/keyboard.h>
34#include <asm/io.h>
35#include <asm/hardware/iomd.h>
36#include <asm/system.h>
37
38extern struct tasklet_struct keyboard_tasklet;
39extern void kbd_reset_kdown(void);
40int kbd_read_mask;
41
42#define TX_DONE 0
43#define TX_SENT 1
44#define TX_SEND 2
45
46static volatile int tx_state;
47
48#define VERSION 100
49
50#define KBD_REPORT_ERR
51#define KBD_REPORT_UNKN
52
53#define KBD_ESCAPEE0	0xe0		/* in */
54#define KBD_ESCAPEE1	0xe1		/* in */
55
56#define ESCE0(x)	(0xe000|(x))
57#define ESCE1(x)	(0xe100|(x))
58
59#define KBD_BAT		0xaa		/* in */
60#define KBD_SETLEDS	0xed		/* out */
61#define KBD_ECHO	0xee		/* in/out */
62#define KBD_BREAK	0xf0		/* in */
63#define KBD_TYPRATEDLY	0xf3		/* out */
64#define KBD_SCANENABLE	0xf4		/* out */
65#define KBD_DEFDISABLE	0xf5		/* out */
66#define KBD_DEFAULT	0xf6		/* out */
67#define KBD_ACK		0xfa		/* in */
68#define KBD_DIAGFAIL	0xfd		/* in */
69#define KBD_RESEND	0xfe		/* in/out */
70#define KBD_RESET	0xff		/* out */
71
72#define CODE_BREAK	1
73#define CODE_ESCAPEE0	2
74#define CODE_ESCAPEE1	4
75#define CODE_ESCAPE12	8
76
77#define K_NONE		0x7f
78#define K_ESC		0x00
79#define K_F1		0x01
80#define K_F2		0x02
81#define K_F3		0x03
82#define K_F4		0x04
83#define K_F5		0x05
84#define K_F6		0x06
85#define K_F7		0x07
86#define K_F8		0x08
87#define K_F9		0x09
88#define K_F10		0x0a
89#define K_F11		0x0b
90#define K_F12		0x0c
91#define K_PRNT		0x0d
92#define K_SCRL		0x0e
93#define K_BRK		0x0f
94#define K_AGR		0x10
95#define K_1		0x11
96#define K_2		0x12
97#define K_3		0x13
98#define K_4		0x14
99#define K_5		0x15
100#define K_6		0x16
101#define K_7		0x17
102#define K_8		0x18
103#define K_9		0x19
104#define K_0		0x1a
105#define K_MINS		0x1b
106#define K_EQLS		0x1c
107#define K_BKSP		0x1e
108#define K_INS		0x1f
109#define K_HOME		0x20
110#define K_PGUP		0x21
111#define K_NUML		0x22
112#define KP_SLH		0x23
113#define KP_STR		0x24
114#define KP_MNS		0x3a
115#define K_TAB		0x26
116#define K_Q		0x27
117#define K_W		0x28
118#define K_E		0x29
119#define K_R		0x2a
120#define K_T		0x2b
121#define K_Y		0x2c
122#define K_U		0x2d
123#define K_I		0x2e
124#define K_O		0x2f
125#define K_P		0x30
126#define K_LSBK		0x31
127#define K_RSBK		0x32
128#define K_ENTR		0x47
129#define K_DEL		0x34
130#define K_END		0x35
131#define K_PGDN		0x36
132#define KP_7		0x37
133#define KP_8		0x38
134#define KP_9		0x39
135#define KP_PLS		0x4b
136#define K_CAPS		0x5d
137#define K_A		0x3c
138#define K_S		0x3d
139#define K_D		0x3e
140#define K_F		0x3f
141#define K_G		0x40
142#define K_H		0x41
143#define K_J		0x42
144#define K_K		0x43
145#define K_L		0x44
146#define K_SEMI		0x45
147#define K_SQOT		0x46
148#define K_HASH		0x1d
149#define KP_4		0x48
150#define KP_5		0x49
151#define KP_6		0x4a
152#define K_LSFT		0x4c
153#define K_BSLH		0x33
154#define K_Z		0x4e
155#define K_X		0x4f
156#define K_C		0x50
157#define K_V		0x51
158#define K_B		0x52
159#define K_N		0x53
160#define K_M		0x54
161#define K_COMA		0x55
162#define K_DOT		0x56
163#define K_FSLH		0x57
164#define K_RSFT		0x58
165#define K_UP		0x59
166#define KP_1		0x5a
167#define KP_2		0x5b
168#define KP_3		0x5c
169#define KP_ENT		0x67
170#define K_LCTL		0x3b
171#define K_LALT		0x5e
172#define K_SPCE		0x5f
173#define K_RALT		0x60
174#define K_RCTL		0x61
175#define K_LEFT		0x62
176#define K_DOWN		0x63
177#define K_RGHT		0x64
178#define KP_0		0x65
179#define KP_DOT		0x66
180
181static unsigned char keycode_translate[256] =
182{
183/* 00 */  K_NONE, K_F9  , K_NONE, K_F5  , K_F3  , K_F1  , K_F2  , K_F12 ,
184/* 08 */  K_NONE, K_F10 , K_F8  , K_F6  , K_F4  , K_TAB , K_AGR , K_NONE,
185/* 10 */  K_NONE, K_LALT, K_LSFT, K_NONE, K_LCTL, K_Q   , K_1   , K_NONE,
186/* 18 */  K_NONE, K_NONE, K_Z   , K_S   , K_A   , K_W   , K_2   , K_NONE,
187/* 20 */  K_NONE, K_C   , K_X   , K_D   , K_E   , K_4   , K_3   , K_NONE,
188/* 28 */  K_NONE, K_SPCE, K_V   , K_F   , K_T   , K_R   , K_5   , K_NONE,
189/* 30 */  K_NONE, K_N   , K_B   , K_H   , K_G   , K_Y   , K_6   , K_NONE,
190/* 38 */  K_NONE, K_NONE, K_M   , K_J   , K_U   , K_7   , K_8   , K_NONE,
191/* 40 */  K_NONE, K_COMA, K_K   , K_I   , K_O   , K_0   , K_9   , K_NONE,
192/* 48 */  K_NONE, K_DOT , K_FSLH, K_L   , K_SEMI, K_P   , K_MINS, K_NONE,
193/* 50 */  K_NONE, K_NONE, K_SQOT, K_NONE, K_LSBK, K_EQLS, K_NONE, K_NONE,
194/* 58 */  K_CAPS, K_RSFT, K_ENTR, K_RSBK, K_NONE, K_HASH, K_NONE, K_NONE,
195/* 60 */  K_NONE, K_BSLH, K_NONE, K_NONE, K_NONE, K_NONE, K_BKSP, K_NONE,
196/* 68 */  K_NONE, KP_1  , K_NONE, KP_4  , KP_7  , K_NONE, K_NONE, K_NONE,
197/* 70 */  KP_0  , KP_DOT, KP_2  , KP_5  , KP_6  , KP_8  , K_ESC , K_NUML,
198/* 78 */  K_F11 , KP_PLS, KP_3  , KP_MNS, KP_STR, KP_9  , K_SCRL, K_NONE,
199	  K_NONE, K_NONE, K_NONE, K_F7  , K_NONE, K_NONE, K_NONE, K_NONE,
200	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
201	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
202	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
203	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
204	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
205	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
206	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
207	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
208	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
209	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
210	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
211	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
212	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE
213};
214
215#ifdef CONFIG_MAGIC_SYSRQ
216static unsigned char ps2kbd_sysrq_xlate[] =
217{
218    27,    0,    0,    0,    0,    0,    0,    0,
219     0,    0,    0,    0,    0,    0,    0,    0,
220   '`',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
221   '8',  '9',  '0',  '-',  '=',  '�',  127,    0,
222     0,    0,    0,  '/',  '*',  '#',    9,  'q',
223   'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',
224   'p',  '[',  ']', '\\',  22,    23,   25,  '7',
225   '8',  '9',  '-',    0,  'a',  's',  'd',  'f',
226   'g',  'h',  'j',  'k',  'l',  ';', '\'',   13,
227   '4',  '5',  '6',  '+',    0,    0,  'z',  'x',
228   'c',  'v',  'b',  'n',  'm',  ',',  '.',  '/',
229     0,    0,  '1',  '2',  '3',    0,    0,  ' ',
230     0,    0,    0,    0,    0,  '0',  '.',   10,
231     0,    0,    0,    0,    0,    0,    0,    0,
232     0,    0,    0,    0,    0,    0,    0,    0,
233     0,    0,    0,    0,    0,    0,    0,    0,
234};
235#endif
236
237static inline void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
238{
239	handle_scancode(keycode, !up_flag);
240}
241
242static inline void ps2kbd_sendbyte(unsigned char val)
243{
244	int tries = 3, timeout = 1000;
245
246	tx_state = TX_SEND;
247
248	do {
249		switch (tx_state) {
250		case TX_SEND:
251			tx_state = TX_SENT;
252			timeout = 1000;
253			tries --;
254
255			while(!(iomd_readb(IOMD_KCTRL) & (1 << 7)));
256			iomd_writeb(val, IOMD_KARTTX);
257			break;
258
259		case TX_SENT:
260			udelay(1000);
261			if (--timeout == 0) {
262				printk(KERN_ERR "Keyboard timeout\n");
263				tx_state = TX_DONE;
264			}
265			break;
266
267		case TX_DONE:
268			break;
269		}
270	} while (tries > 0 && tx_state != TX_DONE);
271}
272
273static unsigned char status;
274static unsigned char ncodes;
275static unsigned char bi;
276static unsigned char buffer[4];
277
278static inline void ps2kbd_reset(void)
279{
280	status = 0;
281	kbd_reset_kdown();
282}
283
284static void handle_rawcode(int keyval)
285{
286	int keysym;
287
288	if (keyval > 0x83) {
289		switch (keyval) {
290		case KBD_ESCAPEE0:
291			ncodes = 2;
292			bi = 0;
293			break;
294
295		case KBD_ESCAPEE1:
296			ncodes = 3;
297			bi = 0;
298			break;
299
300		case KBD_ACK:
301			tx_state = TX_DONE;
302			return;
303
304		case KBD_RESEND:
305			tx_state = TX_SEND;
306			return;
307
308		case KBD_BREAK:
309			status |= CODE_BREAK;
310			return;
311
312		default:
313			return;
314		}
315	}
316
317	if (ncodes) {
318		buffer[bi++] = keyval;
319		ncodes -= 1;
320		if (ncodes)
321			return;
322		keysym = K_NONE;
323		switch (buffer[0] << 8 | buffer[1]) {
324		case ESCE0(0x11): keysym = K_RALT; break;
325		case ESCE0(0x14): keysym = K_RCTL; break;
326		/*
327		 * take care of MS extra keys (actually
328		 * 0x7d - 0x7f, but last one is already K_NONE
329		 */
330		case ESCE0(0x1f): keysym = 124;    break;
331		case ESCE0(0x27): keysym = 125;    break;
332		case ESCE0(0x2f): keysym = 126;    break;
333		case ESCE0(0x4a): keysym = KP_SLH; break;
334		case ESCE0(0x5a): keysym = KP_ENT; break;
335		case ESCE0(0x69): keysym = K_END;  break;
336		case ESCE0(0x6b): keysym = K_LEFT; break;
337		case ESCE0(0x6c): keysym = K_HOME; break;
338		case ESCE0(0x70): keysym = K_INS;  break;
339		case ESCE0(0x71): keysym = K_DEL;  break;
340		case ESCE0(0x72): keysym = K_DOWN; break;
341		case ESCE0(0x74): keysym = K_RGHT; break;
342		case ESCE0(0x75): keysym = K_UP;   break;
343		case ESCE0(0x7a): keysym = K_PGDN; break;
344		case ESCE0(0x7c): keysym = K_PRNT; break;
345		case ESCE0(0x7d): keysym = K_PGUP; break;
346		case ESCE1(0x14):
347			if (buffer[2] == 0x77)
348				keysym = K_BRK;
349			break;
350		case ESCE0(0x12):		/* ignore escaped shift key */
351			status = 0;
352			return;
353		}
354	} else {
355		bi = 0;
356		keysym = keycode_translate[keyval];
357	}
358
359	if (keysym != K_NONE)
360		ps2kbd_key(keysym, status & CODE_BREAK);
361	status = 0;
362}
363
364static void ps2kbd_leds(unsigned char leds)
365{
366	ps2kbd_sendbyte(KBD_SETLEDS);
367	ps2kbd_sendbyte(leds);
368	ps2kbd_sendbyte(KBD_SCANENABLE);
369}
370
371static void ps2kbd_rx(int irq, void *dev_id, struct pt_regs *regs)
372{
373	kbd_pt_regs = regs;
374
375	while (iomd_readb(IOMD_KCTRL) & (1 << 5))
376		handle_rawcode(iomd_readb(IOMD_KARTRX));
377	tasklet_schedule(&keyboard_tasklet);
378}
379
380static void ps2kbd_tx(int irq, void *dev_id, struct pt_regs *regs)
381{
382}
383
384static int ps2kbd_translate(unsigned char scancode, unsigned char *keycode, char rawmode)
385{
386	*keycode = scancode;
387	return 1;
388}
389
390static char ps2kbd_unexpected_up(unsigned char scancode)
391{
392	return 0200;
393}
394
395int __init ps2kbd_init_hw(void)
396{
397	/* Reset the keyboard state machine. */
398	iomd_writeb(0, IOMD_KCTRL);
399	iomd_writeb(8, IOMD_KCTRL);
400	iomd_readb(IOMD_KARTRX);
401
402	if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0)
403		panic("Could not allocate keyboard receive IRQ!");
404	if (request_irq (IRQ_KEYBOARDTX, ps2kbd_tx, 0, "keyboard", NULL) != 0)
405		panic("Could not allocate keyboard transmit IRQ!");
406
407	k_translate	= ps2kbd_translate;
408	k_unexpected_up	= ps2kbd_unexpected_up;
409	k_leds		= ps2kbd_leds;
410#ifdef CONFIG_MAGIC_SYSRQ
411	k_sysrq_xlate	= ps2kbd_sysrq_xlate;
412	k_sysrq_key	= 13;
413#endif
414
415	return 0;
416}
417