usbd.c 19 KB

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