7 parsedev(Dev *xd, uchar *b, int n)
17 hd = hexstr(b, Ddevlen);
18 fprint(2, "%s: parsedev %s: %s\n", argv0, xd->dir, hd);
21 if(dd->bLength < Ddevlen){
22 werrstr("short dev descr. (%d < %d)", dd->bLength, Ddevlen);
25 if(dd->bDescriptorType != Ddev){
26 werrstr("%d is not a dev descriptor", dd->bDescriptorType);
29 d->csp = CSP(dd->bDevClass, dd->bDevSubClass, dd->bDevProtocol);
30 d->ver = GET2(dd->bcdUSB);
31 xd->isusb3 = (d->ver >= 0x0300);
33 d->ep[0]->maxpkt = xd->maxpkt = 1<<dd->bMaxPacketSize0;
35 d->ep[0]->maxpkt = xd->maxpkt = dd->bMaxPacketSize0;
36 d->class = dd->bDevClass;
37 d->nconf = dd->bNumConfigurations;
39 dprint(2, "%s: %s: no configurations\n", argv0, xd->dir);
40 d->vid = GET2(dd->idVendor);
41 d->did = GET2(dd->idProduct);
42 d->dno = GET2(dd->bcdDev);
43 d->vsid = dd->iManufacturer;
44 d->psid = dd->iProduct;
45 d->ssid = dd->iSerialNumber;
46 if(n > Ddevlen && usbdebug>1)
47 fprint(2, "%s: %s: parsedev: %d bytes left",
48 argv0, xd->dir, n - Ddevlen);
53 parseiface(Usbdev *d, Conf *c, uchar *b, int n, Iface **ipp, Altc **app)
55 int class, subclass, proto;
60 assert(d != nil && c != nil);
62 werrstr("short interface descriptor");
66 ifid = dip->bInterfaceNumber;
67 if(ifid < 0 || ifid >= nelem(c->iface)){
68 werrstr("bad interface number %d", ifid);
71 if(c->iface[ifid] == nil)
72 c->iface[ifid] = emallocz(sizeof(Iface), 1);
74 class = dip->bInterfaceClass;
75 subclass = dip->bInterfaceSubClass;
76 proto = dip->bInterfaceProtocol;
77 ip->csp = CSP(class, subclass, proto);
80 if(d->csp == 0) /* use csp from 1st iface */
81 d->csp = ip->csp; /* if device has none */
85 if(c == d->conf[0] && ifid == 0) /* ep0 was already there */
87 altid = dip->bAlternateSetting;
88 if(altid < 0 || altid >= nelem(ip->altc)){
89 werrstr("bad alternate conf. number %d", altid);
92 if(ip->altc[altid] == nil)
93 ip->altc[altid] = emallocz(sizeof(Altc), 1);
95 *app = ip->altc[altid];
99 extern Ep* mkep(Usbdev *, int);
102 parseendpt(Usbdev *d, Conf *c, Iface *ip, Altc *altc, uchar *b, int n, Ep **epp)
104 int i, dir, epid, type, addr;
108 assert(d != nil && c != nil && ip != nil && altc != nil);
110 werrstr("short endpoint descriptor");
114 altc->attrib = dep->bmAttributes; /* here? */
115 altc->interval = dep->bInterval;
117 type = dep->bmAttributes & 0x03;
118 addr = dep->bEndpointAddress;
123 epid = addr & 0xF; /* default map to 0..15 */
124 assert(epid < nelem(d->ep));
129 }else if((ep->addr & 0x80) != (addr & 0x80)){
134 * resolve conflict when same endpoint number
135 * is used for different input and output types.
136 * map input endpoint to 16..31 and output to 0..15.
138 ep->id = ((ep->addr & 0x80) != 0)<<4 | (ep->addr & 0xF);
140 epid = ep->id ^ 0x10;
145 ep->maxpkt = GET2(dep->wMaxPacketSize);
146 ep->ntds = 1 + ((ep->maxpkt >> 11) & 3);
148 altc->maxpkt = ep->maxpkt;
149 altc->ntds = ep->ntds;
152 ep->isotype = (dep->bmAttributes>>2) & 0x03;
155 for(i = 0; i < nelem(ip->ep); i++)
158 if(i == nelem(ip->ep)){
159 werrstr("parseendpt: bug: too many end points on interface "
160 "with csp %#lux", ip->csp);
161 fprint(2, "%s: %r\n", argv0);
164 *epp = ip->ep[i] = ep;
172 case Ddev: return "device";
173 case Dconf: return "config";
174 case Dstr: return "string";
175 case Diface: return "interface";
176 case Dep: return "endpoint";
177 case Dreport: return "report";
178 case Dphysical: return "phys";
179 default: return "desc";
184 parsedesc(Usbdev *d, Conf *c, uchar *b, int n)
192 assert(d != nil && c != nil);
197 for(nd = 0; nd < nelem(d->ddesc); nd++)
198 if(d->ddesc[nd] == nil)
201 while(n > 2 && b[0] != 0 && b[0] <= n){
205 fprint(2, "%s:\t\tparsedesc %s %x[%d] %s\n",
206 argv0, dname(b[1]), b[1], b[0], hd);
212 werrstr("unexpected descriptor %d", b[1]);
213 ddprint(2, "%s\tparsedesc: %r", argv0);
216 if(parseiface(d, c, b, n, &ip, &altc) < 0){
217 ddprint(2, "%s\tparsedesc: %r\n", argv0);
222 if(ip == nil || altc == nil){
223 werrstr("unexpected endpoint descriptor");
226 if(parseendpt(d, c, ip, altc, b, n, &ep) < 0){
227 ddprint(2, "%s\tparsedesc: %r\n", argv0);
232 if(nd == nelem(d->ddesc)){
233 fprint(2, "%s: parsedesc: too many "
234 "device-specific descriptors for device"
236 argv0, d->vendor, d->product);
239 d->ddesc[nd] = emallocz(sizeof(Desc)+b[0], 0);
240 d->ddesc[nd]->iface = ip;
241 d->ddesc[nd]->ep = ep;
242 d->ddesc[nd]->altc = altc;
243 d->ddesc[nd]->conf = c;
244 memmove(&d->ddesc[nd]->data, b, len);
255 parseconf(Usbdev *d, Conf *c, uchar *b, int n)
262 assert(d != nil && c != nil);
265 hd = hexstr(b, Dconflen);
266 fprint(2, "%s:\tparseconf %s\n", argv0, hd);
269 if(dc->bLength < Dconflen){
270 werrstr("short configuration descriptor");
273 if(dc->bDescriptorType != Dconf){
274 werrstr("not a configuration descriptor");
277 c->cval = dc->bConfigurationValue;
278 c->attrib = dc->bmAttributes;
279 c->milliamps = dc->MaxPower*2;
280 l = GET2(dc->wTotalLength);
282 werrstr("truncated configuration info");
288 if(n > 0 && (nr=parsedesc(d, c, b, n)) < 0)
291 if(n > 0 && usbdebug>1)
292 fprint(2, "%s:\tparseconf: %d bytes left\n", argv0, n);