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, 35*d584e620SDavid du Colombier [Qdata] "%s", 0660, 36*d584e620SDavid 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 84d5789509SDavid du Colombier /* BUG: separate reset per port */ 855e4f5c78SDavid du Colombier int 865e4f5c78SDavid du Colombier serialreset(Serial *ser) 875e4f5c78SDavid du Colombier { 88d5789509SDavid du Colombier Serialport *p; 89d5789509SDavid du Colombier int i; 90d5789509SDavid du Colombier 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) 9780e9508eSDavid du Colombier ser->reset(ser); 985e4f5c78SDavid du Colombier return 0; 995e4f5c78SDavid du Colombier } 1005e4f5c78SDavid du Colombier 1015e4f5c78SDavid du Colombier /* call this if something goes wrong */ 1025e4f5c78SDavid du Colombier int 1035e4f5c78SDavid du Colombier serialrecover(Serial *ser, char *err) 1045e4f5c78SDavid du Colombier { 1055e4f5c78SDavid du Colombier if(strstr(err, "detached") != nil) 1065e4f5c78SDavid du Colombier return -1; 10716146bc9SDavid du Colombier if(ser->recover > 1) 1085e4f5c78SDavid du Colombier serialfatal(ser); 10916146bc9SDavid du Colombier ser->recover++; 1105e4f5c78SDavid du Colombier if(serialreset(ser) < 0) 1115e4f5c78SDavid du Colombier return -1; 11216146bc9SDavid du Colombier ser->recover = 0; 1135e4f5c78SDavid du Colombier return 0; 1145e4f5c78SDavid du Colombier } 1155e4f5c78SDavid du Colombier 1165e4f5c78SDavid du Colombier static int 117d5789509SDavid du Colombier serialctl(Serialport *p, char *cmd) 1185e4f5c78SDavid du Colombier { 119d5789509SDavid du Colombier Serial *ser; 1205e4f5c78SDavid du Colombier int c, i, n, nf, nop, nw, par, drain, set, lines; 1215e4f5c78SDavid du Colombier char *f[16]; 1225e4f5c78SDavid du Colombier uchar x; 1235e4f5c78SDavid du Colombier 124d5789509SDavid du Colombier ser = p->s; 1255e4f5c78SDavid du Colombier drain = set = lines = 0; 1265e4f5c78SDavid du Colombier nf = tokenize(cmd, f, nelem(f)); 1275e4f5c78SDavid du Colombier for(i = 0; i < nf; i++){ 1285e4f5c78SDavid du Colombier if(strncmp(f[i], "break", 5) == 0){ 129d5789509SDavid du Colombier if(ser->setbreak != nil) 130d5789509SDavid du Colombier ser->setbreak(p, 1); 1315e4f5c78SDavid du Colombier continue; 1325e4f5c78SDavid du Colombier } 1335e4f5c78SDavid du Colombier 1345e4f5c78SDavid du Colombier nop = 0; 1355e4f5c78SDavid du Colombier n = atoi(f[i]+1); 1365e4f5c78SDavid du Colombier c = *f[i]; 1375e4f5c78SDavid du Colombier if (isascii(c) && isupper(c)) 1385e4f5c78SDavid du Colombier c = tolower(c); 1395e4f5c78SDavid du Colombier switch(c){ 1405e4f5c78SDavid du Colombier case 'b': 1415e4f5c78SDavid du Colombier drain++; 1425e4f5c78SDavid du Colombier p->baud = n; 1435e4f5c78SDavid du Colombier set++; 1445e4f5c78SDavid du Colombier break; 1455e4f5c78SDavid du Colombier case 'c': 1465e4f5c78SDavid du Colombier p->dcd = n; 1475e4f5c78SDavid du Colombier // lines++; 1485e4f5c78SDavid du Colombier ++nop; 1495e4f5c78SDavid du Colombier break; 1505e4f5c78SDavid du Colombier case 'd': 1515e4f5c78SDavid du Colombier p->dtr = n; 1525e4f5c78SDavid du Colombier lines++; 1535e4f5c78SDavid du Colombier break; 1545e4f5c78SDavid du Colombier case 'e': 1555e4f5c78SDavid du Colombier p->dsr = n; 1565e4f5c78SDavid du Colombier // lines++; 1575e4f5c78SDavid du Colombier ++nop; 1585e4f5c78SDavid du Colombier break; 1595e4f5c78SDavid du Colombier case 'f': /* flush the pipes */ 1605e4f5c78SDavid du Colombier drain++; 1615e4f5c78SDavid du Colombier break; 1625e4f5c78SDavid du Colombier case 'h': /* hangup?? */ 1635e4f5c78SDavid du Colombier p->rts = p->dtr = 0; 1645e4f5c78SDavid du Colombier lines++; 1655e4f5c78SDavid du Colombier fprint(2, "serial: %c, unsure ctl\n", c); 1665e4f5c78SDavid du Colombier break; 1675e4f5c78SDavid du Colombier case 'i': 1685e4f5c78SDavid du Colombier ++nop; 1695e4f5c78SDavid du Colombier break; 1705e4f5c78SDavid du Colombier case 'k': 1715e4f5c78SDavid du Colombier drain++; 172d5789509SDavid du Colombier ser->setbreak(p, 1); 1735e4f5c78SDavid du Colombier sleep(n); 174d5789509SDavid du Colombier ser->setbreak(p, 0); 1755e4f5c78SDavid du Colombier break; 1765e4f5c78SDavid du Colombier case 'l': 1775e4f5c78SDavid du Colombier drain++; 1785e4f5c78SDavid du Colombier p->bits = n; 1795e4f5c78SDavid du Colombier set++; 1805e4f5c78SDavid du Colombier break; 1815e4f5c78SDavid du Colombier case 'm': 1825e4f5c78SDavid du Colombier drain++; 183d5789509SDavid du Colombier if(ser->modemctl != nil) 184d5789509SDavid du Colombier ser->modemctl(p, n); 1855e4f5c78SDavid du Colombier if(n == 0) 1865e4f5c78SDavid du Colombier p->cts = 0; 1875e4f5c78SDavid du Colombier break; 1885e4f5c78SDavid du Colombier case 'n': 1895e4f5c78SDavid du Colombier p->blocked = n; 1905e4f5c78SDavid du Colombier ++nop; 1915e4f5c78SDavid du Colombier break; 1925e4f5c78SDavid du Colombier case 'p': /* extended... */ 1935e4f5c78SDavid du Colombier if(strlen(f[i]) != 2) 1945e4f5c78SDavid du Colombier return -1; 1955e4f5c78SDavid du Colombier drain++; 19680e9508eSDavid du Colombier par = f[i][1]; 1975e4f5c78SDavid du Colombier if(par == 'n') 1985e4f5c78SDavid du Colombier p->parity = 0; 1995e4f5c78SDavid du Colombier else if(par == 'o') 2005e4f5c78SDavid du Colombier p->parity = 1; 2015e4f5c78SDavid du Colombier else if(par == 'e') 2025e4f5c78SDavid du Colombier p->parity = 2; 2035e4f5c78SDavid du Colombier else if(par == 'm') /* mark parity */ 2045e4f5c78SDavid du Colombier p->parity = 3; 2055e4f5c78SDavid du Colombier else if(par == 's') /* space parity */ 2065e4f5c78SDavid du Colombier p->parity = 4; 2075e4f5c78SDavid du Colombier else 2085e4f5c78SDavid du Colombier return -1; 2095e4f5c78SDavid du Colombier set++; 2105e4f5c78SDavid du Colombier break; 2115e4f5c78SDavid du Colombier case 'q': 2125e4f5c78SDavid du Colombier // drain++; 2135e4f5c78SDavid du Colombier p->limit = n; 2145e4f5c78SDavid du Colombier ++nop; 2155e4f5c78SDavid du Colombier break; 2165e4f5c78SDavid du Colombier case 'r': 2175e4f5c78SDavid du Colombier drain++; 2185e4f5c78SDavid du Colombier p->rts = n; 2195e4f5c78SDavid du Colombier lines++; 2205e4f5c78SDavid du Colombier break; 2215e4f5c78SDavid du Colombier case 's': 2225e4f5c78SDavid du Colombier drain++; 2235e4f5c78SDavid du Colombier p->stop = n; 2245e4f5c78SDavid du Colombier set++; 2255e4f5c78SDavid du Colombier break; 2265e4f5c78SDavid du Colombier case 'w': 2275e4f5c78SDavid du Colombier /* ?? how do I put this */ 2285e4f5c78SDavid du Colombier p->timer = n * 100000LL; 2295e4f5c78SDavid du Colombier ++nop; 2305e4f5c78SDavid du Colombier break; 2315e4f5c78SDavid du Colombier case 'x': 2325e4f5c78SDavid du Colombier if(n == 0) 2335e4f5c78SDavid du Colombier x = CTLS; 2345e4f5c78SDavid du Colombier else 2355e4f5c78SDavid du Colombier x = CTLQ; 236d5789509SDavid du Colombier if(ser->wait4write != nil) 237d5789509SDavid du Colombier nw = ser->wait4write(p, &x, 1); 23880e9508eSDavid du Colombier else 2395e4f5c78SDavid du Colombier nw = write(p->epout->dfd, &x, 1); 2405e4f5c78SDavid du Colombier if(nw != 1){ 241d5789509SDavid du Colombier serialrecover(ser, ""); 2425e4f5c78SDavid du Colombier return -1; 2435e4f5c78SDavid du Colombier } 2445e4f5c78SDavid du Colombier break; 2455e4f5c78SDavid du Colombier } 246ecc2a7c8SDavid du Colombier /* 247ecc2a7c8SDavid du Colombier * don't print. the condition is harmless and the print 248ecc2a7c8SDavid du Colombier * splatters all over the display. 249ecc2a7c8SDavid du Colombier */ 250ecc2a7c8SDavid du Colombier USED(nop); 251ecc2a7c8SDavid du Colombier if (0 && nop) 2525e4f5c78SDavid du Colombier fprint(2, "serial: %c, unsupported nop ctl\n", c); 2535e4f5c78SDavid du Colombier } 2545e4f5c78SDavid du Colombier if(drain) 2555e4f5c78SDavid du Colombier serialdrain(p); 25680e9508eSDavid du Colombier if(lines && !set){ 257d5789509SDavid du Colombier if(ser->sendlines != nil && ser->sendlines(p) < 0) 2585e4f5c78SDavid du Colombier return -1; 25980e9508eSDavid du Colombier } else if(set){ 260d5789509SDavid du Colombier if(ser->setparam != nil && ser->setparam(p) < 0) 26180e9508eSDavid du Colombier return -1; 26280e9508eSDavid du Colombier } 2635e4f5c78SDavid du Colombier return 0; 2645e4f5c78SDavid du Colombier } 2655e4f5c78SDavid du Colombier 2665e4f5c78SDavid du Colombier char *pformat = "noems"; 2675e4f5c78SDavid du Colombier 2685e4f5c78SDavid du Colombier char * 269d5789509SDavid du Colombier serdumpst(Serialport *p, char *buf, int bufsz) 2705e4f5c78SDavid du Colombier { 2715e4f5c78SDavid du Colombier char *e, *s; 272d5789509SDavid du Colombier Serial *ser; 273d5789509SDavid du Colombier 274d5789509SDavid du Colombier ser = p->s; 2755e4f5c78SDavid du Colombier 2765e4f5c78SDavid du Colombier e = buf + bufsz; 277d5789509SDavid du Colombier s = seprint(buf, e, "b%d ", p->baud); 278d5789509SDavid du Colombier s = seprint(s, e, "c%d ", p->dcd); /* unimplemented */ 279d5789509SDavid du Colombier s = seprint(s, e, "d%d ", p->dtr); 280d5789509SDavid du Colombier s = seprint(s, e, "e%d ", p->dsr); /* unimplemented */ 281d5789509SDavid du Colombier s = seprint(s, e, "l%d ", p->bits); 282d5789509SDavid du Colombier s = seprint(s, e, "m%d ", p->mctl); 283d5789509SDavid du Colombier if(p->parity >= 0 || p->parity < strlen(pformat)) 284d5789509SDavid du Colombier s = seprint(s, e, "p%c ", pformat[p->parity]); 2855e4f5c78SDavid du Colombier else 2865e4f5c78SDavid du Colombier s = seprint(s, e, "p%c ", '?'); 287d5789509SDavid du Colombier s = seprint(s, e, "r%d ", p->rts); 288d5789509SDavid du Colombier s = seprint(s, e, "s%d ", p->stop); 289d5789509SDavid du Colombier s = seprint(s, e, "i%d ", p->fifo); 2905e4f5c78SDavid du Colombier s = seprint(s, e, "\ndev(%d) ", 0); 2915e4f5c78SDavid du Colombier s = seprint(s, e, "type(%d) ", ser->type); 292d5789509SDavid du Colombier s = seprint(s, e, "framing(%d) ", p->nframeerr); 293d5789509SDavid du Colombier s = seprint(s, e, "overruns(%d) ", p->novererr); 294d5789509SDavid du Colombier s = seprint(s, e, "berr(%d) ", p->nbreakerr); 295ed868a7cSDavid du Colombier s = seprint(s, e, " serr(%d)\n", p->nparityerr); 2965e4f5c78SDavid du Colombier return s; 2975e4f5c78SDavid du Colombier } 2985e4f5c78SDavid du Colombier 2995e4f5c78SDavid du Colombier static int 300d5789509SDavid du Colombier serinit(Serialport *p) 3015e4f5c78SDavid du Colombier { 3025e4f5c78SDavid du Colombier int res; 30380e9508eSDavid du Colombier res = 0; 304d5789509SDavid du Colombier Serial *ser; 305d5789509SDavid du Colombier 306d5789509SDavid du Colombier ser = p->s; 307d5789509SDavid du Colombier 30880e9508eSDavid du Colombier if(ser->init != nil) 309d5789509SDavid du Colombier res = ser->init(p); 31080e9508eSDavid du Colombier if(ser->getparam != nil) 311d5789509SDavid du Colombier ser->getparam(p); 312d5789509SDavid du Colombier p->nframeerr = p->nparityerr = p->nbreakerr = p->novererr = 0; 313d5789509SDavid du Colombier 3145e4f5c78SDavid du Colombier return res; 3155e4f5c78SDavid du Colombier } 3165e4f5c78SDavid du Colombier 3175e4f5c78SDavid du Colombier static int 3185e4f5c78SDavid du Colombier dwalk(Usbfs *fs, Fid *fid, char *name) 3195e4f5c78SDavid du Colombier { 3205e4f5c78SDavid du Colombier int i; 3215e4f5c78SDavid du Colombier char *dname; 3225e4f5c78SDavid du Colombier Qid qid; 323d5789509SDavid du Colombier Serialport *p; 3245e4f5c78SDavid du Colombier 3255e4f5c78SDavid du Colombier qid = fid->qid; 3265e4f5c78SDavid du Colombier if((qid.type & QTDIR) == 0){ 3275e4f5c78SDavid du Colombier werrstr("walk in non-directory"); 3285e4f5c78SDavid du Colombier return -1; 3295e4f5c78SDavid du Colombier } 3305e4f5c78SDavid du Colombier 3315e4f5c78SDavid du Colombier if(strcmp(name, "..") == 0){ 3325e4f5c78SDavid du Colombier /* must be /eiaU%d; i.e. our root dir. */ 3335e4f5c78SDavid du Colombier fid->qid.path = Qroot | fs->qid; 3345e4f5c78SDavid du Colombier fid->qid.vers = 0; 3355e4f5c78SDavid du Colombier fid->qid.type = QTDIR; 3365e4f5c78SDavid du Colombier return 0; 3375e4f5c78SDavid du Colombier } 3385e4f5c78SDavid du Colombier 339d5789509SDavid du Colombier p = fs->aux; 3405e4f5c78SDavid du Colombier for(i = 1; i < nelem(dirtab); i++){ 341*d584e620SDavid du Colombier dname = smprint(dirtab[i].name, p->name); 3425e4f5c78SDavid du Colombier if(strcmp(name, dname) == 0){ 3435e4f5c78SDavid du Colombier qid.path = i | fs->qid; 3445e4f5c78SDavid du Colombier qid.vers = 0; 3455e4f5c78SDavid du Colombier qid.type = dirtab[i].mode >> 24; 3465e4f5c78SDavid du Colombier fid->qid = qid; 3475e4f5c78SDavid du Colombier free(dname); 3485e4f5c78SDavid du Colombier return 0; 3495e4f5c78SDavid du Colombier } else 3505e4f5c78SDavid du Colombier free(dname); 3515e4f5c78SDavid du Colombier } 3525e4f5c78SDavid du Colombier werrstr(Enotfound); 3535e4f5c78SDavid du Colombier return -1; 3545e4f5c78SDavid du Colombier } 3555e4f5c78SDavid du Colombier 3565e4f5c78SDavid du Colombier static void 3575e4f5c78SDavid du Colombier dostat(Usbfs *fs, int path, Dir *d) 3585e4f5c78SDavid du Colombier { 3595e4f5c78SDavid du Colombier Dirtab *t; 360d5789509SDavid du Colombier Serialport *p; 3615e4f5c78SDavid du Colombier 3625e4f5c78SDavid du Colombier t = &dirtab[path]; 3635e4f5c78SDavid du Colombier d->qid.path = path; 3645e4f5c78SDavid du Colombier d->qid.type = t->mode >> 24; 3655e4f5c78SDavid du Colombier d->mode = t->mode; 366d5789509SDavid du Colombier p = fs->aux; 3675e4f5c78SDavid du Colombier 3685e4f5c78SDavid du Colombier if(strcmp(t->name, "/") == 0) 3695e4f5c78SDavid du Colombier d->name = t->name; 3705e4f5c78SDavid du Colombier else 371d5789509SDavid du Colombier snprint(d->name, Namesz, t->name, p->fs.name); 3725e4f5c78SDavid du Colombier d->length = 0; 3735e4f5c78SDavid du Colombier } 3745e4f5c78SDavid du Colombier 3755e4f5c78SDavid du Colombier static int 3765e4f5c78SDavid du Colombier dstat(Usbfs *fs, Qid qid, Dir *d) 3775e4f5c78SDavid du Colombier { 3785e4f5c78SDavid du Colombier int path; 3795e4f5c78SDavid du Colombier 3805e4f5c78SDavid du Colombier path = qid.path & ~fs->qid; 3815e4f5c78SDavid du Colombier dostat(fs, path, d); 3825e4f5c78SDavid du Colombier d->qid.path |= fs->qid; 3835e4f5c78SDavid du Colombier return 0; 3845e4f5c78SDavid du Colombier } 3855e4f5c78SDavid du Colombier 3865e4f5c78SDavid du Colombier static int 3875e4f5c78SDavid du Colombier dopen(Usbfs *fs, Fid *fid, int) 3885e4f5c78SDavid du Colombier { 3895e4f5c78SDavid du Colombier ulong path; 390ed868a7cSDavid du Colombier Serialport *p; 3915e4f5c78SDavid du Colombier 3925e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid; 393ed868a7cSDavid du Colombier p = fs->aux; 3945e4f5c78SDavid du Colombier switch(path){ /* BUG: unneeded? */ 3955e4f5c78SDavid du Colombier case Qdata: 3964d52e0f0SDavid du Colombier dsprint(2, "serial, opened data\n"); 3975e4f5c78SDavid du Colombier break; 3985e4f5c78SDavid du Colombier case Qctl: 3994d52e0f0SDavid du Colombier dsprint(2, "serial, opened ctl\n"); 400*d584e620SDavid du Colombier if(p->isjtag) 401*d584e620SDavid du Colombier return 0; 402ed868a7cSDavid du Colombier serialctl(p, "l8 i1"); /* default line parameters */ 4035e4f5c78SDavid du Colombier break; 4045e4f5c78SDavid du Colombier } 4055e4f5c78SDavid du Colombier return 0; 4065e4f5c78SDavid du Colombier } 4075e4f5c78SDavid du Colombier 4085e4f5c78SDavid du Colombier 4095e4f5c78SDavid du Colombier static void 410*d584e620SDavid du Colombier filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i, void *v) 4115e4f5c78SDavid du Colombier { 412*d584e620SDavid du Colombier Serialport *p; 413*d584e620SDavid du Colombier 414*d584e620SDavid du Colombier p = v; 4155e4f5c78SDavid du Colombier d->qid.path = i | fs->qid; 4165e4f5c78SDavid du Colombier d->mode = tab->mode; 4175e4f5c78SDavid du Colombier if((d->mode & DMDIR) != 0) 4185e4f5c78SDavid du Colombier d->qid.type = QTDIR; 4195e4f5c78SDavid du Colombier else 4205e4f5c78SDavid du Colombier d->qid.type = QTFILE; 421*d584e620SDavid du Colombier sprint(d->name, tab->name, p->name); /* hope it fits */ 4225e4f5c78SDavid du Colombier } 4235e4f5c78SDavid du Colombier 4245e4f5c78SDavid du Colombier static int 425*d584e620SDavid du Colombier dirgen(Usbfs *fs, Qid, int i, Dir *d, void *p) 4265e4f5c78SDavid du Colombier { 4275e4f5c78SDavid du Colombier i++; /* skip root */ 42880e9508eSDavid du Colombier if(i >= nelem(dirtab)) 4295e4f5c78SDavid du Colombier return -1; 430*d584e620SDavid du Colombier filldir(fs, d, &dirtab[i], i, p); 4315e4f5c78SDavid du Colombier return 0; 4325e4f5c78SDavid du Colombier } 4335e4f5c78SDavid du Colombier 434bfb6eab9SDavid du Colombier enum { 435bfb6eab9SDavid du Colombier Serbufsize = 255, 436bfb6eab9SDavid du Colombier }; 437bfb6eab9SDavid du Colombier 4385e4f5c78SDavid du Colombier static long 4395e4f5c78SDavid du Colombier dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) 4405e4f5c78SDavid du Colombier { 4415e4f5c78SDavid du Colombier int dfd; 4425e4f5c78SDavid du Colombier long rcount; 4435e4f5c78SDavid du Colombier ulong path; 44480e9508eSDavid du Colombier char *e, *buf, *err; /* change */ 4455e4f5c78SDavid du Colombier Qid q; 446d5789509SDavid du Colombier Serialport *p; 4475e4f5c78SDavid du Colombier Serial *ser; 448ecc2a7c8SDavid du Colombier static int errrun, good; 4495e4f5c78SDavid du Colombier 4505e4f5c78SDavid du Colombier q = fid->qid; 4515e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid; 452d5789509SDavid du Colombier p = fs->aux; 453d5789509SDavid du Colombier ser = p->s; 4545e4f5c78SDavid du Colombier 455bfb6eab9SDavid du Colombier buf = emallocz(Serbufsize, 1); 456bfb6eab9SDavid du Colombier err = emallocz(Serbufsize, 1); 4575e4f5c78SDavid du Colombier qlock(ser); 4585e4f5c78SDavid du Colombier switch(path){ 4595e4f5c78SDavid du Colombier case Qroot: 460*d584e620SDavid du Colombier count = usbdirread(fs, q, data, count, offset, dirgen, p); 4615e4f5c78SDavid du Colombier break; 4625e4f5c78SDavid du Colombier case Qdata: 46380e9508eSDavid du Colombier if(count > ser->maxread) 46480e9508eSDavid du Colombier count = ser->maxread; 46580e9508eSDavid du Colombier dsprint(2, "serial: reading from data\n"); 4665e4f5c78SDavid du Colombier do { 4674d52e0f0SDavid du Colombier err[0] = 0; 468d5789509SDavid du Colombier dfd = p->epin->dfd; 46980e9508eSDavid du Colombier if(usbdebug >= 3) 47080e9508eSDavid du Colombier dsprint(2, "serial: reading: %ld\n", count); 47180e9508eSDavid du Colombier 472ecc2a7c8SDavid du Colombier assert(count > 0); 47380e9508eSDavid du Colombier if(ser->wait4data != nil) 474d5789509SDavid du Colombier rcount = ser->wait4data(p, data, count); 47580e9508eSDavid du Colombier else{ 47680e9508eSDavid du Colombier qunlock(ser); 4775e4f5c78SDavid du Colombier rcount = read(dfd, data, count); 4785e4f5c78SDavid du Colombier qlock(ser); 47980e9508eSDavid du Colombier } 48025fc6993SDavid du Colombier /* 48125fc6993SDavid du Colombier * if we encounter a long run of continuous read 48225fc6993SDavid du Colombier * errors, do something drastic so that our caller 48325fc6993SDavid du Colombier * doesn't just spin its wheels forever. 48425fc6993SDavid du Colombier */ 48525fc6993SDavid du Colombier if(rcount < 0) { 486bfb6eab9SDavid du Colombier snprint(err, Serbufsize, "%r"); 487ecc2a7c8SDavid du Colombier ++errrun; 488ecc2a7c8SDavid du Colombier sleep(20); 489ecc2a7c8SDavid du Colombier if (good > 0 && errrun > 10000) { 49025fc6993SDavid du Colombier /* the line has been dropped; give up */ 49125fc6993SDavid du Colombier qunlock(ser); 492ecc2a7c8SDavid du Colombier fprint(2, "%s: line %s is gone: %r\n", 493d5789509SDavid du Colombier argv0, p->fs.name); 49425fc6993SDavid du Colombier threadexitsall("serial line gone"); 49525fc6993SDavid du Colombier } 496ecc2a7c8SDavid du Colombier } else { 49725fc6993SDavid du Colombier errrun = 0; 498ecc2a7c8SDavid du Colombier good++; 499ecc2a7c8SDavid du Colombier } 50080e9508eSDavid du Colombier if(usbdebug >= 3) 50180e9508eSDavid du Colombier dsprint(2, "serial: read: %s %ld\n", err, rcount); 5025e4f5c78SDavid du Colombier } while(rcount < 0 && strstr(err, "timed out") != nil); 5035e4f5c78SDavid du Colombier 50480e9508eSDavid du Colombier dsprint(2, "serial: read from bulk %ld, %10.10s\n", rcount, err); 5055e4f5c78SDavid du Colombier if(rcount < 0){ 5065e4f5c78SDavid du Colombier dsprint(2, "serial: need to recover, data read %ld %r\n", 5075e4f5c78SDavid du Colombier count); 5085e4f5c78SDavid du Colombier serialrecover(ser, err); 5095e4f5c78SDavid du Colombier } 51080e9508eSDavid du Colombier dsprint(2, "serial: read from bulk %ld\n", rcount); 5115e4f5c78SDavid du Colombier count = rcount; 5125e4f5c78SDavid du Colombier break; 5135e4f5c78SDavid du Colombier case Qctl: 51480e9508eSDavid du Colombier if(offset != 0) 5155e4f5c78SDavid du Colombier count = 0; 51680e9508eSDavid du Colombier else { 517*d584e620SDavid du Colombier if(!p->isjtag){ 518d5789509SDavid du Colombier e = serdumpst(p, buf, Serbufsize); 5195e4f5c78SDavid du Colombier count = usbreadbuf(data, count, 0, buf, e - buf); 52080e9508eSDavid du Colombier } 521*d584e620SDavid du Colombier } 5225e4f5c78SDavid du Colombier break; 5235e4f5c78SDavid du Colombier } 5245e4f5c78SDavid du Colombier qunlock(ser); 5255e4f5c78SDavid du Colombier free(err); 5265e4f5c78SDavid du Colombier free(buf); 5275e4f5c78SDavid du Colombier return count; 5285e4f5c78SDavid du Colombier } 5295e4f5c78SDavid du Colombier 5305e4f5c78SDavid du Colombier static long 531d5789509SDavid du Colombier altwrite(Serialport *p, uchar *buf, long count) 53280e9508eSDavid du Colombier { 53380e9508eSDavid du Colombier int nw, dfd; 53480e9508eSDavid du Colombier char err[128]; 535d5789509SDavid du Colombier Serial *ser; 53680e9508eSDavid du Colombier 537d5789509SDavid du Colombier ser = p->s; 53880e9508eSDavid du Colombier do{ 539*d584e620SDavid du Colombier dsprint(2, "serial: write to bulk %ld\n", count); 540*d584e620SDavid du Colombier 54180e9508eSDavid du Colombier if(ser->wait4write != nil) 54280e9508eSDavid du Colombier /* unlocked inside later */ 543d5789509SDavid du Colombier nw = ser->wait4write(p, buf, count); 54480e9508eSDavid du Colombier else{ 545d5789509SDavid du Colombier dfd = p->epout->dfd; 54680e9508eSDavid du Colombier qunlock(ser); 54780e9508eSDavid du Colombier nw = write(dfd, buf, count); 54880e9508eSDavid du Colombier qlock(ser); 54980e9508eSDavid du Colombier } 55080e9508eSDavid du Colombier rerrstr(err, sizeof err); 551*d584e620SDavid du Colombier dsprint(2, "serial: written %s %d\n", err, nw); 55280e9508eSDavid du Colombier } while(nw < 0 && strstr(err, "timed out") != nil); 55380e9508eSDavid du Colombier 55480e9508eSDavid du Colombier if(nw != count){ 55580e9508eSDavid du Colombier dsprint(2, "serial: need to recover, status in write %d %r\n", 55680e9508eSDavid du Colombier nw); 55780e9508eSDavid du Colombier snprint(err, sizeof err, "%r"); 558d5789509SDavid du Colombier serialrecover(p->s, err); 55980e9508eSDavid du Colombier } 56080e9508eSDavid du Colombier return nw; 56180e9508eSDavid du Colombier } 56280e9508eSDavid du Colombier 56380e9508eSDavid du Colombier static long 5645e4f5c78SDavid du Colombier dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong) 5655e4f5c78SDavid du Colombier { 5665e4f5c78SDavid du Colombier ulong path; 5675e4f5c78SDavid du Colombier char *cmd; 568d5789509SDavid du Colombier Serialport *p; 5695e4f5c78SDavid du Colombier Serial *ser; 5705e4f5c78SDavid du Colombier 571d5789509SDavid du Colombier p = fs->aux; 572d5789509SDavid du Colombier ser = p->s; 5735e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid; 5745e4f5c78SDavid du Colombier 5755e4f5c78SDavid du Colombier qlock(ser); 5765e4f5c78SDavid du Colombier switch(path){ 5775e4f5c78SDavid du Colombier case Qdata: 578d5789509SDavid du Colombier count = altwrite(p, (uchar *)buf, count); 5795e4f5c78SDavid du Colombier break; 5805e4f5c78SDavid du Colombier case Qctl: 581*d584e620SDavid du Colombier if(p->isjtag) 582*d584e620SDavid du Colombier break; 5835e4f5c78SDavid du Colombier cmd = emallocz(count+1, 1); 5845e4f5c78SDavid du Colombier memmove(cmd, buf, count); 5855e4f5c78SDavid du Colombier cmd[count] = 0; 586d5789509SDavid du Colombier if(serialctl(p, cmd) < 0){ 5875e4f5c78SDavid du Colombier qunlock(ser); 5885e4f5c78SDavid du Colombier werrstr(Ebadctl); 5895e4f5c78SDavid du Colombier free(cmd); 5905e4f5c78SDavid du Colombier return -1; 5915e4f5c78SDavid du Colombier } 5925e4f5c78SDavid du Colombier free(cmd); 5935e4f5c78SDavid du Colombier break; 5945e4f5c78SDavid du Colombier default: 5955e4f5c78SDavid du Colombier qunlock(ser); 5965e4f5c78SDavid du Colombier werrstr(Eperm); 5975e4f5c78SDavid du Colombier return -1; 5985e4f5c78SDavid du Colombier } 5995e4f5c78SDavid du Colombier qunlock(ser); 6005e4f5c78SDavid du Colombier return count; 6015e4f5c78SDavid du Colombier } 6025e4f5c78SDavid du Colombier 6035e4f5c78SDavid du Colombier static int 604d5789509SDavid du Colombier openeps(Serialport *p, int epin, int epout, int epintr) 6055e4f5c78SDavid du Colombier { 606d5789509SDavid du Colombier Serial *ser; 607d5789509SDavid du Colombier 608d5789509SDavid du Colombier ser = p->s; 609d5789509SDavid du Colombier p->epin = openep(ser->dev, epin); 610d5789509SDavid du Colombier if(p->epin == nil){ 6115e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epin); 6125e4f5c78SDavid du Colombier return -1; 6135e4f5c78SDavid du Colombier } 614d5789509SDavid du Colombier p->epout = openep(ser->dev, epout); 615d5789509SDavid du Colombier if(p->epout == nil){ 6165e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epout); 617d5789509SDavid du Colombier closedev(p->epin); 6185e4f5c78SDavid du Colombier return -1; 6195e4f5c78SDavid du Colombier } 6204d52e0f0SDavid du Colombier 621*d584e620SDavid du Colombier if(!p->isjtag){ 622d5789509SDavid du Colombier devctl(p->epin, "timeout 1000"); 623d5789509SDavid du Colombier devctl(p->epout, "timeout 1000"); 624*d584e620SDavid du Colombier } 6254d52e0f0SDavid du Colombier 6264d52e0f0SDavid du Colombier if(ser->hasepintr){ 627d5789509SDavid du Colombier p->epintr = openep(ser->dev, epintr); 628d5789509SDavid du Colombier if(p->epintr == nil){ 6295e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epintr); 630d5789509SDavid du Colombier closedev(p->epin); 631d5789509SDavid du Colombier closedev(p->epout); 6325e4f5c78SDavid du Colombier return -1; 6335e4f5c78SDavid du Colombier } 634d5789509SDavid du Colombier opendevdata(p->epintr, OREAD); 635d5789509SDavid du Colombier devctl(p->epintr, "timeout 1000"); 6364d52e0f0SDavid du Colombier } 6375e4f5c78SDavid du Colombier 63880e9508eSDavid du Colombier if(ser->seteps!= nil) 639d5789509SDavid du Colombier ser->seteps(p); 640d5789509SDavid du Colombier opendevdata(p->epin, OREAD); 641d5789509SDavid du Colombier opendevdata(p->epout, OWRITE); 642d5789509SDavid du Colombier if(p->epin->dfd < 0 ||p->epout->dfd < 0 || 643d5789509SDavid du Colombier (ser->hasepintr && p->epintr->dfd < 0)){ 6445e4f5c78SDavid du Colombier fprint(2, "serial: open i/o ep data: %r\n"); 645d5789509SDavid du Colombier closedev(p->epin); 646d5789509SDavid du Colombier closedev(p->epout); 6474d52e0f0SDavid du Colombier if(ser->hasepintr) 648d5789509SDavid du Colombier closedev(p->epintr); 6495e4f5c78SDavid du Colombier return -1; 6505e4f5c78SDavid du Colombier } 6515e4f5c78SDavid du Colombier return 0; 6525e4f5c78SDavid du Colombier } 6535e4f5c78SDavid du Colombier 6545e4f5c78SDavid du Colombier static int 655d5789509SDavid du Colombier findendpoints(Serial *ser, int ifc) 6565e4f5c78SDavid du Colombier { 6575e4f5c78SDavid du Colombier int i, epin, epout, epintr; 65880e9508eSDavid du Colombier Ep *ep, **eps; 6595e4f5c78SDavid du Colombier 6605e4f5c78SDavid du Colombier epintr = epin = epout = -1; 66180e9508eSDavid du Colombier 66280e9508eSDavid du Colombier /* 66380e9508eSDavid du Colombier * interfc 0 means start from the start which is equiv to 66480e9508eSDavid du Colombier * iterate through endpoints probably, could be done better 66580e9508eSDavid du Colombier */ 666d5789509SDavid du Colombier eps = ser->dev->usb->conf[0]->iface[ifc]->ep; 66780e9508eSDavid du Colombier 66880e9508eSDavid du Colombier for(i = 0; i < Niface; i++){ 66980e9508eSDavid du Colombier if((ep = eps[i]) == nil) 6705e4f5c78SDavid du Colombier continue; 67180e9508eSDavid du Colombier if(ser->hasepintr && ep->type == Eintr && 67280e9508eSDavid du Colombier ep->dir == Ein && epintr == -1) 6735e4f5c78SDavid du Colombier epintr = ep->id; 6745e4f5c78SDavid du Colombier if(ep->type == Ebulk){ 6755e4f5c78SDavid du Colombier if(ep->dir == Ein && epin == -1) 6765e4f5c78SDavid du Colombier epin = ep->id; 6775e4f5c78SDavid du Colombier if(ep->dir == Eout && epout == -1) 6785e4f5c78SDavid du Colombier epout = ep->id; 6795e4f5c78SDavid du Colombier } 6805e4f5c78SDavid du Colombier } 681d5789509SDavid du Colombier dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr); 6824d52e0f0SDavid du Colombier if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1)) 6835e4f5c78SDavid du Colombier return -1; 6844d52e0f0SDavid du Colombier 685d5789509SDavid du Colombier if(openeps(&ser->p[ifc], epin, epout, epintr) < 0) 6865e4f5c78SDavid du Colombier return -1; 6875e4f5c78SDavid du Colombier 688d5789509SDavid du Colombier dprint(2, "serial: ep in %s out %s\n", ser->p[ifc].epin->dir, ser->p[ifc].epout->dir); 6894d52e0f0SDavid du Colombier if(ser->hasepintr) 690d5789509SDavid du Colombier dprint(2, "serial: ep intr %s\n", ser->p[ifc].epintr->dir); 6915e4f5c78SDavid du Colombier 6925e4f5c78SDavid du Colombier if(usbdebug > 1 || serialdebug > 2){ 693d5789509SDavid du Colombier devctl(ser->p[ifc].epin, "debug 1"); 694d5789509SDavid du Colombier devctl(ser->p[ifc].epout, "debug 1"); 6954d52e0f0SDavid du Colombier if(ser->hasepintr) 696d5789509SDavid du Colombier devctl(ser->p[ifc].epintr, "debug 1"); 6975e4f5c78SDavid du Colombier devctl(ser->dev, "debug 1"); 6985e4f5c78SDavid du Colombier } 6995e4f5c78SDavid du Colombier return 0; 7005e4f5c78SDavid du Colombier } 7015e4f5c78SDavid du Colombier 70280e9508eSDavid du Colombier /* keep in sync with main.c */ 7035e4f5c78SDavid du Colombier static int 7045e4f5c78SDavid du Colombier usage(void) 7055e4f5c78SDavid du Colombier { 70680e9508eSDavid du Colombier werrstr("usage: usb/serial [-dD] [-m mtpt] [-s srv]"); 7075e4f5c78SDavid du Colombier return -1; 7085e4f5c78SDavid du Colombier } 7095e4f5c78SDavid du Colombier 7105e4f5c78SDavid du Colombier static void 7115e4f5c78SDavid du Colombier serdevfree(void *a) 7125e4f5c78SDavid du Colombier { 7135e4f5c78SDavid du Colombier Serial *ser = a; 714d5789509SDavid du Colombier Serialport *p; 715d5789509SDavid du Colombier int i; 7165e4f5c78SDavid du Colombier 7175e4f5c78SDavid du Colombier if(ser == nil) 7185e4f5c78SDavid du Colombier return; 719d5789509SDavid du Colombier 720d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){ 721d5789509SDavid du Colombier p = &ser->p[i]; 722d5789509SDavid du Colombier 7234d52e0f0SDavid du Colombier if(ser->hasepintr) 724d5789509SDavid du Colombier closedev(p->epintr); 725d5789509SDavid du Colombier closedev(p->epin); 726d5789509SDavid du Colombier closedev(p->epout); 727d5789509SDavid du Colombier p->epintr = p->epin = p->epout = nil; 728d5789509SDavid du Colombier if(p->w4data != nil) 729d5789509SDavid du Colombier chanfree(p->w4data); 730d5789509SDavid du Colombier if(p->gotdata != nil) 731d5789509SDavid du Colombier chanfree(p->gotdata); 732d5789509SDavid du Colombier if(p->readc) 733d5789509SDavid du Colombier chanfree(p->readc); 734d5789509SDavid du Colombier 735d5789509SDavid du Colombier } 7365e4f5c78SDavid du Colombier free(ser); 7375e4f5c78SDavid du Colombier } 7385e4f5c78SDavid du Colombier 7395e4f5c78SDavid du Colombier static Usbfs serialfs = { 7405e4f5c78SDavid du Colombier .walk = dwalk, 7415e4f5c78SDavid du Colombier .open = dopen, 7425e4f5c78SDavid du Colombier .read = dread, 7435e4f5c78SDavid du Colombier .write= dwrite, 7445e4f5c78SDavid du Colombier .stat = dstat, 7455e4f5c78SDavid du Colombier }; 7465e4f5c78SDavid du Colombier 747d5789509SDavid du Colombier static void 748d5789509SDavid du Colombier serialfsend(Usbfs *fs) 749d5789509SDavid du Colombier { 750d5789509SDavid du Colombier Serialport *p; 751d5789509SDavid du Colombier 752d5789509SDavid du Colombier p = fs->aux; 753d5789509SDavid du Colombier 754d5789509SDavid du Colombier if(p->w4data != nil) 755d5789509SDavid du Colombier chanclose(p->w4data); 756d5789509SDavid du Colombier if(p->gotdata != nil) 757d5789509SDavid du Colombier chanclose(p->gotdata); 758d5789509SDavid du Colombier if(p->readc) 759d5789509SDavid du Colombier chanclose(p->readc); 760d5789509SDavid du Colombier } 761d5789509SDavid du Colombier 7625e4f5c78SDavid du Colombier int 7635e4f5c78SDavid du Colombier serialmain(Dev *dev, int argc, char* argv[]) 7645e4f5c78SDavid du Colombier { 7655e4f5c78SDavid du Colombier Serial *ser; 766d5789509SDavid du Colombier Serialport *p; 7674d52e0f0SDavid du Colombier char buf[50]; 768ed868a7cSDavid du Colombier int i, devid; 7695e4f5c78SDavid du Colombier 770ed868a7cSDavid du Colombier devid = dev->id; 7715e4f5c78SDavid du Colombier ARGBEGIN{ 7725e4f5c78SDavid du Colombier case 'd': 7735e4f5c78SDavid du Colombier serialdebug++; 7745e4f5c78SDavid du Colombier break; 775ed868a7cSDavid du Colombier case 'N': 776ed868a7cSDavid du Colombier devid = atoi(EARGF(usage())); 777ed868a7cSDavid du Colombier break; 7785e4f5c78SDavid du Colombier default: 7795e4f5c78SDavid du Colombier return usage(); 7805e4f5c78SDavid du Colombier }ARGEND 7815e4f5c78SDavid du Colombier if(argc != 0) 7825e4f5c78SDavid du Colombier return usage(); 7835e4f5c78SDavid du Colombier 7845e4f5c78SDavid du Colombier ser = dev->aux = emallocz(sizeof(Serial), 1); 785d5789509SDavid du Colombier ser->maxrtrans = ser->maxwtrans = sizeof ser->p[0].data; 786d5789509SDavid du Colombier ser->maxread = ser->maxwrite = sizeof ser->p[0].data; 7875e4f5c78SDavid du Colombier ser->dev = dev; 7885e4f5c78SDavid du Colombier dev->free = serdevfree; 789d5789509SDavid du Colombier ser->jtag = -1; 790d5789509SDavid du Colombier ser->nifcs = 1; 7914d52e0f0SDavid du Colombier 7924d52e0f0SDavid du Colombier snprint(buf, sizeof buf, "vid %#06x did %#06x", 7934d52e0f0SDavid du Colombier dev->usb->vid, dev->usb->did); 7944d52e0f0SDavid du Colombier if(plmatch(buf) == 0){ 7954d52e0f0SDavid du Colombier ser->hasepintr = 1; 7964d52e0f0SDavid du Colombier ser->Serialops = plops; 79780e9508eSDavid du Colombier } else if(uconsmatch(buf) == 0) 7984d52e0f0SDavid du Colombier ser->Serialops = uconsops; 79980e9508eSDavid du Colombier else if(ftmatch(ser, buf) == 0) 80080e9508eSDavid du Colombier ser->Serialops = ftops; 80180e9508eSDavid du Colombier else { 80280e9508eSDavid du Colombier werrstr("serial: no serial devices found"); 8035e4f5c78SDavid du Colombier return -1; 8045e4f5c78SDavid du Colombier } 8055e4f5c78SDavid du Colombier 806d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){ 807d5789509SDavid du Colombier p = &ser->p[i]; 808d5789509SDavid du Colombier p->interfc = i; 809d5789509SDavid du Colombier p->s = ser; 810d5789509SDavid du Colombier p->fs = serialfs; 811*d584e620SDavid du Colombier if(i == ser->jtag){ 812*d584e620SDavid du Colombier p->isjtag++; 813*d584e620SDavid du Colombier } 814d5789509SDavid du Colombier if(findendpoints(ser, i) < 0){ 815d5789509SDavid du Colombier werrstr("serial: no endpoints found for ifc %d", i); 81680e9508eSDavid du Colombier return -1; 81780e9508eSDavid du Colombier } 818d5789509SDavid du Colombier p->w4data = chancreate(sizeof(ulong), 0); 819d5789509SDavid du Colombier p->gotdata = chancreate(sizeof(ulong), 0); 820d5789509SDavid du Colombier } 821d5789509SDavid du Colombier 822d5789509SDavid du Colombier qlock(ser); 823d5789509SDavid du Colombier serialreset(ser); 824d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){ 825d5789509SDavid du Colombier p = &ser->p[i]; 826d5789509SDavid du Colombier dprint(2, "serial: valid interface, calling serinit\n"); 827d5789509SDavid du Colombier if(serinit(p) < 0){ 8285e4f5c78SDavid du Colombier dprint(2, "serial: serinit: %r\n"); 8295e4f5c78SDavid du Colombier return -1; 8305e4f5c78SDavid du Colombier } 8315e4f5c78SDavid du Colombier 832d5789509SDavid du Colombier dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p); 833*d584e620SDavid du Colombier if(p->isjtag){ 834*d584e620SDavid du Colombier snprint(p->name, sizeof p->name, "jtag"); 835*d584e620SDavid du Colombier dsprint(2, "serial: JTAG interface %d %p\n", i, p); 836*d584e620SDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "jtag%d.%d", devid, i); 837*d584e620SDavid du Colombier } else { 838*d584e620SDavid du Colombier snprint(p->name, sizeof p->name, "eiaU"); 839ed868a7cSDavid du Colombier if(i == 0) 840ed868a7cSDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "eiaU%d", devid); 841ed868a7cSDavid du Colombier else 842ed868a7cSDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i); 843*d584e620SDavid du Colombier } 844d5789509SDavid du Colombier fprint(2, "%s\n", p->fs.name); 845d5789509SDavid du Colombier p->fs.dev = dev; 8465e4f5c78SDavid du Colombier incref(dev); 847d5789509SDavid du Colombier p->fs.aux = p; 848d5789509SDavid du Colombier p->fs.end = serialfsend; 849d5789509SDavid du Colombier usbfsadd(&p->fs); 850d5789509SDavid du Colombier } 8515e4f5c78SDavid du Colombier 852d5789509SDavid du Colombier qunlock(ser); 8535e4f5c78SDavid du Colombier return 0; 8545e4f5c78SDavid du Colombier } 855