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