1bd389b36SDavid du Colombier #include <u.h>
2bd389b36SDavid du Colombier #include <libc.h>
3bd389b36SDavid du Colombier
4bd389b36SDavid du Colombier enum
5bd389b36SDavid du Colombier {
6bd389b36SDavid du Colombier Sleep500 = 500,
7bd389b36SDavid du Colombier Sleep1000 = 1000,
8bd389b36SDavid du Colombier Sleep2000 = 2000,
9219b2ee8SDavid du Colombier
10219b2ee8SDavid du Colombier TIMEOUT = 5000, /* timeout for writes */
11bd389b36SDavid du Colombier };
12bd389b36SDavid du Colombier
13bd389b36SDavid du Colombier char *speeds[] =
14bd389b36SDavid du Colombier {
15bd389b36SDavid du Colombier "b1200",
16bd389b36SDavid du Colombier "b2400",
17bd389b36SDavid du Colombier "b4800",
18bd389b36SDavid du Colombier "b9600",
19bd389b36SDavid du Colombier 0,
20bd389b36SDavid du Colombier };
21bd389b36SDavid du Colombier
22219b2ee8SDavid du Colombier int button2;
23219b2ee8SDavid du Colombier
24bd389b36SDavid du Colombier #define DEBUG if(debug)
25bd389b36SDavid du Colombier
26bd389b36SDavid du Colombier int can9600; /* true if type W mouse can be set to 9600 */
27bd389b36SDavid du Colombier int debug;
28219b2ee8SDavid du Colombier int dontset; /* true if we shouldn't try to set the mouse type */
29bd389b36SDavid du Colombier
30bd389b36SDavid du Colombier static void
usage(void)31bd389b36SDavid du Colombier usage(void)
32bd389b36SDavid du Colombier {
33bd389b36SDavid du Colombier fprint(2, "%s: usage: %s [device]\n", argv0, argv0);
34bd389b36SDavid du Colombier exits("usage");
35bd389b36SDavid du Colombier }
36bd389b36SDavid du Colombier
37bd389b36SDavid du Colombier static void
catch(void * a,char * msg)38bd389b36SDavid du Colombier catch(void *a, char *msg)
39bd389b36SDavid du Colombier {
40bd389b36SDavid du Colombier USED(a, msg);
41219b2ee8SDavid du Colombier if(strstr(msg, "alarm"))
42bd389b36SDavid du Colombier noted(NCONT);
43219b2ee8SDavid du Colombier noted(NDFLT);
44bd389b36SDavid du Colombier }
45bd389b36SDavid du Colombier
46bd389b36SDavid du Colombier static void
dumpbuf(char * buf,int nbytes,char * s)47bd389b36SDavid du Colombier dumpbuf(char *buf, int nbytes, char *s)
48bd389b36SDavid du Colombier {
49bd389b36SDavid du Colombier print(s);
50219b2ee8SDavid du Colombier while(nbytes-- > 0)
51bd389b36SDavid du Colombier print("#%ux ", *buf++ & 0xFF);
52bd389b36SDavid du Colombier print("\n");
53bd389b36SDavid du Colombier }
54bd389b36SDavid du Colombier
55219b2ee8SDavid du Colombier static long
timedwrite(int fd,void * p,int n)56219b2ee8SDavid du Colombier timedwrite(int fd, void *p, int n)
57219b2ee8SDavid du Colombier {
58219b2ee8SDavid du Colombier long rv;
59219b2ee8SDavid du Colombier
60219b2ee8SDavid du Colombier alarm(TIMEOUT);
61219b2ee8SDavid du Colombier rv = write(fd, p, n);
62219b2ee8SDavid du Colombier alarm(0);
63219b2ee8SDavid du Colombier if(rv < 0){
64219b2ee8SDavid du Colombier fprint(2, "%s: timed out\n", argv0);
65219b2ee8SDavid du Colombier exits("timeout");
66219b2ee8SDavid du Colombier }
67219b2ee8SDavid du Colombier return rv;
68219b2ee8SDavid du Colombier }
69219b2ee8SDavid du Colombier
70bd389b36SDavid du Colombier static int
readbyte(int fd)71bd389b36SDavid du Colombier readbyte(int fd)
72bd389b36SDavid du Colombier {
73bd389b36SDavid du Colombier uchar c;
749a747e4fSDavid du Colombier char buf[ERRMAX];
75bd389b36SDavid du Colombier
76bd389b36SDavid du Colombier alarm(200);
77bd389b36SDavid du Colombier if(read(fd, &c, sizeof(c)) == -1){
78bd389b36SDavid du Colombier alarm(0);
799a747e4fSDavid du Colombier errstr(buf, sizeof buf);
80bd389b36SDavid du Colombier if(strcmp(buf, "interrupted") == 0)
81bd389b36SDavid du Colombier return -1;
82bd389b36SDavid du Colombier fprint(2, "%s: readbyte failed - %s\n", argv0, buf);
83bd389b36SDavid du Colombier exits("read");
84bd389b36SDavid du Colombier }
85bd389b36SDavid du Colombier alarm(0);
86bd389b36SDavid du Colombier return c;
87bd389b36SDavid du Colombier }
88bd389b36SDavid du Colombier
89bd389b36SDavid du Colombier static int
slowread(int fd,char * buf,int nbytes,char * msg)90219b2ee8SDavid du Colombier slowread(int fd, char *buf, int nbytes, char *msg)
91bd389b36SDavid du Colombier {
92bd389b36SDavid du Colombier char *p;
93bd389b36SDavid du Colombier int c;
94bd389b36SDavid du Colombier
95219b2ee8SDavid du Colombier for(p = buf; nbytes > 1 && (c = readbyte(fd)) != -1; *p++ = c, nbytes--)
96bd389b36SDavid du Colombier ;
97bd389b36SDavid du Colombier *p = 0;
98219b2ee8SDavid du Colombier DEBUG dumpbuf(buf, p-buf, msg);
99bd389b36SDavid du Colombier return p-buf;
100bd389b36SDavid du Colombier }
101bd389b36SDavid du Colombier
102bd389b36SDavid du Colombier static void
toggleRTS(int fd)103bd389b36SDavid du Colombier toggleRTS(int fd)
104bd389b36SDavid du Colombier {
105bd389b36SDavid du Colombier /*
106bd389b36SDavid du Colombier *
107bd389b36SDavid du Colombier * reset the mouse (toggle RTS)
108bd389b36SDavid du Colombier * must be >100mS
109bd389b36SDavid du Colombier */
1107dd7cddfSDavid du Colombier timedwrite(fd, "d1", 2);
1117dd7cddfSDavid du Colombier timedwrite(fd, "r1", 2);
1127dd7cddfSDavid du Colombier sleep(Sleep500);
113219b2ee8SDavid du Colombier timedwrite(fd, "d0", 2);
114219b2ee8SDavid du Colombier timedwrite(fd, "r0", 2);
115bd389b36SDavid du Colombier sleep(Sleep500);
116219b2ee8SDavid du Colombier timedwrite(fd, "d1", 2);
117219b2ee8SDavid du Colombier timedwrite(fd, "r1", 2);
118bd389b36SDavid du Colombier sleep(Sleep500);
119bd389b36SDavid du Colombier }
120bd389b36SDavid du Colombier
121bd389b36SDavid du Colombier static void
setupeia(int fd,char * baud,char * bits)122bd389b36SDavid du Colombier setupeia(int fd, char *baud, char *bits)
123bd389b36SDavid du Colombier {
124219b2ee8SDavid du Colombier alarm(TIMEOUT);
125bd389b36SDavid du Colombier /*
126bd389b36SDavid du Colombier * set the speed to 1200/2400/4800/9600 baud,
127bd389b36SDavid du Colombier * 7/8-bit data, one stop bit and no parity
128bd389b36SDavid du Colombier */
129bd389b36SDavid du Colombier DEBUG print("setupeia(%s,%s)\n", baud, bits);
130219b2ee8SDavid du Colombier timedwrite(fd, baud, strlen(baud));
131219b2ee8SDavid du Colombier timedwrite(fd, bits, strlen(bits));
132219b2ee8SDavid du Colombier timedwrite(fd, "s1", 2);
133219b2ee8SDavid du Colombier timedwrite(fd, "pn", 2);
134*39734e7eSDavid du Colombier timedwrite(fd, "i1", 2);
135219b2ee8SDavid du Colombier alarm(0);
136bd389b36SDavid du Colombier }
137bd389b36SDavid du Colombier
138bd389b36SDavid du Colombier /*
139bd389b36SDavid du Colombier * check for a types M, M3, & W
140bd389b36SDavid du Colombier *
141bd389b36SDavid du Colombier * we talk to all these mice using 1200 baud
142bd389b36SDavid du Colombier */
143bd389b36SDavid du Colombier int
MorW(int ctl,int data)144bd389b36SDavid du Colombier MorW(int ctl, int data)
145bd389b36SDavid du Colombier {
146bd389b36SDavid du Colombier char buf[256];
147bd389b36SDavid du Colombier int c;
148bd389b36SDavid du Colombier
149bd389b36SDavid du Colombier /*
150bd389b36SDavid du Colombier * set up for type M, V or W
151bd389b36SDavid du Colombier * flush any pending data
152bd389b36SDavid du Colombier */
153bd389b36SDavid du Colombier setupeia(ctl, "b1200", "l7");
154bd389b36SDavid du Colombier toggleRTS(ctl);
155219b2ee8SDavid du Colombier while(slowread(data, buf, sizeof(buf), "flush: ") > 0)
156219b2ee8SDavid du Colombier ;
157bd389b36SDavid du Colombier toggleRTS(ctl);
158bd389b36SDavid du Colombier
159bd389b36SDavid du Colombier /*
160bd389b36SDavid du Colombier * see if there's any data from the mouse
161bd389b36SDavid du Colombier * (type M, V and W mice)
162bd389b36SDavid du Colombier */
163219b2ee8SDavid du Colombier c = slowread(data, buf, sizeof(buf), "check M: ");
164bd389b36SDavid du Colombier
165bd389b36SDavid du Colombier /*
166bd389b36SDavid du Colombier * type M, V and W mice return "M" or "M3" after reset.
167bd389b36SDavid du Colombier * check for type W by sending a 'Send Standard Configuration'
168bd389b36SDavid du Colombier * command, "*?".
169219b2ee8SDavid du Colombier *
170219b2ee8SDavid du Colombier * the second check is a kludge for some type W mice on next's
171219b2ee8SDavid du Colombier * that send a garbage character back before the "M3".
172bd389b36SDavid du Colombier */
173219b2ee8SDavid du Colombier if((c > 0 && buf[0] == 'M') || (c > 1 && buf[1] == 'M')){
174219b2ee8SDavid du Colombier timedwrite(data, "*?", 2);
175219b2ee8SDavid du Colombier c = slowread(data, buf, sizeof(buf), "check W: ");
176bd389b36SDavid du Colombier /*
177bd389b36SDavid du Colombier * 4 bytes back
178bd389b36SDavid du Colombier * indicates a type W mouse
179bd389b36SDavid du Colombier */
180219b2ee8SDavid du Colombier if(c == 4){
181bd389b36SDavid du Colombier if(buf[1] & (1<<4))
182bd389b36SDavid du Colombier can9600 = 1;
183bd389b36SDavid du Colombier setupeia(ctl, "b1200", "l8");
184219b2ee8SDavid du Colombier timedwrite(data, "*U", 2);
185219b2ee8SDavid du Colombier slowread(data, buf, sizeof(buf), "check W: ");
186bd389b36SDavid du Colombier return 'W';
187bd389b36SDavid du Colombier }
188bd389b36SDavid du Colombier return 'M';
189bd389b36SDavid du Colombier }
190bd389b36SDavid du Colombier return 0;
191bd389b36SDavid du Colombier }
192bd389b36SDavid du Colombier
193bd389b36SDavid du Colombier /*
194bd389b36SDavid du Colombier * check for type C by seeing if it responds to the status
195bd389b36SDavid du Colombier * command "s". the mouse is at an unknown speed so we
196bd389b36SDavid du Colombier * have to check all possible speeds.
197bd389b36SDavid du Colombier */
198bd389b36SDavid du Colombier int
C(int ctl,int data)199bd389b36SDavid du Colombier C(int ctl, int data)
200bd389b36SDavid du Colombier {
201bd389b36SDavid du Colombier char **s;
202bd389b36SDavid du Colombier int c;
203bd389b36SDavid du Colombier char buf[256];
204bd389b36SDavid du Colombier
205bd389b36SDavid du Colombier sleep(100);
206bd389b36SDavid du Colombier for(s = speeds; *s; s++){
207bd389b36SDavid du Colombier DEBUG print("%s\n", *s);
208bd389b36SDavid du Colombier setupeia(ctl, *s, "l8");
209219b2ee8SDavid du Colombier timedwrite(data, "s", 1);
210219b2ee8SDavid du Colombier c = slowread(data, buf, sizeof(buf), "check C: ");
211bd389b36SDavid du Colombier if(c >= 1 && (*buf & 0xBF) == 0x0F){
212bd389b36SDavid du Colombier sleep(100);
213219b2ee8SDavid du Colombier timedwrite(data, "*n", 2);
214bd389b36SDavid du Colombier sleep(100);
215bd389b36SDavid du Colombier setupeia(ctl, "b1200", "l8");
216219b2ee8SDavid du Colombier timedwrite(data, "s", 1);
217219b2ee8SDavid du Colombier c = slowread(data, buf, sizeof(buf), "recheck C: ");
218bd389b36SDavid du Colombier if(c >= 1 && (*buf & 0xBF) == 0x0F){
219219b2ee8SDavid du Colombier timedwrite(data, "U", 1);
220bd389b36SDavid du Colombier return 'C';
221bd389b36SDavid du Colombier }
222bd389b36SDavid du Colombier }
223bd389b36SDavid du Colombier sleep(100);
224bd389b36SDavid du Colombier }
225bd389b36SDavid du Colombier
226bd389b36SDavid du Colombier return 0;
227bd389b36SDavid du Colombier }
228bd389b36SDavid du Colombier
229bd389b36SDavid du Colombier char *bauderr = "mouse: can't set baud rate, mouse at 1200\n";
230bd389b36SDavid du Colombier
231bd389b36SDavid du Colombier void
Cbaud(int ctl,int data,int baud)232bd389b36SDavid du Colombier Cbaud(int ctl, int data, int baud)
233bd389b36SDavid du Colombier {
234bd389b36SDavid du Colombier char buf[32];
235bd389b36SDavid du Colombier
236bd389b36SDavid du Colombier switch(baud){
237bd389b36SDavid du Colombier case 0:
238bd389b36SDavid du Colombier case 1200:
239bd389b36SDavid du Colombier return;
240bd389b36SDavid du Colombier case 2400:
241bd389b36SDavid du Colombier buf[1] = 'o';
242bd389b36SDavid du Colombier break;
243bd389b36SDavid du Colombier case 4800:
244bd389b36SDavid du Colombier buf[1] = 'p';
245bd389b36SDavid du Colombier break;
246bd389b36SDavid du Colombier case 9600:
247bd389b36SDavid du Colombier buf[1] = 'q';
248bd389b36SDavid du Colombier break;
249bd389b36SDavid du Colombier default:
250bd389b36SDavid du Colombier fprint(2, bauderr);
251bd389b36SDavid du Colombier return;
252bd389b36SDavid du Colombier }
253bd389b36SDavid du Colombier
254bd389b36SDavid du Colombier buf[0] = '*';
255bd389b36SDavid du Colombier buf[2] = 0;
256bd389b36SDavid du Colombier sleep(100);
257219b2ee8SDavid du Colombier timedwrite(data, buf, 2);
258bd389b36SDavid du Colombier sleep(100);
259219b2ee8SDavid du Colombier timedwrite(data, buf, 2);
260bd389b36SDavid du Colombier sprint(buf, "b%d", baud);
261bd389b36SDavid du Colombier setupeia(ctl, buf, "l8");
262bd389b36SDavid du Colombier }
263bd389b36SDavid du Colombier
264bd389b36SDavid du Colombier void
Wbaud(int ctl,int data,int baud)265bd389b36SDavid du Colombier Wbaud(int ctl, int data, int baud)
266bd389b36SDavid du Colombier {
267bd389b36SDavid du Colombier char buf[32];
268bd389b36SDavid du Colombier
269bd389b36SDavid du Colombier switch(baud){
270bd389b36SDavid du Colombier case 0:
271bd389b36SDavid du Colombier case 1200:
272bd389b36SDavid du Colombier return;
273bd389b36SDavid du Colombier case 9600:
274bd389b36SDavid du Colombier if(can9600)
275bd389b36SDavid du Colombier break;
276bd389b36SDavid du Colombier /* fall through */
277bd389b36SDavid du Colombier default:
278bd389b36SDavid du Colombier fprint(2, bauderr);
279bd389b36SDavid du Colombier return;
280bd389b36SDavid du Colombier }
281219b2ee8SDavid du Colombier timedwrite(data, "*q", 2);
282bd389b36SDavid du Colombier setupeia(ctl, "b9600", "l8");
283219b2ee8SDavid du Colombier slowread(data, buf, sizeof(buf), "setbaud: ");
284219b2ee8SDavid du Colombier }
285219b2ee8SDavid du Colombier
286bd389b36SDavid du Colombier void
main(int argc,char * argv[])287bd389b36SDavid du Colombier main(int argc, char *argv[])
288bd389b36SDavid du Colombier {
289bd389b36SDavid du Colombier char *p;
290bd389b36SDavid du Colombier int baud;
2917dd7cddfSDavid du Colombier int tries, conf, ctl, data, def, type;
292bd389b36SDavid du Colombier char buf[256];
293bd389b36SDavid du Colombier
294bd389b36SDavid du Colombier def = 0;
295bd389b36SDavid du Colombier baud = 0;
296bd389b36SDavid du Colombier ARGBEGIN{
297bd389b36SDavid du Colombier case 'b':
298bd389b36SDavid du Colombier baud = atoi(ARGF());
299bd389b36SDavid du Colombier break;
300bd389b36SDavid du Colombier case 'd':
301bd389b36SDavid du Colombier p = ARGF();
302bd389b36SDavid du Colombier def = *p;
303bd389b36SDavid du Colombier break;
304219b2ee8SDavid du Colombier case 'n':
305219b2ee8SDavid du Colombier dontset = 1;
306219b2ee8SDavid du Colombier break;
307bd389b36SDavid du Colombier case 'D':
308bd389b36SDavid du Colombier debug = 1;
309bd389b36SDavid du Colombier break;
310bd389b36SDavid du Colombier default:
311bd389b36SDavid du Colombier usage();
312bd389b36SDavid du Colombier }ARGEND
313bd389b36SDavid du Colombier
314bd389b36SDavid du Colombier p = "0";
315bd389b36SDavid du Colombier if(argc)
316bd389b36SDavid du Colombier p = *argv;
317bd389b36SDavid du Colombier
3187dd7cddfSDavid du Colombier if((conf = open("/dev/mousectl", OWRITE)) == -1){
3197dd7cddfSDavid du Colombier fprint(2, "%s: can't open /dev/mousectl - %r\n", argv0);
320219b2ee8SDavid du Colombier if(dontset == 0)
3217dd7cddfSDavid du Colombier exits("open /dev/mousectl");
322bd389b36SDavid du Colombier }
323bd389b36SDavid du Colombier
3247dd7cddfSDavid du Colombier if(strncmp(p, "ps2", 3) == 0){
3257dd7cddfSDavid du Colombier if(write(conf, p, strlen(p)) < 0){
326bd389b36SDavid du Colombier fprint(2, "%s: error setting mouse type - %r\n", argv0);
327bd389b36SDavid du Colombier exits("write conf");
328bd389b36SDavid du Colombier }
329bd389b36SDavid du Colombier exits(0);
330bd389b36SDavid du Colombier }
331bd389b36SDavid du Colombier
3327dd7cddfSDavid du Colombier type = 0;
3337dd7cddfSDavid du Colombier for(tries = 0; type == 0 && tries < 6; tries++){
3347dd7cddfSDavid du Colombier if(tries)
3357dd7cddfSDavid du Colombier fprint(2, "%s: Unknown mouse type, retrying...\n", argv0);
336bd389b36SDavid du Colombier sprint(buf, "#t/eia%sctl", p);
337bd389b36SDavid du Colombier if((ctl = open(buf, ORDWR)) == -1){
338bd389b36SDavid du Colombier fprint(2, "%s: can't open %s - %r\n", argv0, buf);
339bd389b36SDavid du Colombier exits("open ctl");
340bd389b36SDavid du Colombier }
341bd389b36SDavid du Colombier sprint(buf, "#t/eia%s", p);
342bd389b36SDavid du Colombier if((data = open(buf, ORDWR)) == -1){
343bd389b36SDavid du Colombier fprint(2, "%s: can't open %s - %r\n", argv0, buf);
344bd389b36SDavid du Colombier exits("open data");
345bd389b36SDavid du Colombier }
346bd389b36SDavid du Colombier
347bd389b36SDavid du Colombier notify(catch);
348bd389b36SDavid du Colombier
349bd389b36SDavid du Colombier type = MorW(ctl, data);
350bd389b36SDavid du Colombier if(type == 0)
351bd389b36SDavid du Colombier type = C(ctl, data);
352bd389b36SDavid du Colombier if(type == 0){
353219b2ee8SDavid du Colombier /* with the default we can't assume anything */
354219b2ee8SDavid du Colombier baud = 0;
355219b2ee8SDavid du Colombier
356bd389b36SDavid du Colombier /* try the default */
357bd389b36SDavid du Colombier switch(def){
358bd389b36SDavid du Colombier case 'C':
359bd389b36SDavid du Colombier setupeia(ctl, "b1200", "l8");
360bd389b36SDavid du Colombier break;
361bd389b36SDavid du Colombier case 'M':
362bd389b36SDavid du Colombier setupeia(ctl, "b1200", "l7");
363bd389b36SDavid du Colombier break;
364bd389b36SDavid du Colombier }
365219b2ee8SDavid du Colombier
366bd389b36SDavid du Colombier type = def;
367bd389b36SDavid du Colombier }
368bd389b36SDavid du Colombier
369bd389b36SDavid du Colombier sprint(buf, "serial %s", p);
370bd389b36SDavid du Colombier switch(type){
371bd389b36SDavid du Colombier case 0:
3727dd7cddfSDavid du Colombier close(data);
3737dd7cddfSDavid du Colombier close(ctl);
3747dd7cddfSDavid du Colombier continue;
375bd389b36SDavid du Colombier case 'C':
376219b2ee8SDavid du Colombier DEBUG print("Logitech 5 byte mouse\n");
377bd389b36SDavid du Colombier Cbaud(ctl, data, baud);
378bd389b36SDavid du Colombier break;
379bd389b36SDavid du Colombier case 'W':
380219b2ee8SDavid du Colombier DEBUG print("Type W mouse\n");
381bd389b36SDavid du Colombier Wbaud(ctl, data, baud);
382bd389b36SDavid du Colombier break;
383bd389b36SDavid du Colombier case 'M':
384219b2ee8SDavid du Colombier DEBUG print("Microsoft compatible mouse\n");
385bd389b36SDavid du Colombier strcat(buf, " M");
386bd389b36SDavid du Colombier break;
387bd389b36SDavid du Colombier }
3887dd7cddfSDavid du Colombier }
3897dd7cddfSDavid du Colombier
3907dd7cddfSDavid du Colombier if(type == 0){
3917dd7cddfSDavid du Colombier fprint(2, "%s: Unknown mouse type, giving up\n", argv0);
3927dd7cddfSDavid du Colombier exits("no mouse");
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier
395bd389b36SDavid du Colombier DEBUG fprint(2, "mouse configured as '%s'\n", buf);
396219b2ee8SDavid du Colombier if(dontset == 0 && write(conf, buf, strlen(buf)) < 0){
397bd389b36SDavid du Colombier fprint(2, "%s: error setting mouse type - %r\n", argv0);
398bd389b36SDavid du Colombier exits("write conf");
399bd389b36SDavid du Colombier }
4007dd7cddfSDavid du Colombier
401bd389b36SDavid du Colombier exits(0);
402bd389b36SDavid du Colombier }
403