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