1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include "usb.h"
6 #include "usbfs.h"
7 #include "usbd.h"
8
9 static Channel *portc;
10 static int win;
11 static int verbose;
12
13 int mainstacksize = Stack;
14 static Hub *hubs;
15 static int nhubs;
16 static int mustdump;
17 static int pollms = Pollms;
18
19 static char *dsname[] = { "disabled", "attached", "configed" };
20
21 static int
hubfeature(Hub * h,int port,int f,int on)22 hubfeature(Hub *h, int port, int f, int on)
23 {
24 int cmd;
25
26 if(on)
27 cmd = Rsetfeature;
28 else
29 cmd = Rclearfeature;
30 return usbcmd(h->dev, Rh2d|Rclass|Rother, cmd, f, port, nil, 0);
31 }
32
33 /*
34 * This may be used to detect overcurrent on the hub
35 */
36 static void
checkhubstatus(Hub * h)37 checkhubstatus(Hub *h)
38 {
39 uchar buf[4];
40 int sts;
41
42 if(h->isroot) /* not for root hubs */
43 return;
44 if(usbcmd(h->dev, Rd2h|Rclass|Rdev, Rgetstatus, 0, 0, buf, 4) < 0){
45 dprint(2, "%s: get hub status: %r\n", h->dev->dir);
46 return;
47 }
48 sts = GET2(buf);
49 dprint(2, "hub %s: status %#ux\n", h->dev->dir, sts);
50 }
51
52 static int
confighub(Hub * h)53 confighub(Hub *h)
54 {
55 int type;
56 uchar buf[128]; /* room for extra descriptors */
57 int i, dt, dl;
58 Usbdev *d;
59 DHub *dd;
60 Port *pp;
61 int nr;
62 int nmap;
63 uchar *PortPwrCtrlMask;
64 int offset;
65 int mask;
66
67 d = h->dev->usb;
68 if(h->dev->isusb3){
69 dt = Dsshub;
70 dl = Dsshublen;
71 } else {
72 dt = Dhub;
73 dl = Dhublen;
74 }
75 for(i = 0; i < nelem(d->ddesc); i++)
76 if(d->ddesc[i] == nil)
77 break;
78 else if(d->ddesc[i]->data.bDescriptorType == dt){
79 dd = (DHub*)&d->ddesc[i]->data;
80 nr = d->ddesc[i]->data.bLength;
81 goto Config;
82 }
83 type = Rd2h|Rclass|Rdev;
84 nr = usbcmd(h->dev, type, Rgetdesc, dt<<8|0, 0, buf, sizeof buf);
85 if(nr < 0){
86 dprint(2, "%s: %s: getdesc hub: %r\n", argv0, h->dev->dir);
87 return -1;
88 }
89 dd = (DHub*)buf;
90 Config:
91 if(nr < dl){
92 fprint(2, "%s: %s: hub descriptor too small (%d < %d)\n", argv0, h->dev->dir, nr, dl);
93 return -1;
94 }
95 if(h->dev->isusb3){
96 DSSHub *ds;
97 ds = (DSSHub*)dd;
98 h->nport = ds->bNbrPorts;
99 nmap = 1 + h->nport/8;
100 if(nr < 10 + nmap){
101 fprint(2, "%s: %s: descr. too small\n", argv0, h->dev->dir);
102 return -1;
103 }
104 h->port = emallocz((h->nport+1)*sizeof(Port), 1);
105 h->pwrms = ds->bPwrOn2PwrGood*2;
106 if(h->pwrms < Powerdelay)
107 h->pwrms = Powerdelay;
108 h->maxcurrent = ds->bHubContrCurrent;
109 h->pwrmode = ds->wHubCharacteristics[0] & 3;
110 h->compound = (ds->wHubCharacteristics[0] & (1<<2))!=0;
111 h->leds = (ds->wHubCharacteristics[0] & (1<<7)) != 0;
112 for(i = 1; i <= h->nport; i++){
113 pp = &h->port[i];
114 offset = i/8;
115 mask = 1<<(i%8);
116 pp->removable = (ds->DeviceRemovable[offset] & mask) != 0;
117 }
118 if(usbcmd(h->dev, Rh2d|Rclass|Rdev, Rsethubdepth, h->dev->depth, 0, nil, 0) < 0){
119 fprint(2, "%s: %s: sethubdepth: %r\n", argv0, h->dev->dir);
120 return -1;
121 }
122 return 0;
123 }
124 h->nport = dd->bNbrPorts;
125 nmap = 1 + h->nport/8;
126 if(nr < 7 + 2*nmap){
127 fprint(2, "%s: %s: descr. too small\n", argv0, h->dev->dir);
128 return -1;
129 }
130 h->port = emallocz((h->nport+1)*sizeof(Port), 1);
131 h->pwrms = dd->bPwrOn2PwrGood*2;
132 if(h->pwrms < Powerdelay)
133 h->pwrms = Powerdelay;
134 h->maxcurrent = dd->bHubContrCurrent;
135 h->pwrmode = dd->wHubCharacteristics[0] & 3;
136 h->compound = (dd->wHubCharacteristics[0] & (1<<2))!=0;
137 h->leds = (dd->wHubCharacteristics[0] & (1<<7)) != 0;
138 PortPwrCtrlMask = dd->DeviceRemovable + nmap;
139 for(i = 1; i <= h->nport; i++){
140 pp = &h->port[i];
141 offset = i/8;
142 mask = 1<<(i%8);
143 pp->removable = (dd->DeviceRemovable[offset] & mask) != 0;
144 pp->pwrctl = (PortPwrCtrlMask[offset] & mask) != 0;
145 }
146 return 0;
147 }
148
149 static void
configroothub(Hub * h)150 configroothub(Hub *h)
151 {
152 Dev *d;
153 char buf[1024];
154 char *p;
155 int nr;
156
157 d = h->dev;
158 h->nport = 2;
159 h->maxpkt = 8;
160 seek(d->cfd, 0, 0);
161 nr = read(d->cfd, buf, sizeof(buf)-1);
162 if(nr < 0)
163 goto Done;
164 buf[nr] = 0;
165
166 d->isusb3 = strstr(buf, "speed super") != nil;
167 p = strstr(buf, "ports ");
168 if(p == nil)
169 fprint(2, "%s: %s: no port information\n", argv0, d->dir);
170 else
171 h->nport = atoi(p+6);
172 p = strstr(buf, "maxpkt ");
173 if(p == nil)
174 fprint(2, "%s: %s: no maxpkt information\n", argv0, d->dir);
175 else
176 h->maxpkt = atoi(p+7);
177 Done:
178 h->port = emallocz((h->nport+1)*sizeof(Port), 1);
179 dprint(2, "%s: %s: ports %d maxpkt %d\n", argv0, d->dir, h->nport, h->maxpkt);
180 }
181
182 Hub*
newhub(char * fn,Dev * d)183 newhub(char *fn, Dev *d)
184 {
185 Hub *h;
186 int i;
187 Usbdev *ud;
188 int usbpower;
189 static int firsttime;
190 char *p;
191
192 h = emallocz(sizeof(Hub), 1);
193 h->isroot = (d == nil);
194 if(h->isroot){
195 h->dev = opendev(fn);
196 if(h->dev == nil){
197 fprint(2, "%s: opendev: %s: %r", argv0, fn);
198 goto Fail;
199 }
200 if(opendevdata(h->dev, ORDWR) < 0){
201 fprint(2, "%s: opendevdata: %s: %r\n", argv0, fn);
202 goto Fail;
203 }
204 h->dev->depth = -1;
205 configroothub(h); /* never fails */
206 }else{
207 h->dev = d;
208 if(confighub(h) < 0){
209 fprint(2, "%s: %s: config: %r\n", argv0, fn);
210 goto Fail;
211 }
212 }
213 if(h->dev == nil){
214 fprint(2, "%s: opendev: %s: %r\n", argv0, fn);
215 goto Fail;
216 }
217 devctl(h->dev, "hub");
218 ud = h->dev->usb;
219 if(h->isroot)
220 devctl(h->dev, "info roothub csp %#08ux ports %d",
221 0x000009, h->nport);
222 else{
223 devctl(h->dev, "info hub csp %#08ulx ports %d %q %q",
224 ud->csp, h->nport, ud->vendor, ud->product);
225 if(!firsttime++ && (p = getenv("usbpower")) != nil){
226 usbpower = atoi(p);
227 for(i = 1; i <= h->nport; i++)
228 if(hubfeature(h, i, Fportpower, 0) < 0)
229 fprint(2, "%s: %s: power: %r\n", argv0, fn);
230 sleep(usbpower);
231 }
232 for(i = 1; i <= h->nport; i++)
233 if(hubfeature(h, i, Fportpower, 1) < 0)
234 fprint(2, "%s: %s: power: %r\n", argv0, fn);
235 sleep(h->pwrms);
236 for(i = 1; i <= h->nport; i++)
237 if(h->leds != 0)
238 hubfeature(h, i, Fportindicator, 1);
239 }
240 h->next = hubs;
241 hubs = h;
242 nhubs++;
243 dprint(2, "%s: hub %#p allocated:", argv0, h);
244 dprint(2, " ports %d pwrms %d max curr %d pwrm %d cmp %d leds %d\n",
245 h->nport, h->pwrms, h->maxcurrent,
246 h->pwrmode, h->compound, h->leds);
247 incref(h->dev);
248 return h;
249 Fail:
250 if(d != nil)
251 devctl(d, "detach");
252 free(h->port);
253 free(h);
254 dprint(2, "%s: hub %#p failed to start:", argv0, h);
255 return nil;
256 }
257
258 static void portdetach(Hub *h, int p);
259
260 /*
261 * If during enumeration we get an I/O error the hub is gone or
262 * in pretty bad shape. Because of retries of failed usb commands
263 * (and the sleeps they include) it can take a while to detach all
264 * ports for the hub. This detaches all ports and makes the hub void.
265 * The parent hub will detect a detach (probably right now) and
266 * close it later.
267 */
268 static void
hubfail(Hub * h)269 hubfail(Hub *h)
270 {
271 int i;
272
273 for(i = 1; i <= h->nport; i++)
274 portdetach(h, i);
275 h->failed = 1;
276 }
277
278 static void
closehub(Hub * h)279 closehub(Hub *h)
280 {
281 Hub **hl;
282
283 dprint(2, "%s: closing hub %#p\n", argv0, h);
284 for(hl = &hubs; *hl != nil; hl = &(*hl)->next)
285 if(*hl == h)
286 break;
287 if(*hl == nil)
288 sysfatal("closehub: no hub");
289 *hl = h->next;
290 nhubs--;
291 hubfail(h); /* detach all ports */
292 free(h->port);
293 assert(h->dev != nil);
294 devctl(h->dev, "detach");
295 closedev(h->dev);
296 free(h);
297 }
298
299 static int
portstatus(Hub * h,int p)300 portstatus(Hub *h, int p)
301 {
302 Dev *d;
303 uchar buf[4];
304 int t;
305 int sts;
306 int dbg;
307
308 dbg = usbdebug;
309 if(dbg != 0 && dbg < 4)
310 usbdebug = 1; /* do not be too chatty */
311 d = h->dev;
312 t = Rd2h|Rclass|Rother;
313 if(usbcmd(d, t, Rgetstatus, 0, p, buf, sizeof(buf)) < 0)
314 sts = -1;
315 else
316 sts = GET2(buf);
317 usbdebug = dbg;
318 return sts;
319 }
320
321 static char*
stsstr(int sts,int isusb3)322 stsstr(int sts, int isusb3)
323 {
324 static char s[80];
325 char *e;
326
327 e = s;
328 if(!isusb3){
329 if(sts&PSsuspend)
330 *e++ = 'z';
331 if(sts&PSslow)
332 *e++ = 'l';
333 if(sts&PShigh)
334 *e++ = 'h';
335 if(sts&PSchange)
336 *e++ = 'c';
337 if(sts&PSstatuschg)
338 *e++ = 's';
339 }
340 if(sts&PSreset)
341 *e++ = 'r';
342 if(sts&PSenable)
343 *e++ = 'e';
344 if(sts&PSpresent)
345 *e++ = 'p';
346 if(e == s)
347 *e++ = '-';
348 *e = 0;
349 return s;
350 }
351
352 static int
getmaxpkt(Dev * d,int islow)353 getmaxpkt(Dev *d, int islow)
354 {
355 uchar buf[64]; /* More room to try to get device-specific descriptors */
356 DDev *dd;
357
358 dd = (DDev*)buf;
359 if(islow)
360 dd->bMaxPacketSize0 = 8;
361 else
362 dd->bMaxPacketSize0 = 64;
363 if(usbcmd(d, Rd2h|Rstd|Rdev, Rgetdesc, Ddev<<8|0, 0, buf, sizeof(buf)) < 0)
364 return -1;
365 if((dd->bcdUSB[1] & 0xF) == 3)
366 return 1 << dd->bMaxPacketSize0;
367 return dd->bMaxPacketSize0;
368 }
369
370 /*
371 * BUG: does not consider max. power avail.
372 */
373 static Dev*
portattach(Hub * h,int p,int sts)374 portattach(Hub *h, int p, int sts)
375 {
376 Dev *d;
377 Port *pp;
378 Dev *nd;
379 char fname[80];
380 char buf[40];
381 char *sp;
382 int mp;
383 int nr;
384
385 d = h->dev;
386 pp = &h->port[p];
387 nd = nil;
388 pp->state = Pattached;
389 dprint(2, "%s: %s: port %d attach sts %#ux\n", argv0, d->dir, p, sts);
390 sleep(Connectdelay);
391 if(h->dev->isusb3){
392 sleep(Enabledelay);
393 sts = portstatus(h, p);
394 if(sts == -1)
395 goto Fail;
396 if((sts & PSenable) == 0){
397 dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
398 goto Fail;
399 }
400 sp = "super";
401 } else {
402 sleep(Enabledelay);
403 if(hubfeature(h, p, Fportreset, 1) < 0){
404 dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p);
405 goto Fail;
406 }
407 sleep(Resetdelay);
408 sts = portstatus(h, p);
409 if(sts < 0)
410 goto Fail;
411 if((sts & PSenable) == 0){
412 dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
413 hubfeature(h, p, Fportenable, 1);
414 sts = portstatus(h, p);
415 if((sts & PSenable) == 0)
416 goto Fail;
417 }
418 sp = "full";
419 if(sts & PSslow)
420 sp = "low";
421 if(sts & PShigh)
422 sp = "high";
423 dprint(2, "%s: %s: port %d: attached status %#ux\n", argv0, d->dir, p, sts);
424 }
425
426 if(devctl(d, "newdev %s %d", sp, p) < 0){
427 fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p);
428 goto Fail;
429 }
430 seek(d->cfd, 0, 0);
431 nr = read(d->cfd, buf, sizeof(buf)-1);
432 if(nr == 0){
433 fprint(2, "%s: %s: port %d: newdev: eof\n", argv0, d->dir, p);
434 goto Fail;
435 }
436 if(nr < 0){
437 fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p);
438 goto Fail;
439 }
440 buf[nr] = 0;
441 snprint(fname, sizeof(fname), "/dev/usb/%s", buf);
442 nd = opendev(fname);
443 if(nd == nil){
444 fprint(2, "%s: %s: port %d: opendev: %r\n", argv0, d->dir, p);
445 goto Fail;
446 }
447 nd->depth = h->dev->depth+1;
448 nd->isusb3 = h->dev->isusb3;
449 if(usbdebug > 2)
450 devctl(nd, "debug 1");
451 if(opendevdata(nd, ORDWR) < 0){
452 fprint(2, "%s: %s: opendevdata: %r\n", argv0, nd->dir);
453 goto Fail;
454 }
455 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){
456 dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p);
457 goto Fail;
458 }
459 if(devctl(nd, "address") < 0){
460 dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
461 goto Fail;
462 }
463
464 mp=getmaxpkt(nd, strcmp(sp, "low") == 0);
465 if(mp < 0){
466 dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p);
467 goto Fail;
468 }else{
469 dprint(2, "%s; %s: port %d: maxpkt %d\n", argv0, d->dir, p, mp);
470 devctl(nd, "maxpkt %d", mp);
471 }
472 if(!h->dev->isusb3 && (sts & PSslow) != 0 && strcmp(sp, "full") == 0)
473 dprint(2, "%s: %s: port %d: %s is full speed when port is low\n",
474 argv0, d->dir, p, nd->dir);
475 if(configdev(nd) < 0){
476 dprint(2, "%s: %s: port %d: configdev: %r\n", argv0, d->dir, p);
477 goto Fail;
478 }
479 /*
480 * We always set conf #1. BUG.
481 */
482 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0){
483 dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p);
484 unstall(nd, nd, Eout);
485 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0)
486 goto Fail;
487 }
488 dprint(2, "%s: %U", argv0, nd);
489 pp->state = Pconfiged;
490 dprint(2, "%s: %s: port %d: configed: %s\n",
491 argv0, d->dir, p, nd->dir);
492 return pp->dev = nd;
493 Fail:
494 pp->state = Pdisabled;
495 pp->sts = 0;
496 if(pp->hub != nil)
497 pp->hub = nil; /* hub closed by enumhub */
498 if(!h->dev->isusb3)
499 hubfeature(h, p, Fportenable, 0);
500 if(nd != nil)
501 devctl(nd, "detach");
502 closedev(nd);
503 return nil;
504 }
505
506 static void
portdetach(Hub * h,int p)507 portdetach(Hub *h, int p)
508 {
509 Dev *d;
510 Port *pp;
511 extern void usbfsgone(char*);
512 d = h->dev;
513 pp = &h->port[p];
514
515 /*
516 * Clear present, so that we detect an attach on reconnects.
517 */
518 pp->sts &= ~(PSpresent|PSenable);
519
520 if(pp->state == Pdisabled)
521 return;
522 pp->state = Pdisabled;
523 dprint(2, "%s: %s: port %d: detached\n", argv0, d->dir, p);
524
525 if(pp->hub != nil){
526 closehub(pp->hub);
527 pp->hub = nil;
528 }
529 if(pp->devmaskp != nil)
530 putdevnb(pp->devmaskp, pp->devnb);
531 pp->devmaskp = nil;
532 if(pp->dev != nil){
533 devctl(pp->dev, "detach");
534 usbfsgone(pp->dev->dir);
535 closedev(pp->dev);
536 pp->dev = nil;
537 }
538 }
539
540 /*
541 * The next two functions are included to
542 * perform a port reset asked for by someone (usually a driver).
543 * This must be done while no other device is in using the
544 * configuration address and with care to keep the old address.
545 * To keep drivers decoupled from usbd they write the reset request
546 * to the #u/usb/epN.0/ctl file and then exit.
547 * This is unfortunate because usbd must now poll twice as much.
548 *
549 * An alternative to this reset process would be for the driver to detach
550 * the device. The next function could see that, issue a port reset, and
551 * then restart the driver once to see if it's a temporary error.
552 *
553 * The real fix would be to use interrupt endpoints for non-root hubs
554 * (would probably make some hubs fail) and add an events file to
555 * the kernel to report events to usbd. This is a severe change not
556 * yet implemented.
557 */
558 static int
portresetwanted(Hub * h,int p)559 portresetwanted(Hub *h, int p)
560 {
561 char buf[5];
562 Port *pp;
563 Dev *nd;
564
565 pp = &h->port[p];
566 nd = pp->dev;
567 if(nd != nil && nd->cfd >= 0 && pread(nd->cfd, buf, 5, 0LL) == 5)
568 return strncmp(buf, "reset", 5) == 0;
569 else
570 return 0;
571 }
572
573 static void
portreset(Hub * h,int p)574 portreset(Hub *h, int p)
575 {
576 int i, sts;
577 Dev *d, *nd;
578 Port *pp;
579
580 d = h->dev;
581 pp = &h->port[p];
582 nd = pp->dev;
583 dprint(2, "%s: %s: port %d: resetting\n", argv0, d->dir, p);
584 if(hubfeature(h, p, Fportreset, 1) < 0){
585 dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p);
586 goto Fail;
587 }
588 sts = 0;
589 for(i = 0; i < 10; i++){
590 sleep(Resetdelay);
591 sts = portstatus(h, p);
592 if(sts < 0)
593 goto Fail;
594 if((sts & PSreset) == 0)
595 break;
596 }
597 dprint(2, "%s: %s: port %d sts %x after %d ms\n", argv0, d->dir, p, sts, (i+1)*Resetdelay);
598 if((sts & PSenable) == 0){
599 dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
600 hubfeature(h, p, Fportenable, 1);
601 sts = portstatus(h, p);
602 if((sts & PSenable) == 0)
603 goto Fail;
604 }
605 nd = pp->dev;
606 if(opendevdata(nd, ORDWR) < 0){
607 fprint(2, "%s: %s: opendevdata: %r\n", argv0, nd->dir);
608 goto Fail;
609 }
610 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){
611 dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p);
612 goto Fail;
613 }
614 if(devctl(nd, "address") < 0){
615 dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
616 goto Fail;
617 }
618 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0){
619 dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p);
620 unstall(nd, nd, Eout);
621 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0)
622 goto Fail;
623 }
624 if(nd->dfd >= 0)
625 close(nd->dfd);
626 return;
627 Fail:
628 pp->state = Pdisabled;
629 pp->sts = 0;
630 if(pp->hub != nil)
631 pp->hub = nil; /* hub closed by enumhub */
632 hubfeature(h, p, Fportenable, 0);
633 if(nd != nil)
634 devctl(nd, "detach");
635 closedev(nd);
636 }
637
638 static int
portgone(Port * pp,int sts)639 portgone(Port *pp, int sts)
640 {
641 if(sts < 0)
642 return 1;
643 /*
644 * If it was enabled and it's not now then it may be reconnect.
645 * We pretend it's gone and later we'll see it as attached.
646 */
647 if((pp->sts & PSenable) != 0 && (sts & PSenable) == 0)
648 return 1;
649 return (pp->sts & PSpresent) != 0 && (sts & PSpresent) == 0;
650 }
651
652 static int
enumhub(Hub * h,int p)653 enumhub(Hub *h, int p)
654 {
655 int sts, sts0;
656 Dev *d;
657 Port *pp;
658 int onhubs;
659
660 if(h->failed)
661 return 0;
662 d = h->dev;
663 if(usbdebug > 3)
664 fprint(2, "%s: %s: port %d enumhub\n", argv0, d->dir, p);
665
666 sts = portstatus(h, p);
667 if(sts < 0){
668 hubfail(h); /* avoid delays on detachment */
669 return -1;
670 }
671 pp = &h->port[p];
672 onhubs = nhubs;
673 if(!h->dev->isusb3 && (sts & PSsuspend) != 0){
674 if(hubfeature(h, p, Fportenable, 1) < 0)
675 dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p);
676 sleep(Enabledelay);
677 sts0 = sts;
678 sts = portstatus(h, p);
679 fprint(2, "%s: %s: port %d: resumed (sts %#ux -> %#ux)\n", argv0, d->dir, p, sts0, sts);
680 }
681 if((pp->sts & PSpresent) == 0 && (sts & PSpresent) != 0){
682 if(portattach(h, p, sts) != nil)
683 if(startdev(pp) < 0)
684 portdetach(h, p);
685 }else if(portgone(pp, sts))
686 portdetach(h, p);
687 else if(portresetwanted(h, p))
688 portreset(h, p);
689 else if(pp->sts != sts){
690 dprint(2, "%s: %s port %d: sts %s %#x ->",
691 argv0, d->dir, p, stsstr(pp->sts, h->dev->isusb3), pp->sts);
692 dprint(2, " %s %#x\n",stsstr(sts, h->dev->isusb3), sts);
693 }
694 pp->sts = sts;
695 if(onhubs != nhubs)
696 return -1;
697 return 0;
698 }
699
700 static void
dump(void)701 dump(void)
702 {
703 Hub *h;
704 int i;
705
706 mustdump = 0;
707 for(h = hubs; h != nil; h = h->next)
708 for(i = 1; i <= h->nport; i++)
709 fprint(2, "%s: hub %#p %s port %d: %U",
710 argv0, h, h->dev->dir, i, h->port[i].dev);
711 usbfsdirdump();
712
713 }
714
715 static void
work(void * a)716 work(void *a)
717 {
718 Channel *portc;
719 char *fn;
720 Hub *h;
721 int i;
722
723 portc = a;
724 threadsetname("work");
725 hubs = nil;
726 /*
727 * Receive requests for root hubs
728 */
729 while((fn = recvp(portc)) != nil){
730 dprint(2, "%s: %s starting\n", argv0, fn);
731 h = newhub(fn, nil);
732 if(h == nil)
733 fprint(2, "%s: %s: newhub failed: %r\n", argv0, fn);
734 free(fn);
735 }
736 /*
737 * Enumerate (and acknowledge after first enumeration).
738 * Do NOT perform enumeration concurrently for the same
739 * controller. new devices attached respond to a default
740 * address (0) after reset, thus enumeration has to work
741 * one device at a time at least before addresses have been
742 * assigned.
743 * Do not use hub interrupt endpoint because we
744 * have to poll the root hub(s) in any case.
745 */
746 for(;;){
747 Again:
748 for(h = hubs; h != nil; h = h->next)
749 for(i = 1; i <= h->nport; i++)
750 if(enumhub(h, i) < 0){
751 /* changes in hub list; repeat */
752 goto Again;
753 }
754 if(portc != nil){
755 sendp(portc, nil);
756 portc = nil;
757 }
758 sleep(pollms);
759 if(mustdump)
760 dump();
761 }
762 }
763
764 static int
cfswalk(Usbfs *,Fid *,char *)765 cfswalk(Usbfs*, Fid *, char *)
766 {
767 werrstr(Enotfound);
768 return -1;
769 }
770
771 static int
cfsopen(Usbfs *,Fid *,int)772 cfsopen(Usbfs*, Fid *, int)
773 {
774 return 0;
775 }
776
777 static long
cfsread(Usbfs *,Fid *,void *,long,vlong)778 cfsread(Usbfs*, Fid *, void *, long , vlong )
779 {
780 return 0;
781 }
782
783 static void
setdrvargs(char * name,char * args)784 setdrvargs(char *name, char *args)
785 {
786 Devtab *dt;
787 extern Devtab devtab[];
788
789 for(dt = devtab; dt->name != nil; dt++)
790 if(strstr(dt->name, name) != nil)
791 dt->args = estrdup(args);
792 }
793
794 static void
setdrvauto(char * name,int on)795 setdrvauto(char *name, int on)
796 {
797 Devtab *dt;
798 extern Devtab devtab[];
799
800 for(dt = devtab; dt->name != nil; dt++)
801 if(strstr(dt->name, name) != nil)
802 dt->noauto = !on;
803 }
804
805 static long
cfswrite(Usbfs *,Fid *,void * data,long cnt,vlong)806 cfswrite(Usbfs*, Fid *, void *data, long cnt, vlong )
807 {
808 char *cmd, *arg;
809 char buf[80];
810 char *toks[4];
811
812 if(cnt > sizeof(buf))
813 cnt = sizeof(buf) - 1;
814 strncpy(buf, data, cnt);
815 buf[cnt] = 0;
816 if(cnt > 0 && buf[cnt-1] == '\n')
817 buf[cnt-1] = 0;
818 if(strncmp(buf, "dump", 4) == 0){
819 mustdump = 1;
820 return cnt;
821 }
822 if(strncmp(buf, "reset", 5) == 0){
823 werrstr("reset not implemented");
824 return -1;
825 }
826 if(strncmp(buf, "exit", 4) == 0){
827 threadexitsall(nil);
828 return cnt;
829 }
830 if(tokenize(buf, toks, nelem(toks)) != 2){
831 werrstr("usage: auto|debug|diskargs|fsdebug|kbargs|noauto n");
832 return -1;
833 }
834 cmd = toks[0];
835 arg = toks[1];
836 if(strcmp(cmd, "auto") == 0)
837 setdrvauto(arg, 1);
838 else if(strcmp(cmd, "debug") == 0)
839 usbdebug = atoi(arg);
840 else if(strcmp(cmd, "diskargs") == 0)
841 setdrvargs("disk", arg);
842 else if(strcmp(cmd, "etherargs") == 0)
843 setdrvargs("ether", arg);
844 else if(strcmp(cmd, "fsdebug") == 0)
845 usbfsdebug = atoi(arg);
846 else if(strcmp(cmd, "kbargs") == 0)
847 setdrvargs("kb", arg);
848 else if(strcmp(cmd, "noauto") == 0)
849 setdrvauto(arg, 0);
850 else{
851 werrstr("unknown ctl '%s'", buf);
852 return -1;
853 }
854 fprint(2, "%s: debug %d fsdebug %d\n", argv0, usbdebug, usbfsdebug);
855 return cnt;
856 }
857
858 static int
cfsstat(Usbfs * fs,Qid qid,Dir * d)859 cfsstat(Usbfs* fs, Qid qid, Dir *d)
860 {
861 d->qid = qid;
862 d->qid.path |= fs->qid;
863 d->qid.type = 0;
864 d->qid.vers = 0;
865 d->name = "usbdctl";
866 d->length = 0;
867 d->mode = 0664;
868 return 0;
869 }
870
871 static Usbfs ctlfs =
872 {
873 .walk = cfswalk,
874 .open = cfsopen,
875 .read = cfsread,
876 .write = cfswrite,
877 .stat = cfsstat
878 };
879
880 static void
getenvint(char * env,int * lp)881 getenvint(char *env, int *lp)
882 {
883 char *s;
884
885 s = getenv(env);
886 if (s != nil)
887 *lp = atoi(s);
888 free(s);
889 }
890
891 static void
getenvdrvargs(char * env,char * argname)892 getenvdrvargs(char *env, char *argname)
893 {
894 char *s;
895
896 s = getenv(env);
897 if(s != nil)
898 setdrvargs(argname, s);
899 free(s);
900 }
901
902 static void
args(void)903 args(void)
904 {
905 getenvint("usbdebug", &usbdebug);
906 getenvint("usbfsdebug", &usbfsdebug);
907 getenvdrvargs("kbargs", "kb");
908 getenvdrvargs("diskargs", "disk");
909 getenvdrvargs("etherargs", "ether");
910 }
911
912 static void
usage(void)913 usage(void)
914 {
915 fprint(2, "usage: %s [-Dd] [-s srv] [-m mnt] [dev...]\n", argv0);
916 threadexitsall("usage");
917 }
918
919 extern void usbfsexits(int);
920
921 void
threadmain(int argc,char ** argv)922 threadmain(int argc, char **argv)
923 {
924 int fd, i, nd;
925 char *err, *mnt, *srv;
926 Dir *d;
927
928 srv = "usb";
929 mnt = "/dev";
930 ARGBEGIN{
931 case 'D':
932 usbfsdebug++;
933 break;
934 case 'd':
935 usbdebug++;
936 break;
937 case 's':
938 srv = EARGF(usage());
939 break;
940 case 'i':
941 pollms = atoi(EARGF(usage()));
942 break;
943 case 'm':
944 mnt = EARGF(usage());
945 break;
946 default:
947 usage();
948 }ARGEND;
949 if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
950 sysfatal("#u: %r");
951
952 args();
953
954 fmtinstall('U', Ufmt);
955 quotefmtinstall();
956 rfork(RFNOTEG);
957 portc = chancreate(sizeof(char *), 0);
958 if(portc == nil)
959 sysfatal("chancreate");
960 proccreate(work, portc, Stack);
961 if(argc == 0){
962 fd = open("/dev/usb", OREAD);
963 if(fd < 0)
964 sysfatal("/dev/usb: %r");
965 nd = dirreadall(fd, &d);
966 close(fd);
967 if(nd < 2)
968 sysfatal("/dev/usb: no hubs");
969 for(i = 0; i < nd; i++)
970 if(strcmp(d[i].name, "ctl") != 0)
971 sendp(portc, smprint("/dev/usb/%s", d[i].name));
972 free(d);
973 }else
974 for(i = 0; i < argc; i++)
975 sendp(portc, strdup(argv[i]));
976 sendp(portc, nil);
977 err = recvp(portc);
978 chanfree(portc);
979 usbfsexits(0);
980 usbfsinit(srv, mnt, &usbdirfs, MAFTER);
981 snprint(ctlfs.name, sizeof(ctlfs.name), "usbdctl");
982 usbfsadd(&ctlfs);
983 threadexits(err);
984 }
985