only ask for 128 bytes of the first descriptor. if this isn't the complete descriptor, keep asking for more in 128-byte chunks until we hit 4k or have the whole thing. also, don't set the leds on a mouse. :-) Reference: /n/atom/patch/applied/usbkbsmalldesc Date: Tue Apr 1 04:22:30 CES 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/cmd/usb/kb/kb.c Tue Apr 1 04:21:40 2014 +++ /sys/src/cmd/usb/kb/kb.c Tue Apr 1 04:21:41 2014 @@ -184,7 +184,7 @@ static int ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb); static int -setbootproto(KDev* f, int eid, uchar *, int) +setbootproto(KDev* f, int eid, uchar **) { int nr, r, id; @@ -213,18 +213,56 @@ return usbcmd(f->dev, r, Setreport, Reportout | Ledreport, id, led, 1); } -static uchar ignoredesc[128]; +int +fullreportdesc(uchar *p, int n) +{ + int i, dsize; + + for(i = 0; i < n; i += dsize+1){ + dsize = (1 << (p[i] & 3)) >> 1; + if(p[i] == HidEnd) + return 1; + } + return 0; +} static int -setfirstconfig(KDev* f, int eid, uchar *desc, int descsz) +usbcmdcfg(Dev *d, int type, int req, int value, int index, uchar **data) { + uchar *p; + int a, n; + + assert((type & Rd2h) == Rd2h); + *data = nil; + p = nil; + + for(a = 128; a < 4096; a += 128){ + p = realloc(p, a); + n = usbcmd(d, type, req, value, index, p, a); + if(n <= 0){ + free(p); + return -1; + } + if(fullreportdesc(p, n)){ + *data = p; + return n; + } + } + free(p); + return 0; +} + +static int +setfirstconfig(KDev* f, int eid, uchar **desc) +{ + uchar *ignore, *p; int nr, r, id, i; dprint(2, "setting first config %d\n", eid); - if(desc == nil){ - descsz = sizeof ignoredesc; - desc = ignoredesc; - } + if(desc == nil) + desc = &ignore; + *desc = nil; + id = f->dev->usb->ep[eid]->iface->id; r = Rh2d | Rstd | Rdev; nr = usbcmd(f->dev, r, Rsetconf, 1, 0, nil, 0); @@ -235,18 +273,21 @@ if(nr < 0) return -1; r = Rd2h | Rstd | Riface; - nr=usbcmd(f->dev, r, Rgetdesc, Dreport<<8, id, desc, descsz); + nr = usbcmdcfg(f->dev, r, Rgetdesc, Dreport<<8, id, desc); if(nr <= 0) return -1; if(f->debug){ fprint(2, "report descriptor:"); + p = *desc; for(i = 0; i < nr; i++){ if(i%8 == 0) fprint(2, "\n\t"); - fprint(2, "%#2.2ux ", desc[i]); + fprint(2, "%.2ux ", p[i]); } fprint(2, "\n"); } + if(desc == &ignore) + free(*desc); f->ptrvals = ptrrepvals; return nr; } @@ -269,9 +310,9 @@ if(opendevdata(f->dev, ORDWR) >= 0){ if(f->bootp) /* TODO func pointer */ - setbootproto(f, f->eid, nil, 0); + setbootproto(f, f->eid, nil); else - setfirstconfig(f, f->eid, nil, 0); + setfirstconfig(f, f->eid, nil); break; } /* else usbd still working... */ @@ -679,6 +720,9 @@ threadsetname("kbd %s", f->ep->dir); kbdfd = f->ep->dfd; + f->led = Lnum; + setled(f, f->led); + if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) kbfatal(f, "weird maxpkt"); @@ -745,7 +789,7 @@ static void kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), KDev *kd) { - uchar desc[512]; + uchar *desc, otghack[128]; int n, res; qlock(&inlck); @@ -774,23 +818,24 @@ * Set nonzero idle time to return more frequent reports * of keyboard state, to avoid losing key up/down events. */ - n = read(d->cfd, desc, sizeof desc - 1); + n = read(d->cfd, otghack, sizeof otghack - 1); if(n > 0){ - desc[n] = 0; - if(strstr((char*)desc, "dwcotg") != nil) + otghack[n] = 0; + if(strstr((char*)otghack, "dwcotg") != nil) kd->idle = Dwcidle; } } res = -1; if(!kd->bootp){ - n = setfirstconfig(kd, ep->id, desc, sizeof desc); + n = setfirstconfig(kd, ep->id, &desc); if(n > 0) res = parsereportdesc(&kd->templ, desc, n); + free(desc); } /* if we could not set the first config, we give up */ if(kd->bootp || res < 0){ kd->bootp = 1; - if(setbootproto(kd, ep->id, nil, 0) < 0){ + if(setbootproto(kd, ep->id, nil) < 0){ fprint(2, "kb: %s: bootproto: %r\n", d->dir); return; } @@ -802,9 +847,6 @@ kd->ep = nil; return; } - - kd->led = Lnum; - setled(kd, kd->led); incref(d); proccreate(f, kd, Stack);