1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include <bio.h> 5 #include "usb.h" 6 7 int 8 parsedev(Dev *xd, uchar *b, int n) 9 { 10 Usbdev *d; 11 DDev *dd; 12 char *hd; 13 14 d = xd->usb; 15 assert(d != nil); 16 dd = (DDev*)b; 17 if(usbdebug>1){ 18 hd = hexstr(b, Ddevlen); 19 fprint(2, "%s: parsedev %s: %s\n", argv0, xd->dir, hd); 20 free(hd); 21 } 22 if(dd->bLength < Ddevlen){ 23 werrstr("short dev descr. (%d < %d)", dd->bLength, Ddevlen); 24 return -1; 25 } 26 if(dd->bDescriptorType != Ddev){ 27 werrstr("%d is not a dev descriptor", dd->bDescriptorType); 28 return -1; 29 } 30 d->csp = CSP(dd->bDevClass, dd->bDevSubClass, dd->bDevProtocol); 31 d->ep[0]->maxpkt = xd->maxpkt = dd->bMaxPacketSize0; 32 d->class = dd->bDevClass; 33 d->nconf = dd->bNumConfigurations; 34 if(d->nconf == 0) 35 dprint(2, "%s: %s: no configurations\n", argv0, xd->dir); 36 d->vid = GET2(dd->idVendor); 37 d->did = GET2(dd->idProduct); 38 d->vsid = dd->iManufacturer; 39 d->psid = dd->iProduct; 40 d->ssid = dd->iSerialNumber; 41 if(n > Ddevlen && usbdebug>1) 42 fprint(2, "%s: %s: parsedev: %d bytes left", 43 argv0, xd->dir, n - Ddevlen); 44 return Ddevlen; 45 } 46 47 static int 48 parseiface(Usbdev *d, Conf *c, uchar *b, int n, Iface **ipp, Altc **app) 49 { 50 int class, subclass, proto; 51 int ifid, altid; 52 DIface *dip; 53 Iface *ip; 54 55 assert(d != nil && c != nil); 56 if(n < Difacelen){ 57 werrstr("short interface descriptor"); 58 return -1; 59 } 60 dip = (DIface *)b; 61 ifid = dip->bInterfaceNumber; 62 if(ifid < 0 || ifid >= nelem(c->iface)){ 63 werrstr("bad interface number %d", ifid); 64 return -1; 65 } 66 if(c->iface[ifid] == nil) 67 c->iface[ifid] = emallocz(sizeof(Iface), 1); 68 ip = c->iface[ifid]; 69 class = dip->bInterfaceClass; 70 subclass = dip->bInterfaceSubClass; 71 proto = dip->bInterfaceProtocol; 72 ip->csp = CSP(class, subclass, proto); 73 if(d->csp == 0) /* use csp from 1st iface */ 74 d->csp = ip->csp; /* if device has none */ 75 if(d->class == 0) 76 d->class = class; 77 ip->id = ifid; 78 if(c == d->conf[0] && ifid == 0) /* ep0 was already there */ 79 d->ep[0]->iface = ip; 80 altid = dip->bAlternateSetting; 81 if(altid < 0 || altid >= nelem(ip->altc)){ 82 werrstr("bad alternate conf. number %d", altid); 83 return -1; 84 } 85 if(ip->altc[altid] == nil) 86 ip->altc[altid] = emallocz(sizeof(Altc), 1); 87 *ipp = ip; 88 *app = ip->altc[altid]; 89 return Difacelen; 90 } 91 92 extern Ep* mkep(Usbdev *, int); 93 94 static int 95 parseendpt(Usbdev *d, Conf *c, Iface *ip, Altc *altc, uchar *b, int n, Ep **epp) 96 { 97 int i, dir, epid; 98 Ep *ep; 99 DEp *dep; 100 101 assert(d != nil && c != nil && ip != nil && altc != nil); 102 if(n < Deplen){ 103 werrstr("short endpoint descriptor"); 104 return -1; 105 } 106 dep = (DEp *)b; 107 altc->attrib = dep->bmAttributes; /* here? */ 108 altc->interval = dep->bInterval; 109 110 epid = dep->bEndpointAddress & 0xF; 111 assert(epid < nelem(d->ep)); 112 if(dep->bEndpointAddress & 0x80) 113 dir = Ein; 114 else 115 dir = Eout; 116 ep = d->ep[epid]; 117 if(ep == nil){ 118 ep = mkep(d, epid); 119 ep->dir = dir; 120 }else if((ep->addr & 0x80) != (dep->bEndpointAddress & 0x80)) 121 ep->dir = Eboth; 122 ep->maxpkt = GET2(dep->wMaxPacketSize); 123 ep->ntds = 1 + ((ep->maxpkt >> 11) & 3); 124 ep->maxpkt &= 0x7FF; 125 ep->addr = dep->bEndpointAddress; 126 ep->type = dep->bmAttributes & 0x03; 127 ep->isotype = (dep->bmAttributes>>2) & 0x03; 128 ep->conf = c; 129 ep->iface = ip; 130 for(i = 0; i < nelem(ip->ep); i++) 131 if(ip->ep[i] == nil) 132 break; 133 if(i == nelem(ip->ep)){ 134 werrstr("parseendpt: bug: too many end points on interface " 135 "with csp %#lux", ip->csp); 136 fprint(2, "%s: %r\n", argv0); 137 return -1; 138 } 139 *epp = ip->ep[i] = ep; 140 return Dep; 141 } 142 143 static char* 144 dname(int dtype) 145 { 146 switch(dtype){ 147 case Ddev: return "device"; 148 case Dconf: return "config"; 149 case Dstr: return "string"; 150 case Diface: return "interface"; 151 case Dep: return "endpoint"; 152 case Dreport: return "report"; 153 case Dphysical: return "phys"; 154 default: return "desc"; 155 } 156 } 157 158 int 159 parsedesc(Usbdev *d, Conf *c, uchar *b, int n) 160 { 161 int len, nd, tot; 162 Iface *ip; 163 Ep *ep; 164 Altc *altc; 165 char *hd; 166 167 assert(d != nil && c != nil); 168 tot = 0; 169 ip = nil; 170 ep = nil; 171 altc = nil; 172 for(nd = 0; nd < nelem(d->ddesc); nd++) 173 if(d->ddesc[nd] == nil) 174 break; 175 176 while(n > 2 && b[0] != 0 && b[0] <= n){ 177 len = b[0]; 178 if(usbdebug>1){ 179 hd = hexstr(b, len); 180 fprint(2, "%s:\t\tparsedesc %s %x[%d] %s\n", 181 argv0, dname(b[1]), b[1], b[0], hd); 182 free(hd); 183 } 184 switch(b[1]){ 185 case Ddev: 186 case Dconf: 187 werrstr("unexpected descriptor %d", b[1]); 188 ddprint(2, "%s\tparsedesc: %r", argv0); 189 break; 190 case Diface: 191 if(parseiface(d, c, b, n, &ip, &altc) < 0){ 192 ddprint(2, "%s\tparsedesc: %r\n", argv0); 193 return -1; 194 } 195 break; 196 case Dep: 197 if(ip == nil || altc == nil){ 198 werrstr("unexpected endpoint descriptor"); 199 break; 200 } 201 if(parseendpt(d, c, ip, altc, b, n, &ep) < 0){ 202 ddprint(2, "%s\tparsedesc: %r\n", argv0); 203 return -1; 204 } 205 break; 206 default: 207 if(nd == nelem(d->ddesc)){ 208 fprint(2, "%s: parsedesc: too many " 209 "device-specific descriptors for device" 210 " %s %s\n", 211 argv0, d->vendor, d->product); 212 break; 213 } 214 d->ddesc[nd] = emallocz(sizeof(Desc)+b[0], 0); 215 d->ddesc[nd]->iface = ip; 216 d->ddesc[nd]->ep = ep; 217 d->ddesc[nd]->altc = altc; 218 d->ddesc[nd]->conf = c; 219 memmove(&d->ddesc[nd]->data, b, len); 220 ++nd; 221 } 222 n -= len; 223 b += len; 224 tot += len; 225 } 226 return tot; 227 } 228 229 int 230 parseconf(Usbdev *d, Conf *c, uchar *b, int n) 231 { 232 DConf* dc; 233 int l; 234 int nr; 235 char *hd; 236 237 assert(d != nil && c != nil); 238 dc = (DConf*)b; 239 if(usbdebug>1){ 240 hd = hexstr(b, Dconflen); 241 fprint(2, "%s:\tparseconf %s\n", argv0, hd); 242 free(hd); 243 } 244 if(dc->bLength < Dconflen){ 245 werrstr("short configuration descriptor"); 246 return -1; 247 } 248 if(dc->bDescriptorType != Dconf){ 249 werrstr("not a configuration descriptor"); 250 return -1; 251 } 252 c->cval = dc->bConfigurationValue; 253 c->attrib = dc->bmAttributes; 254 c->milliamps = dc->MaxPower*2; 255 l = GET2(dc->wTotalLength); 256 if(n < l){ 257 werrstr("truncated configuration info"); 258 return -1; 259 } 260 n -= Dconflen; 261 b += Dconflen; 262 nr = 0; 263 if(n > 0 && (nr=parsedesc(d, c, b, n)) < 0) 264 return -1; 265 n -= nr; 266 if(n > 0 && usbdebug>1) 267 fprint(2, "%s:\tparseconf: %d bytes left\n", argv0, n); 268 return l; 269 } 270