FreeBSD/Linux Kernel Cross Reference
sys/pc/kbd.c
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
58 /*
59 * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
60 * A 'standard' keyboard doesn't produce anything above 0x58.
61 */
62 Rune kbtab[Nscan] =
63 {
64 [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6',
65 [0x08] '7', '8', '9', '', '-', '=', '\b', '\t',
66 [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
67 [0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's',
68 [0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
69 [0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v',
70 [0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*',
71 [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
72 [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
73 [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
74 [0x50] '2', '3', '', '.', No, No, No, KF|11,
75 [0x58] KF|12, No, No, No, No, No, No, No,
76 [0x60] No, No, No, No, No, No, No, No,
77 [0x68] No, No, No, No, No, No, No, No,
78 [0x70] No, No, No, No, No, No, No, No,
79 [0x78] No, View, No, Up, No, No, No, No,
80 };
81
82 Rune kbtabshift[Nscan] =
83 {
84 [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^',
85 [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
86 [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
87 [0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S',
88 [0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
89 [0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V',
90 [0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*',
91 [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
92 [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
93 [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
94 [0x50] '2', '3', '', '.', No, No, No, KF|11,
95 [0x58] KF|12, No, No, No, No, No, No, No,
96 [0x60] No, No, No, No, No, No, No, No,
97 [0x68] No, No, No, No, No, No, No, No,
98 [0x70] No, No, No, No, No, No, No, No,
99 [0x78] No, Up, No, Up, No, No, No, No,
100 };
101
102 Rune kbtabesc1[Nscan] =
103 {
104 [0x00] No, No, No, No, No, No, No, No,
105 [0x08] No, No, No, No, No, No, No, No,
106 [0x10] No, No, No, No, No, No, No, No,
107 [0x18] No, No, No, No, '\n', Ctrl, No, No,
108 [0x20] No, No, No, No, No, No, No, No,
109 [0x28] No, No, Shift, No, No, No, No, No,
110 [0x30] No, No, No, No, No, '/', No, Print,
111 [0x38] Altgr, No, No, No, No, No, No, No,
112 [0x40] No, No, No, No, No, No, Break, Home,
113 [0x48] Up, Pgup, No, Left, No, Right, No, End,
114 [0x50] Down, Pgdown, Ins, Del, No, No, No, No,
115 [0x58] No, No, No, No, No, No, No, No,
116 [0x60] No, No, No, No, No, No, No, No,
117 [0x68] No, No, No, No, No, No, No, No,
118 [0x70] No, No, No, No, No, No, No, No,
119 [0x78] No, Up, No, No, No, No, No, No,
120 };
121
122 Rune kbtabaltgr[Nscan] =
123 {
124 [0x00] No, No, No, No, No, No, No, No,
125 [0x08] No, No, No, No, No, No, No, No,
126 [0x10] No, No, No, No, No, No, No, No,
127 [0x18] No, No, No, No, '\n', Ctrl, No, No,
128 [0x20] No, No, No, No, No, No, No, No,
129 [0x28] No, No, Shift, No, No, No, No, No,
130 [0x30] No, No, No, No, No, '/', No, Print,
131 [0x38] Altgr, No, No, No, No, No, No, No,
132 [0x40] No, No, No, No, No, No, Break, Home,
133 [0x48] Up, Pgup, No, Left, No, Right, No, End,
134 [0x50] Down, Pgdown, Ins, Del, No, No, No, No,
135 [0x58] No, No, No, No, No, No, No, No,
136 [0x60] No, No, No, No, No, No, No, No,
137 [0x68] No, No, No, No, No, No, No, No,
138 [0x70] No, No, No, No, No, No, No, No,
139 [0x78] No, Up, No, No, No, No, No, No,
140 };
141
142 Rune kbtabctrl[Nscan] =
143 {
144 [0x00] No, '', '', '', '', '', '', '',
145 [0x08] '', '', '', '', '
', '', '\b', '\t',
146 [0x10] '', '', '', '', '', '', '', '\t',
147 [0x18] '', '', '', '', '\n', Ctrl, '', '',
148 [0x20] '', '', '', '\b', '\n', '', '', '',
149 [0x28] '', No, Shift, '', '', '', '', '',
150 [0x30] '', '', '
', '', '', '', Shift, '\n',
151 [0x38] Latin, No, Ctrl, '', '', '', '', '',
152 [0x40] '', '', '', '
', '', '', '', '',
153 [0x48] '', '', '
', '', '', '', '', '',
154 [0x50] '', '', '', '', No, No, No, '',
155 [0x58] '', No, No, No, No, No, No, No,
156 [0x60] No, No, No, No, No, No, No, No,
157 [0x68] No, No, No, No, No, No, No, No,
158 [0x70] No, No, No, No, No, No, No, No,
159 [0x78] No, '', No, '\b', No, No, No, No,
160 };
161
162 enum
163 {
164 /* controller command byte */
165 Cscs1= (1<<6), /* scan code set 1 */
166 Cauxdis= (1<<5), /* mouse disable */
167 Ckbddis= (1<<4), /* kbd disable */
168 Csf= (1<<2), /* system flag */
169 Cauxint= (1<<1), /* mouse interrupt enable */
170 Ckbdint= (1<<0), /* kbd interrupt enable */
171 };
172
173 int mouseshifted;
174 void (*kbdmouse)(int);
175
176 static Lock i8042lock;
177 static uchar ccc;
178 static void (*auxputc)(int, int);
179 static int nokbd = 1;
180
181 /*
182 * wait for output no longer busy
183 */
184 static int
185 outready(void)
186 {
187 int tries;
188
189 for(tries = 0; (inb(Status) & Outbusy); tries++){
190 if(tries > 500)
191 return -1;
192 delay(2);
193 }
194 return 0;
195 }
196
197 /*
198 * wait for input
199 */
200 static int
201 inready(void)
202 {
203 int tries;
204
205 for(tries = 0; !(inb(Status) & Inready); tries++){
206 if(tries > 500)
207 return -1;
208 delay(2);
209 }
210 return 0;
211 }
212
213 /*
214 * ask 8042 to reset the machine
215 */
216 void
217 i8042reset(void)
218 {
219 int i, x;
220
221 if(nokbd)
222 return;
223
224 *((ushort*)KADDR(0x472)) = 0x1234; /* BIOS warm-boot flag */
225
226 /*
227 * newer reset the machine command
228 */
229 outready();
230 outb(Cmd, 0xFE);
231 outready();
232
233 /*
234 * Pulse it by hand (old somewhat reliable)
235 */
236 x = 0xDF;
237 for(i = 0; i < 5; i++){
238 x ^= 1;
239 outready();
240 outb(Cmd, 0xD1);
241 outready();
242 outb(Data, x); /* toggle reset */
243 delay(100);
244 }
245 }
246
247 int
248 i8042auxcmd(int cmd)
249 {
250 unsigned int c;
251 int tries;
252
253 c = 0;
254 tries = 0;
255
256 ilock(&i8042lock);
257 do{
258 if(tries++ > 2)
259 break;
260 if(outready() < 0)
261 break;
262 outb(Cmd, 0xD4);
263 if(outready() < 0)
264 break;
265 outb(Data, cmd);
266 if(outready() < 0)
267 break;
268 if(inready() < 0)
269 break;
270 c = inb(Data);
271 } while(c == 0xFE || c == 0);
272 iunlock(&i8042lock);
273
274 if(c != 0xFA){
275 print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
276 return -1;
277 }
278 return 0;
279 }
280
281 int
282 i8042auxcmds(uchar *cmd, int ncmd)
283 {
284 int i;
285
286 ilock(&i8042lock);
287 for(i=0; i<ncmd; i++){
288 if(outready() < 0)
289 break;
290 outb(Cmd, 0xD4);
291 if(outready() < 0)
292 break;
293 outb(Data, cmd[i]);
294 }
295 iunlock(&i8042lock);
296 return i;
297 }
298
299 typedef struct Kbscan Kbscan;
300 struct Kbscan {
301 int esc1;
302 int esc2;
303 int alt;
304 int altgr;
305 int caps;
306 int ctl;
307 int num;
308 int shift;
309 int collecting;
310 int nk;
311 Rune kc[5];
312 int buttons;
313 };
314
315 Kbscan kbscans[2]; /* kernel and external scan code state */
316 static int kdebug;
317 /*
318 * Scan code processing
319 */
320 void
321 kbdputsc(int c, int external)
322 {
323 int i, keyup;
324 Kbscan *kbscan;
325
326 if(external)
327 kbscan = &kbscans[1];
328 else
329 kbscan = &kbscans[0];
330
331 if(kdebug)
332 print("sc %x ms %d\n", c, mouseshifted);
333 /*
334 * e0's is the first of a 2 character sequence, e1 the first
335 * of a 3 character sequence (on the safari)
336 */
337 if(c == 0xe0){
338 kbscan->esc1 = 1;
339 return;
340 } else if(c == 0xe1){
341 kbscan->esc2 = 2;
342 return;
343 }
344
345 keyup = c & 0x80;
346 c &= 0x7f;
347 if(c > sizeof kbtab){
348 c |= keyup;
349 if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */
350 print("unknown key %ux\n", c);
351 return;
352 }
353
354 if(kbscan->esc1){
355 c = kbtabesc1[c];
356 kbscan->esc1 = 0;
357 } else if(kbscan->esc2){
358 kbscan->esc2--;
359 return;
360 } else if(kbscan->shift)
361 c = kbtabshift[c];
362 else if(kbscan->altgr)
363 c = kbtabaltgr[c];
364 else if(kbscan->ctl)
365 c = kbtabctrl[c];
366 else
367 c = kbtab[c];
368
369 if(kbscan->caps && c<='z' && c>='a')
370 c += 'A' - 'a';
371
372 /*
373 * keyup only important for shifts
374 */
375 if(keyup){
376 switch(c){
377 case Latin:
378 kbscan->alt = 0;
379 break;
380 case Shift:
381 kbscan->shift = 0;
382 mouseshifted = 0;
383 if(kdebug)
384 print("shiftclr\n");
385 break;
386 case Ctrl:
387 kbscan->ctl = 0;
388 break;
389 case Altgr:
390 kbscan->altgr = 0;
391 break;
392 case Kmouse|1:
393 case Kmouse|2:
394 case Kmouse|3:
395 case Kmouse|4:
396 case Kmouse|5:
397 kbscan->buttons &= ~(1<<(c-Kmouse-1));
398 if(kbdmouse)
399 kbdmouse(kbscan->buttons);
400 break;
401 }
402 return;
403 }
404
405 /*
406 * normal character
407 */
408 if(!(c & (Spec|KF))){
409 if(kbscan->ctl)
410 if(kbscan->alt && c == Del)
411 exit(0);
412 if(!kbscan->collecting){
413 kbdputc(kbdq, c);
414 return;
415 }
416 kbscan->kc[kbscan->nk++] = c;
417 c = latin1(kbscan->kc, kbscan->nk);
418 if(c < -1) /* need more keystrokes */
419 return;
420 if(c != -1) /* valid sequence */
421 kbdputc(kbdq, c);
422 else /* dump characters */
423 for(i=0; i<kbscan->nk; i++)
424 kbdputc(kbdq, kbscan->kc[i]);
425 kbscan->nk = 0;
426 kbscan->collecting = 0;
427 return;
428 } else {
429 switch(c){
430 case Caps:
431 kbscan->caps ^= 1;
432 return;
433 case Num:
434 kbscan->num ^= 1;
435 return;
436 case Shift:
437 kbscan->shift = 1;
438 if(kdebug)
439 print("shift\n");
440 mouseshifted = 1;
441 return;
442 case Latin:
443 kbscan->alt = 1;
444 /*
445 * VMware and Qemu use Ctl-Alt as the key combination
446 * to make the VM give up keyboard and mouse focus.
447 * This has the unfortunate side effect that when you
448 * come back into focus, Plan 9 thinks you want to type
449 * a compose sequence (you just typed alt).
450 *
451 * As a clumsy hack around this, we look for ctl-alt
452 * and don't treat it as the start of a compose sequence.
453 */
454 if(!kbscan->ctl){
455 kbscan->collecting = 1;
456 kbscan->nk = 0;
457 }
458 return;
459 case Ctrl:
460 kbscan->ctl = 1;
461 return;
462 case Altgr:
463 kbscan->altgr = 1;
464 return;
465 case Kmouse|1:
466 case Kmouse|2:
467 case Kmouse|3:
468 case Kmouse|4:
469 case Kmouse|5:
470 kbscan->buttons |= 1<<(c-Kmouse-1);
471 if(kbdmouse)
472 kbdmouse(kbscan->buttons);
473 return;
474 case KF|11:
475 kdebug = 1;
476 break;
477 case KF|12:
478 kdebug = 0;
479 break;
480 }
481 }
482 kbdputc(kbdq, c);
483 }
484
485 /*
486 * keyboard interrupt
487 */
488 static void
489 i8042intr(Ureg*, void*)
490 {
491 int s, c;
492
493 /*
494 * get status
495 */
496 ilock(&i8042lock);
497 s = inb(Status);
498 if(!(s&Inready)){
499 iunlock(&i8042lock);
500 return;
501 }
502
503 /*
504 * get the character
505 */
506 c = inb(Data);
507 iunlock(&i8042lock);
508
509 /*
510 * if it's the aux port...
511 */
512 if(s & Minready){
513 if(auxputc != nil)
514 auxputc(c, kbscans[0].shift); /* internal source */
515 return;
516 }
517
518 kbdputsc(c, 0); /* internal source */
519 }
520
521 void
522 i8042auxenable(void (*putc)(int, int))
523 {
524 char *err = "i8042: aux init failed\n";
525
526 /* enable kbd/aux xfers and interrupts */
527 ccc &= ~Cauxdis;
528 ccc |= Cauxint;
529
530 ilock(&i8042lock);
531 if(outready() < 0)
532 print(err);
533 outb(Cmd, 0x60); /* write control register */
534 if(outready() < 0)
535 print(err);
536 outb(Data, ccc);
537 if(outready() < 0)
538 print(err);
539 outb(Cmd, 0xA8); /* auxiliary device enable */
540 if(outready() < 0){
541 iunlock(&i8042lock);
542 return;
543 }
544 auxputc = putc;
545 intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
546 iunlock(&i8042lock);
547 }
548
549 static char *initfailed = "i8042: kbdinit failed\n";
550
551 static int
552 outbyte(int port, int c)
553 {
554 outb(port, c);
555 if(outready() < 0) {
556 print(initfailed);
557 return -1;
558 }
559 return 0;
560 }
561
562 void
563 kbdinit(void)
564 {
565 int c, try;
566
567 /* wait for a quiescent controller */
568 try = 1000;
569 while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
570 if(c & Inready)
571 inb(Data);
572 delay(1);
573 }
574 if (try <= 0) {
575 print(initfailed);
576 return;
577 }
578
579 /* get current controller command byte */
580 outb(Cmd, 0x20);
581 if(inready() < 0){
582 print("i8042: kbdinit can't read ccc\n");
583 ccc = 0;
584 } else
585 ccc = inb(Data);
586
587 /* enable kbd xfers and interrupts */
588 ccc &= ~Ckbddis;
589 ccc |= Csf | Ckbdint | Cscs1;
590 if(outready() < 0) {
591 print(initfailed);
592 return;
593 }
594
595 nokbd = 0;
596
597 /* disable mouse */
598 if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0)
599 print("i8042: kbdinit mouse disable failed\n");
600 }
601
602 void
603 kbdenable(void)
604 {
605 kbdq = qopen(4*1024, 0, 0, 0);
606 if(kbdq == nil)
607 panic("kbdinit");
608 qnoblock(kbdq, 1);
609
610 ioalloc(Data, 1, 0, "kbd");
611 ioalloc(Cmd, 1, 0, "kbd");
612
613 intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
614 }
615
616 void
617 kbdputmap(ushort m, ushort scanc, Rune r)
618 {
619 if(scanc >= Nscan)
620 error(Ebadarg);
621 switch(m) {
622 default:
623 error(Ebadarg);
624 case 0:
625 kbtab[scanc] = r;
626 break;
627 case 1:
628 kbtabshift[scanc] = r;
629 break;
630 case 2:
631 kbtabesc1[scanc] = r;
632 break;
633 case 3:
634 kbtabaltgr[scanc] = r;
635 break;
636 case 4:
637 kbtabctrl[scanc] = r;
638 break;
639 }
640 }
641
642 int
643 kbdgetmap(uint offset, int *t, int *sc, Rune *r)
644 {
645 if ((int)offset < 0)
646 error(Ebadarg);
647 *t = offset/Nscan;
648 *sc = offset%Nscan;
649 switch(*t) {
650 default:
651 return 0;
652 case 0:
653 *r = kbtab[*sc];
654 return 1;
655 case 1:
656 *r = kbtabshift[*sc];
657 return 1;
658 case 2:
659 *r = kbtabesc1[*sc];
660 return 1;
661 case 3:
662 *r = kbtabaltgr[*sc];
663 return 1;
664 case 4:
665 *r = kbtabctrl[*sc];
666 return 1;
667 }
668 }
Cache object: feae64083b7660231cb085f4b1a6cc9d
|