kbd.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #include "all.h"
  2. #include "mem.h"
  3. #include "io.h"
  4. #include "ureg.h"
  5. enum {
  6. Data= 0x60, /* data port */
  7. Status= 0x64, /* status port */
  8. Inready= 0x01, /* input character ready */
  9. Outbusy= 0x02, /* output busy */
  10. Sysflag= 0x04, /* system flag */
  11. Cmddata= 0x08, /* cmd==0, data==1 */
  12. Inhibit= 0x10, /* keyboard/mouse inhibited */
  13. Minready= 0x20, /* mouse character ready */
  14. Rtimeout= 0x40, /* general timeout */
  15. Parity= 0x80,
  16. Cmd= 0x64, /* command port (write only) */
  17. CTdata= 0x0, /* chips & Technologies ps2 data port */
  18. CTstatus= 0x1, /* chips & Technologies ps2 status port */
  19. Enable= 1<<7,
  20. Clear= 1<<6,
  21. Error= 1<<5,
  22. Intenable= 1<<4,
  23. Reset= 1<<3,
  24. Tready= 1<<2,
  25. Rready= 1<<1,
  26. Idle= 1<<0,
  27. Spec= 0x80,
  28. PF= Spec|0x20, /* num pad function key */
  29. View= Spec|0x00, /* view (shift window up) */
  30. KF= Spec|0x40, /* function key */
  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. No= 0x00, /* peter */
  39. Home= KF|13,
  40. Up= KF|14,
  41. Pgup= KF|15,
  42. Print= KF|16,
  43. Left= View,
  44. Right= View,
  45. End= '\r',
  46. Down= View,
  47. Pgdown= View,
  48. Ins= KF|20,
  49. Del= 0x7F,
  50. Rbutton=4,
  51. Mbutton=2,
  52. Lbutton=1,
  53. };
  54. uchar kbtab[] =
  55. {
  56. [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6',
  57. [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
  58. [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
  59. [0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's',
  60. [0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
  61. [0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v',
  62. [0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*',
  63. [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
  64. [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, '7',
  65. [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
  66. [0x50] '2', '3', '0', '.', Del, No, No, KF|11,
  67. [0x58] KF|12, No, No, No, No, No, No, No,
  68. };
  69. uchar kbtabshift[] =
  70. {
  71. [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^',
  72. [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
  73. [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
  74. [0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S',
  75. [0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
  76. [0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V',
  77. [0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*',
  78. [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
  79. [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, '7',
  80. [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
  81. [0x50] '2', '3', '0', '.', No, No, No, KF|11,
  82. [0x58] KF|12, No, No, No, No, No, No, No,
  83. };
  84. uchar kbtabesc1[] =
  85. {
  86. [0x00] No, No, No, No, No, No, No, No,
  87. [0x08] No, No, No, No, No, No, No, No,
  88. [0x10] No, No, No, No, No, No, No, No,
  89. [0x18] No, No, No, No, '\n', Ctrl, No, No,
  90. [0x20] No, No, No, No, No, No, No, No,
  91. [0x28] No, No, Shift, No, No, No, No, No,
  92. [0x30] No, No, No, No, No, '/', No, Print,
  93. [0x38] Latin, No, No, No, No, No, No, No,
  94. [0x40] No, No, No, No, No, No, Break, Home,
  95. [0x48] Up, Pgup, No, Left, No, Right, No, End,
  96. [0x50] Down, Pgdown, Ins, Del, No, No, No, No,
  97. [0x58] No, No, No, No, No, No, No, No,
  98. };
  99. static uchar ccc;
  100. static int shift;
  101. enum
  102. {
  103. /* controller command byte */
  104. Cscs1= (1<<6), /* scan code set 1 */
  105. Cmousedis= (1<<5), /* mouse disable */
  106. Ckbddis= (1<<4), /* kbd disable */
  107. Csf= (1<<2), /* system flag */
  108. Cmouseint= (1<<1), /* mouse interrupt enable */
  109. Ckbdint= (1<<0), /* kbd interrupt enable */
  110. };
  111. /*
  112. * wait for output no longer busy
  113. */
  114. static int
  115. outready(void)
  116. {
  117. int tries;
  118. for(tries = 0; (inb(Status) & Outbusy); tries++){
  119. if(tries > 500)
  120. return -1;
  121. delay(2);
  122. }
  123. return 0;
  124. }
  125. /*
  126. * wait for input
  127. */
  128. static int
  129. inready(void)
  130. {
  131. int tries;
  132. for(tries = 0; !(inb(Status) & Inready); tries++){
  133. if(tries > 500)
  134. return -1;
  135. delay(2);
  136. }
  137. return 0;
  138. }
  139. /*
  140. * ask 8042 to enable the use of address bit 20
  141. */
  142. void
  143. i8042a20(void)
  144. {
  145. outready();
  146. outb(Cmd, 0xD1);
  147. outready();
  148. outb(Data, 0xDF);
  149. outready();
  150. }
  151. /*
  152. * ask 8042 to reset the machine
  153. */
  154. void
  155. i8042reset(void)
  156. {
  157. ushort *s = (ushort*)(KZERO|0x472);
  158. *s = 0x1234; /* BIOS warm-boot flag */
  159. outready();
  160. outb(Cmd, 0xFE); /* pulse reset line (means resend on AT&T machines) */
  161. outready();
  162. }
  163. /*
  164. * keyboard processing
  165. */
  166. int
  167. kbdintr0(void)
  168. {
  169. int s, c;
  170. static int esc1, esc2;
  171. static int caps;
  172. static int ctl;
  173. static int num;
  174. int keyup;
  175. /*
  176. * get status
  177. */
  178. s = inb(Status);
  179. if(!(s&Inready))
  180. return -1;
  181. /*
  182. * get the character
  183. */
  184. c = inb(Data);
  185. /*
  186. * e0's is the first of a 2 character sequence
  187. */
  188. if(c == 0xe0){
  189. esc1 = 1;
  190. return -1;
  191. } else if(c == 0xe1){
  192. esc2 = 2;
  193. return -1;
  194. }
  195. keyup = c&0x80;
  196. c &= 0x7f;
  197. if(c > sizeof kbtab){
  198. print("unknown key %ux\n", c|keyup);
  199. return -1;
  200. }
  201. if(esc1){
  202. c = kbtabesc1[c];
  203. esc1 = 0;
  204. } else if(esc2){
  205. esc2--;
  206. return -1;
  207. } else if(shift)
  208. c = kbtabshift[c];
  209. else
  210. c = kbtab[c];
  211. if(caps && c<='z' && c>='a')
  212. c += 'A' - 'a';
  213. /*
  214. * keyup only important for shifts
  215. */
  216. if(keyup){
  217. switch(c){
  218. case Shift:
  219. shift = 0;
  220. break;
  221. case Ctrl:
  222. ctl = 0;
  223. break;
  224. }
  225. return -1;
  226. }
  227. /*
  228. * normal character
  229. */
  230. if(!(c & Spec)){
  231. if(ctl)
  232. c &= 0x1f;
  233. return c;
  234. } else {
  235. switch(c){
  236. case Caps:
  237. caps ^= 1;
  238. return -1;
  239. case Num:
  240. num ^= 1;
  241. return -1;
  242. case Shift:
  243. shift = 1;
  244. return -1;
  245. case Ctrl:
  246. ctl = 1;
  247. return -1;
  248. }
  249. }
  250. return c;
  251. }
  252. static void
  253. kbdintr(Ureg *ur, void *v)
  254. {
  255. int c;
  256. USED(ur, v);
  257. if((c = kbdintr0()) >= 0)
  258. kbdchar(c);
  259. }
  260. int
  261. kbdgetc(void)
  262. {
  263. int c;
  264. if((c = kbdintr0()) < 0)
  265. return 0;
  266. return c;
  267. }
  268. void
  269. kbdinit(void)
  270. {
  271. int c;
  272. setvec(Kbdvec, kbdintr, 0);
  273. /* wait for a quiescent controller */
  274. while((c = inb(Status)) & (Outbusy | Inready))
  275. if(c & Inready)
  276. inb(Data);
  277. /* get current controller command byte */
  278. outb(Cmd, 0x20);
  279. if(inready() < 0){
  280. print("kbdinit: can't read ccc\n");
  281. ccc = 0;
  282. } else
  283. ccc = inb(Data);
  284. /* enable kbd xfers and interrupts */
  285. ccc &= ~Ckbddis;
  286. ccc |= Csf | Ckbdint | Cscs1;
  287. if(outready() < 0)
  288. print("kbd init failed\n");
  289. outb(Cmd, 0x60);
  290. if(outready() < 0)
  291. print("kbd init failed\n");
  292. outb(Data, ccc);
  293. outready();
  294. }