1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 9 enum 10 { 11 Data= 0x60, /* data port */ 12 13 Status= 0x64, /* status port */ 14 Inready= 0x01, /* input character ready */ 15 Outbusy= 0x02, /* output busy */ 16 Sysflag= 0x04, /* system flag */ 17 Cmddata= 0x08, /* cmd==0, data==1 */ 18 Inhibit= 0x10, /* keyboard/mouse inhibited */ 19 Minready= 0x20, /* mouse character ready */ 20 Rtimeout= 0x40, /* general timeout */ 21 Parity= 0x80, 22 23 Cmd= 0x64, /* command port (write only) */ 24 25 CTdata= 0x0, /* chips & Technologies ps2 data port */ 26 CTstatus= 0x1, /* chips & Technologies ps2 status port */ 27 Enable= 1<<7, 28 Clear= 1<<6, 29 Error= 1<<5, 30 Intenable= 1<<4, 31 Reset= 1<<3, 32 Tready= 1<<2, 33 Rready= 1<<1, 34 Idle= 1<<0, 35 36 Spec= 0x80, 37 38 PF= Spec|0x20, /* num pad function key */ 39 View= Spec|0x00, /* view (shift window up) */ 40 KF= Spec|0x40, /* function key */ 41 Shift= Spec|0x60, 42 Break= Spec|0x61, 43 Ctrl= Spec|0x62, 44 Latin= Spec|0x63, 45 Caps= Spec|0x64, 46 Num= Spec|0x65, 47 Middle= Spec|0x66, 48 No= 0x00, /* peter */ 49 50 Home= KF|13, 51 Up= KF|14, 52 Pgup= KF|15, 53 Print= KF|16, 54 Left= View, 55 Right= View, 56 End= '\r', 57 Down= View, 58 Pgdown= View, 59 Ins= KF|20, 60 Del= 0x7F, 61 62 Rbutton=4, 63 Mbutton=2, 64 Lbutton=1, 65 }; 66 67 uchar 68 kbtab[] = { 69 [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6', 70 [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t', 71 [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 72 [0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's', 73 [0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 74 [0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v', 75 [0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*', 76 [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5, 77 [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, '7', 78 [0x48] '8', '9', '-', '4', '5', '6', '+', '1', 79 [0x50] '2', '3', '0', '.', No, No, No, KF|11, 80 [0x58] KF|12, No, No, No, No, No, No, No, 81 }; 82 83 uchar 84 kbtabshift[] = { 85 [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^', 86 [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t', 87 [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 88 [0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S', 89 [0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 90 [0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V', 91 [0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*', 92 [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5, 93 [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, '7', 94 [0x48] '8', '9', '-', '4', '5', '6', '+', '1', 95 [0x50] '2', '3', '0', '.', No, No, No, KF|11, 96 [0x58] KF|12, No, No, No, No, No, No, No, 97 }; 98 99 uchar 100 kbtabesc1[] = { 101 [0x00] No, No, No, No, No, No, No, No, 102 [0x08] No, No, No, No, No, No, No, No, 103 [0x10] No, No, No, No, No, No, No, No, 104 [0x18] No, No, No, No, '\n', Ctrl, No, No, 105 [0x20] No, No, No, No, No, No, No, No, 106 [0x28] No, No, Shift, No, No, No, No, No, 107 [0x30] No, No, No, No, No, '/', No, Print, 108 [0x38] Latin, No, No, No, No, No, No, No, 109 [0x40] No, No, No, No, No, No, Break, Home, 110 [0x48] Up, Pgup, No, Left, No, Right, No, End, 111 [0x50] Down, Pgdown, Ins, Del, No, No, No, No, 112 [0x58] No, No, No, No, No, No, No, No, 113 }; 114 115 static int keybuttons; 116 static uchar ccc; 117 static int shift; 118 119 enum 120 { 121 /* controller command byte */ 122 Cscs1= (1<<6), /* scan code set 1 */ 123 Cmousedis= (1<<5), /* mouse disable */ 124 Ckbddis= (1<<4), /* kbd disable */ 125 Csf= (1<<2), /* system flag */ 126 Cmouseint= (1<<1), /* mouse interrupt enable */ 127 Ckbdint= (1<<0), /* kbd interrupt enable */ 128 }; 129 130 /* 131 * wait for output no longer busy 132 */ 133 static int 134 outready(void) 135 { 136 int tries; 137 138 for(tries = 0; (superio_readctl() & Outbusy); tries++){ 139 if(tries > 500) 140 return -1; 141 microdelay(2); 142 } 143 return 0; 144 } 145 146 /* 147 * wait for input 148 */ 149 static int 150 inready(void) 151 { 152 int tries; 153 154 for(tries = 0; !(superio_readctl() & Inready); tries++){ 155 if(tries > 500) 156 return -1; 157 microdelay(2); 158 } 159 return 0; 160 } 161 162 /* 163 * send a command to the mouse 164 */ 165 static int 166 mousecmd(int cmd) 167 { 168 unsigned int c; 169 int tries; 170 171 c = 0; 172 tries = 0; 173 do{ 174 if(tries++ > 2) 175 break; 176 if(outready() < 0) 177 break; 178 superio_writectl(0xD4); 179 if(outready() < 0) 180 break; 181 superio_writedata(cmd); 182 if(outready() < 0) 183 break; 184 if(inready() < 0) 185 break; 186 c = superio_readdata(); 187 } while(c == 0xFE || c == 0); 188 189 if(c != 0xFA){ 190 print("mouse returns %2.2ux to the %2.2ux command\n", c, cmd); 191 return -1; 192 } 193 return 0; 194 } 195 196 /* 197 * ask 8042 to enable the use of address bit 20 198 */ 199 void 200 i8042a20(void) 201 { 202 outready(); 203 superio_writectl(0xD1); 204 outready(); 205 superio_writedata(0xDF); 206 outready(); 207 } 208 209 /* 210 * ask 8042 to reset the machine 211 */ 212 void 213 i8042reset(void) 214 { 215 ushort *s = (ushort*)(KZERO|0x472); 216 int i, x; 217 218 *s = 0x1234; /* BIOS warm-boot flag */ 219 220 /* 221 * newer reset the machine command 222 */ 223 outready(); 224 superio_writectl(0xFE); 225 outready(); 226 227 /* 228 * Pulse it by hand (old somewhat reliable) 229 */ 230 x = 0xDF; 231 for(i = 0; i < 5; i++){ 232 x ^= 1; 233 outready(); 234 superio_writectl(0xD1); 235 outready(); 236 superio_writedata(x); /* toggle reset */ 237 microdelay(100); 238 } 239 } 240 241 /* 242 * ps/2 mouse message is three bytes 243 * 244 * byte 0 - 0 0 SDY SDX 1 M R L 245 * byte 1 - DX 246 * byte 2 - DY 247 * 248 * shift & left button is the same as middle button 249 */ 250 static int 251 ps2mouseputc(int c) 252 { 253 static short msg[3]; 254 static int nb; 255 static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 }; 256 int buttons, dx, dy; 257 258 /* 259 * check byte 0 for consistency 260 */ 261 if(nb==0 && (c&0xc8)!=0x08) 262 return 0; 263 264 msg[nb] = c; 265 if(++nb == 3) { 266 nb = 0; 267 if(msg[0] & 0x10) 268 msg[1] |= 0xFF00; 269 if(msg[0] & 0x20) 270 msg[2] |= 0xFF00; 271 272 buttons = b[(msg[0]&7) | (shift ? 8 : 0)] | keybuttons; 273 dx = msg[1]; 274 dy = -msg[2]; 275 mousetrack(buttons, dx, dy, 1); 276 } 277 return 0; 278 } 279 280 /* 281 * keyboard interrupt 282 */ 283 void 284 kbdintr(void) 285 { 286 int s, c, i; 287 static int esc1, esc2; 288 static int caps; 289 static int ctl; 290 static int num; 291 static int collecting, nk; 292 static int alt; 293 static Rune kc[5]; 294 int keyup; 295 296 /* 297 * get status 298 */ 299 s = superio_readctl(); 300 if(!(s&Inready)) 301 return; 302 303 /* 304 * get the character 305 */ 306 c = superio_readdata(); 307 308 /* 309 * if it's the mouse... 310 */ 311 if(s & Minready) { 312 ps2mouseputc(c); 313 return; 314 } 315 316 /* 317 * e0's is the first of a 2 character sequence 318 */ 319 if(c == 0xe0){ 320 esc1 = 1; 321 return; 322 } else if(c == 0xe1){ 323 esc2 = 2; 324 return; 325 } 326 327 keyup = c&0x80; 328 c &= 0x7f; 329 if(c > sizeof kbtab){ 330 /* print("unknown key %ux\n", c|keyup); */ 331 return; 332 } 333 334 if(esc1){ 335 c = kbtabesc1[c]; 336 esc1 = 0; 337 } else if(esc2){ 338 esc2--; 339 return; 340 } else if(shift) 341 c = kbtabshift[c]; 342 else 343 c = kbtab[c]; 344 345 if(caps && c<='z' && c>='a') 346 c += 'A' - 'a'; 347 348 /* 349 * keyup only important for shifts 350 */ 351 if(keyup){ 352 switch(c){ 353 case Latin: 354 alt = 0; 355 break; 356 case Shift: 357 shift = 0; 358 break; 359 case Ctrl: 360 ctl = 0; 361 break; 362 } 363 return; 364 } 365 366 /* 367 * normal character 368 */ 369 if(!(c & Spec)){ 370 if(ctl){ 371 if(alt && c == Del) 372 exit(0); 373 c &= 0x1f; 374 } 375 if(!collecting){ 376 kbdputc(kbdq, c); 377 return; 378 } 379 kc[nk++] = c; 380 c = latin1(kc, nk); 381 if(c < -1) /* need more keystrokes */ 382 return; 383 if(c != -1) /* valid sequence */ 384 kbdputc(kbdq, c); 385 else /* dump characters */ 386 for(i=0; i<nk; i++) 387 kbdputc(kbdq, kc[i]); 388 nk = 0; 389 collecting = 0; 390 return; 391 } else { 392 switch(c){ 393 case Caps: 394 caps ^= 1; 395 return; 396 case Num: 397 num ^= 1; 398 return; 399 case Shift: 400 shift = 1; 401 return; 402 case Latin: 403 alt = 1; 404 collecting = 1; 405 nk = 0; 406 return; 407 case Ctrl: 408 ctl = 1; 409 return; 410 } 411 } 412 kbdputc(kbdq, c); 413 } 414 415 /* 416 * set up a ps2 mouse 417 */ 418 static void 419 ps2mouse(void) 420 { 421 int x; 422 423 /* enable kbd/mouse xfers and interrupts */ 424 x = splhi(); 425 ccc &= ~Cmousedis; 426 ccc |= Cmouseint; 427 if(outready() < 0) 428 print("mouse init failed\n"); 429 superio_writectl(0x60); 430 if(outready() < 0) 431 print("mouse init failed\n"); 432 superio_writedata(ccc); 433 if(outready() < 0) 434 print("mouse init failed\n"); 435 superio_writectl(0xA8); 436 if(outready() < 0){ 437 splx(x); 438 return; 439 } 440 441 /* make mouse streaming, enabled */ 442 mousecmd(0xEA); 443 mousecmd(0xF4); 444 splx(x); 445 } 446 447 void 448 kbdinit(void) 449 { 450 int c; 451 452 kbdq = qopen(4*1024, 0, 0, 0); 453 qnoblock(kbdq, 1); 454 455 /* wait for a quiescent controller */ 456 while((c = superio_readctl()) & (Outbusy | Inready)) 457 if(c & Inready) 458 superio_readdata(); 459 460 /* get current controller command byte */ 461 superio_writectl(0x20); 462 if(inready() < 0){ 463 print("kbdinit: can't read ccc\n"); 464 ccc = 0; 465 } else 466 ccc = superio_readdata(); 467 468 /* enable kbd xfers and interrupts */ 469 /* disable mouse */ 470 ccc &= ~Ckbddis; 471 ccc |= Csf | Ckbdint | Cscs1 | Cmousedis; 472 if(outready() < 0) 473 print("kbd init failed\n"); 474 superio_writectl(0x60); 475 if(outready() < 0) 476 print("kbd init failed\n"); 477 superio_writedata(ccc); 478 outready(); 479 480 /* Assume ps2 mouse */ 481 ps2mouse(); 482 } 483