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