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