1b2495906SDavid du Colombier /* 2b2495906SDavid du Colombier * This part takes care of locking except for initialization and 3b2495906SDavid du Colombier * other threads created by the hw dep. drivers. 4b2495906SDavid du Colombier */ 5b2495906SDavid du Colombier 65e4f5c78SDavid du Colombier #include <u.h> 75e4f5c78SDavid du Colombier #include <libc.h> 85e4f5c78SDavid du Colombier #include <ctype.h> 95e4f5c78SDavid du Colombier #include <thread.h> 105e4f5c78SDavid du Colombier #include "usb.h" 115e4f5c78SDavid du Colombier #include "usbfs.h" 125e4f5c78SDavid du Colombier #include "serial.h" 134d52e0f0SDavid du Colombier #include "prolific.h" 144d52e0f0SDavid du Colombier #include "ucons.h" 1580e9508eSDavid du Colombier #include "ftdi.h" 164d52e0f0SDavid du Colombier 175e4f5c78SDavid du Colombier int serialdebug; 185e4f5c78SDavid du Colombier 195e4f5c78SDavid du Colombier enum { 205e4f5c78SDavid du Colombier /* Qids. Maintain order (relative to dirtabs structs) */ 215e4f5c78SDavid du Colombier Qroot = 0, 225e4f5c78SDavid du Colombier Qctl, 235e4f5c78SDavid du Colombier Qdata, 245e4f5c78SDavid du Colombier Qmax, 255e4f5c78SDavid du Colombier }; 265e4f5c78SDavid du Colombier 275e4f5c78SDavid du Colombier typedef struct Dirtab Dirtab; 285e4f5c78SDavid du Colombier struct Dirtab { 295e4f5c78SDavid du Colombier char *name; 305e4f5c78SDavid du Colombier int mode; 315e4f5c78SDavid du Colombier }; 325e4f5c78SDavid du Colombier 335e4f5c78SDavid du Colombier static Dirtab dirtab[] = { 345e4f5c78SDavid du Colombier [Qroot] "/", DMDIR|0555, 35d584e620SDavid du Colombier [Qdata] "%s", 0660, 36d584e620SDavid du Colombier [Qctl] "%sctl", 0664, 375e4f5c78SDavid du Colombier }; 385e4f5c78SDavid du Colombier 395e4f5c78SDavid du Colombier static int sdebug; 405e4f5c78SDavid du Colombier 415e4f5c78SDavid du Colombier static void 425e4f5c78SDavid du Colombier serialfatal(Serial *ser) 435e4f5c78SDavid du Colombier { 44d5789509SDavid du Colombier Serialport *p; 45d5789509SDavid du Colombier int i; 46d5789509SDavid du Colombier 475e4f5c78SDavid du Colombier dsprint(2, "serial: fatal error, detaching\n"); 485e4f5c78SDavid du Colombier devctl(ser->dev, "detach"); 49d5789509SDavid du Colombier 50d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){ 51d5789509SDavid du Colombier p = &ser->p[i]; 52d5789509SDavid du Colombier usbfsdel(&p->fs); 53d5789509SDavid du Colombier if(p->w4data != nil) 54d5789509SDavid du Colombier chanclose(p->w4data); 55d5789509SDavid du Colombier if(p->gotdata != nil) 56d5789509SDavid du Colombier chanclose(p->gotdata); 57d5789509SDavid du Colombier if(p->readc) 58d5789509SDavid du Colombier chanclose(p->readc); 59d5789509SDavid du Colombier } 605e4f5c78SDavid du Colombier } 615e4f5c78SDavid du Colombier 6280e9508eSDavid du Colombier /* I sleep with the lock... only way to drain in general */ 635e4f5c78SDavid du Colombier static void 64d5789509SDavid du Colombier serialdrain(Serialport *p) 655e4f5c78SDavid du Colombier { 66d5789509SDavid du Colombier Serial *ser; 6780e9508eSDavid du Colombier uint baud, pipesize; 685e4f5c78SDavid du Colombier 69d5789509SDavid du Colombier ser = p->s; 70d5789509SDavid du Colombier baud = p->baud; 71d5789509SDavid du Colombier 72d5789509SDavid du Colombier if(p->baud == ~0) 73d5789509SDavid du Colombier return; 74d5789509SDavid du Colombier if(ser->maxwtrans < 256) 7580e9508eSDavid du Colombier pipesize = 256; 7680e9508eSDavid du Colombier else 77d5789509SDavid du Colombier pipesize = ser->maxwtrans; 7880e9508eSDavid du Colombier /* wait for the at least 256-byte pipe to clear */ 7980e9508eSDavid du Colombier sleep(10 + pipesize/((1 + baud)*1000)); 8080e9508eSDavid du Colombier if(ser->clearpipes != nil) 81d5789509SDavid du Colombier ser->clearpipes(p); 825e4f5c78SDavid du Colombier } 835e4f5c78SDavid du Colombier 845e4f5c78SDavid du Colombier int 855e4f5c78SDavid du Colombier serialreset(Serial *ser) 865e4f5c78SDavid du Colombier { 87d5789509SDavid du Colombier Serialport *p; 88c8a340cdSDavid du Colombier int i, res; 89d5789509SDavid du Colombier 90c8a340cdSDavid du Colombier res = 0; 915e4f5c78SDavid du Colombier /* cmd for reset */ 92d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){ 93d5789509SDavid du Colombier p = &ser->p[i]; 94d5789509SDavid du Colombier serialdrain(p); 95d5789509SDavid du Colombier } 9680e9508eSDavid du Colombier if(ser->reset != nil) 97c8a340cdSDavid du Colombier res = ser->reset(ser, nil); 98c8a340cdSDavid du Colombier return res; 995e4f5c78SDavid du Colombier } 1005e4f5c78SDavid du Colombier 101c8a340cdSDavid du Colombier /* call this if something goes wrong, must be qlocked */ 1025e4f5c78SDavid du Colombier int 103c8a340cdSDavid du Colombier serialrecover(Serial *ser, Serialport *p, Dev *ep, char *err) 1045e4f5c78SDavid du Colombier { 105c8a340cdSDavid du Colombier if(p != nil) 106c8a340cdSDavid du Colombier dprint(2, "serial[%d], %s: %s, level %d\n", p->interfc, 107c8a340cdSDavid du Colombier p->name, err, ser->recover); 108c8a340cdSDavid du Colombier else 109c8a340cdSDavid du Colombier dprint(2, "serial[%s], global error, level %d\n", 110c8a340cdSDavid du Colombier ser->p[0].name, ser->recover); 111c8a340cdSDavid du Colombier ser->recover++; 1125e4f5c78SDavid du Colombier if(strstr(err, "detached") != nil) 1135e4f5c78SDavid du Colombier return -1; 114c8a340cdSDavid du Colombier if(ser->recover < 3){ 115*84860c5dSDavid du Colombier if(p != nil){ 116c8a340cdSDavid du Colombier if(ep != nil){ 117*84860c5dSDavid du Colombier if(ep == p->epintr) 118c8a340cdSDavid du Colombier unstall(ser->dev, p->epintr, Ein); 119*84860c5dSDavid du Colombier if(ep == p->epin) 120c8a340cdSDavid du Colombier unstall(ser->dev, p->epin, Ein); 121*84860c5dSDavid du Colombier if(ep == p->epout) 122c8a340cdSDavid du Colombier unstall(ser->dev, p->epout, Eout); 123c8a340cdSDavid du Colombier return 0; 124c8a340cdSDavid du Colombier } 125*84860c5dSDavid du Colombier 126c8a340cdSDavid du Colombier if(p->epintr != nil) 127c8a340cdSDavid du Colombier unstall(ser->dev, p->epintr, Ein); 128c8a340cdSDavid du Colombier if(p->epin != nil) 129c8a340cdSDavid du Colombier unstall(ser->dev, p->epin, Ein); 130c8a340cdSDavid du Colombier if(p->epout != nil) 131c8a340cdSDavid du Colombier unstall(ser->dev, p->epout, Eout); 132c8a340cdSDavid du Colombier } 133c8a340cdSDavid du Colombier return 0; 134c8a340cdSDavid du Colombier } 135c8a340cdSDavid du Colombier if(ser->recover > 4 && ser->recover < 8) 1365e4f5c78SDavid du Colombier serialfatal(ser); 137c8a340cdSDavid du Colombier if(ser->recover > 8){ 138c8a340cdSDavid du Colombier ser->reset(ser, p); 139c8a340cdSDavid du Colombier return 0; 140c8a340cdSDavid du Colombier } 1415e4f5c78SDavid du Colombier if(serialreset(ser) < 0) 1425e4f5c78SDavid du Colombier return -1; 1435e4f5c78SDavid du Colombier return 0; 1445e4f5c78SDavid du Colombier } 1455e4f5c78SDavid du Colombier 1465e4f5c78SDavid du Colombier static int 147d5789509SDavid du Colombier serialctl(Serialport *p, char *cmd) 1485e4f5c78SDavid du Colombier { 149d5789509SDavid du Colombier Serial *ser; 1505e4f5c78SDavid du Colombier int c, i, n, nf, nop, nw, par, drain, set, lines; 1515e4f5c78SDavid du Colombier char *f[16]; 1525e4f5c78SDavid du Colombier uchar x; 1535e4f5c78SDavid du Colombier 154d5789509SDavid du Colombier ser = p->s; 1555e4f5c78SDavid du Colombier drain = set = lines = 0; 1565e4f5c78SDavid du Colombier nf = tokenize(cmd, f, nelem(f)); 1575e4f5c78SDavid du Colombier for(i = 0; i < nf; i++){ 1585e4f5c78SDavid du Colombier if(strncmp(f[i], "break", 5) == 0){ 159d5789509SDavid du Colombier if(ser->setbreak != nil) 160d5789509SDavid du Colombier ser->setbreak(p, 1); 1615e4f5c78SDavid du Colombier continue; 1625e4f5c78SDavid du Colombier } 1635e4f5c78SDavid du Colombier 1645e4f5c78SDavid du Colombier nop = 0; 1655e4f5c78SDavid du Colombier n = atoi(f[i]+1); 1665e4f5c78SDavid du Colombier c = *f[i]; 1675e4f5c78SDavid du Colombier if (isascii(c) && isupper(c)) 1685e4f5c78SDavid du Colombier c = tolower(c); 1695e4f5c78SDavid du Colombier switch(c){ 1705e4f5c78SDavid du Colombier case 'b': 1715e4f5c78SDavid du Colombier drain++; 1725e4f5c78SDavid du Colombier p->baud = n; 1735e4f5c78SDavid du Colombier set++; 1745e4f5c78SDavid du Colombier break; 1755e4f5c78SDavid du Colombier case 'c': 1765e4f5c78SDavid du Colombier p->dcd = n; 1775e4f5c78SDavid du Colombier // lines++; 1785e4f5c78SDavid du Colombier ++nop; 1795e4f5c78SDavid du Colombier break; 1805e4f5c78SDavid du Colombier case 'd': 1815e4f5c78SDavid du Colombier p->dtr = n; 1825e4f5c78SDavid du Colombier lines++; 1835e4f5c78SDavid du Colombier break; 1845e4f5c78SDavid du Colombier case 'e': 1855e4f5c78SDavid du Colombier p->dsr = n; 1865e4f5c78SDavid du Colombier // lines++; 1875e4f5c78SDavid du Colombier ++nop; 1885e4f5c78SDavid du Colombier break; 1895e4f5c78SDavid du Colombier case 'f': /* flush the pipes */ 1905e4f5c78SDavid du Colombier drain++; 1915e4f5c78SDavid du Colombier break; 1925e4f5c78SDavid du Colombier case 'h': /* hangup?? */ 1935e4f5c78SDavid du Colombier p->rts = p->dtr = 0; 1945e4f5c78SDavid du Colombier lines++; 1955e4f5c78SDavid du Colombier fprint(2, "serial: %c, unsure ctl\n", c); 1965e4f5c78SDavid du Colombier break; 1975e4f5c78SDavid du Colombier case 'i': 1985e4f5c78SDavid du Colombier ++nop; 1995e4f5c78SDavid du Colombier break; 2005e4f5c78SDavid du Colombier case 'k': 2015e4f5c78SDavid du Colombier drain++; 202d5789509SDavid du Colombier ser->setbreak(p, 1); 2035e4f5c78SDavid du Colombier sleep(n); 204d5789509SDavid du Colombier ser->setbreak(p, 0); 2055e4f5c78SDavid du Colombier break; 2065e4f5c78SDavid du Colombier case 'l': 2075e4f5c78SDavid du Colombier drain++; 2085e4f5c78SDavid du Colombier p->bits = n; 2095e4f5c78SDavid du Colombier set++; 2105e4f5c78SDavid du Colombier break; 2115e4f5c78SDavid du Colombier case 'm': 2125e4f5c78SDavid du Colombier drain++; 213d5789509SDavid du Colombier if(ser->modemctl != nil) 214d5789509SDavid du Colombier ser->modemctl(p, n); 2155e4f5c78SDavid du Colombier if(n == 0) 2165e4f5c78SDavid du Colombier p->cts = 0; 2175e4f5c78SDavid du Colombier break; 2185e4f5c78SDavid du Colombier case 'n': 2195e4f5c78SDavid du Colombier p->blocked = n; 2205e4f5c78SDavid du Colombier ++nop; 2215e4f5c78SDavid du Colombier break; 2225e4f5c78SDavid du Colombier case 'p': /* extended... */ 2235e4f5c78SDavid du Colombier if(strlen(f[i]) != 2) 2245e4f5c78SDavid du Colombier return -1; 2255e4f5c78SDavid du Colombier drain++; 22680e9508eSDavid du Colombier par = f[i][1]; 2275e4f5c78SDavid du Colombier if(par == 'n') 2285e4f5c78SDavid du Colombier p->parity = 0; 2295e4f5c78SDavid du Colombier else if(par == 'o') 2305e4f5c78SDavid du Colombier p->parity = 1; 2315e4f5c78SDavid du Colombier else if(par == 'e') 2325e4f5c78SDavid du Colombier p->parity = 2; 2335e4f5c78SDavid du Colombier else if(par == 'm') /* mark parity */ 2345e4f5c78SDavid du Colombier p->parity = 3; 2355e4f5c78SDavid du Colombier else if(par == 's') /* space parity */ 2365e4f5c78SDavid du Colombier p->parity = 4; 2375e4f5c78SDavid du Colombier else 2385e4f5c78SDavid du Colombier return -1; 2395e4f5c78SDavid du Colombier set++; 2405e4f5c78SDavid du Colombier break; 2415e4f5c78SDavid du Colombier case 'q': 2425e4f5c78SDavid du Colombier // drain++; 2435e4f5c78SDavid du Colombier p->limit = n; 2445e4f5c78SDavid du Colombier ++nop; 2455e4f5c78SDavid du Colombier break; 2465e4f5c78SDavid du Colombier case 'r': 2475e4f5c78SDavid du Colombier drain++; 2485e4f5c78SDavid du Colombier p->rts = n; 2495e4f5c78SDavid du Colombier lines++; 2505e4f5c78SDavid du Colombier break; 2515e4f5c78SDavid du Colombier case 's': 2525e4f5c78SDavid du Colombier drain++; 2535e4f5c78SDavid du Colombier p->stop = n; 2545e4f5c78SDavid du Colombier set++; 2555e4f5c78SDavid du Colombier break; 2565e4f5c78SDavid du Colombier case 'w': 2575e4f5c78SDavid du Colombier /* ?? how do I put this */ 2585e4f5c78SDavid du Colombier p->timer = n * 100000LL; 2595e4f5c78SDavid du Colombier ++nop; 2605e4f5c78SDavid du Colombier break; 2615e4f5c78SDavid du Colombier case 'x': 2625e4f5c78SDavid du Colombier if(n == 0) 2635e4f5c78SDavid du Colombier x = CTLS; 2645e4f5c78SDavid du Colombier else 2655e4f5c78SDavid du Colombier x = CTLQ; 266d5789509SDavid du Colombier if(ser->wait4write != nil) 267d5789509SDavid du Colombier nw = ser->wait4write(p, &x, 1); 26880e9508eSDavid du Colombier else 2695e4f5c78SDavid du Colombier nw = write(p->epout->dfd, &x, 1); 2705e4f5c78SDavid du Colombier if(nw != 1){ 271*84860c5dSDavid du Colombier serialrecover(ser, p, p->epout, ""); 2725e4f5c78SDavid du Colombier return -1; 2735e4f5c78SDavid du Colombier } 2745e4f5c78SDavid du Colombier break; 2755e4f5c78SDavid du Colombier } 276ecc2a7c8SDavid du Colombier /* 277ecc2a7c8SDavid du Colombier * don't print. the condition is harmless and the print 278ecc2a7c8SDavid du Colombier * splatters all over the display. 279ecc2a7c8SDavid du Colombier */ 280ecc2a7c8SDavid du Colombier USED(nop); 281ecc2a7c8SDavid du Colombier if (0 && nop) 2825e4f5c78SDavid du Colombier fprint(2, "serial: %c, unsupported nop ctl\n", c); 2835e4f5c78SDavid du Colombier } 2845e4f5c78SDavid du Colombier if(drain) 2855e4f5c78SDavid du Colombier serialdrain(p); 28680e9508eSDavid du Colombier if(lines && !set){ 287d5789509SDavid du Colombier if(ser->sendlines != nil && ser->sendlines(p) < 0) 2885e4f5c78SDavid du Colombier return -1; 28980e9508eSDavid du Colombier } else if(set){ 290d5789509SDavid du Colombier if(ser->setparam != nil && ser->setparam(p) < 0) 29180e9508eSDavid du Colombier return -1; 29280e9508eSDavid du Colombier } 293c8a340cdSDavid du Colombier ser->recover = 0; 2945e4f5c78SDavid du Colombier return 0; 2955e4f5c78SDavid du Colombier } 2965e4f5c78SDavid du Colombier 2975e4f5c78SDavid du Colombier char *pformat = "noems"; 2985e4f5c78SDavid du Colombier 2995e4f5c78SDavid du Colombier char * 300d5789509SDavid du Colombier serdumpst(Serialport *p, char *buf, int bufsz) 3015e4f5c78SDavid du Colombier { 3025e4f5c78SDavid du Colombier char *e, *s; 303d5789509SDavid du Colombier Serial *ser; 304d5789509SDavid du Colombier 305d5789509SDavid du Colombier ser = p->s; 3065e4f5c78SDavid du Colombier 3075e4f5c78SDavid du Colombier e = buf + bufsz; 308d5789509SDavid du Colombier s = seprint(buf, e, "b%d ", p->baud); 309d5789509SDavid du Colombier s = seprint(s, e, "c%d ", p->dcd); /* unimplemented */ 310d5789509SDavid du Colombier s = seprint(s, e, "d%d ", p->dtr); 311d5789509SDavid du Colombier s = seprint(s, e, "e%d ", p->dsr); /* unimplemented */ 312d5789509SDavid du Colombier s = seprint(s, e, "l%d ", p->bits); 313d5789509SDavid du Colombier s = seprint(s, e, "m%d ", p->mctl); 314d5789509SDavid du Colombier if(p->parity >= 0 || p->parity < strlen(pformat)) 315d5789509SDavid du Colombier s = seprint(s, e, "p%c ", pformat[p->parity]); 3165e4f5c78SDavid du Colombier else 3175e4f5c78SDavid du Colombier s = seprint(s, e, "p%c ", '?'); 318d5789509SDavid du Colombier s = seprint(s, e, "r%d ", p->rts); 319d5789509SDavid du Colombier s = seprint(s, e, "s%d ", p->stop); 320d5789509SDavid du Colombier s = seprint(s, e, "i%d ", p->fifo); 3215e4f5c78SDavid du Colombier s = seprint(s, e, "\ndev(%d) ", 0); 3225e4f5c78SDavid du Colombier s = seprint(s, e, "type(%d) ", ser->type); 323d5789509SDavid du Colombier s = seprint(s, e, "framing(%d) ", p->nframeerr); 324d5789509SDavid du Colombier s = seprint(s, e, "overruns(%d) ", p->novererr); 325d5789509SDavid du Colombier s = seprint(s, e, "berr(%d) ", p->nbreakerr); 326ed868a7cSDavid du Colombier s = seprint(s, e, " serr(%d)\n", p->nparityerr); 3275e4f5c78SDavid du Colombier return s; 3285e4f5c78SDavid du Colombier } 3295e4f5c78SDavid du Colombier 3305e4f5c78SDavid du Colombier static int 331d5789509SDavid du Colombier serinit(Serialport *p) 3325e4f5c78SDavid du Colombier { 3335e4f5c78SDavid du Colombier int res; 33480e9508eSDavid du Colombier res = 0; 335d5789509SDavid du Colombier Serial *ser; 336d5789509SDavid du Colombier 337d5789509SDavid du Colombier ser = p->s; 338d5789509SDavid du Colombier 33980e9508eSDavid du Colombier if(ser->init != nil) 340d5789509SDavid du Colombier res = ser->init(p); 34180e9508eSDavid du Colombier if(ser->getparam != nil) 342d5789509SDavid du Colombier ser->getparam(p); 343d5789509SDavid du Colombier p->nframeerr = p->nparityerr = p->nbreakerr = p->novererr = 0; 344d5789509SDavid du Colombier 3455e4f5c78SDavid du Colombier return res; 3465e4f5c78SDavid du Colombier } 3475e4f5c78SDavid du Colombier 3485e4f5c78SDavid du Colombier static int 3495e4f5c78SDavid du Colombier dwalk(Usbfs *fs, Fid *fid, char *name) 3505e4f5c78SDavid du Colombier { 3515e4f5c78SDavid du Colombier int i; 3525e4f5c78SDavid du Colombier char *dname; 3535e4f5c78SDavid du Colombier Qid qid; 354d5789509SDavid du Colombier Serialport *p; 3555e4f5c78SDavid du Colombier 3565e4f5c78SDavid du Colombier qid = fid->qid; 3575e4f5c78SDavid du Colombier if((qid.type & QTDIR) == 0){ 3585e4f5c78SDavid du Colombier werrstr("walk in non-directory"); 3595e4f5c78SDavid du Colombier return -1; 3605e4f5c78SDavid du Colombier } 3615e4f5c78SDavid du Colombier 3625e4f5c78SDavid du Colombier if(strcmp(name, "..") == 0){ 3635e4f5c78SDavid du Colombier /* must be /eiaU%d; i.e. our root dir. */ 3645e4f5c78SDavid du Colombier fid->qid.path = Qroot | fs->qid; 3655e4f5c78SDavid du Colombier fid->qid.vers = 0; 3665e4f5c78SDavid du Colombier fid->qid.type = QTDIR; 3675e4f5c78SDavid du Colombier return 0; 3685e4f5c78SDavid du Colombier } 3695e4f5c78SDavid du Colombier 370d5789509SDavid du Colombier p = fs->aux; 3715e4f5c78SDavid du Colombier for(i = 1; i < nelem(dirtab); i++){ 372d584e620SDavid du Colombier dname = smprint(dirtab[i].name, p->name); 3735e4f5c78SDavid du Colombier if(strcmp(name, dname) == 0){ 3745e4f5c78SDavid du Colombier qid.path = i | fs->qid; 3755e4f5c78SDavid du Colombier qid.vers = 0; 3765e4f5c78SDavid du Colombier qid.type = dirtab[i].mode >> 24; 3775e4f5c78SDavid du Colombier fid->qid = qid; 3785e4f5c78SDavid du Colombier free(dname); 3795e4f5c78SDavid du Colombier return 0; 3805e4f5c78SDavid du Colombier } else 3815e4f5c78SDavid du Colombier free(dname); 3825e4f5c78SDavid du Colombier } 3835e4f5c78SDavid du Colombier werrstr(Enotfound); 3845e4f5c78SDavid du Colombier return -1; 3855e4f5c78SDavid du Colombier } 3865e4f5c78SDavid du Colombier 3875e4f5c78SDavid du Colombier static void 3885e4f5c78SDavid du Colombier dostat(Usbfs *fs, int path, Dir *d) 3895e4f5c78SDavid du Colombier { 3905e4f5c78SDavid du Colombier Dirtab *t; 391d5789509SDavid du Colombier Serialport *p; 3925e4f5c78SDavid du Colombier 3935e4f5c78SDavid du Colombier t = &dirtab[path]; 3945e4f5c78SDavid du Colombier d->qid.path = path; 3955e4f5c78SDavid du Colombier d->qid.type = t->mode >> 24; 3965e4f5c78SDavid du Colombier d->mode = t->mode; 397d5789509SDavid du Colombier p = fs->aux; 3985e4f5c78SDavid du Colombier 3995e4f5c78SDavid du Colombier if(strcmp(t->name, "/") == 0) 4005e4f5c78SDavid du Colombier d->name = t->name; 4015e4f5c78SDavid du Colombier else 402d5789509SDavid du Colombier snprint(d->name, Namesz, t->name, p->fs.name); 4035e4f5c78SDavid du Colombier d->length = 0; 4045e4f5c78SDavid du Colombier } 4055e4f5c78SDavid du Colombier 4065e4f5c78SDavid du Colombier static int 4075e4f5c78SDavid du Colombier dstat(Usbfs *fs, Qid qid, Dir *d) 4085e4f5c78SDavid du Colombier { 4095e4f5c78SDavid du Colombier int path; 4105e4f5c78SDavid du Colombier 4115e4f5c78SDavid du Colombier path = qid.path & ~fs->qid; 4125e4f5c78SDavid du Colombier dostat(fs, path, d); 4135e4f5c78SDavid du Colombier d->qid.path |= fs->qid; 4145e4f5c78SDavid du Colombier return 0; 4155e4f5c78SDavid du Colombier } 4165e4f5c78SDavid du Colombier 4175e4f5c78SDavid du Colombier static int 4185e4f5c78SDavid du Colombier dopen(Usbfs *fs, Fid *fid, int) 4195e4f5c78SDavid du Colombier { 4205e4f5c78SDavid du Colombier ulong path; 421ed868a7cSDavid du Colombier Serialport *p; 4225e4f5c78SDavid du Colombier 4235e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid; 424ed868a7cSDavid du Colombier p = fs->aux; 4255e4f5c78SDavid du Colombier switch(path){ /* BUG: unneeded? */ 4265e4f5c78SDavid du Colombier case Qdata: 4274d52e0f0SDavid du Colombier dsprint(2, "serial, opened data\n"); 4285e4f5c78SDavid du Colombier break; 4295e4f5c78SDavid du Colombier case Qctl: 4304d52e0f0SDavid du Colombier dsprint(2, "serial, opened ctl\n"); 431d584e620SDavid du Colombier if(p->isjtag) 432d584e620SDavid du Colombier return 0; 433ed868a7cSDavid du Colombier serialctl(p, "l8 i1"); /* default line parameters */ 4345e4f5c78SDavid du Colombier break; 4355e4f5c78SDavid du Colombier } 4365e4f5c78SDavid du Colombier return 0; 4375e4f5c78SDavid du Colombier } 4385e4f5c78SDavid du Colombier 4395e4f5c78SDavid du Colombier 4405e4f5c78SDavid du Colombier static void 441d584e620SDavid du Colombier filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i, void *v) 4425e4f5c78SDavid du Colombier { 443d584e620SDavid du Colombier Serialport *p; 444d584e620SDavid du Colombier 445d584e620SDavid du Colombier p = v; 4465e4f5c78SDavid du Colombier d->qid.path = i | fs->qid; 4475e4f5c78SDavid du Colombier d->mode = tab->mode; 4485e4f5c78SDavid du Colombier if((d->mode & DMDIR) != 0) 4495e4f5c78SDavid du Colombier d->qid.type = QTDIR; 4505e4f5c78SDavid du Colombier else 4515e4f5c78SDavid du Colombier d->qid.type = QTFILE; 452d584e620SDavid du Colombier sprint(d->name, tab->name, p->name); /* hope it fits */ 4535e4f5c78SDavid du Colombier } 4545e4f5c78SDavid du Colombier 4555e4f5c78SDavid du Colombier static int 456d584e620SDavid du Colombier dirgen(Usbfs *fs, Qid, int i, Dir *d, void *p) 4575e4f5c78SDavid du Colombier { 4585e4f5c78SDavid du Colombier i++; /* skip root */ 45980e9508eSDavid du Colombier if(i >= nelem(dirtab)) 4605e4f5c78SDavid du Colombier return -1; 461d584e620SDavid du Colombier filldir(fs, d, &dirtab[i], i, p); 4625e4f5c78SDavid du Colombier return 0; 4635e4f5c78SDavid du Colombier } 4645e4f5c78SDavid du Colombier 465bfb6eab9SDavid du Colombier enum { 466bfb6eab9SDavid du Colombier Serbufsize = 255, 467bfb6eab9SDavid du Colombier }; 468bfb6eab9SDavid du Colombier 4695e4f5c78SDavid du Colombier static long 4705e4f5c78SDavid du Colombier dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) 4715e4f5c78SDavid du Colombier { 4725e4f5c78SDavid du Colombier int dfd; 4735e4f5c78SDavid du Colombier long rcount; 4745e4f5c78SDavid du Colombier ulong path; 47580e9508eSDavid du Colombier char *e, *buf, *err; /* change */ 4765e4f5c78SDavid du Colombier Qid q; 477d5789509SDavid du Colombier Serialport *p; 4785e4f5c78SDavid du Colombier Serial *ser; 479ecc2a7c8SDavid du Colombier static int errrun, good; 4805e4f5c78SDavid du Colombier 4815e4f5c78SDavid du Colombier q = fid->qid; 4825e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid; 483d5789509SDavid du Colombier p = fs->aux; 484d5789509SDavid du Colombier ser = p->s; 4855e4f5c78SDavid du Colombier 486bfb6eab9SDavid du Colombier buf = emallocz(Serbufsize, 1); 487bfb6eab9SDavid du Colombier err = emallocz(Serbufsize, 1); 4885e4f5c78SDavid du Colombier qlock(ser); 4895e4f5c78SDavid du Colombier switch(path){ 4905e4f5c78SDavid du Colombier case Qroot: 491d584e620SDavid du Colombier count = usbdirread(fs, q, data, count, offset, dirgen, p); 4925e4f5c78SDavid du Colombier break; 4935e4f5c78SDavid du Colombier case Qdata: 49480e9508eSDavid du Colombier if(count > ser->maxread) 49580e9508eSDavid du Colombier count = ser->maxread; 49680e9508eSDavid du Colombier dsprint(2, "serial: reading from data\n"); 4975e4f5c78SDavid du Colombier do { 4984d52e0f0SDavid du Colombier err[0] = 0; 499d5789509SDavid du Colombier dfd = p->epin->dfd; 50080e9508eSDavid du Colombier if(usbdebug >= 3) 50180e9508eSDavid du Colombier dsprint(2, "serial: reading: %ld\n", count); 50280e9508eSDavid du Colombier 503ecc2a7c8SDavid du Colombier assert(count > 0); 50480e9508eSDavid du Colombier if(ser->wait4data != nil) 505d5789509SDavid du Colombier rcount = ser->wait4data(p, data, count); 50680e9508eSDavid du Colombier else{ 50780e9508eSDavid du Colombier qunlock(ser); 5085e4f5c78SDavid du Colombier rcount = read(dfd, data, count); 5095e4f5c78SDavid du Colombier qlock(ser); 51080e9508eSDavid du Colombier } 51125fc6993SDavid du Colombier /* 51225fc6993SDavid du Colombier * if we encounter a long run of continuous read 51325fc6993SDavid du Colombier * errors, do something drastic so that our caller 51425fc6993SDavid du Colombier * doesn't just spin its wheels forever. 51525fc6993SDavid du Colombier */ 51625fc6993SDavid du Colombier if(rcount < 0) { 517bfb6eab9SDavid du Colombier snprint(err, Serbufsize, "%r"); 518ecc2a7c8SDavid du Colombier ++errrun; 519ecc2a7c8SDavid du Colombier sleep(20); 520ecc2a7c8SDavid du Colombier if (good > 0 && errrun > 10000) { 52125fc6993SDavid du Colombier /* the line has been dropped; give up */ 52225fc6993SDavid du Colombier qunlock(ser); 523ecc2a7c8SDavid du Colombier fprint(2, "%s: line %s is gone: %r\n", 524d5789509SDavid du Colombier argv0, p->fs.name); 52525fc6993SDavid du Colombier threadexitsall("serial line gone"); 52625fc6993SDavid du Colombier } 527ecc2a7c8SDavid du Colombier } else { 52825fc6993SDavid du Colombier errrun = 0; 529ecc2a7c8SDavid du Colombier good++; 530ecc2a7c8SDavid du Colombier } 53180e9508eSDavid du Colombier if(usbdebug >= 3) 53280e9508eSDavid du Colombier dsprint(2, "serial: read: %s %ld\n", err, rcount); 5335e4f5c78SDavid du Colombier } while(rcount < 0 && strstr(err, "timed out") != nil); 5345e4f5c78SDavid du Colombier 53580e9508eSDavid du Colombier dsprint(2, "serial: read from bulk %ld, %10.10s\n", rcount, err); 5365e4f5c78SDavid du Colombier if(rcount < 0){ 5375e4f5c78SDavid du Colombier dsprint(2, "serial: need to recover, data read %ld %r\n", 5385e4f5c78SDavid du Colombier count); 539*84860c5dSDavid du Colombier serialrecover(ser, p, p->epin, err); 5405e4f5c78SDavid du Colombier } 54180e9508eSDavid du Colombier dsprint(2, "serial: read from bulk %ld\n", rcount); 5425e4f5c78SDavid du Colombier count = rcount; 5435e4f5c78SDavid du Colombier break; 5445e4f5c78SDavid du Colombier case Qctl: 54580e9508eSDavid du Colombier if(offset != 0) 5465e4f5c78SDavid du Colombier count = 0; 54780e9508eSDavid du Colombier else { 548d584e620SDavid du Colombier if(!p->isjtag){ 549d5789509SDavid du Colombier e = serdumpst(p, buf, Serbufsize); 5505e4f5c78SDavid du Colombier count = usbreadbuf(data, count, 0, buf, e - buf); 55180e9508eSDavid du Colombier } 552d584e620SDavid du Colombier } 5535e4f5c78SDavid du Colombier break; 5545e4f5c78SDavid du Colombier } 555c8a340cdSDavid du Colombier if(count >= 0) 556c8a340cdSDavid du Colombier ser->recover = 0; 5575e4f5c78SDavid du Colombier qunlock(ser); 5585e4f5c78SDavid du Colombier free(err); 5595e4f5c78SDavid du Colombier free(buf); 5605e4f5c78SDavid du Colombier return count; 5615e4f5c78SDavid du Colombier } 5625e4f5c78SDavid du Colombier 5635e4f5c78SDavid du Colombier static long 564d5789509SDavid du Colombier altwrite(Serialport *p, uchar *buf, long count) 56580e9508eSDavid du Colombier { 56680e9508eSDavid du Colombier int nw, dfd; 56780e9508eSDavid du Colombier char err[128]; 568d5789509SDavid du Colombier Serial *ser; 56980e9508eSDavid du Colombier 570d5789509SDavid du Colombier ser = p->s; 57180e9508eSDavid du Colombier do{ 572d584e620SDavid du Colombier dsprint(2, "serial: write to bulk %ld\n", count); 573d584e620SDavid du Colombier 57480e9508eSDavid du Colombier if(ser->wait4write != nil) 57580e9508eSDavid du Colombier /* unlocked inside later */ 576d5789509SDavid du Colombier nw = ser->wait4write(p, buf, count); 57780e9508eSDavid du Colombier else{ 578d5789509SDavid du Colombier dfd = p->epout->dfd; 57980e9508eSDavid du Colombier qunlock(ser); 58080e9508eSDavid du Colombier nw = write(dfd, buf, count); 58180e9508eSDavid du Colombier qlock(ser); 58280e9508eSDavid du Colombier } 58380e9508eSDavid du Colombier rerrstr(err, sizeof err); 584d584e620SDavid du Colombier dsprint(2, "serial: written %s %d\n", err, nw); 58580e9508eSDavid du Colombier } while(nw < 0 && strstr(err, "timed out") != nil); 58680e9508eSDavid du Colombier 58780e9508eSDavid du Colombier if(nw != count){ 58880e9508eSDavid du Colombier dsprint(2, "serial: need to recover, status in write %d %r\n", 58980e9508eSDavid du Colombier nw); 59080e9508eSDavid du Colombier snprint(err, sizeof err, "%r"); 591*84860c5dSDavid du Colombier serialrecover(p->s, p, p->epout, err); 59280e9508eSDavid du Colombier } 59380e9508eSDavid du Colombier return nw; 59480e9508eSDavid du Colombier } 59580e9508eSDavid du Colombier 59680e9508eSDavid du Colombier static long 5975e4f5c78SDavid du Colombier dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong) 5985e4f5c78SDavid du Colombier { 5995e4f5c78SDavid du Colombier ulong path; 6005e4f5c78SDavid du Colombier char *cmd; 601d5789509SDavid du Colombier Serialport *p; 6025e4f5c78SDavid du Colombier Serial *ser; 6035e4f5c78SDavid du Colombier 604d5789509SDavid du Colombier p = fs->aux; 605d5789509SDavid du Colombier ser = p->s; 6065e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid; 6075e4f5c78SDavid du Colombier 6085e4f5c78SDavid du Colombier qlock(ser); 6095e4f5c78SDavid du Colombier switch(path){ 6105e4f5c78SDavid du Colombier case Qdata: 611d5789509SDavid du Colombier count = altwrite(p, (uchar *)buf, count); 6125e4f5c78SDavid du Colombier break; 6135e4f5c78SDavid du Colombier case Qctl: 614d584e620SDavid du Colombier if(p->isjtag) 615d584e620SDavid du Colombier break; 6165e4f5c78SDavid du Colombier cmd = emallocz(count+1, 1); 6175e4f5c78SDavid du Colombier memmove(cmd, buf, count); 6185e4f5c78SDavid du Colombier cmd[count] = 0; 619d5789509SDavid du Colombier if(serialctl(p, cmd) < 0){ 6205e4f5c78SDavid du Colombier qunlock(ser); 6215e4f5c78SDavid du Colombier werrstr(Ebadctl); 6225e4f5c78SDavid du Colombier free(cmd); 6235e4f5c78SDavid du Colombier return -1; 6245e4f5c78SDavid du Colombier } 6255e4f5c78SDavid du Colombier free(cmd); 6265e4f5c78SDavid du Colombier break; 6275e4f5c78SDavid du Colombier default: 6285e4f5c78SDavid du Colombier qunlock(ser); 6295e4f5c78SDavid du Colombier werrstr(Eperm); 6305e4f5c78SDavid du Colombier return -1; 6315e4f5c78SDavid du Colombier } 632c8a340cdSDavid du Colombier if(count >= 0) 633c8a340cdSDavid du Colombier ser->recover = 0; 634c8a340cdSDavid du Colombier else 635*84860c5dSDavid du Colombier serialrecover(ser, p, p->epout, "writing"); 6365e4f5c78SDavid du Colombier qunlock(ser); 6375e4f5c78SDavid du Colombier return count; 6385e4f5c78SDavid du Colombier } 6395e4f5c78SDavid du Colombier 6405e4f5c78SDavid du Colombier static int 641d5789509SDavid du Colombier openeps(Serialport *p, int epin, int epout, int epintr) 6425e4f5c78SDavid du Colombier { 643d5789509SDavid du Colombier Serial *ser; 644d5789509SDavid du Colombier 645d5789509SDavid du Colombier ser = p->s; 646d5789509SDavid du Colombier p->epin = openep(ser->dev, epin); 647d5789509SDavid du Colombier if(p->epin == nil){ 6485e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epin); 6495e4f5c78SDavid du Colombier return -1; 6505e4f5c78SDavid du Colombier } 651d5789509SDavid du Colombier p->epout = openep(ser->dev, epout); 652d5789509SDavid du Colombier if(p->epout == nil){ 6535e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epout); 654d5789509SDavid du Colombier closedev(p->epin); 6555e4f5c78SDavid du Colombier return -1; 6565e4f5c78SDavid du Colombier } 6574d52e0f0SDavid du Colombier 658d584e620SDavid du Colombier if(!p->isjtag){ 659d5789509SDavid du Colombier devctl(p->epin, "timeout 1000"); 660d5789509SDavid du Colombier devctl(p->epout, "timeout 1000"); 661d584e620SDavid du Colombier } 6624d52e0f0SDavid du Colombier 6634d52e0f0SDavid du Colombier if(ser->hasepintr){ 664d5789509SDavid du Colombier p->epintr = openep(ser->dev, epintr); 665d5789509SDavid du Colombier if(p->epintr == nil){ 6665e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epintr); 667d5789509SDavid du Colombier closedev(p->epin); 668d5789509SDavid du Colombier closedev(p->epout); 6695e4f5c78SDavid du Colombier return -1; 6705e4f5c78SDavid du Colombier } 671d5789509SDavid du Colombier opendevdata(p->epintr, OREAD); 672d5789509SDavid du Colombier devctl(p->epintr, "timeout 1000"); 6734d52e0f0SDavid du Colombier } 6745e4f5c78SDavid du Colombier 67580e9508eSDavid du Colombier if(ser->seteps!= nil) 676d5789509SDavid du Colombier ser->seteps(p); 677d5789509SDavid du Colombier opendevdata(p->epin, OREAD); 678d5789509SDavid du Colombier opendevdata(p->epout, OWRITE); 679d5789509SDavid du Colombier if(p->epin->dfd < 0 ||p->epout->dfd < 0 || 680d5789509SDavid du Colombier (ser->hasepintr && p->epintr->dfd < 0)){ 6815e4f5c78SDavid du Colombier fprint(2, "serial: open i/o ep data: %r\n"); 682d5789509SDavid du Colombier closedev(p->epin); 683d5789509SDavid du Colombier closedev(p->epout); 6844d52e0f0SDavid du Colombier if(ser->hasepintr) 685d5789509SDavid du Colombier closedev(p->epintr); 6865e4f5c78SDavid du Colombier return -1; 6875e4f5c78SDavid du Colombier } 6885e4f5c78SDavid du Colombier return 0; 6895e4f5c78SDavid du Colombier } 6905e4f5c78SDavid du Colombier 6915e4f5c78SDavid du Colombier static int 692d5789509SDavid du Colombier findendpoints(Serial *ser, int ifc) 6935e4f5c78SDavid du Colombier { 6945e4f5c78SDavid du Colombier int i, epin, epout, epintr; 69580e9508eSDavid du Colombier Ep *ep, **eps; 6965e4f5c78SDavid du Colombier 6975e4f5c78SDavid du Colombier epintr = epin = epout = -1; 69880e9508eSDavid du Colombier 69980e9508eSDavid du Colombier /* 70080e9508eSDavid du Colombier * interfc 0 means start from the start which is equiv to 70180e9508eSDavid du Colombier * iterate through endpoints probably, could be done better 70280e9508eSDavid du Colombier */ 703d5789509SDavid du Colombier eps = ser->dev->usb->conf[0]->iface[ifc]->ep; 70480e9508eSDavid du Colombier 70580e9508eSDavid du Colombier for(i = 0; i < Niface; i++){ 70680e9508eSDavid du Colombier if((ep = eps[i]) == nil) 7075e4f5c78SDavid du Colombier continue; 70880e9508eSDavid du Colombier if(ser->hasepintr && ep->type == Eintr && 70980e9508eSDavid du Colombier ep->dir == Ein && epintr == -1) 7105e4f5c78SDavid du Colombier epintr = ep->id; 7115e4f5c78SDavid du Colombier if(ep->type == Ebulk){ 7125e4f5c78SDavid du Colombier if(ep->dir == Ein && epin == -1) 7135e4f5c78SDavid du Colombier epin = ep->id; 7145e4f5c78SDavid du Colombier if(ep->dir == Eout && epout == -1) 7155e4f5c78SDavid du Colombier epout = ep->id; 7165e4f5c78SDavid du Colombier } 7175e4f5c78SDavid du Colombier } 718d5789509SDavid du Colombier dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr); 7194d52e0f0SDavid du Colombier if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1)) 7205e4f5c78SDavid du Colombier return -1; 7214d52e0f0SDavid du Colombier 722d5789509SDavid du Colombier if(openeps(&ser->p[ifc], epin, epout, epintr) < 0) 7235e4f5c78SDavid du Colombier return -1; 7245e4f5c78SDavid du Colombier 725d5789509SDavid du Colombier dprint(2, "serial: ep in %s out %s\n", ser->p[ifc].epin->dir, ser->p[ifc].epout->dir); 7264d52e0f0SDavid du Colombier if(ser->hasepintr) 727d5789509SDavid du Colombier dprint(2, "serial: ep intr %s\n", ser->p[ifc].epintr->dir); 7285e4f5c78SDavid du Colombier 7295e4f5c78SDavid du Colombier if(usbdebug > 1 || serialdebug > 2){ 730d5789509SDavid du Colombier devctl(ser->p[ifc].epin, "debug 1"); 731d5789509SDavid du Colombier devctl(ser->p[ifc].epout, "debug 1"); 7324d52e0f0SDavid du Colombier if(ser->hasepintr) 733d5789509SDavid du Colombier devctl(ser->p[ifc].epintr, "debug 1"); 7345e4f5c78SDavid du Colombier devctl(ser->dev, "debug 1"); 7355e4f5c78SDavid du Colombier } 7365e4f5c78SDavid du Colombier return 0; 7375e4f5c78SDavid du Colombier } 7385e4f5c78SDavid du Colombier 73980e9508eSDavid du Colombier /* keep in sync with main.c */ 7405e4f5c78SDavid du Colombier static int 7415e4f5c78SDavid du Colombier usage(void) 7425e4f5c78SDavid du Colombier { 74380e9508eSDavid du Colombier werrstr("usage: usb/serial [-dD] [-m mtpt] [-s srv]"); 7445e4f5c78SDavid du Colombier return -1; 7455e4f5c78SDavid du Colombier } 7465e4f5c78SDavid du Colombier 7475e4f5c78SDavid du Colombier static void 7485e4f5c78SDavid du Colombier serdevfree(void *a) 7495e4f5c78SDavid du Colombier { 7505e4f5c78SDavid du Colombier Serial *ser = a; 751d5789509SDavid du Colombier Serialport *p; 752d5789509SDavid du Colombier int i; 7535e4f5c78SDavid du Colombier 7545e4f5c78SDavid du Colombier if(ser == nil) 7555e4f5c78SDavid du Colombier return; 756d5789509SDavid du Colombier 757d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){ 758d5789509SDavid du Colombier p = &ser->p[i]; 759d5789509SDavid du Colombier 7604d52e0f0SDavid du Colombier if(ser->hasepintr) 761d5789509SDavid du Colombier closedev(p->epintr); 762d5789509SDavid du Colombier closedev(p->epin); 763d5789509SDavid du Colombier closedev(p->epout); 764d5789509SDavid du Colombier p->epintr = p->epin = p->epout = nil; 765d5789509SDavid du Colombier if(p->w4data != nil) 766d5789509SDavid du Colombier chanfree(p->w4data); 767d5789509SDavid du Colombier if(p->gotdata != nil) 768d5789509SDavid du Colombier chanfree(p->gotdata); 769d5789509SDavid du Colombier if(p->readc) 770d5789509SDavid du Colombier chanfree(p->readc); 771d5789509SDavid du Colombier 772d5789509SDavid du Colombier } 7735e4f5c78SDavid du Colombier free(ser); 7745e4f5c78SDavid du Colombier } 7755e4f5c78SDavid du Colombier 7765e4f5c78SDavid du Colombier static Usbfs serialfs = { 7775e4f5c78SDavid du Colombier .walk = dwalk, 7785e4f5c78SDavid du Colombier .open = dopen, 7795e4f5c78SDavid du Colombier .read = dread, 7805e4f5c78SDavid du Colombier .write= dwrite, 7815e4f5c78SDavid du Colombier .stat = dstat, 7825e4f5c78SDavid du Colombier }; 7835e4f5c78SDavid du Colombier 784d5789509SDavid du Colombier static void 785d5789509SDavid du Colombier serialfsend(Usbfs *fs) 786d5789509SDavid du Colombier { 787d5789509SDavid du Colombier Serialport *p; 788d5789509SDavid du Colombier 789d5789509SDavid du Colombier p = fs->aux; 790d5789509SDavid du Colombier 791d5789509SDavid du Colombier if(p->w4data != nil) 792d5789509SDavid du Colombier chanclose(p->w4data); 793d5789509SDavid du Colombier if(p->gotdata != nil) 794d5789509SDavid du Colombier chanclose(p->gotdata); 795d5789509SDavid du Colombier if(p->readc) 796d5789509SDavid du Colombier chanclose(p->readc); 797d5789509SDavid du Colombier } 798d5789509SDavid du Colombier 7995e4f5c78SDavid du Colombier int 8005e4f5c78SDavid du Colombier serialmain(Dev *dev, int argc, char* argv[]) 8015e4f5c78SDavid du Colombier { 8025e4f5c78SDavid du Colombier Serial *ser; 803d5789509SDavid du Colombier Serialport *p; 8044d52e0f0SDavid du Colombier char buf[50]; 805ed868a7cSDavid du Colombier int i, devid; 8065e4f5c78SDavid du Colombier 807ed868a7cSDavid du Colombier devid = dev->id; 8085e4f5c78SDavid du Colombier ARGBEGIN{ 8095e4f5c78SDavid du Colombier case 'd': 8105e4f5c78SDavid du Colombier serialdebug++; 8115e4f5c78SDavid du Colombier break; 812ed868a7cSDavid du Colombier case 'N': 813ed868a7cSDavid du Colombier devid = atoi(EARGF(usage())); 814ed868a7cSDavid du Colombier break; 8155e4f5c78SDavid du Colombier default: 8165e4f5c78SDavid du Colombier return usage(); 8175e4f5c78SDavid du Colombier }ARGEND 8185e4f5c78SDavid du Colombier if(argc != 0) 8195e4f5c78SDavid du Colombier return usage(); 8205e4f5c78SDavid du Colombier 8215e4f5c78SDavid du Colombier ser = dev->aux = emallocz(sizeof(Serial), 1); 822d5789509SDavid du Colombier ser->maxrtrans = ser->maxwtrans = sizeof ser->p[0].data; 823d5789509SDavid du Colombier ser->maxread = ser->maxwrite = sizeof ser->p[0].data; 8245e4f5c78SDavid du Colombier ser->dev = dev; 8255e4f5c78SDavid du Colombier dev->free = serdevfree; 826d5789509SDavid du Colombier ser->jtag = -1; 827d5789509SDavid du Colombier ser->nifcs = 1; 8284d52e0f0SDavid du Colombier 8294d52e0f0SDavid du Colombier snprint(buf, sizeof buf, "vid %#06x did %#06x", 8304d52e0f0SDavid du Colombier dev->usb->vid, dev->usb->did); 8314d52e0f0SDavid du Colombier if(plmatch(buf) == 0){ 8324d52e0f0SDavid du Colombier ser->hasepintr = 1; 8334d52e0f0SDavid du Colombier ser->Serialops = plops; 83480e9508eSDavid du Colombier } else if(uconsmatch(buf) == 0) 8354d52e0f0SDavid du Colombier ser->Serialops = uconsops; 83680e9508eSDavid du Colombier else if(ftmatch(ser, buf) == 0) 83780e9508eSDavid du Colombier ser->Serialops = ftops; 83880e9508eSDavid du Colombier else { 83980e9508eSDavid du Colombier werrstr("serial: no serial devices found"); 8405e4f5c78SDavid du Colombier return -1; 8415e4f5c78SDavid du Colombier } 842d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){ 843d5789509SDavid du Colombier p = &ser->p[i]; 844d5789509SDavid du Colombier p->interfc = i; 845d5789509SDavid du Colombier p->s = ser; 846d5789509SDavid du Colombier p->fs = serialfs; 847d584e620SDavid du Colombier if(i == ser->jtag){ 848d584e620SDavid du Colombier p->isjtag++; 849d584e620SDavid du Colombier } 850d5789509SDavid du Colombier if(findendpoints(ser, i) < 0){ 851d5789509SDavid du Colombier werrstr("serial: no endpoints found for ifc %d", i); 85280e9508eSDavid du Colombier return -1; 85380e9508eSDavid du Colombier } 854d5789509SDavid du Colombier p->w4data = chancreate(sizeof(ulong), 0); 855d5789509SDavid du Colombier p->gotdata = chancreate(sizeof(ulong), 0); 856d5789509SDavid du Colombier } 857d5789509SDavid du Colombier 858d5789509SDavid du Colombier qlock(ser); 859d5789509SDavid du Colombier serialreset(ser); 860d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){ 861d5789509SDavid du Colombier p = &ser->p[i]; 862d5789509SDavid du Colombier dprint(2, "serial: valid interface, calling serinit\n"); 863d5789509SDavid du Colombier if(serinit(p) < 0){ 8645e4f5c78SDavid du Colombier dprint(2, "serial: serinit: %r\n"); 8655e4f5c78SDavid du Colombier return -1; 8665e4f5c78SDavid du Colombier } 8675e4f5c78SDavid du Colombier 868d5789509SDavid du Colombier dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p); 869d584e620SDavid du Colombier if(p->isjtag){ 870d584e620SDavid du Colombier snprint(p->name, sizeof p->name, "jtag"); 871d584e620SDavid du Colombier dsprint(2, "serial: JTAG interface %d %p\n", i, p); 872d584e620SDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "jtag%d.%d", devid, i); 873d584e620SDavid du Colombier } else { 874d584e620SDavid du Colombier snprint(p->name, sizeof p->name, "eiaU"); 875ed868a7cSDavid du Colombier if(i == 0) 876ed868a7cSDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "eiaU%d", devid); 877ed868a7cSDavid du Colombier else 878ed868a7cSDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i); 879d584e620SDavid du Colombier } 880c8a340cdSDavid du Colombier fprint(2, "%s...", p->fs.name); 881d5789509SDavid du Colombier p->fs.dev = dev; 8825e4f5c78SDavid du Colombier incref(dev); 883d5789509SDavid du Colombier p->fs.aux = p; 884d5789509SDavid du Colombier p->fs.end = serialfsend; 885d5789509SDavid du Colombier usbfsadd(&p->fs); 886d5789509SDavid du Colombier } 8875e4f5c78SDavid du Colombier 888d5789509SDavid du Colombier qunlock(ser); 8895e4f5c78SDavid du Colombier return 0; 8905e4f5c78SDavid du Colombier } 891