ref: 9ced712a2ad70557a8ceb89ff3b969b92c85f68c
dir: /sys/src/cmd/aux/mouse.c/
#include <u.h> #include <libc.h> enum { Sleep500 = 500, Sleep1000 = 1000, Sleep2000 = 2000, TIMEOUT = 5000, /* timeout for writes */ }; char *speeds[] = { "b1200", "b2400", "b4800", "b9600", 0, }; int button2; #define DEBUG if(debug) int can9600; /* true if type W mouse can be set to 9600 */ int debug; int dontset; /* true if we shouldn't try to set the mouse type */ static void usage(void) { fprint(2, "%s: usage: %s [device]\n", argv0, argv0); exits("usage"); } static void catch(void *a, char *msg) { USED(a, msg); if(strstr(msg, "alarm")) noted(NCONT); noted(NDFLT); } static void dumpbuf(char *buf, int nbytes, char *s) { print(s); while(nbytes-- > 0) print("#%ux ", *buf++ & 0xFF); print("\n"); } static long timedwrite(int fd, void *p, int n) { long rv; alarm(TIMEOUT); rv = write(fd, p, n); alarm(0); if(rv < 0){ fprint(2, "%s: timed out\n", argv0); exits("timeout"); } return rv; } static int readbyte(int fd) { uchar c; char buf[ERRMAX]; alarm(200); if(read(fd, &c, sizeof(c)) == -1){ alarm(0); errstr(buf, sizeof buf); if(strcmp(buf, "interrupted") == 0) return -1; fprint(2, "%s: readbyte failed - %s\n", argv0, buf); exits("read"); } alarm(0); return c; } static int slowread(int fd, char *buf, int nbytes, char *msg) { char *p; int c; for(p = buf; nbytes > 1 && (c = readbyte(fd)) != -1; *p++ = c, nbytes--) ; *p = 0; DEBUG dumpbuf(buf, p-buf, msg); return p-buf; } static void toggleRTS(int fd) { /* * * reset the mouse (toggle RTS) * must be >100mS */ timedwrite(fd, "d1", 2); timedwrite(fd, "r1", 2); sleep(Sleep500); timedwrite(fd, "d0", 2); timedwrite(fd, "r0", 2); sleep(Sleep500); timedwrite(fd, "d1", 2); timedwrite(fd, "r1", 2); sleep(Sleep500); } static void setupeia(int fd, char *baud, char *bits) { alarm(TIMEOUT); /* * set the speed to 1200/2400/4800/9600 baud, * 7/8-bit data, one stop bit and no parity */ DEBUG print("setupeia(%s,%s)\n", baud, bits); timedwrite(fd, baud, strlen(baud)); timedwrite(fd, bits, strlen(bits)); timedwrite(fd, "s1", 2); timedwrite(fd, "pn", 2); timedwrite(fd, "i1", 2); alarm(0); } /* * check for a types M, M3, & W * * we talk to all these mice using 1200 baud */ int MorW(int ctl, int data) { char buf[256]; int c; /* * set up for type M, V or W * flush any pending data */ setupeia(ctl, "b1200", "l7"); toggleRTS(ctl); while(slowread(data, buf, sizeof(buf), "flush: ") > 0) ; toggleRTS(ctl); /* * see if there's any data from the mouse * (type M, V and W mice) */ c = slowread(data, buf, sizeof(buf), "check M: "); /* * type M, V and W mice return "M" or "M3" after reset. * check for type W by sending a 'Send Standard Configuration' * command, "*?". * * the second check is a kludge for some type W mice on next's * that send a garbage character back before the "M3". */ if((c > 0 && buf[0] == 'M') || (c > 1 && buf[1] == 'M')){ timedwrite(data, "*?", 2); c = slowread(data, buf, sizeof(buf), "check W: "); /* * 4 bytes back * indicates a type W mouse */ if(c == 4){ if(buf[1] & (1<<4)) can9600 = 1; setupeia(ctl, "b1200", "l8"); timedwrite(data, "*U", 2); slowread(data, buf, sizeof(buf), "check W: "); return 'W'; } return 'M'; } return 0; } /* * check for type C by seeing if it responds to the status * command "s". the mouse is at an unknown speed so we * have to check all possible speeds. */ int C(int ctl, int data) { char **s; int c; char buf[256]; sleep(100); for(s = speeds; *s; s++){ DEBUG print("%s\n", *s); setupeia(ctl, *s, "l8"); timedwrite(data, "s", 1); c = slowread(data, buf, sizeof(buf), "check C: "); if(c >= 1 && (*buf & 0xBF) == 0x0F){ sleep(100); timedwrite(data, "*n", 2); sleep(100); setupeia(ctl, "b1200", "l8"); timedwrite(data, "s", 1); c = slowread(data, buf, sizeof(buf), "recheck C: "); if(c >= 1 && (*buf & 0xBF) == 0x0F){ timedwrite(data, "U", 1); return 'C'; } } sleep(100); } return 0; } char *bauderr = "mouse: can't set baud rate, mouse at 1200\n"; void Cbaud(int ctl, int data, int baud) { char buf[32]; switch(baud){ case 0: case 1200: return; case 2400: buf[1] = 'o'; break; case 4800: buf[1] = 'p'; break; case 9600: buf[1] = 'q'; break; default: fprint(2, bauderr); return; } buf[0] = '*'; buf[2] = 0; sleep(100); timedwrite(data, buf, 2); sleep(100); timedwrite(data, buf, 2); sprint(buf, "b%d", baud); setupeia(ctl, buf, "l8"); } void Wbaud(int ctl, int data, int baud) { char buf[32]; switch(baud){ case 0: case 1200: return; case 9600: if(can9600) break; /* fall through */ default: fprint(2, bauderr); return; } timedwrite(data, "*q", 2); setupeia(ctl, "b9600", "l8"); slowread(data, buf, sizeof(buf), "setbaud: "); } void main(int argc, char *argv[]) { char *p; int baud; int tries, conf, ctl, data, def, type; char buf[256]; def = 0; baud = 0; ARGBEGIN{ case 'b': baud = atoi(ARGF()); break; case 'd': p = ARGF(); def = *p; break; case 'n': dontset = 1; break; case 'D': debug = 1; break; default: usage(); }ARGEND p = "0"; if(argc) p = *argv; if((conf = open("/dev/mousectl", OWRITE)) == -1){ fprint(2, "%s: can't open /dev/mousectl - %r\n", argv0); if(dontset == 0) exits("open /dev/mousectl"); } if(strncmp(p, "ps2", 3) == 0){ if(write(conf, p, strlen(p)) < 0){ fprint(2, "%s: error setting mouse type - %r\n", argv0); exits("write conf"); } exits(0); } type = 0; for(tries = 0; type == 0 && tries < 6; tries++){ if(tries) fprint(2, "%s: Unknown mouse type, retrying...\n", argv0); snprint(buf, sizeof buf, "/dev/eia%sctl", p); if((ctl = open(buf, ORDWR)) == -1){ fprint(2, "%s: can't open %s - %r\n", argv0, buf); exits("open ctl"); } snprint(buf, sizeof buf, "/dev/eia%s", p); if((data = open(buf, ORDWR)) == -1){ fprint(2, "%s: can't open %s - %r\n", argv0, buf); exits("open data"); } notify(catch); type = MorW(ctl, data); if(type == 0) type = C(ctl, data); if(type == 0){ /* with the default we can't assume anything */ baud = 0; /* try the default */ switch(def){ case 'C': setupeia(ctl, "b1200", "l8"); break; case 'M': setupeia(ctl, "b1200", "l7"); break; } type = def; } sprint(buf, "serial %s", p); switch(type){ case 0: close(data); close(ctl); continue; case 'C': DEBUG print("Logitech 5 byte mouse\n"); Cbaud(ctl, data, baud); break; case 'W': DEBUG print("Type W mouse\n"); Wbaud(ctl, data, baud); break; case 'M': DEBUG print("Microsoft compatible mouse\n"); strcat(buf, " M"); break; } } if(type == 0){ fprint(2, "%s: Unknown mouse type, giving up\n", argv0); exits("no mouse"); } DEBUG fprint(2, "mouse configured as '%s'\n", buf); if(dontset == 0 && write(conf, buf, strlen(buf)) < 0){ fprint(2, "%s: error setting mouse type - %r\n", argv0); exits("write conf"); } exits(0); }