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