Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"io.h"
7
#include	"../port/error.h"
8
 
9
enum {
10
	Data=		0x60,		/* data port */
11
 
12
	Status=		0x64,		/* status port */
13
	 Inready=	0x01,		/*  input character ready */
14
	 Outbusy=	0x02,		/*  output busy */
15
	 Sysflag=	0x04,		/*  system flag */
16
	 Cmddata=	0x08,		/*  cmd==0, data==1 */
17
	 Inhibit=	0x10,		/*  keyboard/mouse inhibited */
18
	 Minready=	0x20,		/*  mouse character ready */
19
	 Rtimeout=	0x40,		/*  general timeout */
20
	 Parity=	0x80,
21
 
22
	Cmd=		0x64,		/* command port (write only) */
23
 
24
	Spec=		0x80,
25
 
26
	PF=		Spec|0x20,	/* num pad function key */
27
	View=		Spec|0x00,	/* view (shift window up) */
28
	KF=		0xF000,	/* function key (begin Unicode private space) */
29
	Shift=		Spec|0x60,
30
	Break=		Spec|0x61,
31
	Ctrl=		Spec|0x62,
32
	Latin=		Spec|0x63,
33
	Caps=		Spec|0x64,
34
	Num=		Spec|0x65,
35
	Middle=		Spec|0x66,
36
	No=		0x00,		/* peter */
37
 
38
	Home=		KF|13,
39
	Up=		KF|14,
40
	Pgup=		KF|15,
41
	Print=		KF|16,
42
	Left=		KF|17,
43
	Right=		KF|18,
44
	End=		'\r',
45
	Down=		View,
46
	Pgdown=		KF|19,
47
	Ins=		KF|20,
48
	Del=		0x7F,
49
	Scroll=		KF|21,
50
};
51
 
52
/*
53
 * The codes at 0x79 and 0x81 are produed by the PFU Happy Hacking keyboard.
54
 * A 'standard' keyboard doesn't produce anything above 0x58.
55
 */
