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