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