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