1906943f9SDavid du Colombier #include <u.h> 2906943f9SDavid du Colombier #include <libc.h> 3906943f9SDavid du Colombier #include <thread.h> 4906943f9SDavid du Colombier #include "usb.h" 5906943f9SDavid du Colombier 6906943f9SDavid du Colombier /* 7906943f9SDavid du Colombier * epN.M -> N 8906943f9SDavid du Colombier */ 9906943f9SDavid du Colombier static int 10906943f9SDavid du Colombier nameid(char *s) 11906943f9SDavid du Colombier { 12906943f9SDavid du Colombier char *r; 13906943f9SDavid du Colombier char nm[20]; 14906943f9SDavid du Colombier 15906943f9SDavid du Colombier r = strrchr(s, 'p'); 16906943f9SDavid du Colombier if(r == nil) 17906943f9SDavid du Colombier return -1; 18906943f9SDavid du Colombier strecpy(nm, nm+sizeof(nm), r+1); 19906943f9SDavid du Colombier r = strchr(nm, '.'); 20906943f9SDavid du Colombier if(r == nil) 21906943f9SDavid du Colombier return -1; 22906943f9SDavid du Colombier *r = 0; 23906943f9SDavid du Colombier return atoi(nm); 24906943f9SDavid du Colombier } 25906943f9SDavid du Colombier 26906943f9SDavid du Colombier Dev* 27906943f9SDavid du Colombier openep(Dev *d, int id) 28906943f9SDavid du Colombier { 29906943f9SDavid du Colombier char *mode; /* How many modes? */ 30906943f9SDavid du Colombier Ep *ep; 31906943f9SDavid du Colombier Altc *ac; 32906943f9SDavid du Colombier Dev *epd; 33906943f9SDavid du Colombier Usbdev *ud; 34906943f9SDavid du Colombier char name[40]; 35906943f9SDavid du Colombier 3616146bc9SDavid du Colombier if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) 3716146bc9SDavid du Colombier return nil; 38906943f9SDavid du Colombier if(d->cfd < 0 || d->usb == nil){ 39906943f9SDavid du Colombier werrstr("device not configured"); 40906943f9SDavid du Colombier return nil; 41906943f9SDavid du Colombier } 42906943f9SDavid du Colombier ud = d->usb; 43906943f9SDavid du Colombier if(id < 0 || id >= nelem(ud->ep) || ud->ep[id] == nil){ 44906943f9SDavid du Colombier werrstr("bad enpoint number"); 45906943f9SDavid du Colombier return nil; 46906943f9SDavid du Colombier } 47906943f9SDavid du Colombier ep = ud->ep[id]; 48906943f9SDavid du Colombier mode = "rw"; 49906943f9SDavid du Colombier if(ep->dir == Ein) 50906943f9SDavid du Colombier mode = "r"; 51906943f9SDavid du Colombier if(ep->dir == Eout) 52906943f9SDavid du Colombier mode = "w"; 53906943f9SDavid du Colombier snprint(name, sizeof(name), "/dev/usb/ep%d.%d", d->id, id); 54906943f9SDavid du Colombier if(access(name, AEXIST) == 0){ 55906943f9SDavid du Colombier dprint(2, "%s: %s already exists; trying to open\n", argv0, name); 56*d37e33ffSDavid du Colombier epd = opendev(name); 57*d37e33ffSDavid du Colombier if(epd != nil) 58*d37e33ffSDavid du Colombier epd->maxpkt = ep->maxpkt; /* guess */ 59*d37e33ffSDavid du Colombier return epd; 60906943f9SDavid du Colombier } 61906943f9SDavid du Colombier if(devctl(d, "new %d %d %s", id, ep->type, mode) < 0){ 62906943f9SDavid du Colombier dprint(2, "%s: %s: new: %r\n", argv0, d->dir); 63906943f9SDavid du Colombier return nil; 64906943f9SDavid du Colombier } 65906943f9SDavid du Colombier epd = opendev(name); 66906943f9SDavid du Colombier if(epd == nil) 67906943f9SDavid du Colombier return nil; 68906943f9SDavid du Colombier epd->id = id; 69906943f9SDavid du Colombier if(devctl(epd, "maxpkt %d", ep->maxpkt) < 0) 70906943f9SDavid du Colombier fprint(2, "%s: %s: openep: maxpkt: %r\n", argv0, epd->dir); 71906943f9SDavid du Colombier else 72906943f9SDavid du Colombier dprint(2, "%s: %s: maxpkt %d\n", argv0, epd->dir, ep->maxpkt); 73906943f9SDavid du Colombier epd->maxpkt = ep->maxpkt; 74906943f9SDavid du Colombier ac = ep->iface->altc[0]; 75906943f9SDavid du Colombier if(ep->ntds > 1 && devctl(epd, "ntds %d", ep->ntds) < 0) 76906943f9SDavid du Colombier fprint(2, "%s: %s: openep: ntds: %r\n", argv0, epd->dir); 77906943f9SDavid du Colombier else 78906943f9SDavid du Colombier dprint(2, "%s: %s: ntds %d\n", argv0, epd->dir, ep->ntds); 79906943f9SDavid du Colombier 80906943f9SDavid du Colombier /* 81906943f9SDavid du Colombier * For iso endpoints and high speed interrupt endpoints the pollival is 82906943f9SDavid du Colombier * actually 2ⁿ and not n. 83906943f9SDavid du Colombier * The kernel usb driver must take that into account. 84906943f9SDavid du Colombier * It's simpler this way. 85906943f9SDavid du Colombier */ 86906943f9SDavid du Colombier 87906943f9SDavid du Colombier if(ac != nil && (ep->type == Eintr || ep->type == Eiso) && ac->interval != 0) 88906943f9SDavid du Colombier if(devctl(epd, "pollival %d", ac->interval) < 0) 89906943f9SDavid du Colombier fprint(2, "%s: %s: openep: pollival: %r\n", argv0, epd->dir); 90906943f9SDavid du Colombier return epd; 91906943f9SDavid du Colombier } 92906943f9SDavid du Colombier 93906943f9SDavid du Colombier Dev* 94906943f9SDavid du Colombier opendev(char *fn) 95906943f9SDavid du Colombier { 96906943f9SDavid du Colombier Dev *d; 97906943f9SDavid du Colombier int l; 98906943f9SDavid du Colombier 9916146bc9SDavid du Colombier if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) 10016146bc9SDavid du Colombier return nil; 101906943f9SDavid du Colombier d = emallocz(sizeof(Dev), 1); 102906943f9SDavid du Colombier incref(d); 103906943f9SDavid du Colombier 104906943f9SDavid du Colombier l = strlen(fn); 105906943f9SDavid du Colombier d->dfd = -1; 10639dc1420SDavid du Colombier /* 10739dc1420SDavid du Colombier * +30 to allocate extra size to concat "/<epfilename>" 10839dc1420SDavid du Colombier * we should probably remove that feature from the manual 10939dc1420SDavid du Colombier * and from the code after checking out that nobody relies on 11039dc1420SDavid du Colombier * that. 11139dc1420SDavid du Colombier */ 11239dc1420SDavid du Colombier d->dir = emallocz(l + 30, 0); 113906943f9SDavid du Colombier strcpy(d->dir, fn); 114906943f9SDavid du Colombier strcpy(d->dir+l, "/ctl"); 115906943f9SDavid du Colombier d->cfd = open(d->dir, ORDWR|OCEXEC); 116906943f9SDavid du Colombier d->dir[l] = 0; 117906943f9SDavid du Colombier d->id = nameid(fn); 118906943f9SDavid du Colombier if(d->cfd < 0){ 119906943f9SDavid du Colombier werrstr("can't open endpoint %s: %r", d->dir); 120906943f9SDavid du Colombier free(d->dir); 121906943f9SDavid du Colombier free(d); 122906943f9SDavid du Colombier return nil; 123906943f9SDavid du Colombier } 124906943f9SDavid du Colombier dprint(2, "%s: opendev %#p %s\n", argv0, d, fn); 125906943f9SDavid du Colombier return d; 126906943f9SDavid du Colombier } 127906943f9SDavid du Colombier 128906943f9SDavid du Colombier int 129906943f9SDavid du Colombier opendevdata(Dev *d, int mode) 130906943f9SDavid du Colombier { 13139dc1420SDavid du Colombier char buf[80]; /* more than enough for a usb path */ 132906943f9SDavid du Colombier 13339dc1420SDavid du Colombier seprint(buf, buf+sizeof(buf), "%s/data", d->dir); 13439dc1420SDavid du Colombier d->dfd = open(buf, mode|OCEXEC); 135906943f9SDavid du Colombier return d->dfd; 136906943f9SDavid du Colombier } 137906943f9SDavid du Colombier 138906943f9SDavid du Colombier int 139906943f9SDavid du Colombier loaddevconf(Dev *d, int n) 140906943f9SDavid du Colombier { 141906943f9SDavid du Colombier uchar buf[1024]; /* enough room for extra descriptors */ 142906943f9SDavid du Colombier int nr; 143906943f9SDavid du Colombier int type; 144906943f9SDavid du Colombier 145906943f9SDavid du Colombier if(n >= nelem(d->usb->conf)){ 146906943f9SDavid du Colombier werrstr("loaddevconf: bug: out of configurations in device"); 147906943f9SDavid du Colombier fprint(2, "%s: %r\n", argv0); 148906943f9SDavid du Colombier return -1; 149906943f9SDavid du Colombier } 150906943f9SDavid du Colombier type = Rd2h|Rstd|Rdev; 151906943f9SDavid du Colombier nr = usbcmd(d, type, Rgetdesc, Dconf<<8|n, 0, buf, 1024); 152906943f9SDavid du Colombier if(nr < Dconflen) 153906943f9SDavid du Colombier return -1; 154906943f9SDavid du Colombier if(d->usb->conf[n] == nil) 155906943f9SDavid du Colombier d->usb->conf[n] = emallocz(sizeof(Conf), 1); 156906943f9SDavid du Colombier return parseconf(d->usb, d->usb->conf[n], buf, nr); 157906943f9SDavid du Colombier } 158906943f9SDavid du Colombier 159906943f9SDavid du Colombier Ep* 160906943f9SDavid du Colombier mkep(Usbdev *d, int id) 161906943f9SDavid du Colombier { 162906943f9SDavid du Colombier Ep *ep; 163906943f9SDavid du Colombier 164906943f9SDavid du Colombier d->ep[id] = ep = emallocz(sizeof(Ep), 1); 165906943f9SDavid du Colombier ep->id = id; 166906943f9SDavid du Colombier return ep; 167906943f9SDavid du Colombier } 168906943f9SDavid du Colombier 169906943f9SDavid du Colombier static char* 170906943f9SDavid du Colombier mkstr(uchar *b, int n) 171906943f9SDavid du Colombier { 172906943f9SDavid du Colombier Rune r; 173906943f9SDavid du Colombier char *us; 174906943f9SDavid du Colombier char *s; 175906943f9SDavid du Colombier char *e; 176906943f9SDavid du Colombier 177906943f9SDavid du Colombier if(n <= 2 || (n & 1) != 0) 178906943f9SDavid du Colombier return strdup("none"); 179906943f9SDavid du Colombier n = (n - 2)/2; 180906943f9SDavid du Colombier b += 2; 181906943f9SDavid du Colombier us = s = emallocz(n*UTFmax+1, 0); 182906943f9SDavid du Colombier e = s + n*UTFmax+1; 183906943f9SDavid du Colombier for(; --n >= 0; b += 2){ 184906943f9SDavid du Colombier r = GET2(b); 185906943f9SDavid du Colombier s = seprint(s, e, "%C", r); 186906943f9SDavid du Colombier } 187906943f9SDavid du Colombier return us; 188906943f9SDavid du Colombier } 189906943f9SDavid du Colombier 190906943f9SDavid du Colombier char* 191906943f9SDavid du Colombier loaddevstr(Dev *d, int sid) 192906943f9SDavid du Colombier { 193906943f9SDavid du Colombier uchar buf[128]; 194906943f9SDavid du Colombier int type; 195906943f9SDavid du Colombier int nr; 196906943f9SDavid du Colombier 197906943f9SDavid du Colombier if(sid == 0) 198906943f9SDavid du Colombier return estrdup("none"); 199906943f9SDavid du Colombier type = Rd2h|Rstd|Rdev; 200906943f9SDavid du Colombier nr=usbcmd(d, type, Rgetdesc, Dstr<<8|sid, 0, buf, sizeof(buf)); 201906943f9SDavid du Colombier return mkstr(buf, nr); 202906943f9SDavid du Colombier } 203906943f9SDavid du Colombier 204906943f9SDavid du Colombier int 205906943f9SDavid du Colombier loaddevdesc(Dev *d) 206906943f9SDavid du Colombier { 207906943f9SDavid du Colombier uchar buf[Ddevlen+255]; 208906943f9SDavid du Colombier int nr; 209906943f9SDavid du Colombier int type; 210906943f9SDavid du Colombier Ep *ep0; 211906943f9SDavid du Colombier 212906943f9SDavid du Colombier type = Rd2h|Rstd|Rdev; 213906943f9SDavid du Colombier nr = sizeof(buf); 214906943f9SDavid du Colombier memset(buf, 0, Ddevlen); 215906943f9SDavid du Colombier if((nr=usbcmd(d, type, Rgetdesc, Ddev<<8|0, 0, buf, nr)) < 0) 216906943f9SDavid du Colombier return -1; 217906943f9SDavid du Colombier /* 218906943f9SDavid du Colombier * Several hubs are returning descriptors of 17 bytes, not 18. 219906943f9SDavid du Colombier * We accept them and leave number of configurations as zero. 220906943f9SDavid du Colombier * (a get configuration descriptor also fails for them!) 221906943f9SDavid du Colombier */ 222906943f9SDavid du Colombier if(nr < Ddevlen){ 223906943f9SDavid du Colombier print("%s: %s: warning: device with short descriptor\n", 224906943f9SDavid du Colombier argv0, d->dir); 225906943f9SDavid du Colombier if(nr < Ddevlen-1){ 226906943f9SDavid du Colombier werrstr("short device descriptor (%d bytes)", nr); 227906943f9SDavid du Colombier return -1; 228906943f9SDavid du Colombier } 229906943f9SDavid du Colombier } 230906943f9SDavid du Colombier d->usb = emallocz(sizeof(Usbdev), 1); 231906943f9SDavid du Colombier ep0 = mkep(d->usb, 0); 232906943f9SDavid du Colombier ep0->dir = Eboth; 233906943f9SDavid du Colombier ep0->type = Econtrol; 234906943f9SDavid du Colombier ep0->maxpkt = d->maxpkt = 8; /* a default */ 235906943f9SDavid du Colombier nr = parsedev(d, buf, nr); 236906943f9SDavid du Colombier if(nr >= 0){ 237906943f9SDavid du Colombier d->usb->vendor = loaddevstr(d, d->usb->vsid); 238906943f9SDavid du Colombier if(strcmp(d->usb->vendor, "none") != 0){ 239906943f9SDavid du Colombier d->usb->product = loaddevstr(d, d->usb->psid); 240906943f9SDavid du Colombier d->usb->serial = loaddevstr(d, d->usb->ssid); 241906943f9SDavid du Colombier } 242906943f9SDavid du Colombier } 243906943f9SDavid du Colombier return nr; 244906943f9SDavid du Colombier } 245906943f9SDavid du Colombier 246906943f9SDavid du Colombier int 247906943f9SDavid du Colombier configdev(Dev *d) 248906943f9SDavid du Colombier { 249906943f9SDavid du Colombier int i; 250906943f9SDavid du Colombier 251906943f9SDavid du Colombier if(d->dfd < 0) 252906943f9SDavid du Colombier opendevdata(d, ORDWR); 253906943f9SDavid du Colombier if(loaddevdesc(d) < 0) 254906943f9SDavid du Colombier return -1; 255906943f9SDavid du Colombier for(i = 0; i < d->usb->nconf; i++) 256906943f9SDavid du Colombier if(loaddevconf(d, i) < 0) 257906943f9SDavid du Colombier return -1; 258906943f9SDavid du Colombier return 0; 259906943f9SDavid du Colombier } 260906943f9SDavid du Colombier 261906943f9SDavid du Colombier static void 262906943f9SDavid du Colombier closeconf(Conf *c) 263906943f9SDavid du Colombier { 264906943f9SDavid du Colombier int i; 265906943f9SDavid du Colombier int a; 266906943f9SDavid du Colombier 267906943f9SDavid du Colombier if(c == nil) 268906943f9SDavid du Colombier return; 269906943f9SDavid du Colombier for(i = 0; i < nelem(c->iface); i++) 270906943f9SDavid du Colombier if(c->iface[i] != nil){ 271906943f9SDavid du Colombier for(a = 0; a < nelem(c->iface[i]->altc); a++) 272906943f9SDavid du Colombier free(c->iface[i]->altc[a]); 273906943f9SDavid du Colombier free(c->iface[i]); 274906943f9SDavid du Colombier } 275906943f9SDavid du Colombier free(c); 276906943f9SDavid du Colombier } 277906943f9SDavid du Colombier 278906943f9SDavid du Colombier void 279906943f9SDavid du Colombier closedev(Dev *d) 280906943f9SDavid du Colombier { 281906943f9SDavid du Colombier int i; 282906943f9SDavid du Colombier Usbdev *ud; 283906943f9SDavid du Colombier 284906943f9SDavid du Colombier if(d==nil || decref(d) != 0) 285906943f9SDavid du Colombier return; 286906943f9SDavid du Colombier dprint(2, "%s: closedev %#p %s\n", argv0, d, d->dir); 287906943f9SDavid du Colombier if(d->free != nil) 288906943f9SDavid du Colombier d->free(d->aux); 289906943f9SDavid du Colombier if(d->cfd >= 0) 290906943f9SDavid du Colombier close(d->cfd); 291906943f9SDavid du Colombier if(d->dfd >= 0) 292906943f9SDavid du Colombier close(d->dfd); 293906943f9SDavid du Colombier d->cfd = d->dfd = -1; 294906943f9SDavid du Colombier free(d->dir); 295906943f9SDavid du Colombier d->dir = nil; 296906943f9SDavid du Colombier ud = d->usb; 297906943f9SDavid du Colombier d->usb = nil; 298906943f9SDavid du Colombier if(ud != nil){ 299906943f9SDavid du Colombier free(ud->vendor); 300906943f9SDavid du Colombier free(ud->product); 301906943f9SDavid du Colombier free(ud->serial); 302906943f9SDavid du Colombier for(i = 0; i < nelem(ud->ep); i++) 303906943f9SDavid du Colombier free(ud->ep[i]); 304906943f9SDavid du Colombier for(i = 0; i < nelem(ud->ddesc); i++) 305906943f9SDavid du Colombier free(ud->ddesc[i]); 306906943f9SDavid du Colombier 307906943f9SDavid du Colombier for(i = 0; i < nelem(ud->conf); i++) 308906943f9SDavid du Colombier closeconf(ud->conf[i]); 309906943f9SDavid du Colombier free(ud); 310906943f9SDavid du Colombier } 311906943f9SDavid du Colombier free(d); 312906943f9SDavid du Colombier } 313906943f9SDavid du Colombier 314906943f9SDavid du Colombier static char* 315906943f9SDavid du Colombier reqstr(int type, int req) 316906943f9SDavid du Colombier { 317906943f9SDavid du Colombier char *s; 318906943f9SDavid du Colombier static char* ds[] = { "dev", "if", "ep", "oth" }; 319906943f9SDavid du Colombier static char buf[40]; 320906943f9SDavid du Colombier 321906943f9SDavid du Colombier if(type&Rd2h) 322906943f9SDavid du Colombier s = seprint(buf, buf+sizeof(buf), "d2h"); 323906943f9SDavid du Colombier else 324906943f9SDavid du Colombier s = seprint(buf, buf+sizeof(buf), "h2d"); 325906943f9SDavid du Colombier if(type&Rclass) 326906943f9SDavid du Colombier s = seprint(s, buf+sizeof(buf), "|cls"); 327906943f9SDavid du Colombier else if(type&Rvendor) 328906943f9SDavid du Colombier s = seprint(s, buf+sizeof(buf), "|vnd"); 329906943f9SDavid du Colombier else 330906943f9SDavid du Colombier s = seprint(s, buf+sizeof(buf), "|std"); 331906943f9SDavid du Colombier s = seprint(s, buf+sizeof(buf), "|%s", ds[type&3]); 332906943f9SDavid du Colombier 333906943f9SDavid du Colombier switch(req){ 334906943f9SDavid du Colombier case Rgetstatus: s = seprint(s, buf+sizeof(buf), " getsts"); break; 335906943f9SDavid du Colombier case Rclearfeature: s = seprint(s, buf+sizeof(buf), " clrfeat"); break; 336906943f9SDavid du Colombier case Rsetfeature: s = seprint(s, buf+sizeof(buf), " setfeat"); break; 337906943f9SDavid du Colombier case Rsetaddress: s = seprint(s, buf+sizeof(buf), " setaddr"); break; 338906943f9SDavid du Colombier case Rgetdesc: s = seprint(s, buf+sizeof(buf), " getdesc"); break; 339906943f9SDavid du Colombier case Rsetdesc: s = seprint(s, buf+sizeof(buf), " setdesc"); break; 340906943f9SDavid du Colombier case Rgetconf: s = seprint(s, buf+sizeof(buf), " getcnf"); break; 341906943f9SDavid du Colombier case Rsetconf: s = seprint(s, buf+sizeof(buf), " setcnf"); break; 342906943f9SDavid du Colombier case Rgetiface: s = seprint(s, buf+sizeof(buf), " getif"); break; 343906943f9SDavid du Colombier case Rsetiface: s = seprint(s, buf+sizeof(buf), " setif"); break; 344906943f9SDavid du Colombier } 345906943f9SDavid du Colombier USED(s); 346906943f9SDavid du Colombier return buf; 347906943f9SDavid du Colombier } 348906943f9SDavid du Colombier 349906943f9SDavid du Colombier static int 350906943f9SDavid du Colombier cmdreq(Dev *d, int type, int req, int value, int index, uchar *data, int count) 351906943f9SDavid du Colombier { 352906943f9SDavid du Colombier int ndata, n; 353906943f9SDavid du Colombier uchar *wp; 354906943f9SDavid du Colombier uchar buf[8]; 355906943f9SDavid du Colombier char *hd, *rs; 356906943f9SDavid du Colombier 357906943f9SDavid du Colombier assert(d != nil); 358906943f9SDavid du Colombier if(data == nil){ 359906943f9SDavid du Colombier wp = buf; 360906943f9SDavid du Colombier ndata = 0; 361906943f9SDavid du Colombier }else{ 362906943f9SDavid du Colombier ndata = count; 363906943f9SDavid du Colombier wp = emallocz(8+ndata, 0); 364906943f9SDavid du Colombier } 365906943f9SDavid du Colombier wp[0] = type; 366906943f9SDavid du Colombier wp[1] = req; 367906943f9SDavid du Colombier PUT2(wp+2, value); 368906943f9SDavid du Colombier PUT2(wp+4, index); 369906943f9SDavid du Colombier PUT2(wp+6, count); 370906943f9SDavid du Colombier if(data != nil) 371906943f9SDavid du Colombier memmove(wp+8, data, ndata); 372906943f9SDavid du Colombier if(usbdebug>2){ 373906943f9SDavid du Colombier hd = hexstr(wp, ndata+8); 374906943f9SDavid du Colombier rs = reqstr(type, req); 375906943f9SDavid du Colombier fprint(2, "%s: %s val %d|%d idx %d cnt %d out[%d] %s\n", 376906943f9SDavid du Colombier d->dir, rs, value>>8, value&0xFF, 377906943f9SDavid du Colombier index, count, ndata+8, hd); 378906943f9SDavid du Colombier free(hd); 379906943f9SDavid du Colombier } 380906943f9SDavid du Colombier n = write(d->dfd, wp, 8+ndata); 381906943f9SDavid du Colombier if(wp != buf) 382906943f9SDavid du Colombier free(wp); 383906943f9SDavid du Colombier if(n < 0) 384906943f9SDavid du Colombier return -1; 385906943f9SDavid du Colombier if(n != 8+ndata){ 386906943f9SDavid du Colombier dprint(2, "%s: cmd: short write: %d\n", argv0, n); 387906943f9SDavid du Colombier return -1; 388906943f9SDavid du Colombier } 389906943f9SDavid du Colombier return n; 390906943f9SDavid du Colombier } 391906943f9SDavid du Colombier 392906943f9SDavid du Colombier static int 393906943f9SDavid du Colombier cmdrep(Dev *d, void *buf, int nb) 394906943f9SDavid du Colombier { 395906943f9SDavid du Colombier char *hd; 396906943f9SDavid du Colombier 397906943f9SDavid du Colombier nb = read(d->dfd, buf, nb); 398906943f9SDavid du Colombier if(nb >0 && usbdebug > 2){ 399906943f9SDavid du Colombier hd = hexstr(buf, nb); 400906943f9SDavid du Colombier fprint(2, "%s: in[%d] %s\n", d->dir, nb, hd); 401906943f9SDavid du Colombier free(hd); 402906943f9SDavid du Colombier } 403906943f9SDavid du Colombier return nb; 404906943f9SDavid du Colombier } 405906943f9SDavid du Colombier 406906943f9SDavid du Colombier int 407906943f9SDavid du Colombier usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count) 408906943f9SDavid du Colombier { 409906943f9SDavid du Colombier int r; 410906943f9SDavid du Colombier int i; 411906943f9SDavid du Colombier int nerr; 412906943f9SDavid du Colombier char err[64]; 413906943f9SDavid du Colombier 414906943f9SDavid du Colombier /* 415906943f9SDavid du Colombier * Some devices do not respond to commands some times. 416906943f9SDavid du Colombier * Others even report errors but later work just fine. Retry. 417906943f9SDavid du Colombier */ 418906943f9SDavid du Colombier r = -1; 419906943f9SDavid du Colombier *err = 0; 420906943f9SDavid du Colombier for(i = nerr = 0; i < Uctries; i++){ 421906943f9SDavid du Colombier if(type&Rd2h) 422906943f9SDavid du Colombier r = cmdreq(d, type, req, value, index, nil, count); 423906943f9SDavid du Colombier else 424906943f9SDavid du Colombier r = cmdreq(d, type, req, value, index, data, count); 425906943f9SDavid du Colombier if(r > 0){ 426906943f9SDavid du Colombier if((type&Rd2h) == 0) 427906943f9SDavid du Colombier break; 428906943f9SDavid du Colombier r = cmdrep(d, data, count); 429906943f9SDavid du Colombier if(r > 0) 430906943f9SDavid du Colombier break; 431906943f9SDavid du Colombier if(r == 0) 432906943f9SDavid du Colombier werrstr("no data from device"); 433906943f9SDavid du Colombier } 434906943f9SDavid du Colombier nerr++; 435906943f9SDavid du Colombier if(*err == 0) 436906943f9SDavid du Colombier rerrstr(err, sizeof(err)); 437906943f9SDavid du Colombier sleep(Ucdelay); 438906943f9SDavid du Colombier } 439906943f9SDavid du Colombier if(r > 0 && i >= 2){ 440906943f9SDavid du Colombier /* let the user know the device is not in good shape */ 441906943f9SDavid du Colombier fprint(2, "%s: usbcmd: %s: required %d attempts (%s)\n", 442906943f9SDavid du Colombier argv0, d->dir, i, err); 443906943f9SDavid du Colombier } 444906943f9SDavid du Colombier return r; 445906943f9SDavid du Colombier } 446906943f9SDavid du Colombier 447906943f9SDavid du Colombier int 448906943f9SDavid du Colombier unstall(Dev *dev, Dev *ep, int dir) 449906943f9SDavid du Colombier { 450906943f9SDavid du Colombier int r; 451906943f9SDavid du Colombier 452906943f9SDavid du Colombier if(dir == Ein) 453906943f9SDavid du Colombier dir = 0x80; 454906943f9SDavid du Colombier else 455906943f9SDavid du Colombier dir = 0; 456906943f9SDavid du Colombier r = Rh2d|Rstd|Rep; 457906943f9SDavid du Colombier if(usbcmd(dev, r, Rclearfeature, Fhalt, ep->id|dir, nil, 0)<0){ 458906943f9SDavid du Colombier werrstr("unstall: %s: %r", ep->dir); 459906943f9SDavid du Colombier return -1; 460906943f9SDavid du Colombier } 461906943f9SDavid du Colombier if(devctl(ep, "clrhalt") < 0){ 462906943f9SDavid du Colombier werrstr("clrhalt: %s: %r", ep->dir); 463906943f9SDavid du Colombier return -1; 464906943f9SDavid du Colombier } 465906943f9SDavid du Colombier return 0; 466906943f9SDavid du Colombier } 467906943f9SDavid du Colombier 468906943f9SDavid du Colombier /* 469906943f9SDavid du Colombier * To be sure it uses a single write. 470906943f9SDavid du Colombier */ 471906943f9SDavid du Colombier int 472906943f9SDavid du Colombier devctl(Dev *dev, char *fmt, ...) 473906943f9SDavid du Colombier { 474906943f9SDavid du Colombier char buf[128]; 475906943f9SDavid du Colombier va_list arg; 476906943f9SDavid du Colombier char *e; 477906943f9SDavid du Colombier 478906943f9SDavid du Colombier va_start(arg, fmt); 479906943f9SDavid du Colombier e = vseprint(buf, buf+sizeof(buf), fmt, arg); 480906943f9SDavid du Colombier va_end(arg); 481906943f9SDavid du Colombier return write(dev->cfd, buf, e-buf); 482906943f9SDavid du Colombier } 483