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