]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/kb/kb.c
usbd: intoruce /env/usbbusy
[plan9front.git] / sys / src / cmd / nusb / kb / kb.c
1 /*
2  * USB Human Interaction Device: keyboard and mouse.
3  *
4  * If there's no usb keyboard, it tries to setup the mouse, if any.
5  * It should be started at boot time.
6  *
7  * Mouse events are converted to the format of mouse(3)
8  * on mousein file.
9  * Keyboard keycodes are translated to scan codes and sent to kbdfs(8)
10  * on kbin file.
11  *
12  */
13
14 #include <u.h>
15 #include <libc.h>
16 #include <thread.h>
17 #include "usb.h"
18 #include "hid.h"
19
20 enum
21 {
22         Awakemsg=0xdeaddead,
23         Diemsg = 0xbeefbeef,
24 };
25
26 enum
27 {
28         Kbdelay = 500,
29         Kbrepeat = 100,
30 };
31
32 typedef struct Hiddev Hiddev;
33 struct Hiddev
34 {
35         Dev*    dev;            /* usb device*/
36         Dev*    ep;             /* endpoint to get events */
37
38         int     minfd;
39         int     kinfd;
40
41         Channel *repeatc;       /* only for keyboard */
42
43         /* report descriptor */
44         int     nrep;
45         uchar   rep[512];
46 };
47
48 typedef struct Hidreport Hidreport;
49 struct Hidreport
50 {
51         int     x;
52         int     y;
53         int     z;
54
55         int     b;
56         int     m;
57
58         int     absx;
59         int     absy;
60         int     absz;
61
62         int     nk;
63         uchar   k[64];
64
65         int     o;
66         uchar   *e;
67         uchar   p[128];
68 };
69
70 /*
71  * Plan 9 keyboard driver constants.
72  */
73 enum {
74         /* Scan codes (see kbd.c) */
75         SCesc1          = 0xe0,         /* first of a 2-character sequence */
76         SCesc2          = 0xe1,
77         Keyup           = 0x80,         /* flag bit */
78         Keymask         = 0x7f,         /* regular scan code bits */
79 };
80
81 /*
82  * scan codes >= 0x80 are extended (E0 XX)
83  */
84 #define isext(sc)       ((sc) >= 0x80)
85
86 /*
87  * key code to scan code; for the page table used by
88  * the logitech bluetooth keyboard.
89  */
90 static char sctab[256] = 
91 {
92 [0x00]  0x0,    0x0,    0x0,    0x0,    0x1e,   0x30,   0x2e,   0x20,
93 [0x08]  0x12,   0x21,   0x22,   0x23,   0x17,   0x24,   0x25,   0x26,
94 [0x10]  0x32,   0x31,   0x18,   0x19,   0x10,   0x13,   0x1f,   0x14,
95 [0x18]  0x16,   0x2f,   0x11,   0x2d,   0x15,   0x2c,   0x2,    0x3,
96 [0x20]  0x4,    0x5,    0x6,    0x7,    0x8,    0x9,    0xa,    0xb,
97 [0x28]  0x1c,   0x1,    0xe,    0xf,    0x39,   0xc,    0xd,    0x1a,
98 [0x30]  0x1b,   0x2b,   0x2b,   0x27,   0x28,   0x29,   0x33,   0x34,
99 [0x38]  0x35,   0x3a,   0x3b,   0x3c,   0x3d,   0x3e,   0x3f,   0x40,
100 [0x40]  0x41,   0x42,   0x43,   0x44,   0x57,   0x58,   0xe3,   0x46,
101 [0x48]  0xf7,   0xd2,   0xc7,   0xc9,   0xd3,   0xcf,   0xd1,   0xcd,
102 [0x50]  0xcb,   0xd0,   0xc8,   0x45,   0x35,   0x37,   0x4a,   0x4e,
103 [0x58]  0x1c,   0xcf,   0xd0,   0xd1,   0xcb,   0xcc,   0xcd,   0xc7,
104 [0x60]  0xc8,   0xc9,   0xd2,   0xd3,   0x56,   0xff,   0xf4,   0xf5,
105 [0x68]  0xd5,   0xd9,   0xda,   0xdb,   0xdc,   0xdd,   0xde,   0xdf,
106 [0x70]  0xf8,   0xf9,   0xfa,   0xfb,   0x0,    0x0,    0x0,    0x0,
107 [0x78]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0xf1,
108 [0x80]  0xf3,   0xf2,   0x0,    0x0,    0x0,    0xfc,   0x0,    0x0,
109 [0x88]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
110 [0x90]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
111 [0x98]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
112 [0xa0]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
113 [0xa8]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
114 [0xb0]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
115 [0xb8]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
116 [0xc0]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
117 [0xc8]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
118 [0xd0]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
119 [0xd8]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
120 [0xe0]  0x1d,   0x2a,   0x38,   0xfd,   0xe1,   0x36,   0xb8,   0xfe,
121 [0xe8]  0x0,    0x0,    0x0,    0x0,    0x0,    0xf3,   0xf2,   0xf1,
122 [0xf0]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
123 [0xf8]  0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
124 };
125
126 static uchar kbdbootrep[] = {
127 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07,
128 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01,
129 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01,
130 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01,
131 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02,
132 0x95, 0x01, 0x75, 0x03, 0x91, 0x01, 0x95, 0x06,
133 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07,
134 0x19, 0x00, 0x29, 0x65, 0x81, 0x00, 0xc0,
135 };
136
137 static uchar ptrbootrep[] = {
138 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 
139 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 
140 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 
141 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, 
142 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 
143 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 
144 0x81, 0x06, 0xc0, 0x09, 0x3c, 0x15, 0x00, 0x25, 
145 0x01, 0x75, 0x01, 0x95, 0x01, 0xb1, 0x22, 0x95, 
146 0x07, 0xb1, 0x01, 0xc0, 
147 };
148
149 static int debug = 0;
150
151 static int
152 signext(int v, int bits)
153 {
154         int s;
155
156         s = sizeof(v)*8 - bits;
157         v <<= s;
158         v >>= s;
159         return v;
160 }
161
162 static int
163 getbits(uchar *p, uchar *e, int bits, int off)
164 {
165         int v, m;
166
167         p += off/8;
168         off %= 8;
169         v = 0;
170         m = 1;
171         if(p < e){
172                 while(bits--){
173                         if(*p & (1<<off))
174                                 v |= m;
175                         if(++off == 8){
176                                 if(++p >= e)
177                                         break;
178                                 off = 0;
179                         }
180                         m <<= 1;
181                 }
182         }
183         return v;
184 }
185
186 enum {
187         Ng      = RepCnt+1,
188         UsgCnt  = Delim+1,      /* fake */
189         Nl      = UsgCnt+1,
190         Nu      = 256,
191 };
192
193 static uchar*
194 repparse1(uchar *d, uchar *e, int g[], int l[], int c,
195         void (*f)(int t, int v, int g[], int l[], int c, void *a), void *a)
196 {
197         int z, k, t, v, i;
198
199         while(d < e){
200                 v = 0;
201                 t = *d++;
202                 z = t & 3, t >>= 2;
203                 k = t & 3, t >>= 2;
204                 switch(z){
205                 case 3:
206                         d += 4;
207                         if(d > e) continue;
208                         v = d[-4] | d[-3]<<8 | d[-2]<<16 | d[-1]<<24;
209                         break;
210                 case 2:
211                         d += 2;
212                         if(d > e) continue;
213                         v = d[-2] | d[-1]<<8;
214                         break;
215                 case 1:
216                         d++;
217                         if(d > e) continue;
218                         v = d[-1];
219                         break;
220                 }
221                 switch(k){
222                 case 0: /* main item*/
223                         switch(t){
224                         case Collection:
225                                 memset(l, 0, Nl*sizeof(l[0]));
226                                 d = repparse1(d, e, g, l, v, f, a);
227                                 continue;
228                         case CollectionEnd:
229                                 return d;
230                         case Input:
231                         case Output:
232                         case Feature:
233                                 if(l[UsgCnt] == 0 && l[UsagMin] != 0 && l[UsagMin] < l[UsagMax])
234                                         for(i=l[UsagMin]; i<=l[UsagMax] && l[UsgCnt] < Nu; i++)
235                                                 l[Nl + l[UsgCnt]++] = i;
236                                 for(i=0; i<g[RepCnt]; i++){
237                                         if(i < l[UsgCnt])
238                                                 l[Usage] = l[Nl + i];
239                                         (*f)(t, v, g, l, c, a);
240                                 }
241                                 break;
242                         }
243                         memset(l, 0, Nl*sizeof(l[0]));
244                         continue;
245                 case 1: /* global item */
246                         if(t == Push){
247                                 int w[Ng];
248                                 memmove(w, g, sizeof(w));
249                                 d = repparse1(d, e, w, l, c, f, a);
250                         } else if(t == Pop){
251                                 return d;
252                         } else if(t < Ng){
253                                 if(t == RepId)
254                                         v &= 0xFF;
255                                 else if(t == UsagPg)
256                                         v &= 0xFFFF;
257                                 else if(t != RepSize && t != RepCnt){
258                                         v = signext(v, (z == 3) ? 32 : 8*z);
259                                 }
260                                 g[t] = v;
261                         }
262                         continue;
263                 case 2: /* local item */
264                         if(l[Delim] != 0)
265                                 continue;
266                         if(t == Delim){
267                                 l[Delim] = 1;
268                         } else if(t < Delim){
269                                 if(z != 3 && (t == Usage || t == UsagMin || t == UsagMax))
270                                         v = (v & 0xFFFF) | (g[UsagPg] << 16);
271                                 l[t] = v;
272                                 if(t == Usage && l[UsgCnt] < Nu)
273                                         l[Nl + l[UsgCnt]++] = v;
274                         }
275                         continue;
276                 case 3: /* long item */
277                         if(t == 15)
278                                 d += v & 0xFF;
279                         continue;
280                 }
281         }
282         return d;
283 }
284
285 /*
286  * parse the report descriptor and call f for every (Input, Output
287  * and Feature) main item as often as it would appear in the report
288  * data packet.
289  */
290 static void
291 repparse(uchar *d, uchar *e,
292         void (*f)(int t, int v, int g[], int l[], int c, void *a), void *a)
293 {
294         int l[Nl+Nu], g[Ng];
295
296         memset(l, 0, sizeof(l));
297         memset(g, 0, sizeof(g));
298         repparse1(d, e, g, l, 0, f, a);
299 }
300
301 static int
302 setproto(Hiddev *f, int eid)
303 {
304         int id, proto;
305         Iface *iface;
306
307         iface = f->dev->usb->ep[eid]->iface;
308         id = iface->id;
309         f->nrep = usbcmd(f->dev, Rd2h|Rstd|Riface, Rgetdesc, Dreport<<8, id, 
310                 f->rep, sizeof(f->rep));
311         if(f->nrep > 0){
312                 if(debug){
313                         int i;
314
315                         fprint(2, "report descriptor:");
316                         for(i = 0; i < f->nrep; i++){
317                                 if(i%8 == 0)
318                                         fprint(2, "\n\t");
319                                 fprint(2, "%#2.2ux ", f->rep[i]);
320                         }
321                         fprint(2, "\n");
322                 }
323                 proto = Reportproto;
324         } else {
325                 switch(iface->csp){
326                 case KbdCSP:
327                         f->nrep = sizeof(kbdbootrep);
328                         memmove(f->rep, kbdbootrep, f->nrep);
329                         break;
330                 case PtrCSP:
331                         f->nrep = sizeof(ptrbootrep);
332                         memmove(f->rep, ptrbootrep, f->nrep);
333                         break;
334                 default:
335                         werrstr("no report descriptor");
336                         return -1;
337                 }
338                 proto = Bootproto;
339         }
340         return usbcmd(f->dev, Rh2d|Rclass|Riface, Setproto, proto, id, nil, 0);
341 }
342
343 static int
344 setleds(Hiddev* f, int, uchar leds)
345 {
346         return usbcmd(f->dev, Rh2d|Rclass|Riface, Setreport, Reportout, 0, &leds, 1);
347 }
348
349 static void
350 hdfree(Hiddev *f)
351 {
352         if(f->kinfd >= 0)
353                 close(f->kinfd);
354         if(f->minfd >= 0)
355                 close(f->minfd);
356         if(f->ep != nil)
357                 closedev(f->ep);
358         if(f->dev != nil)
359                 closedev(f->dev);
360         free(f);
361 }
362
363 static void
364 hdfatal(Hiddev *f, char *sts)
365 {
366         if(sts != nil)
367                 fprint(2, "%s: fatal: %s\n", argv0, sts);
368         else
369                 fprint(2, "%s: exiting\n", argv0);
370         if(f->repeatc != nil)
371                 sendul(f->repeatc, Diemsg);
372         hdfree(f);
373         threadexits(sts);
374 }
375
376 static void
377 hdrecover(Hiddev *f)
378 {
379         char err[ERRMAX];
380         static QLock l;
381         int i;
382
383         if(canqlock(&l)){
384                 close(f->dev->dfd);
385                 devctl(f->dev, "reset");
386                 for(i=0; i<4; i++){
387                         sleep(500);
388                         if(opendevdata(f->dev, ORDWR) >= 0)
389                                 goto Resetdone;
390                 }
391                 threadexitsall(err);
392         } else {
393                 /* wait for reset to complete */
394                 qlock(&l);
395         }
396 Resetdone:
397         if(setproto(f, f->ep->id) < 0){
398                 rerrstr(err, sizeof(err));
399                 qunlock(&l);
400                 hdfatal(f, err);
401         }
402         qunlock(&l);
403 }
404
405 static void
406 putscan(Hiddev *f, uchar sc, uchar up)
407 {
408         uchar s[2] = {SCesc1, 0};
409
410         if(sc == 0)
411                 return;
412         s[1] = up | sc&Keymask;
413         if(isext(sc))
414                 write(f->kinfd, s, 2);
415         else
416                 write(f->kinfd, s+1, 1);
417 }
418
419 static void
420 sleepproc(void* a)
421 {
422         Channel *c = a;
423         int ms;
424
425         threadsetname("sleepproc");
426         while((ms = recvul(c)) > 0)
427                 sleep(ms);
428         chanfree(c);
429 }
430
431 static void
432 repeatproc(void* arg)
433 {
434         Hiddev *f = arg;
435         Channel *repeatc, *sleepc;
436         ulong l, t;
437         uchar sc;
438         Alt a[3];
439
440         repeatc = f->repeatc;
441         threadsetname("repeatproc");
442         
443         sleepc = chancreate(sizeof(ulong), 0);
444         if(sleepc != nil)
445                 proccreate(sleepproc, sleepc, Stack);
446
447         a[0].c = repeatc;
448         a[0].v = &l;
449         a[0].op = CHANRCV;
450         a[1].c = sleepc;
451         a[1].v = &t;
452         a[1].op = sleepc!=nil ? CHANSND : CHANNOP;
453         a[2].c = nil;
454         a[2].v = nil;
455         a[2].op = CHANEND;
456
457         l = Awakemsg;
458         while(l != Diemsg){
459                 if(l == Awakemsg){
460                         l = recvul(repeatc);
461                         continue;
462                 }
463                 sc = l & 0xff;
464                 t = Kbdelay;
465                 if(alt(a) == 1){
466                         t = Kbrepeat;
467                         while(alt(a) == 1)
468                                 putscan(f, sc, 0);
469                 }
470         }
471         if(sleepc != nil)
472                 sendul(sleepc, 0);
473         chanfree(repeatc);
474         threadexits(nil);
475 }
476
477 static void
478 stoprepeat(Hiddev *f)
479 {
480         sendul(f->repeatc, Awakemsg);
481 }
482
483 static void
484 startrepeat(Hiddev *f, uchar sc)
485 {
486         sendul(f->repeatc, sc);
487 }
488
489 static void
490 hidparse(int t, int f, int g[], int l[], int, void *a)
491 {
492         Hidreport *p = a;
493         int v, m;
494
495         if(t != Input)
496                 return;
497         if(g[RepId] != 0){
498                 if(p->p[0] != g[RepId]){
499                         p->o = 0;
500                         return;
501                 }
502                 if(p->o < 8)
503                         p->o = 8;       /* skip report id byte */
504         }
505         v = getbits(p->p, p->e, g[RepSize], p->o);
506         p->o += g[RepSize];
507
508         if((f & (Fconst|Fdata)) != Fdata)
509                 return;
510
511         if(debug > 1)
512                 fprint(2, "hidparse: t=%x f=%x usage=%x v=%x\n", t, f, l[Usage], v);
513
514         if((l[Usage]>>16) == 0x07){     /* keycode */
515                 if((f & (Fvar|Farray)) == Fvar)
516                         if(v != 0) v = l[Usage] & 0xFF;
517                 if(p->nk < nelem(p->k) && v != 0)
518                         p->k[p->nk++] = v;
519                 return;
520         }
521
522         if(g[LogiMin] < 0)
523                 v = signext(v, g[RepSize]);
524         if((f & (Fvar|Farray)) == Fvar && v >= g[LogiMin] && v <= g[LogiMax]){
525                 /*
526                  * we use logical units below, but need the
527                  * sign to be correct for mouse deltas.
528                  * so if physical unit is signed but logical
529                  * is unsigned, convert to signed but in logical
530                  * units.
531                  */
532                 if((f & (Fabs|Frel)) == Frel
533                 && g[PhysMin] < 0 && g[PhysMax] > 0
534                 && g[LogiMin] >= 0 && g[LogiMin] < g[LogiMax])
535                         v -= (g[PhysMax] * (g[LogiMax] - g[LogiMin])) / (g[PhysMax] - g[PhysMin]);
536
537                 switch(l[Usage]){
538                 case 0x090001:
539                 case 0x090002:
540                 case 0x090003:
541                 case 0x090004:
542                 case 0x090005:
543                 case 0x090006:
544                 case 0x090007:
545                 case 0x090008:
546                         m = 1<<(l[Usage] - 0x090001);
547                         p->m |= m;
548                         p->b &= ~m;
549                         if(v != 0)
550                                 p->b |= m;
551                         break;
552                 case 0x010030:
553                         if((f & (Fabs|Frel)) == Fabs){
554                                 p->x = (v - p->absx);
555                                 p->absx = v;
556                         } else {
557                                 p->x = v;
558                                 p->absx += v;
559                         }
560                         break;
561                 case 0x010031:
562                         if((f & (Fabs|Frel)) == Fabs){
563                                 p->y = (v - p->absy);
564                                 p->absy = v;
565                         } else {
566                                 p->y = v;
567                                 p->absy += v;
568                         }
569                         break;
570                 case 0x010038:
571                         if((f & (Fabs|Frel)) == Fabs){
572                                 p->z = (v - p->absz);
573                                 p->absz = v;
574                         } else {
575                                 p->z = v;
576                                 p->absz += v;
577                         }
578                         break;
579                 }
580         }
581 }
582
583 static void
584 sethipri(void)
585 {
586         char fn[64];
587         int fd;
588
589         snprint(fn, sizeof(fn), "/proc/%d/ctl", getpid());
590         fd = open(fn, OWRITE);
591         if(fd < 0)
592                 return;
593         fprint(fd, "pri 13");
594         close(fd);
595 }
596
597 static void
598 readerproc(void* a)
599 {
600         char    err[ERRMAX], mbuf[80];
601         uchar   lastk[64], uk, dk;
602         int     i, c, b, nerrs, lastb, nlastk;
603         Hidreport p;
604         Hiddev* f = a;
605
606         threadsetname("readerproc %s", f->ep->dir);
607         sethipri();
608
609         memset(&p, 0, sizeof(p));
610         lastb = nlastk = nerrs = 0;
611
612         for(;;){
613                 if(f->ep == nil)
614                         hdfatal(f, nil);
615                 if(f->ep->maxpkt < 1 || f->ep->maxpkt > sizeof(p.p))
616                         hdfatal(f, "hid: weird maxpkt");
617
618                 memset(p.p, 0, sizeof(p.p));
619                 c = read(f->ep->dfd, p.p, f->ep->maxpkt);
620                 if(c <= 0){
621                         if(c < 0)
622                                 rerrstr(err, sizeof(err));
623                         else
624                                 strcpy(err, "zero read");
625                         fprint(2, "%s: hid: %s: read: %s\n", argv0, f->ep->dir, err);
626                         if(++nerrs <= 3){
627                                 hdrecover(f);
628                                 continue;
629                         }
630                         hdfatal(f, err);
631                 }
632                 nerrs = 0;
633
634                 p.o = 0;
635                 p.e = p.p + c;
636                 repparse(f->rep, f->rep+f->nrep, hidparse, &p);
637
638                 if(p.nk != 0 || nlastk != 0){
639                         if(debug){
640                                 fprint(2, "kbd: ");
641                                 for(i = 0; i < p.nk; i++)
642                                         fprint(2, "%#2.2ux ", p.k[i]);
643                                 fprint(2, "\n");
644                         }
645
646                         if(f->kinfd < 0){
647                                 f->kinfd = open("/dev/kbin", OWRITE);
648                                 if(f->kinfd < 0)
649                                         hdfatal(f, "open /dev/kbin");
650
651                                 f->repeatc = chancreate(sizeof(ulong), 0);
652                                 if(f->repeatc == nil)
653                                         hdfatal(f, "chancreate failed");
654                                 proccreate(repeatproc, f, Stack);
655                         }
656         
657                         dk = uk = 0;
658                         for(i=0; i<nlastk; i++){
659                                 if(memchr(p.k, lastk[i], p.nk) == nil){
660                                         uk = sctab[lastk[i]];
661                                         putscan(f, uk, Keyup);
662                                 }
663                         }
664                         for(i=0; i<p.nk; i++){
665                                 if(memchr(lastk, p.k[i], nlastk) == nil){
666                                         dk = sctab[p.k[i]];
667                                         putscan(f, dk, 0);
668                                 }
669                         }
670                         if(uk != 0 && (dk == 0 || dk == uk))
671                                 stoprepeat(f);
672                         else if(dk != 0)
673                                 startrepeat(f, dk);
674
675                         memmove(lastk, p.k, nlastk = p.nk);
676                         p.nk = 0;
677                 }
678
679                 /* map mouse buttons */
680                 b = p.b & 1;
681                 if(p.b & (4|8))
682                         b |= 2;
683                 if(p.b & 2)
684                         b |= 4;
685                 if(p.z != 0)
686                         b |= (p.z > 0) ? 8 : 16;
687
688                 if(p.x != 0 || p.y != 0 || p.z != 0 || b != lastb){
689                         if(debug)
690                                 fprint(2, "ptr: b=%x m=%x x=%d y=%d z=%d\n", p.b, p.m, p.x, p.y, p.z);
691
692                         if(f->minfd < 0){
693                                 f->minfd = open("/dev/mousein", OWRITE);
694                                 if(f->minfd < 0)
695                                         hdfatal(f, "open /dev/mousein");
696                         }
697
698                         seprint(mbuf, mbuf+sizeof(mbuf), "m%11d %11d %11d", p.x, p.y, b);
699                         write(f->minfd, mbuf, strlen(mbuf));
700
701                         lastb = b;
702                 }
703         }
704 }
705
706 static void
707 hdsetup(Dev *d, Ep *ep)
708 {
709         Hiddev *f;
710
711         f = emallocz(sizeof(Hiddev), 1);
712         f->minfd = -1;
713         f->kinfd = -1;
714         incref(d);
715         f->dev = d;
716         if(setproto(f, ep->id) < 0){
717                 fprint(2, "%s: %s: setproto: %r\n", argv0, d->dir);
718                 goto Err;
719         }
720         f->ep = openep(f->dev, ep->id);
721         if(f->ep == nil){
722                 fprint(2, "%s: %s: openep %d: %r\n", argv0, d->dir, ep->id);
723                 goto Err;
724         }
725         if(opendevdata(f->ep, OREAD) < 0){
726                 fprint(2, "%s: %s: opendevdata: %r\n", argv0, f->ep->dir);
727                 goto Err;
728         }
729         procrfork(readerproc, f, Stack, RFNOTEG);
730         return;
731 Err:
732         hdfree(f);
733 }
734
735 static void
736 usage(void)
737 {
738         fprint(2, "usage: %s [-d] devid\n", argv0);
739         threadexits("usage");
740 }
741
742 void
743 threadmain(int argc, char* argv[])
744 {
745         int i;
746         Dev *d;
747         Ep *ep;
748         Usbdev *ud;
749
750         ARGBEGIN{
751         case 'd':
752                 debug++;
753                 break;
754         default:
755                 usage();
756         }ARGEND;
757         if(argc != 1)
758                 usage();
759         d = getdev(*argv);
760         if(d == nil)
761                 sysfatal("getdev: %r");
762         ud = d->usb;
763         for(i = 0; i < nelem(ud->ep); i++){
764                 if((ep = ud->ep[i]) == nil)
765                         continue;
766                 if(ep->type != Eintr || ep->dir != Ein)
767                         continue;
768                 switch(ep->iface->csp){
769                 case KbdCSP:
770                 case PtrCSP:
771                 case HidCSP:
772                         hdsetup(d, ep);
773                         break;
774                 }
775         }
776         closedev(d);
777         threadexits(nil);
778 }