]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/mouse.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / cmd / aux / mouse.c
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 }