]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/kb/kb.c
nusb: use ep->addr instead of ep->id in unstall() library function
[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 kbprocname(KDev *kd, char *name)
341 {
342         char buf[128];
343         snprint(buf, sizeof(buf), "%s %s", name, kd->ep->dir);
344         threadsetname(buf);
345 }
346
347 static void
348 sethipri(void)
349 {
350         char fn[64];
351         int fd;
352
353         snprint(fn, sizeof(fn), "/proc/%d/ctl", getpid());
354         fd = open(fn, OWRITE);
355         if(fd < 0)
356                 return;
357         fprint(fd, "pri 13");
358         close(fd);
359 }
360
361 typedef struct Ptr Ptr;
362 struct Ptr
363 {
364         int     x;
365         int     y;
366         int     z;
367
368         int     b;
369         int     m;
370
371         int     absx;
372         int     absy;
373         int     absz;
374
375         int     o;
376         uchar   *e;
377         uchar   p[128];
378 };
379
380 static void
381 ptrparse(int t, int f, int g[], int l[], int, void *a)
382 {
383         int v, m;
384         Ptr *p = a;
385
386         if(t != Input)
387                 return;
388         if(g[RepId] != 0){
389                 if(p->p[0] != g[RepId]){
390                         p->o = 0;
391                         return;
392                 }
393                 if(p->o < 8)
394                         p->o = 8;       /* skip report id byte */
395         }
396         v = getbits(p->p, p->e, g[RepSize], p->o);
397         if(g[LogiMin] < 0)
398                 v = signext(v, g[RepSize]);
399         if((f & (Fvar|Farray)) == Fvar && v >= g[LogiMin] && v <= g[LogiMax]){
400                 /*
401                  * we use logical units below, but need the
402                  * sign to be correct for mouse deltas.
403                  * so if physical unit is signed but logical
404                  * is unsigned, convert to signed but in logical
405                  * units.
406                  */
407                 if((f & (Fabs|Frel)) == Frel
408                 && g[PhysMin] < 0 && g[PhysMax] > 0
409                 && g[LogiMin] >= 0 && g[LogiMin] < g[LogiMax])
410                         v -= (g[PhysMax] * (g[LogiMax] - g[LogiMin])) / (g[PhysMax] - g[PhysMin]);
411
412                 switch(l[Usage]){
413                 case 0x090001:
414                 case 0x090002:
415                 case 0x090003:
416                 case 0x090004:
417                 case 0x090005:
418                 case 0x090006:
419                 case 0x090007:
420                 case 0x090008:
421                         m = 1<<(l[Usage] - 0x090001);
422                         p->m |= m;
423                         p->b &= ~m;
424                         if(v != 0)
425                                 p->b |= m;
426                         break;
427                 case 0x010030:
428                         if((f & (Fabs|Frel)) == Fabs){
429                                 p->x = (v - p->absx);
430                                 p->absx = v;
431                         } else {
432                                 p->x = v;
433                                 p->absx += v;
434                         }
435                         break;
436                 case 0x010031:
437                         if((f & (Fabs|Frel)) == Fabs){
438                                 p->y = (v - p->absy);
439                                 p->absy = v;
440                         } else {
441                                 p->y = v;
442                                 p->absy += v;
443                         }
444                         break;
445                 case 0x010038:
446                         if((f & (Fabs|Frel)) == Fabs){
447                                 p->z = (v - p->absz);
448                                 p->absz = v;
449                         } else {
450                                 p->z = v;
451                                 p->absz += v;
452                         }
453                         break;
454                 }
455         }
456         p->o += g[RepSize];
457 }
458
459 static void
460 ptrwork(void* a)
461 {
462         char    err[ERRMAX];
463         char    mbuf[80];
464         int     c, b, nerrs, lastb;
465         KDev*   f = a;
466         Ptr     p;
467
468         kbprocname(f, "ptr");
469         sethipri();
470
471         memset(&p, 0, sizeof(p));
472         lastb = 0;
473
474         nerrs = 0;
475         for(;;){
476                 if(f->ep == nil)
477                         kbfatal(f, nil);
478                 if(f->ep->maxpkt < 1 || f->ep->maxpkt > sizeof(p.p))
479                         kbfatal(f, "ptr: weird mouse maxpkt");
480
481                 memset(p.p, 0, sizeof(p.p));
482                 c = read(f->ep->dfd, p.p, f->ep->maxpkt);
483                 if(c <= 0){
484                         if(c < 0)
485                                 rerrstr(err, sizeof(err));
486                         else
487                                 strcpy(err, "zero read");
488                         if(++nerrs < 3){
489                                 fprint(2, "%s: ptr: %s: read: %s\n", argv0, f->ep->dir, err);
490                                 if(strstr(err, "babble") != 0)
491                                         recoverkb(f);
492                                 continue;
493                         }
494                         kbfatal(f, err);
495                 }
496                 nerrs = 0;
497
498                 p.o = 0;
499                 p.e = p.p + c;
500                 repparse(f->rep, f->rep+f->nrep, ptrparse, &p);
501
502                 if(debug)
503                         fprint(2, "ptr: b=%x m=%x x=%d y=%d z=%d\n", p.b, p.m, p.x, p.y, p.z);
504
505                 /* map buttons */
506                 b = p.b & 1;
507                 if(p.b & (4|8))
508                         b |= 2;
509                 if(p.b & 2)
510                         b |= 4;
511                 if(p.z != 0)
512                         b |= (p.z > 0) ? 8 : 16;
513
514                 if(p.x == 0 && p.y == 0 && p.z == 0 && b == lastb)
515                         continue;
516                 lastb = b;
517
518                 seprint(mbuf, mbuf+sizeof(mbuf), "m%11d %11d %11d", p.x, p.y, b);
519                 if(write(f->infd, mbuf, strlen(mbuf)) < 0)
520                         kbfatal(f, "mousein i/o");
521         }
522 }
523
524 static void
525 putscan(int fd, uchar sc, uchar up)
526 {
527         uchar s[2] = {SCesc1, 0};
528
529         if(sc == 0)
530                 return;
531         s[1] = up | sc&Keymask;
532         if(isext(sc))
533                 write(fd, s, 2);
534         else
535                 write(fd, s+1, 1);
536 }
537
538 static void
539 putmod(int fd, uchar mods, uchar omods, uchar mask, uchar esc, uchar sc)
540 {
541         uchar s[4], *p;
542
543         p = s;
544         if((mods&mask) && !(omods&mask)){
545                 if(esc)
546                         *p++ = SCesc1;
547                 *p++ = sc;
548         }
549         if(!(mods&mask) && (omods&mask)){
550                 if(esc)
551                         *p++ = SCesc1;
552                 *p++ = Keyup|sc;
553         }
554         if(p > s)
555                 write(fd, s, p - s);
556 }
557
558 static void
559 sleepproc(void* a)
560 {
561         Channel *c = a;
562         int ms;
563
564         threadsetname("sleepproc");
565         while((ms = recvul(c)) > 0)
566                 sleep(ms);
567         chanfree(c);
568 }
569
570 static void
571 repeatproc(void* arg)
572 {
573         KDev *f = arg;
574         Channel *repeatc, *sleepc;
575         int kbdinfd;
576         ulong l, t;
577         uchar sc;
578         Alt a[3];
579
580         repeatc = f->repeatc;
581         kbdinfd = f->infd;
582         threadsetname("repeatproc");
583         
584         sleepc = chancreate(sizeof(ulong), 0);
585         if(sleepc != nil)
586                 proccreate(sleepproc, sleepc, Stack);
587
588         a[0].c = repeatc;
589         a[0].v = &l;
590         a[0].op = CHANRCV;
591         a[1].c = sleepc;
592         a[1].v = &t;
593         a[1].op = sleepc!=nil ? CHANSND : CHANNOP;
594         a[2].c = nil;
595         a[2].v = nil;
596         a[2].op = CHANEND;
597
598         l = Awakemsg;
599         while(l != Diemsg){
600                 if(l == Awakemsg){
601                         l = recvul(repeatc);
602                         continue;
603                 }
604                 sc = l & 0xff;
605                 t = Kbdelay;
606                 if(alt(a) == 1){
607                         t = Kbrepeat;
608                         while(alt(a) == 1)
609                                 putscan(kbdinfd, sc, 0);
610                 }
611         }
612         if(sleepc != nil)
613                 sendul(sleepc, 0);
614         chanfree(repeatc);
615         threadexits(nil);
616 }
617
618 static void
619 stoprepeat(KDev *f)
620 {
621         sendul(f->repeatc, Awakemsg);
622 }
623
624 static void
625 startrepeat(KDev *f, uchar sc)
626 {
627         sendul(f->repeatc, sc);
628 }
629
630 /*
631  * This routine diffs the state with the last known state
632  * and invents the scan codes that would have been sent
633  * by a non-usb keyboard in that case. This also requires supplying
634  * the extra esc1 byte as well as keyup flags.
635  * The aim is to allow future addition of other keycode pages
636  * for other keyboards.
637  */
638 static uchar
639 putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk)
640 {
641         int i, j;
642         uchar uk;
643         int fd;
644
645         fd = f->infd;
646         putmod(fd, buf[0], obuf[0], Mctrl, 0, SCctrl);
647         putmod(fd, buf[0], obuf[0], (1<<Mlshift), 0, SClshift);
648         putmod(fd, buf[0], obuf[0], (1<<Mrshift), 0, SCrshift);
649         putmod(fd, buf[0], obuf[0], Mcompose, 0, SCcompose);
650         putmod(fd, buf[0], obuf[0], Maltgr, 1, SCcompose);
651
652         /* Report key downs */
653         for(i = 2; i < n; i++){
654                 for(j = 2; j < n; j++)
655                         if(buf[i] == obuf[j])
656                                 break;
657                 if(j == n && buf[i] != 0){
658                         dk = sctab[buf[i]];
659                         putscan(fd, dk, 0);
660                         startrepeat(f, dk);
661                 }
662         }
663
664         /* Report key ups */
665         uk = 0;
666         for(i = 2; i < n; i++){
667                 for(j = 2; j < n; j++)
668                         if(obuf[i] == buf[j])
669                                 break;
670                 if(j == n && obuf[i] != 0){
671                         uk = sctab[obuf[i]];
672                         putscan(fd, uk, Keyup);
673                 }
674         }
675         if(uk && (dk == 0 || dk == uk)){
676                 stoprepeat(f);
677                 dk = 0;
678         }
679         return dk;
680 }
681
682 static int
683 kbdbusy(uchar* buf, int n)
684 {
685         int i;
686
687         for(i = 1; i < n; i++)
688                 if(buf[i] == 0 || buf[i] != buf[0])
689                         return 0;
690         return 1;
691 }
692
693 static void
694 kbdwork(void *a)
695 {
696         uchar dk, buf[64], lbuf[64];
697         int c, i, nerrs;
698         char err[128];
699         KDev *f = a;
700
701         kbprocname(f, "kbd");
702
703         f->repeatc = chancreate(sizeof(ulong), 0);
704         if(f->repeatc == nil)
705                 kbfatal(f, "chancreate failed");
706         proccreate(repeatproc, f, Stack);
707
708         setleds(f, f->ep->id, 0);
709         sethipri();
710
711         memset(lbuf, 0, sizeof lbuf);
712         dk = nerrs = 0;
713         for(;;){
714                 if(f->ep == nil)
715                         kbfatal(f, nil);
716                 if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf)
717                         kbfatal(f, "kbd: weird maxpkt");
718                 memset(buf, 0, sizeof buf);
719                 c = read(f->ep->dfd, buf, f->ep->maxpkt);
720                 if(c <= 0){
721                         if(c < 0)
722                                 rerrstr(err, sizeof(err));
723                         else
724                                 strcpy(err, "zero read");
725                         if(++nerrs < 3){
726                                 fprint(2, "%s: kbd: %s: read: %s\n", argv0, f->ep->dir, err);
727                                 if(strstr(err, "babble") != 0)
728                                         recoverkb(f);
729                                 continue;
730                         }
731                         kbfatal(f, err);
732                 }
733                 nerrs = 0;
734                 if(c < 3)
735                         continue;
736                 if(kbdbusy(buf + 2, c - 2))
737                         continue;
738                 if(usbdebug > 2 || debug > 1){
739                         fprint(2, "kbd mod %x: ", buf[0]);
740                         for(i = 2; i < c; i++)
741                                 fprint(2, "kc %x ", buf[i]);
742                         fprint(2, "\n");
743                 }
744                 dk = putkeys(f, buf, lbuf, f->ep->maxpkt, dk);
745                 memmove(lbuf, buf, c);
746         }
747 }
748
749 static void
750 kbstart(Dev *d, Ep *ep, char *infile, void (*f)(void*))
751 {
752         KDev *kd;
753
754         kd = emallocz(sizeof(KDev), 1);
755         kd->infd = open(infile, OWRITE);
756         if(kd->infd < 0){
757                 fprint(2, "%s: %s: open: %r\n", argv0, d->dir);
758                 goto Err;
759         }
760         incref(d);
761         kd->dev = d;
762         if(setproto(kd, ep->id) < 0){
763                 fprint(2, "%s: %s: setproto: %r\n", argv0, d->dir);
764                 goto Err;
765         }
766         kd->ep = openep(kd->dev, ep->id);
767         if(kd->ep == nil){
768                 fprint(2, "%s: %s: openep %d: %r\n", argv0, d->dir, ep->id);
769                 goto Err;
770         }
771         if(opendevdata(kd->ep, OREAD) < 0){
772                 fprint(2, "%s: %s: opendevdata: %r\n", argv0, kd->ep->dir);
773                 goto Err;
774         }
775         procrfork(f, kd, Stack, RFNOTEG);
776         return;
777 Err:
778         kbfree(kd);
779 }
780
781 static void
782 usage(void)
783 {
784         fprint(2, "usage: %s [-d] devid\n", argv0);
785         threadexits("usage");
786 }
787
788 void
789 threadmain(int argc, char* argv[])
790 {
791         int i;
792         Dev *d;
793         Ep *ep;
794         Usbdev *ud;
795
796         ARGBEGIN{
797         case 'd':
798                 debug++;
799                 break;
800         default:
801                 usage();
802         }ARGEND;
803         if(argc != 1)
804                 usage();
805         d = getdev(atoi(*argv));
806         if(d == nil)
807                 sysfatal("getdev: %r");
808         ud = d->usb;
809         for(i = 0; i < nelem(ud->ep); i++){
810                 if((ep = ud->ep[i]) == nil)
811                         continue;
812                 if(ep->type == Eintr && ep->dir == Ein && ep->iface->csp == KbdCSP)
813                         kbstart(d, ep, "/dev/kbin", kbdwork);
814                 if(ep->type == Eintr && ep->dir == Ein && (ep->iface->csp == PtrCSP || ep->iface->csp == Ptr2CSP))
815                         kbstart(d, ep, "/dev/mousein", ptrwork);
816         }
817         closedev(d);
818         threadexits(nil);
819 }