1 /*
2 * keyboard input
3 */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "mem.h"
7 #include "dat.h"
8 #include "fns.h"
9 #include "io.h"
10 #include "../port/error.h"
11
12 enum {
13 Data= 0x60, /* data port */
14
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 */
23 Parity= 0x80,
24
25 Cmd= 0x64, /* command port (write only) */
26
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) */
31 Shift= Spec|0x60,
32 Break= Spec|0x61,
33 Ctrl= Spec|0x62,
34 Latin= Spec|0x63,
35 Caps= Spec|0x64,
36 Num= Spec|0x65,
37 Middle= Spec|0x66,
38 Altgr= Spec|0x67,
39 Kmouse= Spec|0x100,
40 No= 0x00, /* peter */
41
42 Home= KF|13,
43 Up= KF|14,
44 Pgup= KF|15,
45 Print= KF|16,
46 Left= KF|17,
47 Right= KF|18,
48 End= KF|24,
49 Down= View,
50 Pgdown= KF|19,
51 Ins= KF|20,
52 Del= 0x7F,
53 Scroll= KF|21,
54
55 Nscan= 128,
56
57 Int= 0, /* kbscans indices */
58 Ext,
59 Nscans,
60 };
61
62 /*
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.
65 */
66 Rune kbtab[Nscan] =
67 {
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,
84 };
85
86 Rune kbtabshift[Nscan] =
87 {
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,
104 };
105
106 Rune kbtabesc1[Nscan] =
107 {
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,
124 };
125
126 Rune kbtabaltgr[Nscan] =
127 {
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,
144 };
145
146 Rune kbtabctrl[Nscan] =
147 {
148 [0x00] No, '', '', '', '', '', '', '',
149 [0x08] '', '', '', '', '
150 ', '', '\b', '\t',
151 [0x10] '', '', '', '', '', '', '', '\t',
152 [0x18] '', '', '', '', '\n', Ctrl, '', '',
153 [0x20] '', '', '', '\b', '\n', '', '', '',
154 [0x28] '', No, Shift, '', '', '', '', '',
155 [0x30] '', '', '
156 ', '', '', '', Shift, '\n',
157 [0x38] Latin, No, Ctrl, '', '', '', '', '',
158 [0x40] '', '', '', '
159 ', '', '', '', '',
160 [0x48] '', '', '
161 ', '', '', '', '', '',
162 [0x50] '', '', '', '', No, No, No, '',
163 [0x58] '', No, No, No, No, No, No, No,
164 [0x60] No, No, No, No, No, No, No, No,
165 [0x68] No, No, No, No, No, No, No, No,
166 [0x70] No, No, No, No, No, No, No, No,
167 [0x78] No, '', No, '\b', No, No, No, No,
168 };
169
170 enum
171 {
172 /* controller command byte */
173 Cscs1= (1<<6), /* scan code set 1 */
174 Cauxdis= (1<<5), /* mouse disable */
175 Ckbddis= (1<<4), /* kbd disable */
176 Csf= (1<<2), /* system flag */
177 Cauxint= (1<<1), /* mouse interrupt enable */
178 Ckbdint= (1<<0), /* kbd interrupt enable */
179 };
180
181 int mouseshifted;
182 void (*kbdmouse)(int);
183
184 static Lock i8042lock;
185 static uchar ccc;
186 static void (*auxputc)(int, int);
187 static int nokbd = 1; /* flag: no PS/2 keyboard */
188
outready(void)189 /*
190 * wait for output no longer busy
191 */
192 static int
193 outready(void)
194 {
195 int tries;
196
197 for(tries = 0; (inb(Status) & Outbusy); tries++){
198 if(tries > 500)
199 return -1;
200 delay(2);
201 }
202 return 0;
203 }
204
inready(void)205 /*
206 * wait for input
207 */
208 static int
209 inready(void)
210 {
211 int tries;
212
213 for(tries = 0; !(inb(Status) & Inready); tries++){
214 if(tries > 500)
215 return -1;
216 delay(2);
217 }
218 return 0;
219 }
220
i8042a20(void)221 /*
222 * ask 8042 to enable the use of address bit 20
223 */
224 void
225 i8042a20(void)
226 {
227 outready();
228 outb(Cmd, 0xD1);
229 outready();
230 outb(Data, 0xDF);
231 outready();
232 }
233
i8042reset(void)234 /*
235 * ask 8042 to reset the machine
236 */
237 void
238 i8042reset(void)
239 {
240 int i, x;
241
242 if(nokbd)
243 return;
244
245 *((ushort*)KADDR(0x472)) = 0x1234; /* BIOS warm-boot flag */
246
247 /*
248 * newer reset the machine command
249 */
250 outready();
251 outb(Cmd, 0xFE);
252 outready();
253
254 /*
255 * Pulse it by hand (old somewhat reliable)
256 */
257 x = 0xDF;
258 for(i = 0; i < 5; i++){
259 x ^= 1;
260 outready();
261 outb(Cmd, 0xD1);
262 outready();
263 outb(Data, x); /* toggle reset */
264 delay(100);
265 }
266 }
267
268 int
269 i8042auxcmd(int cmd)
270 {
271 unsigned int c;
272 int tries;
273 static int badkbd;
274
275 if(badkbd)
276 return -1;
277 c = 0;
278 tries = 0;
279
280 ilock(&i8042lock);
281 do{
282 if(tries++ > 2)
283 break;
284 if(outready() < 0)
285 break;
286 outb(Cmd, 0xD4);
287 if(outready() < 0)
288 break;
289 outb(Data, cmd);
290 if(outready() < 0)
291 break;
292 if(inready() < 0)
293 break;
294 c = inb(Data);
295 } while(c == 0xFE || c == 0);
296 iunlock(&i8042lock);
297
298 if(c != 0xFA){
299 print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
300 badkbd = 1; /* don't keep trying; there might not be one */
301 return -1;
302 }
i8042auxcmds(uchar * cmd,int ncmd)303 return 0;
304 }
305
306 int
307 i8042auxcmds(uchar *cmd, int ncmd)
308 {
309 int i;
310
311 ilock(&i8042lock);
312 for(i=0; i<ncmd; i++){
313 if(outready() < 0)
314 break;
315 outb(Cmd, 0xD4);
316 if(outready() < 0)
317 break;
318 outb(Data, cmd[i]);
319 }
320 iunlock(&i8042lock);
321 return i;
322 }
323
324 typedef struct Kbscan Kbscan;
325 struct Kbscan {
326 int esc1;
327 int esc2;
328 int alt;
329 int altgr;
330 int caps;
331 int ctl;
332 int num;
333 int shift;
334 int collecting;
335 int nk;
336 Rune kc[5];
337 int buttons;
338 };
339
340 Kbscan kbscans[Nscans]; /* kernel and external scan code state */
341
342 static int kdebug;
343
344 /*
345 * set keyboard's leds for lock states (scroll, numeric, caps).
346 *
347 * at least one keyboard (from Qtronics) also sets its numeric-lock
348 * behaviour to match the led state, though it has no numeric keypad,
349 * and some BIOSes bring the system up with numeric-lock set and no
350 * setting to change that. this combination steals the keys for these
setleds(Kbscan * kbscan)351 * characters and makes it impossible to generate them: uiolkjm&*().
352 * thus we'd like to be able to force the numeric-lock led (and behaviour) off.
353 */
354 static void
355 setleds(Kbscan *kbscan)
356 {
357 int leds;
358
359 if(nokbd || kbscan != &kbscans[Int])
360 return;
361 leds = 0;
362 if(kbscan->num)
363 leds |= 1<<1;
364 if(0 && kbscan->caps) /* we don't implement caps lock */
365 leds |= 1<<2;
366
367 ilock(&i8042lock);
368 outready();
369 outb(Data, 0xed); /* `reset keyboard lock states' */
370 if(inready() == 0)
371 inb(Data);
372
373 outready();
374 outb(Data, leds);
375 if(inready() == 0)
376 inb(Data);
377
378 outready();
379 iunlock(&i8042lock);
380 }
381
kbdputsc(int c,int external)382 /*
383 * Scan code processing
384 */
385 void
386 kbdputsc(int c, int external)
387 {
388 int i, keyup;
389 Kbscan *kbscan;
390
391 if(external)
392 kbscan = &kbscans[Ext];
393 else
394 kbscan = &kbscans[Int];
395
396 if(kdebug)
397 print("sc %x ms %d\n", c, mouseshifted);
398 /*
399 * e0's is the first of a 2 character sequence, e1 the first
400 * of a 3 character sequence (on the safari)
401 */
402 if(c == 0xe0){
403 kbscan->esc1 = 1;
404 return;
405 } else if(c == 0xe1){
406 kbscan->esc2 = 2;
407 return;
408 }
409
410 keyup = c & 0x80;
411 c &= 0x7f;
412 if(c > sizeof kbtab){
413 c |= keyup;
414 if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */
415 print("unknown key %ux\n", c);
416 return;
417 }
418
419 if(kbscan->esc1){
420 c = kbtabesc1[c];
421 kbscan->esc1 = 0;
422 } else if(kbscan->esc2){
423 kbscan->esc2--;
424 return;
425 } else if(kbscan->shift)
426 c = kbtabshift[c];
427 else if(kbscan->altgr)
428 c = kbtabaltgr[c];
429 else if(kbscan->ctl)
430 c = kbtabctrl[c];
431 else
432 c = kbtab[c];
433
434 if(kbscan->caps && c<='z' && c>='a')
435 c += 'A' - 'a';
436
437 /*
438 * keyup only important for shifts
439 */
440 if(keyup){
441 switch(c){
442 case Latin:
443 kbscan->alt = 0;
444 break;
445 case Shift:
446 kbscan->shift = 0;
447 mouseshifted = 0;
448 if(kdebug)
449 print("shiftclr\n");
450 break;
451 case Ctrl:
452 kbscan->ctl = 0;
453 break;
454 case Altgr:
455 kbscan->altgr = 0;
456 break;
457 case Kmouse|1:
458 case Kmouse|2:
459 case Kmouse|3:
460 case Kmouse|4:
461 case Kmouse|5:
462 kbscan->buttons &= ~(1<<(c-Kmouse-1));
463 if(kbdmouse)
464 kbdmouse(kbscan->buttons);
465 break;
466 }
467 return;
468 }
469
470 /*
471 * normal character
472 */
473 if(!(c & (Spec|KF))){
474 if(kbscan->ctl)
475 if(kbscan->alt && c == Del)
476 exit(0);
477 if(!kbscan->collecting){
478 kbdputc(kbdq, c);
479 return;
480 }
481 kbscan->kc[kbscan->nk++] = c;
482 c = latin1(kbscan->kc, kbscan->nk);
483 if(c < -1) /* need more keystrokes */
484 return;
485 if(c != -1) /* valid sequence */
486 kbdputc(kbdq, c);
487 else /* dump characters */
488 for(i=0; i<kbscan->nk; i++)
489 kbdputc(kbdq, kbscan->kc[i]);
490 kbscan->nk = 0;
491 kbscan->collecting = 0;
492 return;
493 } else {
494 switch(c){
495 case Caps:
496 kbscan->caps ^= 1;
497 return;
498 case Num:
499 kbscan->num ^= 1;
500 if(!external)
501 setleds(kbscan);
502 return;
503 case Shift:
504 kbscan->shift = 1;
505 if(kdebug)
506 print("shift\n");
507 mouseshifted = 1;
508 return;
509 case Latin:
510 kbscan->alt = 1;
511 /*
512 * VMware and Qemu use Ctl-Alt as the key combination
513 * to make the VM give up keyboard and mouse focus.
514 * This has the unfortunate side effect that when you
515 * come back into focus, Plan 9 thinks you want to type
516 * a compose sequence (you just typed alt).
517 *
518 * As a clumsy hack around this, we look for ctl-alt
519 * and don't treat it as the start of a compose sequence.
520 */
521 if(!kbscan->ctl){
522 kbscan->collecting = 1;
523 kbscan->nk = 0;
524 }
525 return;
526 case Ctrl:
527 kbscan->ctl = 1;
528 return;
529 case Altgr:
530 kbscan->altgr = 1;
531 return;
532 case Kmouse|1:
533 case Kmouse|2:
534 case Kmouse|3:
535 case Kmouse|4:
536 case Kmouse|5:
537 kbscan->buttons |= 1<<(c-Kmouse-1);
538 if(kbdmouse)
539 kbdmouse(kbscan->buttons);
540 return;
541 case KF|11:
542 print("kbd debug on, F12 turns it off\n");
543 kdebug = 1;
544 break;
545 case KF|12:
546 kdebug = 0;
547 break;
548 }
549 }
550 kbdputc(kbdq, c);
551 }
552
i8042intr(Ureg *,void *)553 /*
554 * keyboard interrupt
555 */
556 static void
557 i8042intr(Ureg*, void*)
558 {
559 int s, c;
560
561 /*
562 * get status
563 */
564 ilock(&i8042lock);
565 s = inb(Status);
566 if(!(s&Inready)){
567 iunlock(&i8042lock);
568 return;
569 }
570
571 /*
572 * get the character
573 */
574 c = inb(Data);
575 iunlock(&i8042lock);
576
577 /*
578 * if it's the aux port...
579 */
580 if(s & Minready){
581 if(auxputc != nil)
582 auxputc(c, kbscans[Int].shift);
583 return;
584 }
585
586 kbdputsc(c, Int);
587 }
588
589 void
590 i8042auxenable(void (*putc)(int, int))
591 {
592 char *err = "i8042: aux init failed\n";
593
594 /* enable kbd/aux xfers and interrupts */
595 ccc &= ~Cauxdis;
596 ccc |= Cauxint;
597
598 ilock(&i8042lock);
599 if(outready() < 0)
600 print(err);
601 outb(Cmd, 0x60); /* write control register */
602 if(outready() < 0)
603 print(err);
604 outb(Data, ccc);
605 if(outready() < 0)
606 print(err);
607 outb(Cmd, 0xA8); /* auxiliary device enable */
608 if(outready() < 0){
609 iunlock(&i8042lock);
610 return;
611 }
612 auxputc = putc;
613 intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
614 iunlock(&i8042lock);
615 }
outbyte(int port,int c)616
617 static char *initfailed = "i8042: kbdinit failed\n";
618
619 static int
620 outbyte(int port, int c)
621 {
622 outb(port, c);
623 if(outready() < 0) {
624 print(initfailed);
625 return -1;
626 }
kbdinit(void)627 return 0;
628 }
629
630 void
631 kbdinit(void)
632 {
633 int c, try;
634
635 /* wait for a quiescent controller */
636 try = 500;
637 while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
638 if(c & Inready)
639 inb(Data);
640 delay(1);
641 }
642 if (try <= 0) {
643 print(initfailed);
644 return;
645 }
646
647 /* get current controller command byte */
648 outb(Cmd, 0x20);
649 if(inready() < 0){
650 print("i8042: kbdinit can't read ccc\n");
651 ccc = 0;
652 } else
653 ccc = inb(Data);
654
655 /* enable kbd xfers and interrupts */
656 ccc &= ~Ckbddis;
657 ccc |= Csf | Ckbdint | Cscs1;
658 if(outready() < 0) {
659 print(initfailed);
660 return;
661 }
662
663 nokbd = 0;
664
665 /* disable mouse */
666 if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0)
667 print("i8042: kbdinit mouse disable failed\n");
668
669 /* see http://www.computer-engineering.org/ps2keyboard for codes */
670 if(getconf("*typematic") != nil)
671 /* set typematic rate/delay (0 -> delay=250ms & rate=30cps) */
672 if(outbyte(Data, 0xf3) < 0 || outbyte(Data, 0) < 0)
kbdenable(void)673 print("i8042: kbdinit set typematic rate failed\n");
674 }
675
676 void
677 kbdenable(void)
678 {
679 kbdq = qopen(4*1024, 0, 0, 0);
680 if(kbdq == nil)
681 panic("kbdinit");
682 qnoblock(kbdq, 1);
683
684 ioalloc(Data, 1, 0, "kbd");
685 ioalloc(Cmd, 1, 0, "kbd");
686
687 intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
688
689 kbscans[Int].num = 0;
kbdputmap(ushort m,ushort scanc,Rune r)690 setleds(&kbscans[Int]);
691 }
692
693 void
694 kbdputmap(ushort m, ushort scanc, Rune r)
695 {
696 if(scanc >= Nscan)
697 error(Ebadarg);
698 switch(m) {
699 default:
700 error(Ebadarg);
701 case 0:
702 kbtab[scanc] = r;
703 break;
704 case 1:
705 kbtabshift[scanc] = r;
706 break;
707 case 2:
708 kbtabesc1[scanc] = r;
709 break;
710 case 3:
711 kbtabaltgr[scanc] = r;
712 break;
713 case 4:
714 kbtabctrl[scanc] = r;
715 break;
kbdgetmap(uint offset,int * t,int * sc,Rune * r)716 }
717 }
718
719 int
720 kbdgetmap(uint offset, int *t, int *sc, Rune *r)
721 {
722 if ((int)offset < 0)
723 error(Ebadarg);
724 *t = offset/Nscan;
725 *sc = offset%Nscan;
726 switch(*t) {
727 default:
728 return 0;
729 case 0:
730 *r = kbtab[*sc];
731 return 1;
732 case 1:
733 *r = kbtabshift[*sc];
734 return 1;
735 case 2:
736 *r = kbtabesc1[*sc];
737 return 1;
738 case 3:
739 *r = kbtabaltgr[*sc];
740 return 1;
741 case 4:
742 *r = kbtabctrl[*sc];
743 return 1;
744 }
745 }
746