i8042.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. #include "io.h"
  16. enum {
  17. Data= 0x60, /* data port */
  18. Status= 0x64, /* status port */
  19. Inready= 0x01, /* input character ready */
  20. Outbusy= 0x02, /* output busy */
  21. Sysflag= 0x04, /* system flag */
  22. Cmddata= 0x08, /* cmd==0, data==1 */
  23. Inhibit= 0x10, /* keyboard/mouse inhibited */
  24. Minready= 0x20, /* mouse character ready */
  25. Rtimeout= 0x40, /* general timeout */
  26. Parity= 0x80,
  27. Cmd= 0x64, /* command port (write only) */
  28. };
  29. enum
  30. {
  31. /* controller command byte */
  32. Cscs1= (1<<6), /* scan code set 1 */
  33. Cauxdis= (1<<5), /* mouse disable */
  34. Ckeybdis= (1<<4), /* keyb disable */
  35. Csf= (1<<2), /* system flag */
  36. Cauxint= (1<<1), /* mouse interrupt enable */
  37. Ckeybint= (1<<0), /* keyb interrupt enable */
  38. };
  39. static Queue *keybq;
  40. static Queue *mouseq;
  41. static int nokeyb = 1;
  42. static Lock i8042lock;
  43. static uint8_t ccc;
  44. /*
  45. * wait for output no longer busy
  46. */
  47. static int
  48. outready(void)
  49. {
  50. int tries;
  51. for(tries = 0; (inb(Status) & Outbusy); tries++){
  52. if(tries > 500)
  53. return -1;
  54. delay(2);
  55. }
  56. return 0;
  57. }
  58. /*
  59. * wait for input
  60. */
  61. static int
  62. inready(void)
  63. {
  64. int tries;
  65. for(tries = 0; !(inb(Status) & Inready); tries++){
  66. if(tries > 500)
  67. return -1;
  68. delay(2);
  69. }
  70. return 0;
  71. }
  72. void
  73. i8042systemreset(void)
  74. {
  75. uint16_t *s = KADDR(0x472);
  76. int i, x;
  77. if(nokeyb)
  78. return;
  79. *s = 0x1234; /* BIOS warm-boot flag */
  80. /* newer reset the machine command */
  81. outready();
  82. outb(Cmd, 0xFE);
  83. outready();
  84. /* Pulse it by hand (old somewhat reliable) */
  85. x = 0xDF;
  86. for(i = 0; i < 5; i++){
  87. x ^= 1;
  88. outready();
  89. outb(Cmd, 0xD1);
  90. outready();
  91. outb(Data, x); /* toggle reset */
  92. delay(100);
  93. }
  94. }
  95. int
  96. mousecmd(int cmd)
  97. {
  98. unsigned int c;
  99. int tries;
  100. static int badkbd;
  101. if(badkbd)
  102. return -1;
  103. c = 0;
  104. tries = 0;
  105. ilock(&i8042lock);
  106. do{
  107. if(tries++ > 2)
  108. break;
  109. if(outready() < 0)
  110. break;
  111. outb(Cmd, 0xD4);
  112. if(outready() < 0)
  113. break;
  114. outb(Data, cmd);
  115. if(outready() < 0)
  116. break;
  117. if(inready() < 0)
  118. break;
  119. c = inb(Data);
  120. } while(c == 0xFE || c == 0);
  121. iunlock(&i8042lock);
  122. if(c != 0xFA){
  123. print("mousecmd: %2.2ux returned to the %2.2ux command\n", c, cmd);
  124. badkbd = 1; /* don't keep trying; there might not be one */
  125. return -1;
  126. }
  127. return 0;
  128. }
  129. static int
  130. mousecmds(uint8_t *cmd, int ncmd)
  131. {
  132. int i;
  133. ilock(&i8042lock);
  134. for(i=0; i<ncmd; i++){
  135. if(outready() == -1)
  136. break;
  137. outb(Cmd, 0xD4);
  138. if(outready() == -1)
  139. break;
  140. outb(Data, cmd[i]);
  141. }
  142. iunlock(&i8042lock);
  143. return i;
  144. }
  145. static void
  146. i8042intr(Ureg* u, void* v)
  147. {
  148. uint8_t stat, data;
  149. ilock(&i8042lock);
  150. stat = inb(Status);
  151. if((stat&Inready) == 0){
  152. iunlock(&i8042lock);
  153. return;
  154. }
  155. data = inb(Data);
  156. iunlock(&i8042lock);
  157. if(stat & Minready){
  158. if(mouseq != nil)
  159. qiwrite(mouseq, &data, 1);
  160. } else {
  161. if(keybq != nil)
  162. qiwrite(keybq, &data, 1);
  163. }
  164. }
  165. void
  166. kbdputsc(int data, int _)
  167. {
  168. qiwrite(keybq, &data, 1);
  169. }
  170. static int
  171. outbyte(int port, int c)
  172. {
  173. if(outready() == -1) {
  174. return -1;
  175. }
  176. outb(port, c);
  177. if(outready() == -1) {
  178. return -1;
  179. }
  180. return 0;
  181. }
  182. static int32_t
  183. mouserwrite(Chan* c, void *vbuf, int32_t len, int64_t off64)
  184. {
  185. return mousecmds(vbuf, len);
  186. }
  187. static int32_t
  188. mouseread(Chan* c, void *vbuf, int32_t len, int64_t off64)
  189. {
  190. return qread(mouseq, vbuf, len);
  191. }
  192. void
  193. mouseenable(void)
  194. {
  195. mouseq = qopen(32, 0, 0, 0);
  196. if(mouseq == nil)
  197. panic("mouseenable");
  198. qnoblock(mouseq, 1);
  199. ccc &= ~Cauxdis;
  200. ccc |= Cauxint;
  201. ilock(&i8042lock);
  202. if(outready() == -1)
  203. iprint("mouseenable: failed 0\n");
  204. outb(Cmd, 0x60); /* write control register */
  205. if(outready() == -1)
  206. iprint("mouseenable: failed 1\n");
  207. outb(Data, ccc);
  208. if(outready() == -1)
  209. iprint("mouseenable: failed 2\n");
  210. outb(Cmd, 0xA8); /* auxilliary device enable */
  211. if(outready() == -1){
  212. iprint("mouseenable: failed 3\n");
  213. iunlock(&i8042lock);
  214. return;
  215. }
  216. iunlock(&i8042lock);
  217. intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "mouse");
  218. addarchfile("ps2mouse", 0666, mouseread, mouserwrite);
  219. }
  220. void
  221. keybinit(void)
  222. {
  223. int c, try;
  224. /* wait for a quiescent controller */
  225. ilock(&i8042lock);
  226. try = 1000;
  227. while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
  228. if(c & Inready)
  229. inb(Data);
  230. delay(1);
  231. }
  232. if (try <= 0) {
  233. iunlock(&i8042lock);
  234. print("keybinit failed 0\n");
  235. return;
  236. }
  237. /* get current controller command byte */
  238. outb(Cmd, 0x20);
  239. if(inready() == -1){
  240. iunlock(&i8042lock);
  241. print("keybinit failed 1\n");
  242. ccc = 0;
  243. } else
  244. ccc = inb(Data);
  245. /* enable keyb xfers and interrupts */
  246. ccc &= ~(Ckeybdis);
  247. ccc |= Csf | Ckeybint | Cscs1;
  248. if(outready() == -1) {
  249. iunlock(&i8042lock);
  250. print("keybinit failed 2\n");
  251. return;
  252. }
  253. if (outbyte(Cmd, 0x60) == -1){
  254. iunlock(&i8042lock);
  255. print("keybinit failed 3\n");
  256. return;
  257. }
  258. if (outbyte(Data, ccc) == -1){
  259. iunlock(&i8042lock);
  260. print("keybinit failed 4\n");
  261. return;
  262. }
  263. nokeyb = 0;
  264. iunlock(&i8042lock);
  265. }
  266. static int32_t
  267. keybread(Chan* c, void *vbuf, int32_t len, int64_t off64)
  268. {
  269. return qread(keybq, vbuf, len);
  270. }
  271. void
  272. keybenable(void)
  273. {
  274. keybq = qopen(32, 0, 0, 0);
  275. if(keybq == nil)
  276. panic("keybinit");
  277. qnoblock(keybq, 1);
  278. ioalloc(Data, 1, 0, "keyb");
  279. ioalloc(Cmd, 1, 0, "keyb");
  280. intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "keyb");
  281. addarchfile("ps2keyb", 0666, keybread, nil);
  282. }