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