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