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) */
27 Spec= 0xF800, /* Unicode private space */
28 PF= Spec|0x20, /* num pad function key */
29 View= Spec|0x00, /* view (shift window up) */
30 KF= 0xF000, /* function key (begin Unicode private space) */
57 Int= 0, /* kbscans indices */
63 * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
64 * A 'standard' keyboard doesn't produce anything above 0x58.
68 [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6',
69 [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
70 [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
71 [0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's',
72 [0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
73 [0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v',
74 [0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*',
75 [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
76 [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
77 [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
78 [0x50] '2', '3', '0', '.', No, No, No, KF|11,
79 [0x58] KF|12, No, No, No, No, No, No, No,
80 [0x60] No, No, No, No, No, No, No, No,
81 [0x68] No, No, No, No, No, No, No, No,
82 [0x70] No, No, No, No, No, No, No, No,
83 [0x78] No, View, No, Up, No, No, No, No,
86 Rune kbtabshift[Nscan] =
88 [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^',
89 [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
90 [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
91 [0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S',
92 [0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
93 [0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V',
94 [0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*',
95 [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
96 [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
97 [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
98 [0x50] '2', '3', '0', '.', No, No, No, KF|11,
99 [0x58] KF|12, No, No, No, No, No, No, No,
100 [0x60] No, No, No, No, No, No, No, No,
101 [0x68] No, No, No, No, No, No, No, No,
102 [0x70] No, No, No, No, No, No, No, No,
103 [0x78] No, Up, No, Up, No, No, No, No,
106 Rune kbtabesc1[Nscan] =
108 [0x00] No, No, No, No, No, No, No, No,
109 [0x08] No, No, No, No, No, No, No, No,
110 [0x10] No, No, No, No, No, No, No, No,
111 [0x18] No, No, No, No, '\n', Ctrl, No, No,
112 [0x20] No, No, No, No, No, No, No, No,
113 [0x28] No, No, Shift, No, No, No, No, No,
114 [0x30] No, No, No, No, No, '/', No, Print,
115 [0x38] Altgr, No, No, No, No, No, No, No,
116 [0x40] No, No, No, No, No, No, Break, Home,
117 [0x48] Up, Pgup, No, Left, No, Right, No, End,
118 [0x50] Down, Pgdown, Ins, Del, No, No, No, No,
119 [0x58] No, No, No, No, No, No, No, No,
120 [0x60] No, No, No, No, No, No, No, No,
121 [0x68] No, No, No, No, No, No, No, No,
122 [0x70] No, No, No, No, No, No, No, No,
123 [0x78] No, Up, No, No, No, No, No, No,
126 Rune kbtabaltgr[Nscan] =
128 [0x00] No, No, No, No, No, No, No, No,
129 [0x08] No, No, No, No, No, No, No, No,
130 [0x10] No, No, No, No, No, No, No, No,
131 [0x18] No, No, No, No, '\n', Ctrl, No, No,
132 [0x20] No, No, No, No, No, No, No, No,
133 [0x28] No, No, Shift, No, No, No, No, No,
134 [0x30] No, No, No, No, No, '/', No, Print,
135 [0x38] Altgr, No, No, No, No, No, No, No,
136 [0x40] No, No, No, No, No, No, Break, Home,
137 [0x48] Up, Pgup, No, Left, No, Right, No, End,
138 [0x50] Down, Pgdown, Ins, Del, No, No, No, No,
139 [0x58] No, No, No, No, No, No, No, No,
140 [0x60] No, No, No, No, No, No, No, No,
141 [0x68] No, No, No, No, No, No, No, No,
142 [0x70] No, No, No, No, No, No, No, No,
143 [0x78] No, Up, No, No, No, No, No, No,
146 Rune kbtabctrl[Nscan] =
148 [0x00] No, '
\e', '
\11', '
\12', '
\13', '
\14', '
\15', '
\16',
149 [0x08] '
\17', '
\18', '
\19', '
\10', '
\r', '
\1d', '\b', '\t',
150 [0x10] '
\11', '
\17', '
\ 5', '
\12', '
\14', '
\19', '
\15', '\t',
151 [0x18] '
\ f', '
\10', '
\e', '
\1d', '\n', Ctrl, '
\ 1', '
\13',
152 [0x20] '
\ 4', '
\ 6', '
\a', '\b', '\n', '
\v', '
\f', '
\e',
153 [0x28] '
\a', No, Shift, '
\1c', '
\1a', '
\18', '
\ 3', '
\16',
154 [0x30] '
\ 2', '
\ e', '
\r', '
\f', '
\ e', '
\ f', Shift, '\n',
155 [0x38] Latin, No, Ctrl, '
\ 5', '
\ 6', '
\a', '
\ 4', '
\ 5',
156 [0x40] '
\ 6', '
\a', '
\f', '
\r', '
\ e', '
\ 5', '
\ 6', '
\17',
157 [0x48] '
\18', '
\19', '
\r', '
\14', '
\15', '
\16', '
\v', '
\11',
158 [0x50] '
\12', '
\13', '
\10', '
\ e', No, No, No, '
\ f',
159 [0x58] '
\f', No, No, No, No, No, No, No,
160 [0x60] No, No, No, No, No, No, No, No,
161 [0x68] No, No, No, No, No, No, No, No,
162 [0x70] No, No, No, No, No, No, No, No,
163 [0x78] No, '
\a', No, '\b', No, No, No, No,
168 /* controller command byte */
169 Cscs1= (1<<6), /* scan code set 1 */
170 Cauxdis= (1<<5), /* mouse disable */
171 Ckbddis= (1<<4), /* kbd disable */
172 Csf= (1<<2), /* system flag */
173 Cauxint= (1<<1), /* mouse interrupt enable */
174 Ckbdint= (1<<0), /* kbd interrupt enable */
178 void (*kbdmouse)(int);
180 static Lock i8042lock;
182 static void (*auxputc)(int, int);
183 static int nokbd = 1; /* flag: no PS/2 keyboard */
186 * wait for output no longer busy
193 for(tries = 0; (inb(Status) & Outbusy); tries++){
209 for(tries = 0; !(inb(Status) & Inready); tries++){
218 * ask 8042 to reset the machine
228 *((ushort*)KADDR(0x472)) = 0x1234; /* BIOS warm-boot flag */
231 * newer reset the machine command
238 * Pulse it by hand (old somewhat reliable)
241 for(i = 0; i < 5; i++){
246 outb(Data, x); /* toggle reset */
278 } while(c == 0xFE || c == 0);
282 print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
283 badkbd = 1; /* don't keep trying; there might not be one */
290 i8042auxcmds(uchar *cmd, int ncmd)
295 for(i=0; i<ncmd; i++){
307 typedef struct Kbscan Kbscan;
323 Kbscan kbscans[Nscans]; /* kernel and external scan code state */
328 * set keyboard's leds for lock states (scroll, numeric, caps).
330 * at least one keyboard (from Qtronics) also sets its numeric-lock
331 * behaviour to match the led state, though it has no numeric keypad,
332 * and some BIOSes bring the system up with numeric-lock set and no
333 * setting to change that. this combination steals the keys for these
334 * characters and makes it impossible to generate them: uiolkjm&*().
335 * thus we'd like to be able to force the numeric-lock led (and behaviour) off.
338 setleds(Kbscan *kbscan)
342 if(nokbd || kbscan != &kbscans[Int])
347 if(0 && kbscan->caps) /* we don't implement caps lock */
351 outb(Data, 0xed); /* `reset keyboard lock states' */
359 * Scan code processing
362 kbdputsc(int c, int external)
368 kbscan = &kbscans[Ext];
370 kbscan = &kbscans[Int];
373 print("sc %x ms %d\n", c, mouseshifted);
375 * e0's is the first of a 2 character sequence, e1 the first
376 * of a 3 character sequence (on the safari)
381 } else if(c == 0xe1){
388 if(c > sizeof kbtab){
390 if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */
391 print("unknown key %ux\n", c);
398 } else if(kbscan->esc2){
401 } else if(kbscan->shift)
403 else if(kbscan->altgr)
410 if(kbscan->caps && c<='z' && c>='a')
414 * keyup only important for shifts
438 kbscan->buttons &= ~(1<<(c-Kmouse-1));
440 kbdmouse(kbscan->buttons);
449 if(!(c & (Spec|KF))){
451 if(kbscan->alt && c == Del)
453 if(!kbscan->collecting){
457 kbscan->kc[kbscan->nk++] = c;
458 c = latin1(kbscan->kc, kbscan->nk);
459 if(c < -1) /* need more keystrokes */
461 if(c != -1) /* valid sequence */
463 else /* dump characters */
464 for(i=0; i<kbscan->nk; i++)
465 kbdputc(kbdq, kbscan->kc[i]);
467 kbscan->collecting = 0;
488 * VMware and Qemu use Ctl-Alt as the key combination
489 * to make the VM give up keyboard and mouse focus.
490 * This has the unfortunate side effect that when you
491 * come back into focus, Plan 9 thinks you want to type
492 * a compose sequence (you just typed alt).
494 * As a clumsy hack around this, we look for ctl-alt
495 * and don't treat it as the start of a compose sequence.
498 kbscan->collecting = 1;
513 kbscan->buttons |= 1<<(c-Kmouse-1);
515 kbdmouse(kbscan->buttons);
518 print("kbd debug on, F12 turns it off\n");
533 i8042intr(Ureg*, void*)
554 * if it's the aux port...
558 auxputc(c, kbscans[Int].shift);
566 i8042auxenable(void (*putc)(int, int))
568 char *err = "i8042: aux init failed\n";
570 /* enable kbd/aux xfers and interrupts */
577 outb(Cmd, 0x60); /* write control register */
583 outb(Cmd, 0xA8); /* auxiliary device enable */
589 intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
593 static char *initfailed = "i8042: kbdinit failed\n";
596 outbyte(int port, int c)
611 /* wait for a quiescent controller */
613 while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
623 /* get current controller command byte */
626 print("i8042: kbdinit can't read ccc\n");
631 /* enable kbd xfers and interrupts */
633 ccc |= Csf | Ckbdint | Cscs1;
642 if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0)
643 print("i8042: kbdinit mouse disable failed\n");
649 kbdq = qopen(4*1024, 0, 0, 0);
654 ioalloc(Data, 1, 0, "kbd");
655 ioalloc(Cmd, 1, 0, "kbd");
657 intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
659 kbscans[Int].num = 0;
660 setleds(&kbscans[Int]);
664 kbdputmap(ushort m, ushort scanc, Rune r)
675 kbtabshift[scanc] = r;
678 kbtabesc1[scanc] = r;
681 kbtabaltgr[scanc] = r;
684 kbtabctrl[scanc] = r;
690 kbdgetmap(uint offset, int *t, int *sc, Rune *r)
703 *r = kbtabshift[*sc];
709 *r = kbtabaltgr[*sc];