1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "usb.h"
5
6 /*
7 * epN.M -> N
8 */
9 static int
nameid(char * s)10 nameid(char *s)
11 {
12 char *r;
13 char nm[20];
14
15 r = strrchr(s, 'p');
16 if(r == nil)
17 return -1;
18 strecpy(nm, nm+sizeof(nm), r+1);
19 r = strchr(nm, '.');
20 if(r == nil)
21 return -1;
22 *r = 0;
23 return atoi(nm);
24 }
25
26 Dev*
openep(Dev * d,int id)27 openep(Dev *d, int id)
28 {
29 char *mode; /* How many modes? */
30 Ep *ep;
31 Altc *ac;
32 Dev *epd;
33 Usbdev *ud;
34 char name[40];
35
36 if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
37 return nil;
38 if(d->cfd < 0 || d->usb == nil){
39 werrstr("device not configured");
40 return nil;
41 }
42 ud = d->usb;
43 if(id < 0 || id >= nelem(ud->ep) || ud->ep[id] == nil){
44 werrstr("bad enpoint number");
45 return nil;
46 }
47 ep = ud->ep[id];
48 mode = "rw";
49 if(ep->dir == Ein)
50 mode = "r";
51 if(ep->dir == Eout)
52 mode = "w";
53 snprint(name, sizeof(name), "/dev/usb/ep%d.%d", d->id, id);
54 if(access(name, AEXIST) == 0){
55 dprint(2, "%s: %s already exists; trying to open\n", argv0, name);
56 epd = opendev(name);
57 if(epd != nil)
58 epd->maxpkt = ep->maxpkt; /* guess */
59 return epd;
60 }
61 if(devctl(d, "new %d %d %s", id, ep->type, mode) < 0){
62 dprint(2, "%s: %s: new: %r\n", argv0, d->dir);
63 return nil;
64 }
65 epd = opendev(name);
66 if(epd == nil)
67 return nil;
68 epd->id = id;
69 if(devctl(epd, "maxpkt %d", ep->maxpkt) < 0)
70 fprint(2, "%s: %s: openep: maxpkt: %r\n", argv0, epd->dir);
71 else
72 dprint(2, "%s: %s: maxpkt %d\n", argv0, epd->dir, ep->maxpkt);
73 epd->maxpkt = ep->maxpkt;
74 ac = ep->iface->altc[0];
75 if(ep->ntds > 1 && devctl(epd, "ntds %d", ep->ntds) < 0)
76 fprint(2, "%s: %s: openep: ntds: %r\n", argv0, epd->dir);
77 else
78 dprint(2, "%s: %s: ntds %d\n", argv0, epd->dir, ep->ntds);
79
80 /*
81 * For iso endpoints and high speed interrupt endpoints the pollival is
82 * actually 2ⁿ and not n.
83 * The kernel usb driver must take that into account.
84 * It's simpler this way.
85 */
86
87 if(ac != nil && (ep->type == Eintr || ep->type == Eiso) && ac->interval != 0)
88 if(devctl(epd, "pollival %d", ac->interval) < 0)
89 fprint(2, "%s: %s: openep: pollival: %r\n", argv0, epd->dir);
90 return epd;
91 }
92
93 Dev*
opendev(char * fn)94 opendev(char *fn)
95 {
96 Dev *d;
97 int l;
98
99 if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
100 return nil;
101 d = emallocz(sizeof(Dev), 1);
102 incref(d);
103
104 l = strlen(fn);
105 d->dfd = -1;
106 /*
107 * +30 to allocate extra size to concat "/<epfilename>"
108 * we should probably remove that feature from the manual
109 * and from the code after checking out that nobody relies on
110 * that.
111 */
112 d->dir = emallocz(l + 30, 0);
113 strcpy(d->dir, fn);
114 strcpy(d->dir+l, "/ctl");
115 d->cfd = open(d->dir, ORDWR|OCEXEC);
116 d->dir[l] = 0;
117 d->id = nameid(fn);
118 if(d->cfd < 0){
119 werrstr("can't open endpoint %s: %r", d->dir);
120 free(d->dir);
121 free(d);
122 return nil;
123 }
124 dprint(2, "%s: opendev %#p %s\n", argv0, d, fn);
125 return d;
126 }
127
128 int
opendevdata(Dev * d,int mode)129 opendevdata(Dev *d, int mode)
130 {
131 char buf[80]; /* more than enough for a usb path */
132
133 seprint(buf, buf+sizeof(buf), "%s/data", d->dir);
134 d->dfd = open(buf, mode|OCEXEC);
135 return d->dfd;
136 }
137
138 enum
139 {
140 /*
141 * Max device conf is also limited by max control request size as
142 * limited by Maxctllen in the kernel usb.h (both limits are arbitrary).
143 */
144 Maxdevconf = 4 * 1024, /* asking for 16K kills Newsham's disk */
145 };
146
147 int
loaddevconf(Dev * d,int n)148 loaddevconf(Dev *d, int n)
149 {
150 uchar *buf;
151 int nr;
152 int type;
153
154 if(n >= nelem(d->usb->conf)){
155 werrstr("loaddevconf: bug: out of configurations in device");
156 fprint(2, "%s: %r\n", argv0);
157 return -1;
158 }
159 buf = emallocz(Maxdevconf, 0);
160 type = Rd2h|Rstd|Rdev;
161 nr = usbcmd(d, type, Rgetdesc, Dconf<<8|n, 0, buf, Maxdevconf);
162 if(nr < Dconflen){
163 free(buf);
164 return -1;
165 }
166 if(d->usb->conf[n] == nil)
167 d->usb->conf[n] = emallocz(sizeof(Conf), 1);
168 nr = parseconf(d->usb, d->usb->conf[n], buf, nr);
169 free(buf);
170 return nr;
171 }
172
173 Ep*
mkep(Usbdev * d,int id)174 mkep(Usbdev *d, int id)
175 {
176 Ep *ep;
177
178 d->ep[id] = ep = emallocz(sizeof(Ep), 1);
179 ep->id = id;
180 return ep;
181 }
182
183 static char*
mkstr(uchar * b,int n)184 mkstr(uchar *b, int n)
185 {
186 Rune r;
187 char *us;
188 char *s;
189 char *e;
190
191 if(n <= 2 || (n & 1) != 0)
192 return strdup("none");
193 n = (n - 2)/2;
194 b += 2;
195 us = s = emallocz(n*UTFmax+1, 0);
196 e = s + n*UTFmax+1;
197 for(; --n >= 0; b += 2){
198 r = GET2(b);
199 s = seprint(s, e, "%C", r);
200 }
201 return us;
202 }
203
204 char*
loaddevstr(Dev * d,int sid)205 loaddevstr(Dev *d, int sid)
206 {
207 uchar buf[128];
208 int type;
209 int nr;
210
211 if(sid == 0)
212 return estrdup("none");
213 type = Rd2h|Rstd|Rdev;
214 nr=usbcmd(d, type, Rgetdesc, Dstr<<8|sid, 0, buf, sizeof(buf));
215 return mkstr(buf, nr);
216 }
217
218 int
loaddevdesc(Dev * d)219 loaddevdesc(Dev *d)
220 {
221 uchar buf[Ddevlen+255];
222 int nr;
223 int type;
224 Ep *ep0;
225
226 type = Rd2h|Rstd|Rdev;
227 nr = sizeof(buf);
228 memset(buf, 0, Ddevlen);
229 if((nr=usbcmd(d, type, Rgetdesc, Ddev<<8|0, 0, buf, nr)) < 0)
230 return -1;
231 /*
232 * Several hubs are returning descriptors of 17 bytes, not 18.
233 * We accept them and leave number of configurations as zero.
234 * (a get configuration descriptor also fails for them!)
235 */
236 if(nr < Ddevlen){
237 print("%s: %s: warning: device with short descriptor\n",
238 argv0, d->dir);
239 if(nr < Ddevlen-1){
240 werrstr("short device descriptor (%d bytes)", nr);
241 return -1;
242 }
243 }
244 d->usb = emallocz(sizeof(Usbdev), 1);
245 ep0 = mkep(d->usb, 0);
246 ep0->dir = Eboth;
247 ep0->type = Econtrol;
248 ep0->maxpkt = d->maxpkt = 8; /* a default */
249 nr = parsedev(d, buf, nr);
250 if(nr >= 0){
251 d->usb->vendor = loaddevstr(d, d->usb->vsid);
252 if(strcmp(d->usb->vendor, "none") != 0){
253 d->usb->product = loaddevstr(d, d->usb->psid);
254 d->usb->serial = loaddevstr(d, d->usb->ssid);
255 }
256 }
257 return nr;
258 }
259
260 int
configdev(Dev * d)261 configdev(Dev *d)
262 {
263 int i;
264
265 if(d->dfd < 0)
266 opendevdata(d, ORDWR);
267 if(loaddevdesc(d) < 0)
268 return -1;
269 for(i = 0; i < d->usb->nconf; i++)
270 if(loaddevconf(d, i) < 0)
271 return -1;
272 return 0;
273 }
274
275 static void
closeconf(Conf * c)276 closeconf(Conf *c)
277 {
278 int i;
279 int a;
280
281 if(c == nil)
282 return;
283 for(i = 0; i < nelem(c->iface); i++)
284 if(c->iface[i] != nil){
285 for(a = 0; a < nelem(c->iface[i]->altc); a++)
286 free(c->iface[i]->altc[a]);
287 free(c->iface[i]);
288 }
289 free(c);
290 }
291
292 void
closedev(Dev * d)293 closedev(Dev *d)
294 {
295 int i;
296 Usbdev *ud;
297
298 if(d==nil || decref(d) != 0)
299 return;
300 dprint(2, "%s: closedev %#p %s\n", argv0, d, d->dir);
301 if(d->free != nil)
302 d->free(d->aux);
303 if(d->cfd >= 0)
304 close(d->cfd);
305 if(d->dfd >= 0)
306 close(d->dfd);
307 d->cfd = d->dfd = -1;
308 free(d->dir);
309 d->dir = nil;
310 ud = d->usb;
311 d->usb = nil;
312 if(ud != nil){
313 free(ud->vendor);
314 free(ud->product);
315 free(ud->serial);
316 for(i = 0; i < nelem(ud->ep); i++)
317 free(ud->ep[i]);
318 for(i = 0; i < nelem(ud->ddesc); i++)
319 free(ud->ddesc[i]);
320
321 for(i = 0; i < nelem(ud->conf); i++)
322 closeconf(ud->conf[i]);
323 free(ud);
324 }
325 free(d);
326 }
327
328 static char*
reqstr(int type,int req)329 reqstr(int type, int req)
330 {
331 char *s;
332 static char* ds[] = { "dev", "if", "ep", "oth" };
333 static char buf[40];
334
335 if(type&Rd2h)
336 s = seprint(buf, buf+sizeof(buf), "d2h");
337 else
338 s = seprint(buf, buf+sizeof(buf), "h2d");
339 if(type&Rclass)
340 s = seprint(s, buf+sizeof(buf), "|cls");
341 else if(type&Rvendor)
342 s = seprint(s, buf+sizeof(buf), "|vnd");
343 else
344 s = seprint(s, buf+sizeof(buf), "|std");
345 s = seprint(s, buf+sizeof(buf), "|%s", ds[type&3]);
346
347 switch(req){
348 case Rgetstatus: s = seprint(s, buf+sizeof(buf), " getsts"); break;
349 case Rclearfeature: s = seprint(s, buf+sizeof(buf), " clrfeat"); break;
350 case Rsetfeature: s = seprint(s, buf+sizeof(buf), " setfeat"); break;
351 case Rsetaddress: s = seprint(s, buf+sizeof(buf), " setaddr"); break;
352 case Rgetdesc: s = seprint(s, buf+sizeof(buf), " getdesc"); break;
353 case Rsetdesc: s = seprint(s, buf+sizeof(buf), " setdesc"); break;
354 case Rgetconf: s = seprint(s, buf+sizeof(buf), " getcnf"); break;
355 case Rsetconf: s = seprint(s, buf+sizeof(buf), " setcnf"); break;
356 case Rgetiface: s = seprint(s, buf+sizeof(buf), " getif"); break;
357 case Rsetiface: s = seprint(s, buf+sizeof(buf), " setif"); break;
358 }
359 USED(s);
360 return buf;
361 }
362
363 static int
cmdreq(Dev * d,int type,int req,int value,int index,uchar * data,int count)364 cmdreq(Dev *d, int type, int req, int value, int index, uchar *data, int count)
365 {
366 int ndata, n;
367 uchar *wp;
368 uchar buf[8];
369 char *hd, *rs;
370
371 assert(d != nil);
372 if(data == nil){
373 wp = buf;
374 ndata = 0;
375 }else{
376 ndata = count;
377 wp = emallocz(8+ndata, 0);
378 }
379 wp[0] = type;
380 wp[1] = req;
381 PUT2(wp+2, value);
382 PUT2(wp+4, index);
383 PUT2(wp+6, count);
384 if(data != nil)
385 memmove(wp+8, data, ndata);
386 if(usbdebug>2){
387 hd = hexstr(wp, ndata+8);
388 rs = reqstr(type, req);
389 fprint(2, "%s: %s val %d|%d idx %d cnt %d out[%d] %s\n",
390 d->dir, rs, value>>8, value&0xFF,
391 index, count, ndata+8, hd);
392 free(hd);
393 }
394 n = write(d->dfd, wp, 8+ndata);
395 if(wp != buf)
396 free(wp);
397 if(n < 0)
398 return -1;
399 if(n != 8+ndata){
400 dprint(2, "%s: cmd: short write: %d\n", argv0, n);
401 return -1;
402 }
403 return n;
404 }
405
406 static int
cmdrep(Dev * d,void * buf,int nb)407 cmdrep(Dev *d, void *buf, int nb)
408 {
409 char *hd;
410
411 nb = read(d->dfd, buf, nb);
412 if(nb >0 && usbdebug > 2){
413 hd = hexstr(buf, nb);
414 fprint(2, "%s: in[%d] %s\n", d->dir, nb, hd);
415 free(hd);
416 }
417 return nb;
418 }
419
420 int
usbcmd(Dev * d,int type,int req,int value,int index,uchar * data,int count)421 usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count)
422 {
423 int i, r, nerr;
424 char err[64];
425
426 /*
427 * Some devices do not respond to commands some times.
428 * Others even report errors but later work just fine. Retry.
429 */
430 r = -1;
431 *err = 0;
432 for(i = nerr = 0; i < Uctries; i++){
433 if(type & Rd2h)
434 r = cmdreq(d, type, req, value, index, nil, count);
435 else
436 r = cmdreq(d, type, req, value, index, data, count);
437 if(r > 0){
438 if((type & Rd2h) == 0)
439 break;
440 r = cmdrep(d, data, count);
441 if(r > 0)
442 break;
443 if(r == 0)
444 werrstr("no data from device");
445 }
446 nerr++;
447 if(*err == 0)
448 rerrstr(err, sizeof(err));
449 sleep(Ucdelay);
450 }
451 if(r > 0 && i >= 2)
452 /* let the user know the device is not in good shape */
453 fprint(2, "%s: usbcmd: %s: required %d attempts (%s)\n",
454 argv0, d->dir, i, err);
455 return r;
456 }
457
458 int
unstall(Dev * dev,Dev * ep,int dir)459 unstall(Dev *dev, Dev *ep, int dir)
460 {
461 int r;
462
463 if(dir == Ein)
464 dir = 0x80;
465 else
466 dir = 0;
467 r = Rh2d|Rstd|Rep;
468 if(usbcmd(dev, r, Rclearfeature, Fhalt, ep->id|dir, nil, 0)<0){
469 werrstr("unstall: %s: %r", ep->dir);
470 return -1;
471 }
472 if(devctl(ep, "clrhalt") < 0){
473 werrstr("clrhalt: %s: %r", ep->dir);
474 return -1;
475 }
476 return 0;
477 }
478
479 /*
480 * To be sure it uses a single write.
481 */
482 int
devctl(Dev * dev,char * fmt,...)483 devctl(Dev *dev, char *fmt, ...)
484 {
485 char buf[128];
486 va_list arg;
487 char *e;
488
489 va_start(arg, fmt);
490 e = vseprint(buf, buf+sizeof(buf), fmt, arg);
491 va_end(arg);
492 return write(dev->cfd, buf, e-buf);
493 }
494