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