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 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
parseendpt(Usbdev * d,Conf * c,Iface * ip,Altc * altc,uchar * b,int n,Ep ** epp)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*
dname(int dtype)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
parsedesc(Usbdev * d,Conf * c,uchar * b,int n)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
parseconf(Usbdev * d,Conf * c,uchar * b,int n)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