1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <bio.h>
5 #include "usb.h"
6
7 int
parsedev(Dev * xd,uchar * b,int n)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
parseiface(Usbdev * d,Conf * c,uchar * b,int n,Iface ** ipp,Altc ** app)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
parseendpt(Usbdev * d,Conf * c,Iface * ip,Altc * altc,uchar * b,int n,Ep ** epp)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*
dname(int dtype)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
parsedesc(Usbdev * d,Conf * c,uchar * b,int n)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
parseconf(Usbdev * d,Conf * c,uchar * b,int n)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