56
Rune kbtab[] = 
57
{
58
[0x00]	No,	0x1b,	'1',	'2',	'3',	'4',	'5',	'6',
59
[0x08]	'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
60
[0x10]	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
61
[0x18]	'o',	'p',	'[',	']',	'\n',	Ctrl,	'a',	's',
62
[0x20]	'd',	'f',	'g',	'h',	'j',	'k',	'l',	';',
63
[0x28]	'\'',	'`',	Shift,	'\\',	'z',	'x',	'c',	'v',
64
[0x30]	'b',	'n',	'm',	',',	'.',	'/',	Shift,	'*',
65
[0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
66
[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
67
[0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
68
[0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
69
[0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
70
[0x60]	No,	No,	No,	No,	No,	No,	No,	No,
71
[0x68]	No,	No,	No,	No,	No,	No,	No,	No,
72
[0x70]	No,	No,	No,	No,	No,	No,	No,	No,
73
[0x78]	No,	View,	No,	Up,	No,	No,	No,	No,
74
};
75
 
76
Rune kbtabshift[] =
77
{
78
[0x00]	No,	0x1b,	'!',	'@',	'#',	'$',	'%',	'^',
79
[0x08]	'&',	'*',	'(',	')',	'_',	'+',	'\b',	'\t',
80
[0x10]	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I',
81
[0x18]	'O',	'P',	'{',	'}',	'\n',	Ctrl,	'A',	'S',
82
[0x20]	'D',	'F',	'G',	'H',	'J',	'K',	'L',	':',
83
[0x28]	'"',	'~',	Shift,	'|',	'Z',	'X',	'C',	'V',
84
[0x30]	'B',	'N',	'M',	'<',	'>',	'?',	Shift,	'*',
85
[0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
86
[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
87
[0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
88
[0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
89
[0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
90
[0x60]	No,	No,	No,	No,	No,	No,	No,	No,
91
[0x68]	No,	No,	No,	No,	No,	No,	No,	No,
92
[0x70]	No,	No,	No,	No,	No,	No,	No,	No,
93
[0x78]	No,	Up,	No,	Up,	No,	No,	No,	No,
94
};
95
 
96
Rune kbtabesc1[] =
97
{
98
[0x00]	No,	No,	No,	No,	No,	No,	No,	No,
99
[0x08]	No,	No,	No,	No,	No,	No,	No,	No,
100
[0x10]	No,	No,	No,	No,	No,	No,	No,	No,
101
[0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
102
[0x20]	No,	No,	No,	No,	No,	No,	No,	No,
103
[0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
104
[0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
105
[0x38]	Latin,	No,	No,	No,	No,	No,	No,	No,
106
[0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
107
[0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
108
[0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
109
[0x58]	No,	No,	No,	No,	No,	No,	No,	No,
110
[0x60]	No,	No,	No,	No,	No,	No,	No,	No,
111
[0x68]	No,	No,	No,	No,	No,	No,	No,	No,
112
[0x70]	No,	No,	No,	No,	No,	No,	No,	No,
113
[0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
114
};
115
 
116
enum
117
{
118
	/* controller command byte */
119
	Cscs1=		(1<<6),		/* scan code set 1 */
120
	Cauxdis=	(1<<5),		/* mouse disable */
121
	Ckbddis=	(1<<4),		/* kbd disable */
122
	Csf=		(1<<2),		/* system flag */
123
	Cauxint=	(1<<1),		/* mouse interrupt enable */
124
	Ckbdint=	(1<<0),		/* kbd interrupt enable */
125
};
126
 
127
static Lock i8042lock;
128
static uchar ccc;
129
static void (*auxputc)(int, int);
130
 
131
/*
132
 *  wait for output no longer busy
133
 */
134
static int
135
outready(void)
136
{
137
	int tries;
138
 
139
	for(tries = 0; (inb(Status) & Outbusy); tries++){
140
		if(tries > 500)
141
			return -1;
142
		delay(2);
143
	}
144
	return 0;
145
}
146
 
147
/*
148
 *  wait for input
149
 */
150
static int
151
inready(void)
152
{
153
	int tries;
154
 
155
	for(tries = 0; !(inb(Status) & Inready); tries++){
156
		if(tries > 500)
157
			return -1;
158
		delay(2);
159
	}
160
	return 0;
161
}
162
 
163
/*
164
 *  ask 8042 to reset the machine
165
 */
166
void
167
i8042reset(void)
168
{
169
	ushort *s = KADDR(0x472);
170
	int i, x;
171
 
172
	*s = 0x1234;		/* BIOS warm-boot flag */
173
 
174
	/*
175
	 *  newer reset the machine command
176
	 */
177
	outready();
178
	outb(Cmd, 0xFE);
179
	outready();
180
 
181
	/*
182
	 *  Pulse it by hand (old somewhat reliable)
183
	 */
184
	x = 0xDF;
185
	for(i = 0; i < 5; i++){
186
		x ^= 1;
187
		outready();
188
		outb(Cmd, 0xD1);
189
		outready();
190
		outb(Data, x);	/* toggle reset */
191
		delay(100);
192
	}
193
}
194
 
195
int
196
i8042auxcmd(int cmd)
197
{
198
	unsigned int c;
199
	int tries;
200
 
201
	c = 0;
202
	tries = 0;
203
 
204
	ilock(&i8042lock);
205
	do{
206
		if(tries++ > 2)
207
			break;
208
		if(outready() < 0)
209
			break;
210
		outb(Cmd, 0xD4);
211
		if(outready() < 0)
212
			break;
213
		outb(Data, cmd);
214
		if(outready() < 0)
215
			break;
216
		if(inready() < 0)
217
			break;
218
		c = inb(Data);
219
	} while(c == 0xFE || c == 0);
220
	iunlock(&i8042lock);
221
 
222
	if(c != 0xFA){
223
		print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
224
		return -1;
225
	}
226
	return 0;
227
}
228
 
229
/*
230
 *  keyboard interrupt
231
 */
232
static void
233
i8042intr(Ureg*, void*)
234
{
235
	int s, c, i;
236
	static int esc1, esc2;
237
	static int alt, caps, ctl, num, shift;
238
	static int collecting, nk;
239
	static Rune kc[5];
240
	int keyup;
241
 
242
	/*
243
	 *  get status
244
	 */
245
	lock(&i8042lock);
246
	s = inb(Status);
247
	if(!(s&Inready)){
248
		unlock(&i8042lock);
249
		return;
250
	}
251
 
252
	/*
253
	 *  get the character
254
	 */
255
	c = inb(Data);
256
	unlock(&i8042lock);
257
 
258
	/*
259
	 *  if it's the aux port...
260
	 */
261
	if(s & Minready){
262
		if(auxputc != nil)
263
			auxputc(c, shift);
264
		return;
265
	}
266
 
267
	/*
268
	 *  e0's is the first of a 2 character sequence
269
	 */
270
	if(c == 0xe0){
271
		esc1 = 1;
272
		return;
273
	} else if(c == 0xe1){
274
		esc2 = 2;
275
		return;
276
	}
277
 
278
	keyup = c&0x80;
279
	c &= 0x7f;
280
	if(c > sizeof kbtab){
281
		c |= keyup;
282
		if(c != 0xFF)	/* these come fairly often: CAPSLOCK U Y */
283
			print("unknown key %ux\n", c);
284
		return;
285
	}
286
 
287
	if(esc1){
288
		c = kbtabesc1[c];
289
		esc1 = 0;
290
	} else if(esc2){
291
		esc2--;
292
		return;
293
	} else if(shift)
294
		c = kbtabshift[c];
295
	else
296
		c = kbtab[c];
297
 
298
	if(caps && c<='z' && c>='a')
299
		c += 'A' - 'a';
300
 
301
	/*
302
	 *  keyup only important for shifts
303
	 */
304
	if(keyup){
305
		switch(c){
306
		case Latin:
307
			alt = 0;
308
			break;
309
		case Shift:
310
			shift = 0;
311
			break;
312
		case Ctrl:
313
			ctl = 0;
314
			break;
315
		}
316
		return;
317
	}
318
 
319
	/*
320
 	 *  normal character
321
	 */
322
	if(!(c & (Spec|KF))){
323
		if(ctl){
324
			if(alt && c == Del)
325
				exit(0);
326
			c &= 0x1f;
327
		}
328
		if(!collecting){
329
			kbdputc(kbdq, c);
330
			return;
331
		}
332
		kc[nk++] = c;
333
		c = latin1(kc, nk);
334
		if(c < -1)	/* need more keystrokes */
335
			return;
336
		if(c != -1)	/* valid sequence */
337
			kbdputc(kbdq, c);
338
		else	/* dump characters */
339
			for(i=0; i<nk; i++)
340
				kbdputc(kbdq, kc[i]);
341
		nk = 0;
342
		collecting = 0;
343
		return;
344
	} else {
345
		switch(c){
346
		case Caps:
347
			caps ^= 1;
348
			return;
349
		case Num:
350
			num ^= 1;
351
			return;
352
		case Shift:
353
			shift = 1;
354
			return;
355
		case Latin:
356
			alt = 1;
357
			collecting = 1;
358
			nk = 0;
359
			return;
360
		case Ctrl:
361
			ctl = 1;
362
			return;
363
		}
364
	}
365
	kbdputc(kbdq, c);
366
}
367
 
368
void
369
i8042auxenable(void (*putc)(int, int))
370
{
371
	char *err = "i8042: aux init failed\n";
372
 
373
	/* enable kbd/aux xfers and interrupts */
374
	ccc &= ~Cauxdis;
375
	ccc |= Cauxint;
376
 
377
	ilock(&i8042lock);
378
	if(outready() < 0)
379
		print(err);
380
	outb(Cmd, 0x60);			/* write control register */
381
	if(outready() < 0)
382
		print(err);
383
	outb(Data, ccc);
384
	if(outready() < 0)
385
		print(err);
386
	outb(Cmd, 0xA8);			/* auxilliary device enable */
387
	if(outready() < 0){
388
		iunlock(&i8042lock);
389
		return;
390
	}
391
	auxputc = putc;
392
	intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
393
	iunlock(&i8042lock);
394
}
395
 
396
void
397
kbdinit(void)
398
{
399
	int c;
400
 
401
	kbdq = qopen(4*1024, 0, 0, 0);
402
	if(kbdq == nil)
403
		panic("kbdinit");
404
	qnoblock(kbdq, 1);
405
 
406
	ioalloc(Data, 1, 0, "kbd");
407
	ioalloc(Cmd, 1, 0, "kbd");
408
 
409
	intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
410
 
411
	/* wait for a quiescent controller */
412
	while((c = inb(Status)) & (Outbusy | Inready))
413
		if(c & Inready)
414
			inb(Data);
415
 
416
	/* get current controller command byte */
417
	outb(Cmd, 0x20);
418
	if(inready() < 0){
419
		print("kbdinit: can't read ccc\n");
420
		ccc = 0;
421
	} else
422
		ccc = inb(Data);
423
 
424
	/* enable kbd xfers and interrupts */
425
	/* disable mouse */
426
	ccc &= ~Ckbddis;
427
	ccc |= Csf | Ckbdint | Cscs1;
428
	if(outready() < 0)
429
		print("kbd init failed\n");
430
	outb(Cmd, 0x60);
431
	if(outready() < 0)
432
		print("kbd init failed\n");
433
	outb(Data, ccc);
434
	outready();
435
}