rather than guessing at what size configuration is safe to fetch, as for just enough bytes to get the size of the configuration, then fetch the proper number of bytes. this is helpful especially with some mice. many thanks to Oleksandr Iakovliev for pointing this issue out. Reference: /n/atom/patch/applied/usbconflen Date: Tue Apr 1 04:09:12 CES 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/cmd/usb/lib/dev.c Tue Apr 1 04:07:06 2014 +++ /sys/src/cmd/usb/lib/dev.c Tue Apr 1 04:07:07 2014 @@ -138,36 +138,66 @@ enum { /* - * Max device conf is also limited by max control request size as - * limited by Maxctllen in the kernel usb.h (both limits are arbitrary). + * Max device conf is limited by Maxctllen in the kernel usb.h (limit is arbitrary). */ - Maxdevconf = 4 * 1024, /* asking for 16K kills Newsham's disk */ + Maxctllen = 32*1024, }; +static int +usbcmdconf(Dev *d, int type, int req, int value, int index, uchar **data) +{ + uchar dbuf[Dconflen]; + int count, n; + + assert((type & Rd2h) == Rd2h); + *data = nil; + + /* how long is it? */ + if(usbcmd(d, type, req, value, index, dbuf, Dconflen) != Dconflen) + return -1; + count = GET2(dbuf+2); + if(count > Maxctllen){ + fprint(2, "usbcmdconf: bug: Maxctllen limited\n"); + count = Maxctllen; + } + if(count < 8){ + fprint(2, "usbcmdconf: count %d?\n", count); + return -1; + } + + *data = emallocz(count, 0); + n = usbcmd(d, type, req, value, index, *data, count); + if(n != count){ + fprint(2, "usbcmdconf error %d != %d: %r from %#p\n", + n, count, getcallerpc(&d)); + if(n < 0){ + free(*data); + *data = nil; + return -1; + } + } + return n; +} + int loaddevconf(Dev *d, int n) { uchar *buf; - int nr; - int type; + int r; if(n >= nelem(d->usb->conf)){ werrstr("loaddevconf: bug: out of configurations in device"); fprint(2, "%s: %r\n", argv0); return -1; } - buf = emallocz(Maxdevconf, 0); - type = Rd2h|Rstd|Rdev; - nr = usbcmd(d, type, Rgetdesc, Dconf<<8|n, 0, buf, Maxdevconf); - if(nr < Dconflen){ - free(buf); + r = usbcmdconf(d, Rd2h|Rstd|Rdev, Rgetdesc, Dconf<<8|n, 0, &buf); + if(r == -1) return -1; - } if(d->usb->conf[n] == nil) d->usb->conf[n] = emallocz(sizeof(Conf), 1); - nr = parseconf(d->usb, d->usb->conf[n], buf, nr); + r = parseconf(d->usb, d->usb->conf[n], buf, r); free(buf); - return nr; + return r; } Ep* @@ -405,14 +435,9 @@ static int cmdrep(Dev *d, void *buf, int nb) { - char *hd; - nb = read(d->dfd, buf, nb); - if(nb >0 && usbdebug > 2){ - hd = hexstr(buf, nb); - fprint(2, "%s: in[%d] %s\n", d->dir, nb, hd); - free(hd); - } + if(nb > 0 && usbdebug > 2) + fprint(2, "%s: in[%d] %.*lH\n", d->dir, nb, nb, buf); return nb; } @@ -420,7 +445,7 @@ usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count) { int i, r, nerr; - char err[64]; + char err[ERRMAX]; /* * Some devices do not respond to commands some times.