usbd.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <thread.h>
  4. #include "usb.h"
  5. #include "dat.h"
  6. #include "fns.h"
  7. #define STACKSIZE 128*1024
  8. static int dontfork;
  9. Ref busy;
  10. int debug;
  11. typedef struct Enum Enum;
  12. struct Enum
  13. {
  14. Hub *hub;
  15. int port;
  16. };
  17. void (*dprinter[])(Device *, int, ulong, void *b, int n) = {
  18. [STRING] pstring,
  19. [DEVICE] pdevice,
  20. [0x29] phub,
  21. };
  22. static void
  23. usage(void)
  24. {
  25. fprint(2, "usage: usbd [-DfV] [-d mask] [-u root-hub]\n");
  26. threadexitsall("usage");
  27. }
  28. void
  29. work(void *a)
  30. {
  31. int port;
  32. Hub *hub;
  33. Enum *arg;
  34. hub = a;
  35. for(port = 1; port <= hub->nport; port++){
  36. if (debug)
  37. fprint(2, "enumerate port %H.%d\n", hub, port);
  38. arg = emallocz(sizeof(Enum), 1);
  39. arg->hub = hub;
  40. arg->port = port;
  41. incref(&busy);
  42. threadcreate(enumerate, arg, STACKSIZE);
  43. }
  44. decref(&busy);
  45. for(;;) {
  46. yield();
  47. if (busy.ref == 0)
  48. sleep(2000);
  49. }
  50. }
  51. void
  52. threadmain(int argc, char **argv)
  53. {
  54. int i;
  55. Hub *h;
  56. int usbnum;
  57. usbnum = -1;
  58. ARGBEGIN{
  59. case 'd':
  60. debug = atoi(EARGF(usage()));
  61. break;
  62. case 'D':
  63. debugdebug++;
  64. break;
  65. case 'f':
  66. dontfork = 1;
  67. break;
  68. case 'u':
  69. usbnum = atoi(EARGF(usage()));
  70. break;
  71. case 'V':
  72. verbose = 1;
  73. break;
  74. }ARGEND
  75. if(argc)
  76. usage();
  77. if(access("/dev/usb0", 0) < 0 && bind("#U", "/dev", MBEFORE) < 0)
  78. sysfatal("%s: can't bind -b #U /dev: %r\n", argv0);
  79. usbfmtinit();
  80. fmtinstall('H', Hfmt);
  81. if(usbnum < 0){
  82. /* always fork off usb[1—n] */
  83. for(i=1; (h = roothub(i)) != nil; i++) {
  84. incref(&busy);
  85. proccreate(work, h, STACKSIZE);
  86. }
  87. usbnum = 0;
  88. }
  89. /* usb0 might be handled in this proc */
  90. if((h = roothub(usbnum)) != nil){
  91. incref(&busy);
  92. if (dontfork) {
  93. work(h);
  94. } else {
  95. rfork(RFNOTEG);
  96. proccreate(work, h, STACKSIZE);
  97. /* don't hold window open */
  98. close(0);
  99. close(1);
  100. if(!debug && !verbose)
  101. close(2);
  102. }
  103. }
  104. if (debug)
  105. fprint(2, "done\n");
  106. while (busy.ref)
  107. sleep(100);
  108. threadexits(nil);
  109. }
  110. void
  111. enumerate(void *v)
  112. {
  113. int i, port;
  114. Device *d;
  115. Enum *arg;
  116. Hub *h, *nh;
  117. arg = v;
  118. h = arg->hub;
  119. port = arg->port;
  120. free(arg);
  121. for(;;){
  122. if((portstatus(h, port) & (1<<PORT_CONNECTION)) == 0){
  123. decref(&busy);
  124. if(verbose)
  125. fprint(2, "usbd: %H: port %d empty\n", h, port);
  126. do{
  127. yield();
  128. if(debugdebug)
  129. fprint(2, "usbd: probing %H.%d\n",
  130. h, port);
  131. sleep(500);
  132. }while((portstatus(h, port) & (1<<PORT_CONNECTION)) == 0);
  133. incref(&busy);
  134. }
  135. if(verbose)
  136. fprint(2, "usbd: %H: port %d attached\n", h, port);
  137. d = configure(h, port);
  138. if(d == nil){
  139. if(verbose)
  140. fprint(2, "usbd: can't configure port %H.%d\n", h, port);
  141. decref(&busy);
  142. threadexits("configure");
  143. }
  144. if(d->class == Hubclass){
  145. if(debug)
  146. fprint(2, "usbd: %H.%d: hub %d attached\n",
  147. h, port, d->id);
  148. setconfig(d, 1);
  149. nh = newhub(h, d);
  150. if(nh == nil) {
  151. detach(h, port);
  152. decref(&busy);
  153. threadexits("describehub");
  154. }
  155. if(debug)
  156. fprint(2, "usbd: traversing hub %H\n", nh);
  157. /* TO DO: initialise status endpoint */
  158. for(i=1; i<=nh->nport; i++)
  159. portpower(nh, i, 1);
  160. sleep(nh->pwrms);
  161. for(i=1; i<=nh->nport; i++) {
  162. arg = emallocz(sizeof(Enum), 1);
  163. arg->hub = nh;
  164. arg->port = i;
  165. incref(&busy);
  166. threadcreate(enumerate, arg, STACKSIZE);
  167. }
  168. }else{
  169. if(debug)
  170. fprint(2,
  171. "usbd: %H.%d: %d: not hub, %s speed\n",
  172. h, port, d->id, d->ls?"low":"high");
  173. setconfig(d, 1); /* TO DO */
  174. //unconscionable kludge (testing camera)
  175. if(d->class == 10) setup0(d, RH2D|Rinterface, SET_INTERFACE, 10, 0, 0);
  176. }
  177. decref(&busy);
  178. while(portstatus(h, port) & (1<<PORT_CONNECTION)) {
  179. if (debugdebug)
  180. fprint(2, "checking %H.%d\n", h, port);
  181. yield();
  182. if (d->state == Detached) {
  183. if (verbose)
  184. fprint(2,
  185. "%H: port %d detached by parent hub\n",
  186. h, port);
  187. /* parent hub died */
  188. threadexits(nil);
  189. }
  190. }
  191. if(verbose)
  192. fprint(2, "%H: port %d detached\n", h, port);
  193. detach(h, port);
  194. }
  195. }
  196. Device*
  197. configure(Hub *h, int port)
  198. {
  199. Port *p;
  200. Device *d;
  201. int i, s, maxpkt, ls;
  202. portenable(h, port, 1);
  203. sleep(20);
  204. portreset(h, port);
  205. sleep(20);
  206. s = portstatus(h, port);
  207. if (debug)
  208. fprint(2, "%H.%d status %#ux\n", h, port, s);
  209. if ((s & (1<<PORT_CONNECTION)) == 0)
  210. return nil;
  211. if ((s & (1<<PORT_SUSPEND)) == 0) {
  212. if (debug)
  213. fprint(2, "enabling port %H.%d\n", h, port);
  214. portenable(h, port, 1);
  215. s = portstatus(h, port);
  216. if (debug)
  217. fprint(2, "%H.%d status now %#ux\n", h, port, s);
  218. }
  219. ls = (s & (1<<PORT_LOW_SPEED)) != 0;
  220. devspeed(h->dev0, ls);
  221. maxpkt = getmaxpkt(h->dev0);
  222. if(debugdebug)
  223. fprint(2, "%H.%d maxpkt: %d\n", h, port, maxpkt);
  224. if(maxpkt < 0){
  225. Error0:
  226. portenable(h, port, 0);
  227. return nil;
  228. }
  229. d = opendev(h->ctlrno, -1);
  230. d->ls = ls;
  231. d->state = Enabled;
  232. d->ep[0]->maxpkt = maxpkt;
  233. if(fprint(d->ctl, "maxpkt 0 %d", maxpkt) < 0){
  234. Error1:
  235. closedev(d);
  236. goto Error0;
  237. }
  238. if(setaddress(h->dev0, d->id) < 0)
  239. goto Error1;
  240. d->state = Assigned;
  241. devspeed(d, ls);
  242. if(describedevice(d) < 0)
  243. goto Error1;
  244. /* read configurations 0 to n */
  245. for(i=0; i<d->nconf; i++){
  246. if(d->config[i] == nil)
  247. d->config[i] = mallocz(sizeof(*d->config[i]),1);
  248. loadconfig(d, i);
  249. }
  250. for(i=0; i<16; i++)
  251. setdevclass(d, i);
  252. p = &h->port[port-1];
  253. p->d = d;
  254. return d;
  255. }
  256. void
  257. detach(Hub *h, int port)
  258. {
  259. Port *p;
  260. Device *d;
  261. p = &h->port[port-1];
  262. if(p->hub != nil) {
  263. freehub(p->hub);
  264. p->hub = nil;
  265. }
  266. d = p->d;
  267. d->state = Detached; /* return i/o error on access */
  268. closedev(d);
  269. }