summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/mouse.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/mouse.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/mouse.c')
-rwxr-xr-xsys/src/cmd/aux/mouse.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/mouse.c b/sys/src/cmd/aux/mouse.c
new file mode 100755
index 000000000..306553516
--- /dev/null
+++ b/sys/src/cmd/aux/mouse.c
@@ -0,0 +1,402 @@
+#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);
+ sprint(buf, "#t/eia%sctl", p);
+ if((ctl = open(buf, ORDWR)) == -1){
+ fprint(2, "%s: can't open %s - %r\n", argv0, buf);
+ exits("open ctl");
+ }
+ sprint(buf, "#t/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);
+}