5 #include "../port/lib.h"
10 #include "../port/error.h"
13 Data= 0x60, /* data port */
15 Status= 0x64, /* status port */
16 Inready= 0x01, /* input character ready */
17 Outbusy= 0x02, /* output busy */
18 Sysflag= 0x04, /* system flag */
19 Cmddata= 0x08, /* cmd==0, data==1 */
20 Inhibit= 0x10, /* keyboard/mouse inhibited */
21 Minready= 0x20, /* mouse character ready */
22 Rtimeout= 0x40, /* general timeout */
25 Cmd= 0x64, /* command port (write only) */
30 /* controller command byte */
31 Cscs1= (1<<6), /* scan code set 1 */
32 Cauxdis= (1<<5), /* mouse disable */
33 Ckbddis= (1<<4), /* kbd disable */
34 Csf= (1<<2), /* system flag */
35 Cauxint= (1<<1), /* mouse interrupt enable */
36 Ckbdint= (1<<0), /* kbd interrupt enable */
46 static Dirtab kbdtab[] = {
47 ".", {Qdir, 0, QTDIR}, 0, 0555,
48 "scancode", {Qscancode, 0}, 0, 0440,
49 "leds", {Qleds, 0}, 0, 0220,
50 "repeat", {Qrepeat, 0}, 0, 0220,
53 static Lock i8042lock;
55 static void (*auxputc)(int, int);
56 static int nokbd = 1; /* flag: no PS/2 keyboard */
64 * wait for output no longer busy
71 for(tries = 0; (inb(Status) & Outbusy); tries++){
87 for(tries = 0; !(inb(Status) & Inready); tries++){
96 * ask 8042 to reset the machine
106 *((ushort*)KADDR(0x472)) = 0x1234; /* BIOS warm-boot flag */
109 * newer reset the machine command
116 * Pulse it by hand (old somewhat reliable)
119 for(i = 0; i < 5; i++){
124 outb(Data, x); /* toggle reset */
153 } while(c == 0xFE || c == 0);
157 print("i8042: %2.2ux returned to the %2.2ux command (pc=%#p)\n",
158 c, cmd, getcallerpc(&cmd));
165 * set keyboard's leds for lock states (scroll, numeric, caps).
167 * at least one keyboard (from Qtronics) also sets its numeric-lock
168 * behaviour to match the led state, though it has no numeric keypad,
169 * and some BIOSes bring the system up with numeric-lock set and no
170 * setting to change that. this combination steals the keys for these
171 * characters and makes it impossible to generate them: uiolkjm&*().
172 * thus we'd like to be able to force the numeric-lock led (and behaviour) off.
179 if(nokbd || leds == old)
186 outb(Data, 0xed); /* `reset keyboard lock states' */
199 setrepeat(int repeat)
209 outb(Data, 0xf3); /* `set typematic rate and delay' */
224 i8042intr(Ureg*, void*)
246 * if it's the aux port...
255 qproduce(kbd.q, &b, 1);
259 i8042auxenable(void (*putc)(int, int))
261 static char err[] = "i8042: aux init failed\n";
265 /* enable kbd/aux xfers and interrupts */
271 outb(Cmd, 0x60); /* write control register */
277 outb(Cmd, 0xA8); /* auxiliary device enable */
284 intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
292 if(nokbd || qlen(kbd.q) > 0)
302 /* disable kbd and aux xfers and interrupts */
303 ccc &= ~(Ckbdint|Cauxint);
304 ccc |= (Cauxdis|Ckbddis);
313 kbdattach(char *spec)
315 return devattach(L'b', spec);
319 kbdwalk(Chan *c, Chan *nc, char **name, int nname)
321 return devwalk(c, nc, name, nname, kbdtab, nelem(kbdtab), devgen);
325 kbdstat(Chan *c, uchar *dp, int n)
327 return devstat(c, dp, n, kbdtab, nelem(kbdtab), devgen);
331 kbdopen(Chan *c, int omode)
335 if(c->qid.path == Qscancode){
340 if(incref(&kbd.ref) != 1)
342 c = devopen(c, omode, kbdtab, nelem(kbdtab), devgen);
346 return devopen(c, omode, kbdtab, nelem(kbdtab), devgen);
352 if((c->flag & COPEN) && c->qid.path == Qscancode)
357 kbdbread(Chan *c, long n, ulong off)
359 if(c->qid.path == Qscancode){
361 return qbread(kbd.q, n);
363 return devbread(c, n, off);
367 kbdread(Chan *c, void *a, long n, vlong)
369 if(c->qid.path == Qscancode){
371 return qread(kbd.q, a, n);
373 if(c->qid.path == Qdir)
374 return devdirread(c, a, n, kbdtab, nelem(kbdtab), devgen);
380 kbdwrite(Chan *c, void *a, long n, vlong)
386 p = tmp + sizeof(tmp)-1;
387 memmove(tmp, a, p - tmp);
390 if(c->qid.path == Qleds)
392 else if(c->qid.path == Qrepeat)
393 setrepeat(atoi(tmp));
403 static char initfailed[] = "i8042: kbd init failed\n";
406 kbd.q = qopen(1024, Qcoalesce, 0, 0);
411 /* wait for a quiescent controller */
413 while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
423 /* get current controller command byte */
426 print("i8042: can't read ccc\n");
431 /* enable kbd xfers and interrupts */
433 ccc |= Csf | Ckbdint | Cscs1;
435 /* disable ps2 mouse */
449 ioalloc(Cmd, 1, 0, "i8042.cs");
450 ioalloc(Data, 1, 0, "i8042.data");
451 intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");