mouse.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. #include <u.h>
  2. #include <libc.h>
  3. enum
  4. {
  5. Sleep500 = 500,
  6. Sleep1000 = 1000,
  7. Sleep2000 = 2000,
  8. TIMEOUT = 5000, /* timeout for writes */
  9. };
  10. char *speeds[] =
  11. {
  12. "b1200",
  13. "b2400",
  14. "b4800",
  15. "b9600",
  16. 0,
  17. };
  18. int button2;
  19. #define DEBUG if(debug)
  20. int can9600; /* true if type W mouse can be set to 9600 */
  21. int debug;
  22. int dontset; /* true if we shouldn't try to set the mouse type */
  23. static void
  24. usage(void)
  25. {
  26. fprint(2, "%s: usage: %s [device]\n", argv0, argv0);
  27. exits("usage");
  28. }
  29. static void
  30. catch(void *a, char *msg)
  31. {
  32. USED(a, msg);
  33. if(strstr(msg, "alarm"))
  34. noted(NCONT);
  35. noted(NDFLT);
  36. }
  37. static void
  38. dumpbuf(char *buf, int nbytes, char *s)
  39. {
  40. print(s);
  41. while(nbytes-- > 0)
  42. print("#%ux ", *buf++ & 0xFF);
  43. print("\n");
  44. }
  45. static long
  46. timedwrite(int fd, void *p, int n)
  47. {
  48. long rv;
  49. alarm(TIMEOUT);
  50. rv = write(fd, p, n);
  51. alarm(0);
  52. if(rv < 0){
  53. fprint(2, "%s: timed out\n", argv0);
  54. exits("timeout");
  55. }
  56. return rv;
  57. }
  58. static int
  59. readbyte(int fd)
  60. {
  61. uchar c;
  62. char buf[ERRMAX];
  63. alarm(200);
  64. if(read(fd, &c, sizeof(c)) == -1){
  65. alarm(0);
  66. errstr(buf, sizeof buf);
  67. if(strcmp(buf, "interrupted") == 0)
  68. return -1;
  69. fprint(2, "%s: readbyte failed - %s\n", argv0, buf);
  70. exits("read");
  71. }
  72. alarm(0);
  73. return c;
  74. }
  75. static int
  76. slowread(int fd, char *buf, int nbytes, char *msg)
  77. {
  78. char *p;
  79. int c;
  80. for(p = buf; nbytes > 1 && (c = readbyte(fd)) != -1; *p++ = c, nbytes--)
  81. ;
  82. *p = 0;
  83. DEBUG dumpbuf(buf, p-buf, msg);
  84. return p-buf;
  85. }
  86. static void
  87. toggleRTS(int fd)
  88. {
  89. /*
  90. *
  91. * reset the mouse (toggle RTS)
  92. * must be >100mS
  93. */
  94. timedwrite(fd, "d1", 2);
  95. timedwrite(fd, "r1", 2);
  96. sleep(Sleep500);
  97. timedwrite(fd, "d0", 2);
  98. timedwrite(fd, "r0", 2);
  99. sleep(Sleep500);
  100. timedwrite(fd, "d1", 2);
  101. timedwrite(fd, "r1", 2);
  102. sleep(Sleep500);
  103. }
  104. static void
  105. setupeia(int fd, char *baud, char *bits)
  106. {
  107. alarm(TIMEOUT);
  108. /*
  109. * set the speed to 1200/2400/4800/9600 baud,
  110. * 7/8-bit data, one stop bit and no parity
  111. */
  112. DEBUG print("setupeia(%s,%s)\n", baud, bits);
  113. timedwrite(fd, baud, strlen(baud));
  114. timedwrite(fd, bits, strlen(bits));
  115. timedwrite(fd, "s1", 2);
  116. timedwrite(fd, "pn", 2);
  117. timedwrite(fd, "i1", 2);
  118. alarm(0);
  119. }
  120. /*
  121. * check for a types M, M3, & W
  122. *
  123. * we talk to all these mice using 1200 baud
  124. */
  125. int
  126. MorW(int ctl, int data)
  127. {
  128. char buf[256];
  129. int c;
  130. /*
  131. * set up for type M, V or W
  132. * flush any pending data
  133. */
  134. setupeia(ctl, "b1200", "l7");
  135. toggleRTS(ctl);
  136. while(slowread(data, buf, sizeof(buf), "flush: ") > 0)
  137. ;
  138. toggleRTS(ctl);
  139. /*
  140. * see if there's any data from the mouse
  141. * (type M, V and W mice)
  142. */
  143. c = slowread(data, buf, sizeof(buf), "check M: ");
  144. /*
  145. * type M, V and W mice return "M" or "M3" after reset.
  146. * check for type W by sending a 'Send Standard Configuration'
  147. * command, "*?".
  148. *
  149. * the second check is a kludge for some type W mice on next's
  150. * that send a garbage character back before the "M3".
  151. */
  152. if((c > 0 && buf[0] == 'M') || (c > 1 && buf[1] == 'M')){
  153. timedwrite(data, "*?", 2);
  154. c = slowread(data, buf, sizeof(buf), "check W: ");
  155. /*
  156. * 4 bytes back
  157. * indicates a type W mouse
  158. */
  159. if(c == 4){
  160. if(buf[1] & (1<<4))
  161. can9600 = 1;
  162. setupeia(ctl, "b1200", "l8");
  163. timedwrite(data, "*U", 2);
  164. slowread(data, buf, sizeof(buf), "check W: ");
  165. return 'W';
  166. }
  167. return 'M';
  168. }
  169. return 0;
  170. }
  171. /*
  172. * check for type C by seeing if it responds to the status
  173. * command "s". the mouse is at an unknown speed so we
  174. * have to check all possible speeds.
  175. */
  176. int
  177. C(int ctl, int data)
  178. {
  179. char **s;
  180. int c;
  181. char buf[256];
  182. sleep(100);
  183. for(s = speeds; *s; s++){
  184. DEBUG print("%s\n", *s);
  185. setupeia(ctl, *s, "l8");
  186. timedwrite(data, "s", 1);
  187. c = slowread(data, buf, sizeof(buf), "check C: ");
  188. if(c >= 1 && (*buf & 0xBF) == 0x0F){
  189. sleep(100);
  190. timedwrite(data, "*n", 2);
  191. sleep(100);
  192. setupeia(ctl, "b1200", "l8");
  193. timedwrite(data, "s", 1);
  194. c = slowread(data, buf, sizeof(buf), "recheck C: ");
  195. if(c >= 1 && (*buf & 0xBF) == 0x0F){
  196. timedwrite(data, "U", 1);
  197. return 'C';
  198. }
  199. }
  200. sleep(100);
  201. }
  202. return 0;
  203. }
  204. char *bauderr = "mouse: can't set baud rate, mouse at 1200\n";
  205. void
  206. Cbaud(int ctl, int data, int baud)
  207. {
  208. char buf[32];
  209. switch(baud){
  210. case 0:
  211. case 1200:
  212. return;
  213. case 2400:
  214. buf[1] = 'o';
  215. break;
  216. case 4800:
  217. buf[1] = 'p';
  218. break;
  219. case 9600:
  220. buf[1] = 'q';
  221. break;
  222. default:
  223. fprint(2, bauderr);
  224. return;
  225. }
  226. buf[0] = '*';
  227. buf[2] = 0;
  228. sleep(100);
  229. timedwrite(data, buf, 2);
  230. sleep(100);
  231. timedwrite(data, buf, 2);
  232. sprint(buf, "b%d", baud);
  233. setupeia(ctl, buf, "l8");
  234. }
  235. void
  236. Wbaud(int ctl, int data, int baud)
  237. {
  238. char buf[32];
  239. switch(baud){
  240. case 0:
  241. case 1200:
  242. return;
  243. case 9600:
  244. if(can9600)
  245. break;
  246. /* fall through */
  247. default:
  248. fprint(2, bauderr);
  249. return;
  250. }
  251. timedwrite(data, "*q", 2);
  252. setupeia(ctl, "b9600", "l8");
  253. slowread(data, buf, sizeof(buf), "setbaud: ");
  254. }
  255. void
  256. main(int argc, char *argv[])
  257. {
  258. char *p;
  259. int baud;
  260. int tries, conf, ctl, data, def, type;
  261. char buf[256];
  262. def = 0;
  263. baud = 0;
  264. ARGBEGIN{
  265. case 'b':
  266. baud = atoi(ARGF());
  267. break;
  268. case 'd':
  269. p = ARGF();
  270. def = *p;
  271. break;
  272. case 'n':
  273. dontset = 1;
  274. break;
  275. case 'D':
  276. debug = 1;
  277. break;
  278. default:
  279. usage();
  280. }ARGEND
  281. p = "0";
  282. if(argc)
  283. p = *argv;
  284. if((conf = open("/dev/mousectl", OWRITE)) == -1){
  285. fprint(2, "%s: can't open /dev/mousectl - %r\n", argv0);
  286. if(dontset == 0)
  287. exits("open /dev/mousectl");
  288. }
  289. if(strncmp(p, "ps2", 3) == 0){
  290. if(write(conf, p, strlen(p)) < 0){
  291. fprint(2, "%s: error setting mouse type - %r\n", argv0);
  292. exits("write conf");
  293. }
  294. exits(0);
  295. }
  296. type = 0;
  297. for(tries = 0; type == 0 && tries < 6; tries++){
  298. if(tries)
  299. fprint(2, "%s: Unknown mouse type, retrying...\n", argv0);
  300. sprint(buf, "#t/eia%sctl", p);
  301. if((ctl = open(buf, ORDWR)) == -1){
  302. fprint(2, "%s: can't open %s - %r\n", argv0, buf);
  303. exits("open ctl");
  304. }
  305. sprint(buf, "#t/eia%s", p);
  306. if((data = open(buf, ORDWR)) == -1){
  307. fprint(2, "%s: can't open %s - %r\n", argv0, buf);
  308. exits("open data");
  309. }
  310. notify(catch);
  311. type = MorW(ctl, data);
  312. if(type == 0)
  313. type = C(ctl, data);
  314. if(type == 0){
  315. /* with the default we can't assume anything */
  316. baud = 0;
  317. /* try the default */
  318. switch(def){
  319. case 'C':
  320. setupeia(ctl, "b1200", "l8");
  321. break;
  322. case 'M':
  323. setupeia(ctl, "b1200", "l7");
  324. break;
  325. }
  326. type = def;
  327. }
  328. sprint(buf, "serial %s", p);
  329. switch(type){
  330. case 0:
  331. close(data);
  332. close(ctl);
  333. continue;
  334. case 'C':
  335. DEBUG print("Logitech 5 byte mouse\n");
  336. Cbaud(ctl, data, baud);
  337. break;
  338. case 'W':
  339. DEBUG print("Type W mouse\n");
  340. Wbaud(ctl, data, baud);
  341. break;
  342. case 'M':
  343. DEBUG print("Microsoft compatible mouse\n");
  344. strcat(buf, " M");
  345. break;
  346. }
  347. }
  348. if(type == 0){
  349. fprint(2, "%s: Unknown mouse type, giving up\n", argv0);
  350. exits("no mouse");
  351. }
  352. DEBUG fprint(2, "mouse configured as '%s'\n", buf);
  353. if(dontset == 0 && write(conf, buf, strlen(buf)) < 0){
  354. fprint(2, "%s: error setting mouse type - %r\n", argv0);
  355. exits("write conf");
  356. }
  357. exits(0);
  358. }