mouse.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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. alarm(0);
  118. }
  119. /*
  120. * check for a types M, M3, & W
  121. *
  122. * we talk to all these mice using 1200 baud
  123. */
  124. int
  125. MorW(int ctl, int data)
  126. {
  127. char buf[256];
  128. int c;
  129. /*
  130. * set up for type M, V or W
  131. * flush any pending data
  132. */
  133. setupeia(ctl, "b1200", "l7");
  134. toggleRTS(ctl);
  135. while(slowread(data, buf, sizeof(buf), "flush: ") > 0)
  136. ;
  137. toggleRTS(ctl);
  138. /*
  139. * see if there's any data from the mouse
  140. * (type M, V and W mice)
  141. */
  142. c = slowread(data, buf, sizeof(buf), "check M: ");
  143. /*
  144. * type M, V and W mice return "M" or "M3" after reset.
  145. * check for type W by sending a 'Send Standard Configuration'
  146. * command, "*?".
  147. *
  148. * the second check is a kludge for some type W mice on next's
  149. * that send a garbage character back before the "M3".
  150. */
  151. if((c > 0 && buf[0] == 'M') || (c > 1 && buf[1] == 'M')){
  152. timedwrite(data, "*?", 2);
  153. c = slowread(data, buf, sizeof(buf), "check W: ");
  154. /*
  155. * 4 bytes back
  156. * indicates a type W mouse
  157. */
  158. if(c == 4){
  159. if(buf[1] & (1<<4))
  160. can9600 = 1;
  161. setupeia(ctl, "b1200", "l8");
  162. timedwrite(data, "*U", 2);
  163. slowread(data, buf, sizeof(buf), "check W: ");
  164. return 'W';
  165. }
  166. return 'M';
  167. }
  168. return 0;
  169. }
  170. /*
  171. * check for type C by seeing if it responds to the status
  172. * command "s". the mouse is at an unknown speed so we
  173. * have to check all possible speeds.
  174. */
  175. int
  176. C(int ctl, int data)
  177. {
  178. char **s;
  179. int c;
  180. char buf[256];
  181. sleep(100);
  182. for(s = speeds; *s; s++){
  183. DEBUG print("%s\n", *s);
  184. setupeia(ctl, *s, "l8");
  185. timedwrite(data, "s", 1);
  186. c = slowread(data, buf, sizeof(buf), "check C: ");
  187. if(c >= 1 && (*buf & 0xBF) == 0x0F){
  188. sleep(100);
  189. timedwrite(data, "*n", 2);
  190. sleep(100);
  191. setupeia(ctl, "b1200", "l8");
  192. timedwrite(data, "s", 1);
  193. c = slowread(data, buf, sizeof(buf), "recheck C: ");
  194. if(c >= 1 && (*buf & 0xBF) == 0x0F){
  195. timedwrite(data, "U", 1);
  196. return 'C';
  197. }
  198. }
  199. sleep(100);
  200. }
  201. return 0;
  202. }
  203. char *bauderr = "mouse: can't set baud rate, mouse at 1200\n";
  204. void
  205. Cbaud(int ctl, int data, int baud)
  206. {
  207. char buf[32];
  208. switch(baud){
  209. case 0:
  210. case 1200:
  211. return;
  212. case 2400:
  213. buf[1] = 'o';
  214. break;
  215. case 4800:
  216. buf[1] = 'p';
  217. break;
  218. case 9600:
  219. buf[1] = 'q';
  220. break;
  221. default:
  222. fprint(2, bauderr);
  223. return;
  224. }
  225. buf[0] = '*';
  226. buf[2] = 0;
  227. sleep(100);
  228. timedwrite(data, buf, 2);
  229. sleep(100);
  230. timedwrite(data, buf, 2);
  231. sprint(buf, "b%d", baud);
  232. setupeia(ctl, buf, "l8");
  233. }
  234. void
  235. Wbaud(int ctl, int data, int baud)
  236. {
  237. char buf[32];
  238. switch(baud){
  239. case 0:
  240. case 1200:
  241. return;
  242. case 9600:
  243. if(can9600)
  244. break;
  245. /* fall through */
  246. default:
  247. fprint(2, bauderr);
  248. return;
  249. }
  250. timedwrite(data, "*q", 2);
  251. setupeia(ctl, "b9600", "l8");
  252. slowread(data, buf, sizeof(buf), "setbaud: ");
  253. }
  254. void
  255. main(int argc, char *argv[])
  256. {
  257. char *p;
  258. int baud;
  259. int tries, conf, ctl, data, def, type;
  260. char buf[256];
  261. def = 0;
  262. baud = 0;
  263. ARGBEGIN{
  264. case 'b':
  265. baud = atoi(ARGF());
  266. break;
  267. case 'd':
  268. p = ARGF();
  269. def = *p;
  270. break;
  271. case 'n':
  272. dontset = 1;
  273. break;
  274. case 'D':
  275. debug = 1;
  276. break;
  277. default:
  278. usage();
  279. }ARGEND
  280. p = "0";
  281. if(argc)
  282. p = *argv;
  283. if((conf = open("/dev/mousectl", OWRITE)) == -1){
  284. fprint(2, "%s: can't open /dev/mousectl - %r\n", argv0);
  285. if(dontset == 0)
  286. exits("open /dev/mousectl");
  287. }
  288. if(strncmp(p, "ps2", 3) == 0){
  289. if(write(conf, p, strlen(p)) < 0){
  290. fprint(2, "%s: error setting mouse type - %r\n", argv0);
  291. exits("write conf");
  292. }
  293. exits(0);
  294. }
  295. type = 0;
  296. for(tries = 0; type == 0 && tries < 6; tries++){
  297. if(tries)
  298. fprint(2, "%s: Unknown mouse type, retrying...\n", argv0);
  299. sprint(buf, "#t/eia%sctl", p);
  300. if((ctl = open(buf, ORDWR)) == -1){
  301. fprint(2, "%s: can't open %s - %r\n", argv0, buf);
  302. exits("open ctl");
  303. }
  304. sprint(buf, "#t/eia%s", p);
  305. if((data = open(buf, ORDWR)) == -1){
  306. fprint(2, "%s: can't open %s - %r\n", argv0, buf);
  307. exits("open data");
  308. }
  309. notify(catch);
  310. type = MorW(ctl, data);
  311. if(type == 0)
  312. type = C(ctl, data);
  313. if(type == 0){
  314. /* with the default we can't assume anything */
  315. baud = 0;
  316. /* try the default */
  317. switch(def){
  318. case 'C':
  319. setupeia(ctl, "b1200", "l8");
  320. break;
  321. case 'M':
  322. setupeia(ctl, "b1200", "l7");
  323. break;
  324. }
  325. type = def;
  326. }
  327. sprint(buf, "serial %s", p);
  328. switch(type){
  329. case 0:
  330. close(data);
  331. close(ctl);
  332. continue;
  333. case 'C':
  334. DEBUG print("Logitech 5 byte mouse\n");
  335. Cbaud(ctl, data, baud);
  336. break;
  337. case 'W':
  338. DEBUG print("Type W mouse\n");
  339. Wbaud(ctl, data, baud);
  340. break;
  341. case 'M':
  342. DEBUG print("Microsoft compatible mouse\n");
  343. strcat(buf, " M");
  344. break;
  345. }
  346. }
  347. if(type == 0){
  348. fprint(2, "%s: Unknown mouse type, giving up\n", argv0);
  349. exits("no mouse");
  350. }
  351. DEBUG fprint(2, "mouse configured as '%s'\n", buf);
  352. if(dontset == 0 && write(conf, buf, strlen(buf)) < 0){
  353. fprint(2, "%s: error setting mouse type - %r\n", argv0);
  354. exits("write conf");
  355. }
  356. exits(0);
  357. }