hub.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. Hub*
  8. roothub(int ctlrno)
  9. {
  10. Hub *h;
  11. char name[100];
  12. h = emallocz(sizeof(Hub), 1);
  13. h->isroot = 1;
  14. h->ctlrno = ctlrno;
  15. h->nport = 2; /* BUG */
  16. h->port = emallocz(h->nport*sizeof(Port), 1);
  17. sprint(name, "/dev/usb%d/port", ctlrno);
  18. if((h->portfd = open(name, ORDWR)) < 0){
  19. werrstr("open %s: %r", name);
  20. free(h);
  21. return nil;
  22. }
  23. h->dev0 = opendev(ctlrno, 0);
  24. h->d = h->dev0;
  25. incref(h->d);
  26. return h;
  27. }
  28. Hub*
  29. newhub(Hub *parent, Device *d)
  30. {
  31. Port *p;
  32. Hub *h;
  33. DHub *dd;
  34. byte buf[128], *PortPwrCtrlMask;
  35. int nr, nport, nmap, i, offset, mask;
  36. h = emallocz(sizeof(Hub), 1);
  37. h->d = d;
  38. h->ctlrno = parent->ctlrno;
  39. h->dev0 = parent->dev0;
  40. if (setupreq(d->ep[0], RD2H|Rclass|Rdevice, GET_DESCRIPTOR, HUB<<8|0,
  41. 0, DHUBLEN) < 0 ||
  42. (nr = setupreply(d->ep[0], buf, sizeof(buf))) < DHUBLEN) {
  43. fprint(2, "usbd: error reading hub descriptor\n");
  44. free(h);
  45. return nil;
  46. }
  47. pdesc(d, -1, -1, buf, nr);
  48. dd = (DHub*)buf;
  49. nport = dd->bNbrPorts;
  50. nmap = 1 + nport/8;
  51. if(nr < 7 + 2*nmap) {
  52. fprint(2, "usbd: hub descriptor too small\n");
  53. free(h);
  54. return nil;
  55. }
  56. h->nport = nport;
  57. h->port = emallocz(nport*sizeof(Port), 1);
  58. h->pwrms = dd->bPwrOn2PwrGood*2;
  59. h->maxcurrent = dd->bHubContrCurrent;
  60. h->pwrmode = dd->wHubCharacteristics[0] & 3;
  61. h->compound = (dd->wHubCharacteristics[0] & (1<<2))!=0;
  62. PortPwrCtrlMask = dd->DeviceRemovable + nmap;
  63. for(i = 1; i <= nport; i++) {
  64. p = &h->port[i-1];
  65. offset = i/8;
  66. mask = 1<<(i%8);
  67. p->removable = (dd->DeviceRemovable[offset] & mask) != 0;
  68. p->pwrctl = (PortPwrCtrlMask[offset] & mask) != 0;
  69. }
  70. incref(d);
  71. incref(h->dev0);
  72. return h;
  73. }
  74. void
  75. freehub(Hub *h)
  76. {
  77. int i;
  78. Port *p;
  79. if(h == nil)
  80. return;
  81. for(i = 1; i <= h->nport; i++) {
  82. p = &h->port[i-1];
  83. freehub(p->hub);
  84. closedev(p->d);
  85. }
  86. free(h->port);
  87. if(h->isroot)
  88. close(h->portfd);
  89. else
  90. closedev(h->d);
  91. closedev(h->dev0);
  92. free(h);
  93. }
  94. int
  95. Hfmt(Fmt *f)
  96. {
  97. Hub *h;
  98. h = va_arg(f->args, Hub*);
  99. return fmtprint(f, "usb%d/%d", h->ctlrno, h->d->id);
  100. }
  101. static void
  102. hubfeature(Hub *h, int port, int feature, int on)
  103. {
  104. int cmd;
  105. cmd = CLEAR_FEATURE;
  106. if(on)
  107. cmd = SET_FEATURE;
  108. setup0(h->d, RH2D|Rclass|Rother, cmd, feature, port, 0);
  109. }
  110. void
  111. portenable(Hub *h, int port, int on)
  112. {
  113. if(h->isroot){
  114. if(fprint(h->portfd, "%s %d", on? "enable": "disable", port) < 0)
  115. sysfatal("usbd: portenable: write error: %r");
  116. return;
  117. }
  118. if(port == 0)
  119. return;
  120. hubfeature(h, port, PORT_ENABLE, on);
  121. }
  122. void
  123. portreset(Hub *h, int port)
  124. {
  125. if(h->isroot) {
  126. if(fprint(h->portfd, "reset %d", port) < 0)
  127. sysfatal("usbd: portreset: write error: %r");
  128. sleep(100);
  129. return;
  130. }
  131. if(port == 0)
  132. return;
  133. hubfeature(h, port, PORT_RESET, 1);
  134. }
  135. void
  136. portpower(Hub *h, int port, int on)
  137. {
  138. if(h->isroot) {
  139. /* no power control */
  140. return;
  141. }
  142. if(port == 0)
  143. return;
  144. hubfeature(h, port, PORT_POWER, on);
  145. }
  146. static struct
  147. {
  148. int bit;
  149. char *name;
  150. }
  151. statustab[] =
  152. {
  153. { 1<<PORT_SUSPEND, "suspend", },
  154. { 1<<PORT_RESET, "reset", },
  155. { 1<<PORT_LOW_SPEED, "lowspeed", },
  156. { 1<<PORT_ENABLE, "enable", },
  157. { 1<<PORT_CONNECTION, "present", },
  158. };
  159. int
  160. portstatus(Hub *h, int port)
  161. {
  162. int x;
  163. Endpt *e;
  164. byte buf[4];
  165. int n, nf, i, j;
  166. char *status, *q, *qe, *field[20];
  167. if(h->isroot) {
  168. seek(h->portfd, 0, 0);
  169. status = malloc(8192);
  170. n = read(h->portfd, status, 8192);
  171. if (n <= 0)
  172. sysfatal("usbd: can't read usb port status: %r");
  173. status[n] = '\0';
  174. q = status;
  175. for(;;) {
  176. qe = strchr(q, '\n');
  177. if(qe == nil)
  178. sysfatal("usbd: port %H.%d not found", h, port);
  179. *qe = '\0';
  180. nf = tokenize(q, field, nelem(field));
  181. if(nf < 2)
  182. sysfatal("Ill-formed port status: %s", q);
  183. if(strtol(field[0], nil, 0) == port)
  184. break;
  185. q = qe+1;
  186. }
  187. x = 0;
  188. for(i = 2; i < nf; i++) {
  189. for(j = 0; j < nelem(statustab); j++) {
  190. if(strcmp(field[i], statustab[j].name) == 0) {
  191. x |= statustab[j].bit;
  192. break;
  193. }
  194. }
  195. }
  196. free(status);
  197. return x;
  198. }
  199. e = h->d->ep[0];
  200. if (setupreq(e, RD2H|Rclass|Rother, GET_STATUS, 0, port, sizeof buf) < 0
  201. || setupreply(e, buf, sizeof(buf)) < sizeof(buf)) {
  202. if (debug)
  203. sysfatal("usbd: error reading hub status %H.%d", h, port);
  204. return 0;
  205. }
  206. return GET2(buf);
  207. }