kbd.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  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. enum {
  9. Data= 0x60, /* data port */
  10. Status= 0x64, /* status port */
  11. Inready= 0x01, /* input character ready */
  12. Outbusy= 0x02, /* output busy */
  13. Sysflag= 0x04, /* system flag */
  14. Cmddata= 0x08, /* cmd==0, data==1 */
  15. Inhibit= 0x10, /* keyboard/mouse inhibited */
  16. Minready= 0x20, /* mouse character ready */
  17. Rtimeout= 0x40, /* general timeout */
  18. Parity= 0x80,
  19. Cmd= 0x64, /* command port (write only) */
  20. Spec= 0x80,
  21. PF= Spec|0x20, /* num pad function key */
  22. View= Spec|0x00, /* view (shift window up) */
  23. KF= 0xF000, /* function key (begin Unicode private space) */
  24. Shift= Spec|0x60,
  25. Break= Spec|0x61,
  26. Ctrl= Spec|0x62,
  27. Latin= Spec|0x63,
  28. Caps= Spec|0x64,
  29. Num= Spec|0x65,
  30. Middle= Spec|0x66,
  31. No= 0x00, /* peter */
  32. Home= KF|13,
  33. Up= KF|14,
  34. Pgup= KF|15,
  35. Print= KF|16,
  36. Left= KF|17,
  37. Right= KF|18,
  38. End= '\r',
  39. Down= View,
  40. Pgdown= KF|19,
  41. Ins= KF|20,
  42. Del= 0x7F,
  43. Scroll= KF|21,
  44. };
  45. /*
  46. * The codes at 0x79 and 0x81 are produed by the PFU Happy Hacking keyboard.
  47. * A 'standard' keyboard doesn't produce anything above 0x58.
  48. */
  49. Rune kbtab[] =
  50. {
  51. [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6',
  52. [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
  53. [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
  54. [0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's',
  55. [0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
  56. [0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v',
  57. [0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*',
  58. [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
  59. [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
  60. [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
  61. [0x50] '2', '3', '0', '.', No, No, No, KF|11,
  62. [0x58] KF|12, No, No, No, No, No, No, No,
  63. [0x60] No, No, No, No, No, No, No, No,
  64. [0x68] No, No, No, No, No, No, No, No,
  65. [0x70] No, No, No, No, No, No, No, No,
  66. [0x78] No, View, No, Up, No, No, No, No,
  67. };
  68. Rune kbtabshift[] =
  69. {
  70. [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^',
  71. [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
  72. [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
  73. [0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S',
  74. [0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
  75. [0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V',
  76. [0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*',
  77. [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
  78. [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
  79. [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
  80. [0x50] '2', '3', '0', '.', No, No, No, KF|11,
  81. [0x58] KF|12, No, No, No, No, No, No, No,
  82. [0x60] No, No, No, No, No, No, No, No,
  83. [0x68] No, No, No, No, No, No, No, No,
  84. [0x70] No, No, No, No, No, No, No, No,
  85. [0x78] No, Up, No, Up, No, No, No, No,
  86. };
  87. Rune kbtabesc1[] =
  88. {
  89. [0x00] No, No, No, No, No, No, No, No,
  90. [0x08] No, No, No, No, No, No, No, No,
  91. [0x10] No, No, No, No, No, No, No, No,
  92. [0x18] No, No, No, No, '\n', Ctrl, No, No,
  93. [0x20] No, No, No, No, No, No, No, No,
  94. [0x28] No, No, Shift, No, No, No, No, No,
  95. [0x30] No, No, No, No, No, '/', No, Print,
  96. [0x38] Latin, No, No, No, No, No, No, No,
  97. [0x40] No, No, No, No, No, No, Break, Home,
  98. [0x48] Up, Pgup, No, Left, No, Right, No, End,
  99. [0x50] Down, Pgdown, Ins, Del, No, No, No, No,
  100. [0x58] No, No, No, No, No, No, No, No,
  101. [0x60] No, No, No, No, No, No, No, No,
  102. [0x68] No, No, No, No, No, No, No, No,
  103. [0x70] No, No, No, No, No, No, No, No,
  104. [0x78] No, Up, No, No, No, No, No, No,
  105. };
  106. enum
  107. {
  108. /* controller command byte */
  109. Cscs1= (1<<6), /* scan code set 1 */
  110. Cauxdis= (1<<5), /* mouse disable */
  111. Ckbddis= (1<<4), /* kbd disable */
  112. Csf= (1<<2), /* system flag */
  113. Cauxint= (1<<1), /* mouse interrupt enable */
  114. Ckbdint= (1<<0), /* kbd interrupt enable */
  115. };
  116. int mouseshifted;
  117. static Lock i8042lock;
  118. static uchar ccc;
  119. static void (*auxputc)(int, int);
  120. /*
  121. * wait for output no longer busy
  122. */
  123. static int
  124. outready(void)
  125. {
  126. int tries;
  127. for(tries = 0; (inb(Status) & Outbusy); tries++){
  128. if(tries > 500)
  129. return -1;
  130. delay(2);
  131. }
  132. return 0;
  133. }
  134. /*
  135. * wait for input
  136. */
  137. static int
  138. inready(void)
  139. {
  140. int tries;
  141. for(tries = 0; !(inb(Status) & Inready); tries++){
  142. if(tries > 500)
  143. return -1;
  144. delay(2);
  145. }
  146. return 0;
  147. }
  148. /*
  149. * ask 8042 to reset the machine
  150. */
  151. void
  152. i8042reset(void)
  153. {
  154. ushort *s = KADDR(0x472);
  155. int i, x;
  156. *s = 0x1234; /* BIOS warm-boot flag */
  157. /*
  158. * newer reset the machine command
  159. */
  160. outready();
  161. outb(Cmd, 0xFE);
  162. outready();
  163. /*
  164. * Pulse it by hand (old somewhat reliable)
  165. */
  166. x = 0xDF;
  167. for(i = 0; i < 5; i++){
  168. x ^= 1;
  169. outready();
  170. outb(Cmd, 0xD1);
  171. outready();
  172. outb(Data, x); /* toggle reset */
  173. delay(100);
  174. }
  175. }
  176. int
  177. i8042auxcmd(int cmd)
  178. {
  179. unsigned int c;
  180. int tries;
  181. c = 0;
  182. tries = 0;
  183. ilock(&i8042lock);
  184. do{
  185. if(tries++ > 2)
  186. break;
  187. if(outready() < 0)
  188. break;
  189. outb(Cmd, 0xD4);
  190. if(outready() < 0)
  191. break;
  192. outb(Data, cmd);
  193. if(outready() < 0)
  194. break;
  195. if(inready() < 0)
  196. break;
  197. c = inb(Data);
  198. } while(c == 0xFE || c == 0);
  199. iunlock(&i8042lock);
  200. if(c != 0xFA){
  201. print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
  202. return -1;
  203. }
  204. return 0;
  205. }
  206. int
  207. i8042auxcmds(uchar *cmd, int ncmd)
  208. {
  209. int i;
  210. ilock(&i8042lock);
  211. for(i=0; i<ncmd; i++){
  212. if(outready() < 0)
  213. break;
  214. outb(Cmd, 0xD4);
  215. if(outready() < 0)
  216. break;
  217. outb(Data, cmd[i]);
  218. }
  219. iunlock(&i8042lock);
  220. return i;
  221. }
  222. /*
  223. * keyboard interrupt
  224. */
  225. static void
  226. i8042intr(Ureg*, void*)
  227. {
  228. int s, c, i;
  229. static int esc1, esc2;
  230. static int alt, caps, ctl, num, shift;
  231. static int collecting, nk;
  232. static Rune kc[5];
  233. int keyup;
  234. /*
  235. * get status
  236. */
  237. lock(&i8042lock);
  238. s = inb(Status);
  239. if(!(s&Inready)){
  240. unlock(&i8042lock);
  241. return;
  242. }
  243. /*
  244. * get the character
  245. */
  246. c = inb(Data);
  247. unlock(&i8042lock);
  248. /*
  249. * if it's the aux port...
  250. */
  251. if(s & Minready){
  252. if(auxputc != nil)
  253. auxputc(c, shift);
  254. return;
  255. }
  256. /*
  257. * e0's is the first of a 2 character sequence
  258. */
  259. if(c == 0xe0){
  260. esc1 = 1;
  261. return;
  262. } else if(c == 0xe1){
  263. esc2 = 2;
  264. return;
  265. }
  266. keyup = c&0x80;
  267. c &= 0x7f;
  268. if(c > sizeof kbtab){
  269. c |= keyup;
  270. if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */
  271. print("unknown key %ux\n", c);
  272. return;
  273. }
  274. if(esc1){
  275. c = kbtabesc1[c];
  276. esc1 = 0;
  277. } else if(esc2){
  278. esc2--;
  279. return;
  280. } else if(shift)
  281. c = kbtabshift[c];
  282. else
  283. c = kbtab[c];
  284. if(caps && c<='z' && c>='a')
  285. c += 'A' - 'a';
  286. /*
  287. * keyup only important for shifts
  288. */
  289. if(keyup){
  290. switch(c){
  291. case Latin:
  292. alt = 0;
  293. break;
  294. case Shift:
  295. shift = 0;
  296. mouseshifted = 0;
  297. break;
  298. case Ctrl:
  299. ctl = 0;
  300. break;
  301. }
  302. return;
  303. }
  304. /*
  305. * normal character
  306. */
  307. if(!(c & (Spec|KF))){
  308. if(ctl){
  309. if(alt && c == Del)
  310. exit(0);
  311. c &= 0x1f;
  312. }
  313. if(!collecting){
  314. kbdputc(kbdq, c);
  315. return;
  316. }
  317. kc[nk++] = c;
  318. c = latin1(kc, nk);
  319. if(c < -1) /* need more keystrokes */
  320. return;
  321. if(c != -1) /* valid sequence */
  322. kbdputc(kbdq, c);
  323. else /* dump characters */
  324. for(i=0; i<nk; i++)
  325. kbdputc(kbdq, kc[i]);
  326. nk = 0;
  327. collecting = 0;
  328. return;
  329. } else {
  330. switch(c){
  331. case Caps:
  332. caps ^= 1;
  333. return;
  334. case Num:
  335. num ^= 1;
  336. return;
  337. case Shift:
  338. shift = 1;
  339. mouseshifted = 1;
  340. return;
  341. case Latin:
  342. alt = 1;
  343. /*
  344. * VMware uses Ctl-Alt as the key combination
  345. * to make the VM give up keyboard and mouse focus.
  346. * This has the unfortunate side effect that when you
  347. * come back into focus, Plan 9 thinks you want to type
  348. * a compose sequence (you just typed alt).
  349. *
  350. * As a clumsy hack around this, we look for ctl-alt
  351. * and don't treat it as the start of a compose sequence.
  352. */
  353. if(!ctl){
  354. collecting = 1;
  355. nk = 0;
  356. }
  357. return;
  358. case Ctrl:
  359. collecting = 0;
  360. nk = 0;
  361. ctl = 1;
  362. return;
  363. }
  364. }
  365. kbdputc(kbdq, c);
  366. }
  367. void
  368. i8042auxenable(void (*putc)(int, int))
  369. {
  370. char *err = "i8042: aux init failed\n";
  371. /* enable kbd/aux xfers and interrupts */
  372. ccc &= ~Cauxdis;
  373. ccc |= Cauxint;
  374. ilock(&i8042lock);
  375. if(outready() < 0)
  376. print(err);
  377. outb(Cmd, 0x60); /* write control register */
  378. if(outready() < 0)
  379. print(err);
  380. outb(Data, ccc);
  381. if(outready() < 0)
  382. print(err);
  383. outb(Cmd, 0xA8); /* auxilliary device enable */
  384. if(outready() < 0){
  385. iunlock(&i8042lock);
  386. return;
  387. }
  388. auxputc = putc;
  389. intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
  390. iunlock(&i8042lock);
  391. }
  392. void
  393. kbdinit(void)
  394. {
  395. int c;
  396. /* wait for a quiescent controller */
  397. while((c = inb(Status)) & (Outbusy | Inready))
  398. if(c & Inready)
  399. inb(Data);
  400. /* get current controller command byte */
  401. outb(Cmd, 0x20);
  402. if(inready() < 0){
  403. print("kbdinit: can't read ccc\n");
  404. ccc = 0;
  405. } else
  406. ccc = inb(Data);
  407. /* enable kbd xfers and interrupts */
  408. /* disable mouse */
  409. ccc &= ~Ckbddis;
  410. ccc |= Csf | Ckbdint | Cscs1;
  411. if(outready() < 0)
  412. print("kbd init failed\n");
  413. outb(Cmd, 0x60);
  414. if(outready() < 0)
  415. print("kbd init failed\n");
  416. outb(Data, ccc);
  417. outready();
  418. }
  419. void
  420. kbdenable(void)
  421. {
  422. kbdq = qopen(4*1024, 0, 0, 0);
  423. if(kbdq == nil)
  424. panic("kbdinit");
  425. qnoblock(kbdq, 1);
  426. ioalloc(Data, 1, 0, "kbd");
  427. ioalloc(Cmd, 1, 0, "kbd");
  428. intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
  429. }