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 Ep *ep; 98 DEp *dep; 99 int epid; 100 int dir; 101 int i; 102 103 assert(d != nil && c != nil && ip != nil && altc != nil); 104 if(n < Deplen){ 105 werrstr("short endpoint descriptor"); 106 return -1; 107 } 108 dep = (DEp *)b; 109 altc->attrib = dep->bmAttributes; /* here? */ 110 altc->interval = dep->bInterval; 111 112 epid = dep->bEndpointAddress & 0xF; 113 assert(epid < nelem(d->ep)); 114 if(dep->bEndpointAddress & 0x80) 115 dir = Ein; 116 else 117 dir = Eout; 118 ep = d->ep[epid]; 119 if(ep == nil){ 120 ep = mkep(d, epid); 121 ep->dir = dir; 122 }else if((ep->addr&0x80) != (dep->bEndpointAddress & 0x80)) 123 ep->dir = Eboth; 124 ep->maxpkt = GET2(dep->wMaxPacketSize); 125 ep->ntds = 1 + ((ep->maxpkt >> 11) & 3); 126 ep->maxpkt &= 0x7FF; 127 ep->addr = dep->bEndpointAddress; 128 ep->type = dep->bmAttributes & 0x03; 129 ep->isotype = (dep->bmAttributes>>2) & 0x03; 130 ep->conf = c; 131 ep->iface = ip; 132 for(i = 0; i < nelem(ip->ep); i++) 133 if(ip->ep[i] == nil) 134 break; 135 if(i == nelem(ip->ep)){ 136 werrstr("parseendpt: bug: too many end points"); 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; 163 int tot; 164 Iface *ip; 165 Ep *ep; 166 Altc *altc; 167 int nd; 168 char *hd; 169 170 assert(d != nil && c != nil); 171 tot = 0; 172 ip = nil; 173 ep = nil; 174 altc = nil; 175 for(nd = 0; nd < nelem(d->ddesc); nd++) 176 if(d->ddesc[nd] == nil) 177 break; 178 179 while(n > 2 && b[0] != 0 && b[0] <= n){ 180 len = b[0]; 181 if(usbdebug>1){ 182 hd = hexstr(b, len); 183 fprint(2, "%s:\t\tparsedesc %s %x[%d] %s\n", 184 argv0, dname(b[1]), b[1], b[0], hd); 185 free(hd); 186 } 187 switch(b[1]){ 188 case Ddev: 189 case Dconf: 190 werrstr("unexpected descriptor %d", b[1]); 191 ddprint(2, "%s\tparsedesc: %r", argv0); 192 break; 193 case Diface: 194 if(parseiface(d, c, b, n, &ip, &altc) < 0){ 195 ddprint(2, "%s\tparsedesc: %r\n", argv0); 196 return -1; 197 } 198 break; 199 case Dep: 200 if(ip == nil || altc == nil){ 201 werrstr("unexpected endpoint descriptor"); 202 break; 203 } 204 if(parseendpt(d, c, ip, altc, b, n, &ep) < 0){ 205 ddprint(2, "%s\tparsedesc: %r\n", argv0); 206 return -1; 207 } 208 break; 209 default: 210 if(nd == nelem(d->ddesc)){ 211 fprint(2, "%s: parsedesc: too many ddesc\n", argv0); 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