1#include <linux/keyboard.h>
2
3#include "defkeymap.c"	/* yeah I know it's bad -- Cort */
4
5
6unsigned char shfts, ctls, alts, caps;
7
8#define	KBDATAP		0x60	/* kbd data port */
9#define	KBSTATUSPORT	0x61	/* kbd status */
10#define	KBSTATP		0x64	/* kbd status port */
11#define	KBINRDY		0x01
12#define	KBOUTRDY	0x02
13
14extern unsigned char inb(int port);
15extern void outb(int port, char val);
16extern void puts(const char *);
17extern void puthex(unsigned long val);
18extern void udelay(long x);
19
20static int kbd(int noblock)
21{
22	unsigned char dt, brk, val;
23	unsigned code;
24loop:
25	if (noblock) {
26	    if ((inb(KBSTATP) & KBINRDY) == 0)
27		return (-1);
28	} else while((inb(KBSTATP) & KBINRDY) == 0) ;
29
30	dt = inb(KBDATAP);
31
32	brk = dt & 0x80;	/* brk == 1 on key release */
33	dt = dt & 0x7f;		/* keycode */
34
35	if (shfts)
36	    code = shift_map[dt];
37	else if (ctls)
38	    code = ctrl_map[dt];
39	else
40	    code = plain_map[dt];
41
42	val = KVAL(code);
43	switch (KTYP(code) & 0x0f) {
44	    case KT_LATIN:
45		if (brk)
46		    break;
47		if (alts)
48		    val |= 0x80;
49		if (val == 0x7f)	/* map delete to backspace */
50		    val = '\b';
51		return val;
52
53	    case KT_LETTER:
54		if (brk)
55		    break;
56		if (caps)
57		    val -= 'a'-'A';
58		return val;
59
60	    case KT_SPEC:
61		if (brk)
62		    break;
63		if (val == KVAL(K_CAPS))
64		    caps = !caps;
65		else if (val == KVAL(K_ENTER)) {
66enter:		    /* Wait for key up */
67		    while (1) {
68			while((inb(KBSTATP) & KBINRDY) == 0) ;
69			dt = inb(KBDATAP);
70			if (dt & 0x80) /* key up */ break;
71		    }
72		    return 10;
73		}
74		break;
75
76	    case KT_PAD:
77		if (brk)
78		    break;
79		if (val < 10)
80		    return val;
81		if (val == KVAL(K_PENTER))
82		    goto enter;
83		break;
84
85	    case KT_SHIFT:
86		switch (val) {
87		    case KG_SHIFT:
88		    case KG_SHIFTL:
89		    case KG_SHIFTR:
90			shfts = brk ? 0 : 1;
91			break;
92		    case KG_ALT:
93		    case KG_ALTGR:
94			alts = brk ? 0 : 1;
95			break;
96		    case KG_CTRL:
97		    case KG_CTRLL:
98		    case KG_CTRLR:
99			ctls = brk ? 0 : 1;
100			break;
101		}
102		break;
103
104	    case KT_LOCK:
105		switch (val) {
106		    case KG_SHIFT:
107		    case KG_SHIFTL:
108		    case KG_SHIFTR:
109			if (brk)
110			    shfts = !shfts;
111			break;
112		    case KG_ALT:
113		    case KG_ALTGR:
114			if (brk)
115			    alts = !alts;
116			break;
117		    case KG_CTRL:
118		    case KG_CTRLL:
119		    case KG_CTRLR:
120			if (brk)
121			    ctls = !ctls;
122			break;
123		}
124		break;
125	}
126	if (brk) return (-1);  /* Ignore initial 'key up' codes */
127	goto loop;
128}
129
130static int __kbdreset(void)
131{
132	unsigned char c;
133	int i, t;
134
135	/* flush input queue */
136	t = 2000;
137	while ((inb(KBSTATP) & KBINRDY))
138	{
139		(void)inb(KBDATAP);
140		if (--t == 0)
141			return 1;
142	}
143	/* Send self-test */
144	t = 20000;
145	while (inb(KBSTATP) & KBOUTRDY)
146		if (--t == 0)
147			return 2;
148	outb(KBSTATP,0xAA);
149	t = 200000;
150	while ((inb(KBSTATP) & KBINRDY) == 0)	/* wait input ready */
151		if (--t == 0)
152			return 3;
153	if ((c = inb(KBDATAP)) != 0x55)
154	{
155		puts("Keyboard self test failed - result:");
156		puthex(c);
157		puts("\n");
158	}
159	/* Enable interrupts and keyboard controller */
160	t = 20000;
161	while (inb(KBSTATP) & KBOUTRDY)
162		if (--t == 0) return 4;
163	outb(KBSTATP,0x60);
164	t = 20000;
165	while (inb(KBSTATP) & KBOUTRDY)
166		if (--t == 0) return 5;
167	outb(KBDATAP,0x45);
168	for (i = 0;  i < 10000;  i++) udelay(1);
169
170	t = 20000;
171	while (inb(KBSTATP) & KBOUTRDY)
172		if (--t == 0) return 6;
173	outb(KBSTATP,0x20);
174	t = 200000;
175	while ((inb(KBSTATP) & KBINRDY) == 0)	/* wait input ready */
176		if (--t == 0) return 7;
177	if (! (inb(KBDATAP) & 0x40)) {
178		/*
179		 * Quote from PS/2 System Reference Manual:
180		 *
181		 * "Address hex 0060 and address hex 0064 should be
182		 * written only when the input-buffer-full bit and
183		 * output-buffer-full bit in the Controller Status
184		 * register are set 0." (KBINRDY and KBOUTRDY)
185		 */
186		t = 200000;
187		while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
188			if (--t == 0) return 8;
189		outb(KBDATAP,0xF0);
190		t = 200000;
191		while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
192			if (--t == 0) return 9;
193		outb(KBDATAP,0x01);
194	}
195	t = 20000;
196	while (inb(KBSTATP) & KBOUTRDY)
197		if (--t == 0) return 10;
198	outb(KBSTATP,0xAE);
199	return 0;
200}
201
202static void kbdreset(void)
203{
204	int ret = __kbdreset();
205
206	if (ret) {
207		puts("__kbdreset failed: ");
208		puthex(ret);
209		puts("\n");
210	}
211}
212
213/* We have to actually read the keyboard when CRT_tstc is called,
214 * since the pending data might be a key release code, and therefore
215 * not valid data.  In this case, kbd() will return -1, even though there's
216 * data to be read.  Of course, we might actually read a valid key press,
217 * in which case it gets queued into key_pending for use by CRT_getc.
218 */
219
220static int kbd_reset = 0;
221
222static int key_pending = -1;
223
224int CRT_getc(void)
225{
226	int c;
227	if (!kbd_reset) {kbdreset(); kbd_reset++; }
228
229        if (key_pending != -1) {
230                c = key_pending;
231                key_pending = -1;
232                return c;
233        } else {
234	while ((c = kbd(0)) == 0) ;
235                return c;
236        }
237}
238
239int CRT_tstc(void)
240{
241	if (!kbd_reset) {kbdreset(); kbd_reset++; }
242
243        while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) {
244                key_pending = kbd(1);
245        }
246
247        return (key_pending != -1);
248}
249