usbd.c 19 KB

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