kbd.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. #include "u.h"
  2. #include "lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. enum {
  8. Data= 0x60, /* data port */
  9. Status= 0x64, /* status port */
  10. Inready= 0x01, /* input character ready */
  11. Outbusy= 0x02, /* output busy */
  12. Sysflag= 0x04, /* system flag */
  13. Cmddata= 0x08, /* cmd==0, data==1 */
  14. Inhibit= 0x10, /* keyboard/mouse inhibited */
  15. Minready= 0x20, /* mouse character ready */
  16. Rtimeout= 0x40, /* general timeout */
  17. Parity= 0x80,
  18. Cmd= 0x64, /* command port (write only) */
  19. Spec= 0x80,
  20. PF= Spec|0x20, /* num pad function key */
  21. View= Spec|0x00, /* view (shift window up) */
  22. KF= Spec|0x40, /* function key */
  23. Shift= Spec|0x60,
  24. Break= Spec|0x61,
  25. Ctrl= Spec|0x62,
  26. Latin= Spec|0x63,
  27. Caps= Spec|0x64,
  28. Num= Spec|0x65,
  29. No= Spec|0x7F, /* no mapping */
  30. Home= KF|13,
  31. Up= KF|14,
  32. Pgup= KF|15,
  33. Print= KF|16,
  34. Left= View,
  35. Right= View,
  36. End= '\r',
  37. Down= View,
  38. Pgdown= View,
  39. Ins= KF|20,
  40. Del= 0x7F,
  41. };
  42. uchar kbtab[] =
  43. {
  44. [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6',
  45. [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
  46. [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
  47. [0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's',
  48. [0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
  49. [0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v',
  50. [0x30] 'b', 'n', 'm', ',', '.', '/', Shift, No,
  51. [0x38] Latin, ' ', Caps, KF|1, KF|2, KF|3, KF|4, KF|5,
  52. [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, Home,
  53. [0x48] No, No, No, No, No, No, No, No,
  54. [0x50] No, No, No, No, No, No, No, KF|11,
  55. [0x58] KF|12, No, No, No, No, No, No, No,
  56. };
  57. uchar kbtabshift[] =
  58. {
  59. [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^',
  60. [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
  61. [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
  62. [0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S',
  63. [0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
  64. [0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V',
  65. [0x30] 'B', 'N', 'M', '<', '>', '?', Shift, No,
  66. [0x38] Latin, ' ', Caps, KF|1, KF|2, KF|3, KF|4, KF|5,
  67. [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, Home,
  68. [0x48] No, No, No, No, No, No, No, No,
  69. [0x50] No, No, No, No, No, No, No, KF|11,
  70. [0x58] KF|12, No, No, No, No, No, No, No,
  71. };
  72. uchar kbtabesc1[] =
  73. {
  74. [0x00] No, No, No, No, No, No, No, No,
  75. [0x08] No, No, No, No, No, No, No, No,
  76. [0x10] No, No, No, No, No, No, No, No,
  77. [0x18] No, No, No, No, No, Ctrl, No, No,
  78. [0x20] No, No, No, No, No, No, No, No,
  79. [0x28] No, No, No, No, No, No, No, No,
  80. [0x30] No, No, No, No, No, No, No, Print,
  81. [0x38] Latin, No, No, No, No, No, No, No,
  82. [0x40] No, No, No, No, No, No, Break, Home,
  83. [0x48] Up, Pgup, No, Down, No, Right, No, End,
  84. [0x50] Left, Pgdown, Ins, Del, No, No, No, No,
  85. [0x58] No, No, No, No, No, No, No, No,
  86. };
  87. struct latin
  88. {
  89. uint8_t l;
  90. char c[2];
  91. }latintab[] = {
  92. L'¡', "!!", /* spanish initial ! */
  93. L'¢', "c|", /* cent */
  94. L'¢', "c$", /* cent */
  95. L'£', "l$", /* pound sterling */
  96. L'¤', "g$", /* general currency */
  97. L'¥', "y$", /* yen */
  98. L'¥', "j$", /* yen */
  99. L'¦', "||", /* broken vertical bar */
  100. L'§', "SS", /* section symbol */
  101. L'¨', "\"\"", /* dieresis */
  102. L'©', "cr", /* copyright */
  103. L'©', "cO", /* copyright */
  104. L'ª', "sa", /* super a, feminine ordinal */
  105. L'«', "<<", /* left angle quotation */
  106. L'¬', "no", /* not sign, hooked overbar */
  107. L'­', "--", /* soft hyphen */
  108. L'®', "rg", /* registered trademark */
  109. L'¯', "__", /* macron */
  110. L'°', "s0", /* degree (sup o) */
  111. L'±', "+-", /* plus-minus */
  112. L'²', "s2", /* sup 2 */
  113. L'³', "s3", /* sup 3 */
  114. L'´', "''", /* grave accent */
  115. L'µ', "mu", /* mu */
  116. L'¶', "pg", /* paragraph (pilcrow) */
  117. L'·', "..", /* centered . */
  118. L'¸', ",,", /* cedilla */
  119. L'¹', "s1", /* sup 1 */
  120. L'º', "so", /* sup o */
  121. L'»', ">>", /* right angle quotation */
  122. L'¼', "14", /* 1/4 */
  123. L'½', "12", /* 1/2 */
  124. L'¾', "34", /* 3/4 */
  125. L'¿', "??", /* spanish initial ? */
  126. L'À', "A`", /* A grave */
  127. L'Á', "A'", /* A acute */
  128. L'Â', "A^", /* A circumflex */
  129. L'Ã', "A~", /* A tilde */
  130. L'Ä', "A\"", /* A dieresis */
  131. L'Ä', "A:", /* A dieresis */
  132. L'Å', "Ao", /* A circle */
  133. L'Å', "AO", /* A circle */
  134. L'Æ', "Ae", /* AE ligature */
  135. L'Æ', "AE", /* AE ligature */
  136. L'Ç', "C,", /* C cedilla */
  137. L'È', "E`", /* E grave */
  138. L'É', "E'", /* E acute */
  139. L'Ê', "E^", /* E circumflex */
  140. L'Ë', "E\"", /* E dieresis */
  141. L'Ë', "E:", /* E dieresis */
  142. L'Ì', "I`", /* I grave */
  143. L'Í', "I'", /* I acute */
  144. L'Î', "I^", /* I circumflex */
  145. L'Ï', "I\"", /* I dieresis */
  146. L'Ï', "I:", /* I dieresis */
  147. L'Ð', "D-", /* Eth */
  148. L'Ñ', "N~", /* N tilde */
  149. L'Ò', "O`", /* O grave */
  150. L'Ó', "O'", /* O acute */
  151. L'Ô', "O^", /* O circumflex */
  152. L'Õ', "O~", /* O tilde */
  153. L'Ö', "O\"", /* O dieresis */
  154. L'Ö', "O:", /* O dieresis */
  155. L'Ö', "OE", /* O dieresis */
  156. L'Ö', "Oe", /* O dieresis */
  157. L'×', "xx", /* times sign */
  158. L'Ø', "O/", /* O slash */
  159. L'Ù', "U`", /* U grave */
  160. L'Ú', "U'", /* U acute */
  161. L'Û', "U^", /* U circumflex */
  162. L'Ü', "U\"", /* U dieresis */
  163. L'Ü', "U:", /* U dieresis */
  164. L'Ü', "UE", /* U dieresis */
  165. L'Ü', "Ue", /* U dieresis */
  166. L'Ý', "Y'", /* Y acute */
  167. L'Þ', "P|", /* Thorn */
  168. L'Þ', "Th", /* Thorn */
  169. L'Þ', "TH", /* Thorn */
  170. L'ß', "ss", /* sharp s */
  171. L'à', "a`", /* a grave */
  172. L'á', "a'", /* a acute */
  173. L'â', "a^", /* a circumflex */
  174. L'ã', "a~", /* a tilde */
  175. L'ä', "a\"", /* a dieresis */
  176. L'ä', "a:", /* a dieresis */
  177. L'å', "ao", /* a circle */
  178. L'æ', "ae", /* ae ligature */
  179. L'ç', "c,", /* c cedilla */
  180. L'è', "e`", /* e grave */
  181. L'é', "e'", /* e acute */
  182. L'ê', "e^", /* e circumflex */
  183. L'ë', "e\"", /* e dieresis */
  184. L'ë', "e:", /* e dieresis */
  185. L'ì', "i`", /* i grave */
  186. L'í', "i'", /* i acute */
  187. L'î', "i^", /* i circumflex */
  188. L'ï', "i\"", /* i dieresis */
  189. L'ï', "i:", /* i dieresis */
  190. L'ð', "d-", /* eth */
  191. L'ñ', "n~", /* n tilde */
  192. L'ò', "o`", /* o grave */
  193. L'ó', "o'", /* o acute */
  194. L'ô', "o^", /* o circumflex */
  195. L'õ', "o~", /* o tilde */
  196. L'ö', "o\"", /* o dieresis */
  197. L'ö', "o:", /* o dieresis */
  198. L'ö', "oe", /* o dieresis */
  199. L'÷', "-:", /* divide sign */
  200. L'ø', "o/", /* o slash */
  201. L'ù', "u`", /* u grave */
  202. L'ú', "u'", /* u acute */
  203. L'û', "u^", /* u circumflex */
  204. L'ü', "u\"", /* u dieresis */
  205. L'ü', "u:", /* u dieresis */
  206. L'ü', "ue", /* u dieresis */
  207. L'ý', "y'", /* y acute */
  208. L'þ', "th", /* thorn */
  209. L'þ', "p|", /* thorn */
  210. L'ÿ', "y\"", /* y dieresis */
  211. L'ÿ', "y:", /* y dieresis */
  212. 0, 0,
  213. };
  214. enum
  215. {
  216. /* controller command byte */
  217. Cscs1= (1<<6), /* scan code set 1 */
  218. Cmousedis= (1<<5), /* mouse disable */
  219. Ckbddis= (1<<4), /* kbd disable */
  220. Csf= (1<<2), /* system flag */
  221. Cmouseint= (1<<1), /* mouse interrupt enable */
  222. Ckbdint= (1<<0), /* kbd interrupt enable */
  223. };
  224. static uint8_t ccc;
  225. static int nokbd = 1;
  226. int
  227. latin1(int k1, int k2)
  228. {
  229. struct latin *l;
  230. for(l=latintab; l->l; l++)
  231. if(k1==l->c[0] && k2==l->c[1])
  232. return l->l;
  233. return 0;
  234. }
  235. /*
  236. * wait for output no longer busy
  237. */
  238. static int
  239. outready(void)
  240. {
  241. int tries;
  242. for(tries = 0; (inb(Status) & Outbusy); tries++){
  243. if(tries > 500)
  244. return -1;
  245. delay(2);
  246. }
  247. return 0;
  248. }
  249. /*
  250. * wait for input
  251. */
  252. static int
  253. inready(void)
  254. {
  255. int tries;
  256. for(tries = 0; !(inb(Status) & Inready); tries++){
  257. if(tries > 500)
  258. return -1;
  259. delay(2);
  260. }
  261. return 0;
  262. }
  263. /*
  264. * ask 8042 to enable the use of address bit 20
  265. */
  266. void
  267. i8042a20(void)
  268. {
  269. outready();
  270. outb(Cmd, 0xD1);
  271. outready();
  272. outb(Data, 0xDF);
  273. outready();
  274. }
  275. /*
  276. * ask 8042 to reset the machine
  277. */
  278. void
  279. i8042reset(void)
  280. {
  281. int i, x;
  282. if(nokbd)
  283. return;
  284. *((uint16_t*)KADDR(0x472)) = 0x1234; /* BIOS warm-boot flag */
  285. /*
  286. * newer reset the machine command
  287. */
  288. outready();
  289. outb(Cmd, 0xFE);
  290. outready();
  291. /*
  292. * Pulse it by hand (old somewhat reliable)
  293. */
  294. x = 0xDF;
  295. for(i = 0; i < 5; i++){
  296. x ^= 1;
  297. outready();
  298. outb(Cmd, 0xD1);
  299. outready();
  300. outb(Data, x); /* toggle reset */
  301. delay(100);
  302. }
  303. }
  304. /*
  305. * keyboard interrupt
  306. */
  307. static void
  308. i8042intr(Ureg*, void*)
  309. {
  310. int s, c;
  311. static int esc1, esc2;
  312. static int alt, caps, ctl, num, shift;
  313. static int lstate, k1, k2;
  314. int keyup;
  315. /*
  316. * get status
  317. */
  318. s = inb(Status);
  319. if(!(s&Inready))
  320. return;
  321. /*
  322. * get the character
  323. */
  324. c = inb(Data);
  325. /*
  326. * if it's the aux port...
  327. */
  328. if(s & Minready)
  329. return;
  330. /*
  331. * e0's is the first of a 2 character sequence
  332. */
  333. if(c == 0xe0){
  334. esc1 = 1;
  335. return;
  336. } else if(c == 0xe1){
  337. esc2 = 2;
  338. return;
  339. }
  340. keyup = c&0x80;
  341. c &= 0x7f;
  342. if(c > sizeof kbtab){
  343. c |= keyup;
  344. if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */
  345. print("unknown key %ux\n", c);
  346. return;
  347. }
  348. if(esc1){
  349. c = kbtabesc1[c];
  350. esc1 = 0;
  351. } else if(esc2){
  352. esc2--;
  353. return;
  354. } else if(shift)
  355. c = kbtabshift[c];
  356. else
  357. c = kbtab[c];
  358. if(caps && c<='z' && c>='a')
  359. c += 'A' - 'a';
  360. /*
  361. * keyup only important for shifts
  362. */
  363. if(keyup){
  364. switch(c){
  365. case Latin:
  366. alt = 0;
  367. break;
  368. case Shift:
  369. shift = 0;
  370. break;
  371. case Ctrl:
  372. ctl = 0;
  373. break;
  374. }
  375. return;
  376. }
  377. /*
  378. * normal character
  379. */
  380. if(!(c & Spec)){
  381. if(ctl){
  382. if(alt && c == Del)
  383. warp86("\nCtrl-Alt-Del\n", 0);
  384. c &= 0x1f;
  385. }
  386. switch(lstate){
  387. case 1:
  388. k1 = c;
  389. lstate = 2;
  390. return;
  391. case 2:
  392. k2 = c;
  393. lstate = 0;
  394. c = latin1(k1, k2);
  395. if(c == 0){
  396. kbdchar(k1);
  397. c = k2;
  398. }
  399. /* fall through */
  400. default:
  401. break;
  402. }
  403. } else {
  404. switch(c){
  405. case Caps:
  406. caps ^= 1;
  407. return;
  408. case Num:
  409. num ^= 1;
  410. return;
  411. case Shift:
  412. shift = 1;
  413. return;
  414. case Latin:
  415. alt = 1;
  416. lstate = 1;
  417. return;
  418. case Ctrl:
  419. ctl = 1;
  420. return;
  421. }
  422. }
  423. kbdchar(c);
  424. }
  425. static char *initfailed = "i8042: kbdinit failed\n";
  426. static int
  427. outbyte(int port, int c)
  428. {
  429. outb(port, c);
  430. if(outready() < 0) {
  431. // vga = 0;
  432. print(initfailed);
  433. return -1;
  434. }
  435. return 0;
  436. }
  437. void
  438. i8042init(void)
  439. {
  440. int c, try;
  441. /* wait for a quiescent controller */
  442. try = 1000;
  443. while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
  444. if(c & Inready)
  445. inb(Data);
  446. delay(1);
  447. }
  448. if (try <= 0) {
  449. // vga = 0;
  450. print(initfailed);
  451. return;
  452. }
  453. /* get current controller command byte */
  454. outb(Cmd, 0x20);
  455. if(inready() < 0){
  456. print("i8042: kbdinit can't read ccc\n");
  457. ccc = 0;
  458. } else
  459. ccc = inb(Data);
  460. /* enable kbd xfers and interrupts */
  461. ccc &= ~Ckbddis;
  462. ccc |= Csf | Ckbdint | Cscs1;
  463. if(outready() < 0) {
  464. // vga = 0;
  465. print(initfailed);
  466. return;
  467. }
  468. nokbd = 0;
  469. /* disable mouse */
  470. if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0)
  471. print("i8042: kbdinit mouse disable failed\n");
  472. setvec(VectorKBD, i8042intr, 0);
  473. }