123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900 |
- /*
- * This part takes care of locking except for initialization and
- * other threads created by the hw dep. drivers.
- */
- #include <u.h>
- #include <libc.h>
- #include <ctype.h>
- #include <thread.h>
- #include "usb.h"
- #include "usbfs.h"
- #include "serial.h"
- #include "prolific.h"
- #include "ucons.h"
- #include "ftdi.h"
- #include "silabs.h"
- int serialdebug;
- enum {
- /* Qids. Maintain order (relative to dirtabs structs) */
- Qroot = 0,
- Qctl,
- Qdata,
- Qmax,
- };
- typedef struct Dirtab Dirtab;
- struct Dirtab {
- char *name;
- int mode;
- };
- static Dirtab dirtab[] = {
- [Qroot] "/", DMDIR|0555,
- [Qdata] "%s", 0660,
- [Qctl] "%sctl", 0664,
- };
- static int sdebug;
- static void
- serialfatal(Serial *ser)
- {
- Serialport *p;
- int i;
- dsprint(2, "serial: fatal error, detaching\n");
- devctl(ser->dev, "detach");
- for(i = 0; i < ser->nifcs; i++){
- p = &ser->p[i];
- usbfsdel(&p->fs);
- if(p->w4data != nil)
- chanclose(p->w4data);
- if(p->gotdata != nil)
- chanclose(p->gotdata);
- if(p->readc)
- chanclose(p->readc);
- }
- }
- /* I sleep with the lock... only way to drain in general */
- static void
- serialdrain(Serialport *p)
- {
- Serial *ser;
- uint baud, pipesize;
- ser = p->s;
- baud = p->baud;
- if(p->baud == ~0)
- return;
- if(ser->maxwtrans < 256)
- pipesize = 256;
- else
- pipesize = ser->maxwtrans;
- /* wait for the at least 256-byte pipe to clear */
- sleep(10 + pipesize/((1 + baud)*1000));
- if(ser->clearpipes != nil)
- ser->clearpipes(p);
- }
- int
- serialreset(Serial *ser)
- {
- Serialport *p;
- int i, res;
- res = 0;
- /* cmd for reset */
- for(i = 0; i < ser->nifcs; i++){
- p = &ser->p[i];
- serialdrain(p);
- }
- if(ser->reset != nil)
- res = ser->reset(ser, nil);
- return res;
- }
- /* call this if something goes wrong, must be qlocked */
- int
- serialrecover(Serial *ser, Serialport *p, Dev *ep, char *err)
- {
- if(p != nil)
- dprint(2, "serial[%d], %s: %s, level %d\n", p->interfc,
- p->name, err, ser->recover);
- else
- dprint(2, "serial[%s], global error, level %d\n",
- ser->p[0].name, ser->recover);
- ser->recover++;
- if(strstr(err, "detached") != nil)
- return -1;
- if(ser->recover < 3){
- if(p != nil){
- if(ep != nil){
- if(ep == p->epintr)
- unstall(ser->dev, p->epintr, Ein);
- if(ep == p->epin)
- unstall(ser->dev, p->epin, Ein);
- if(ep == p->epout)
- unstall(ser->dev, p->epout, Eout);
- return 0;
- }
- if(p->epintr != nil)
- unstall(ser->dev, p->epintr, Ein);
- if(p->epin != nil)
- unstall(ser->dev, p->epin, Ein);
- if(p->epout != nil)
- unstall(ser->dev, p->epout, Eout);
- }
- return 0;
- }
- if(ser->recover > 4 && ser->recover < 8)
- serialfatal(ser);
- if(ser->recover > 8){
- ser->reset(ser, p);
- return 0;
- }
- if(serialreset(ser) < 0)
- return -1;
- return 0;
- }
- static int
- serialctl(Serialport *p, char *cmd)
- {
- Serial *ser;
- int c, i, n, nf, nop, nw, par, drain, set, lines;
- char *f[16];
- uchar x;
- ser = p->s;
- drain = set = lines = 0;
- nf = tokenize(cmd, f, nelem(f));
- for(i = 0; i < nf; i++){
- if(strncmp(f[i], "break", 5) == 0){
- if(ser->setbreak != nil)
- ser->setbreak(p, 1);
- continue;
- }
- nop = 0;
- n = atoi(f[i]+1);
- c = *f[i];
- if (isascii(c) && isupper(c))
- c = tolower(c);
- switch(c){
- case 'b':
- drain++;
- p->baud = n;
- set++;
- break;
- case 'c':
- p->dcd = n;
- // lines++;
- ++nop;
- break;
- case 'd':
- p->dtr = n;
- lines++;
- break;
- case 'e':
- p->dsr = n;
- // lines++;
- ++nop;
- break;
- case 'f': /* flush the pipes */
- drain++;
- break;
- case 'h': /* hangup?? */
- p->rts = p->dtr = 0;
- lines++;
- fprint(2, "serial: %c, unsure ctl\n", c);
- break;
- case 'i':
- ++nop;
- break;
- case 'k':
- drain++;
- ser->setbreak(p, 1);
- sleep(n);
- ser->setbreak(p, 0);
- break;
- case 'l':
- drain++;
- p->bits = n;
- set++;
- break;
- case 'm':
- drain++;
- if(ser->modemctl != nil)
- ser->modemctl(p, n);
- if(n == 0)
- p->cts = 0;
- break;
- case 'n':
- p->blocked = n;
- ++nop;
- break;
- case 'p': /* extended... */
- if(strlen(f[i]) != 2)
- return -1;
- drain++;
- par = f[i][1];
- if(par == 'n')
- p->parity = 0;
- else if(par == 'o')
- p->parity = 1;
- else if(par == 'e')
- p->parity = 2;
- else if(par == 'm') /* mark parity */
- p->parity = 3;
- else if(par == 's') /* space parity */
- p->parity = 4;
- else
- return -1;
- set++;
- break;
- case 'q':
- // drain++;
- p->limit = n;
- ++nop;
- break;
- case 'r':
- drain++;
- p->rts = n;
- lines++;
- break;
- case 's':
- drain++;
- p->stop = n;
- set++;
- break;
- case 'w':
- /* ?? how do I put this */
- p->timer = n * 100000LL;
- ++nop;
- break;
- case 'x':
- if(n == 0)
- x = CTLS;
- else
- x = CTLQ;
- if(ser->wait4write != nil)
- nw = ser->wait4write(p, &x, 1);
- else
- nw = write(p->epout->dfd, &x, 1);
- if(nw != 1){
- serialrecover(ser, p, p->epout, "");
- return -1;
- }
- break;
- }
- /*
- * don't print. the condition is harmless and the print
- * splatters all over the display.
- */
- USED(nop);
- if (0 && nop)
- fprint(2, "serial: %c, unsupported nop ctl\n", c);
- }
- if(drain)
- serialdrain(p);
- if(lines && !set){
- if(ser->sendlines != nil && ser->sendlines(p) < 0)
- return -1;
- } else if(set){
- if(ser->setparam != nil && ser->setparam(p) < 0)
- return -1;
- }
- ser->recover = 0;
- return 0;
- }
- char *pformat = "noems";
- char *
- serdumpst(Serialport *p, char *buf, int bufsz)
- {
- char *e, *s;
- Serial *ser;
- ser = p->s;
- e = buf + bufsz;
- s = seprint(buf, e, "b%d ", p->baud);
- s = seprint(s, e, "c%d ", p->dcd); /* unimplemented */
- s = seprint(s, e, "d%d ", p->dtr);
- s = seprint(s, e, "e%d ", p->dsr); /* unimplemented */
- s = seprint(s, e, "l%d ", p->bits);
- s = seprint(s, e, "m%d ", p->mctl);
- if(p->parity >= 0 || p->parity < strlen(pformat))
- s = seprint(s, e, "p%c ", pformat[p->parity]);
- else
- s = seprint(s, e, "p%c ", '?');
- s = seprint(s, e, "r%d ", p->rts);
- s = seprint(s, e, "s%d ", p->stop);
- s = seprint(s, e, "i%d ", p->fifo);
- s = seprint(s, e, "\ndev(%d) ", 0);
- s = seprint(s, e, "type(%d) ", ser->type);
- s = seprint(s, e, "framing(%d) ", p->nframeerr);
- s = seprint(s, e, "overruns(%d) ", p->novererr);
- s = seprint(s, e, "berr(%d) ", p->nbreakerr);
- s = seprint(s, e, " serr(%d)\n", p->nparityerr);
- return s;
- }
- static int
- serinit(Serialport *p)
- {
- int res;
- res = 0;
- Serial *ser;
- ser = p->s;
- if(ser->init != nil)
- res = ser->init(p);
- if(ser->getparam != nil)
- ser->getparam(p);
- p->nframeerr = p->nparityerr = p->nbreakerr = p->novererr = 0;
- return res;
- }
- static int
- dwalk(Usbfs *fs, Fid *fid, char *name)
- {
- int i;
- char *dname;
- Qid qid;
- Serialport *p;
- qid = fid->qid;
- if((qid.type & QTDIR) == 0){
- werrstr("walk in non-directory");
- return -1;
- }
- if(strcmp(name, "..") == 0){
- /* must be /eiaU%d; i.e. our root dir. */
- fid->qid.path = Qroot | fs->qid;
- fid->qid.vers = 0;
- fid->qid.type = QTDIR;
- return 0;
- }
- p = fs->aux;
- for(i = 1; i < nelem(dirtab); i++){
- dname = smprint(dirtab[i].name, p->name);
- if(strcmp(name, dname) == 0){
- qid.path = i | fs->qid;
- qid.vers = 0;
- qid.type = dirtab[i].mode >> 24;
- fid->qid = qid;
- free(dname);
- return 0;
- } else
- free(dname);
- }
- werrstr(Enotfound);
- return -1;
- }
- static void
- dostat(Usbfs *fs, int path, Dir *d)
- {
- Dirtab *t;
- Serialport *p;
- t = &dirtab[path];
- d->qid.path = path;
- d->qid.type = t->mode >> 24;
- d->mode = t->mode;
- p = fs->aux;
- if(strcmp(t->name, "/") == 0)
- d->name = t->name;
- else
- snprint(d->name, Namesz, t->name, p->fs.name);
- d->length = 0;
- }
- static int
- dstat(Usbfs *fs, Qid qid, Dir *d)
- {
- int path;
- path = qid.path & ~fs->qid;
- dostat(fs, path, d);
- d->qid.path |= fs->qid;
- return 0;
- }
- static int
- dopen(Usbfs *fs, Fid *fid, int)
- {
- ulong path;
- Serialport *p;
- path = fid->qid.path & ~fs->qid;
- p = fs->aux;
- switch(path){ /* BUG: unneeded? */
- case Qdata:
- dsprint(2, "serial, opened data\n");
- break;
- case Qctl:
- dsprint(2, "serial, opened ctl\n");
- if(p->isjtag)
- return 0;
- serialctl(p, "l8 i1"); /* default line parameters */
- break;
- }
- return 0;
- }
- static void
- filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i, void *v)
- {
- Serialport *p;
- p = v;
- d->qid.path = i | fs->qid;
- d->mode = tab->mode;
- if((d->mode & DMDIR) != 0)
- d->qid.type = QTDIR;
- else
- d->qid.type = QTFILE;
- sprint(d->name, tab->name, p->name); /* hope it fits */
- }
- static int
- dirgen(Usbfs *fs, Qid, int i, Dir *d, void *p)
- {
- i++; /* skip root */
- if(i >= nelem(dirtab))
- return -1;
- filldir(fs, d, &dirtab[i], i, p);
- return 0;
- }
- enum {
- Serbufsize = 256,
- };
- static long
- dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
- {
- int dfd;
- long rcount;
- ulong path;
- char *e, *buf, *err; /* change */
- Qid q;
- Serialport *p;
- Serial *ser;
- static int errrun, good;
- q = fid->qid;
- path = fid->qid.path & ~fs->qid;
- p = fs->aux;
- ser = p->s;
- buf = emallocz(Serbufsize, 1);
- err = emallocz(Serbufsize, 1);
- qlock(ser);
- switch(path){
- case Qroot:
- count = usbdirread(fs, q, data, count, offset, dirgen, p);
- break;
- case Qdata:
- if(count > ser->maxread)
- count = ser->maxread;
- dsprint(2, "serial: reading from data\n");
- do {
- err[0] = 0;
- dfd = p->epin->dfd;
- if(usbdebug >= 3)
- dsprint(2, "serial: reading: %ld\n", count);
- assert(count > 0);
- if(ser->wait4data != nil)
- rcount = ser->wait4data(p, data, count);
- else{
- qunlock(ser);
- rcount = read(dfd, data, count);
- qlock(ser);
- }
- /*
- * if we encounter a long run of continuous read
- * errors, do something drastic so that our caller
- * doesn't just spin its wheels forever.
- */
- if(rcount < 0) {
- snprint(err, Serbufsize, "%r");
- ++errrun;
- sleep(20);
- if (good > 0 && errrun > 10000) {
- /* the line has been dropped; give up */
- qunlock(ser);
- fprint(2, "%s: line %s is gone: %r\n",
- argv0, p->fs.name);
- threadexitsall("serial line gone");
- }
- } else {
- errrun = 0;
- good++;
- }
- if(usbdebug >= 3)
- dsprint(2, "serial: read: %s %ld\n", err, rcount);
- } while(rcount < 0 && strstr(err, "timed out") != nil);
- dsprint(2, "serial: read from bulk %ld, %10.10s\n", rcount, err);
- if(rcount < 0){
- dsprint(2, "serial: need to recover, data read %ld %r\n",
- count);
- serialrecover(ser, p, p->epin, err);
- }
- dsprint(2, "serial: read from bulk %ld\n", rcount);
- count = rcount;
- break;
- case Qctl:
- if(offset != 0 || p->isjtag)
- count = 0;
- else {
- e = serdumpst(p, buf, Serbufsize);
- count = usbreadbuf(data, count, 0, buf, e - buf);
- }
- break;
- }
- if(count >= 0)
- ser->recover = 0;
- qunlock(ser);
- free(err);
- free(buf);
- return count;
- }
- static long
- altwrite(Serialport *p, uchar *buf, long count)
- {
- int nw, dfd;
- char err[128];
- Serial *ser;
- ser = p->s;
- do{
- dsprint(2, "serial: write to bulk %ld\n", count);
- if(ser->wait4write != nil)
- /* unlocked inside later */
- nw = ser->wait4write(p, buf, count);
- else{
- dfd = p->epout->dfd;
- qunlock(ser);
- nw = write(dfd, buf, count);
- qlock(ser);
- }
- rerrstr(err, sizeof err);
- dsprint(2, "serial: written %s %d\n", err, nw);
- } while(nw < 0 && strstr(err, "timed out") != nil);
- if(nw != count){
- dsprint(2, "serial: need to recover, status in write %d %r\n",
- nw);
- snprint(err, sizeof err, "%r");
- serialrecover(p->s, p, p->epout, err);
- }
- return nw;
- }
- static long
- dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong)
- {
- ulong path;
- char *cmd;
- Serialport *p;
- Serial *ser;
- p = fs->aux;
- ser = p->s;
- path = fid->qid.path & ~fs->qid;
- qlock(ser);
- switch(path){
- case Qdata:
- count = altwrite(p, (uchar *)buf, count);
- break;
- case Qctl:
- if(p->isjtag)
- break;
- cmd = emallocz(count+1, 1);
- memmove(cmd, buf, count);
- cmd[count] = 0;
- if(serialctl(p, cmd) < 0){
- qunlock(ser);
- werrstr(Ebadctl);
- free(cmd);
- return -1;
- }
- free(cmd);
- break;
- default:
- qunlock(ser);
- werrstr(Eperm);
- return -1;
- }
- if(count >= 0)
- ser->recover = 0;
- else
- serialrecover(ser, p, p->epout, "writing");
- qunlock(ser);
- return count;
- }
- static int
- openeps(Serialport *p, int epin, int epout, int epintr)
- {
- Serial *ser;
- ser = p->s;
- p->epin = openep(ser->dev, epin);
- if(p->epin == nil){
- fprint(2, "serial: openep %d: %r\n", epin);
- return -1;
- }
- if(epout == epin){
- incref(p->epin);
- p->epout = p->epin;
- }else
- p->epout = openep(ser->dev, epout);
- if(p->epout == nil){
- fprint(2, "serial: openep %d: %r\n", epout);
- closedev(p->epin);
- return -1;
- }
- if(!p->isjtag){
- devctl(p->epin, "timeout 1000");
- devctl(p->epout, "timeout 1000");
- }
- if(ser->hasepintr){
- p->epintr = openep(ser->dev, epintr);
- if(p->epintr == nil){
- fprint(2, "serial: openep %d: %r\n", epintr);
- closedev(p->epin);
- closedev(p->epout);
- return -1;
- }
- opendevdata(p->epintr, OREAD);
- devctl(p->epintr, "timeout 1000");
- }
- if(ser->seteps!= nil)
- ser->seteps(p);
- if(p->epin == p->epout)
- opendevdata(p->epin, ORDWR);
- else{
- opendevdata(p->epin, OREAD);
- opendevdata(p->epout, OWRITE);
- }
- if(p->epin->dfd < 0 ||p->epout->dfd < 0 ||
- (ser->hasepintr && p->epintr->dfd < 0)){
- fprint(2, "serial: open i/o ep data: %r\n");
- closedev(p->epin);
- closedev(p->epout);
- if(ser->hasepintr)
- closedev(p->epintr);
- return -1;
- }
- return 0;
- }
- static int
- findendpoints(Serial *ser, int ifc)
- {
- int i, epin, epout, epintr;
- Ep *ep, **eps;
- epintr = epin = epout = -1;
- /*
- * interfc 0 means start from the start which is equiv to
- * iterate through endpoints probably, could be done better
- */
- eps = ser->dev->usb->conf[0]->iface[ifc]->ep;
- for(i = 0; i < Niface; i++){
- if((ep = eps[i]) == nil)
- continue;
- if(ser->hasepintr && ep->type == Eintr &&
- ep->dir == Ein && epintr == -1)
- epintr = ep->id;
- if(ep->type == Ebulk){
- if((ep->dir == Ein || ep->dir == Eboth) && epin == -1)
- epin = ep->id;
- if((ep->dir == Eout || ep->dir == Eboth) && epout == -1)
- epout = ep->id;
- }
- }
- dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr);
- if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1))
- return -1;
- if(openeps(&ser->p[ifc], epin, epout, epintr) < 0)
- return -1;
- dprint(2, "serial: ep in %s out %s\n", ser->p[ifc].epin->dir, ser->p[ifc].epout->dir);
- if(ser->hasepintr)
- dprint(2, "serial: ep intr %s\n", ser->p[ifc].epintr->dir);
- if(usbdebug > 1 || serialdebug > 2){
- devctl(ser->p[ifc].epin, "debug 1");
- devctl(ser->p[ifc].epout, "debug 1");
- if(ser->hasepintr)
- devctl(ser->p[ifc].epintr, "debug 1");
- devctl(ser->dev, "debug 1");
- }
- return 0;
- }
- /* keep in sync with main.c */
- static int
- usage(void)
- {
- werrstr("usage: usb/serial [-dD] [-m mtpt] [-s srv]");
- return -1;
- }
- static void
- serdevfree(void *a)
- {
- Serial *ser = a;
- Serialport *p;
- int i;
- if(ser == nil)
- return;
- for(i = 0; i < ser->nifcs; i++){
- p = &ser->p[i];
- if(ser->hasepintr)
- closedev(p->epintr);
- closedev(p->epin);
- closedev(p->epout);
- p->epintr = p->epin = p->epout = nil;
- if(p->w4data != nil)
- chanfree(p->w4data);
- if(p->gotdata != nil)
- chanfree(p->gotdata);
- if(p->readc)
- chanfree(p->readc);
- }
- free(ser);
- }
- static Usbfs serialfs = {
- .walk = dwalk,
- .open = dopen,
- .read = dread,
- .write= dwrite,
- .stat = dstat,
- };
- static void
- serialfsend(Usbfs *fs)
- {
- Serialport *p;
- p = fs->aux;
- if(p->w4data != nil)
- chanclose(p->w4data);
- if(p->gotdata != nil)
- chanclose(p->gotdata);
- if(p->readc)
- chanclose(p->readc);
- }
- int
- serialmain(Dev *dev, int argc, char* argv[])
- {
- Serial *ser;
- Serialport *p;
- char buf[50];
- int i, devid;
- devid = dev->id;
- ARGBEGIN{
- case 'd':
- serialdebug++;
- break;
- case 'N':
- devid = atoi(EARGF(usage()));
- break;
- default:
- return usage();
- }ARGEND
- if(argc != 0)
- return usage();
- ser = dev->aux = emallocz(sizeof(Serial), 1);
- ser->maxrtrans = ser->maxwtrans = sizeof ser->p[0].data;
- ser->maxread = ser->maxwrite = sizeof ser->p[0].data;
- ser->dev = dev;
- dev->free = serdevfree;
- ser->jtag = -1;
- ser->nifcs = 1;
- snprint(buf, sizeof buf, "vid %#06x did %#06x",
- dev->usb->vid, dev->usb->did);
- if(plmatch(buf) == 0){
- ser->hasepintr = 1;
- ser->Serialops = plops;
- } else if(uconsmatch(buf) == 0)
- ser->Serialops = uconsops;
- else if(ftmatch(ser, buf) == 0)
- ser->Serialops = ftops;
- else if(slmatch(buf) == 0)
- ser->Serialops = slops;
- else {
- werrstr("serial: no serial devices found");
- return -1;
- }
- for(i = 0; i < ser->nifcs; i++){
- p = &ser->p[i];
- p->interfc = i;
- p->s = ser;
- p->fs = serialfs;
- if(i == ser->jtag){
- p->isjtag++;
- }
- if(findendpoints(ser, i) < 0){
- werrstr("serial: no endpoints found for ifc %d", i);
- return -1;
- }
- p->w4data = chancreate(sizeof(ulong), 0);
- p->gotdata = chancreate(sizeof(ulong), 0);
- }
- qlock(ser);
- serialreset(ser);
- for(i = 0; i < ser->nifcs; i++){
- p = &ser->p[i];
- dprint(2, "serial: valid interface, calling serinit\n");
- if(serinit(p) < 0){
- dprint(2, "serial: serinit: %r\n");
- return -1;
- }
- dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p);
- if(p->isjtag){
- snprint(p->name, sizeof p->name, "jtag");
- dsprint(2, "serial: JTAG interface %d %p\n", i, p);
- snprint(p->fs.name, sizeof p->fs.name, "jtag%d.%d", devid, i);
- } else {
- snprint(p->name, sizeof p->name, "eiaU");
- if(i == 0)
- snprint(p->fs.name, sizeof p->fs.name, "eiaU%d", devid);
- else
- snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i);
- }
- fprint(2, "%s...", p->fs.name);
- p->fs.dev = dev;
- incref(dev);
- p->fs.aux = p;
- p->fs.end = serialfsend;
- usbfsadd(&p->fs);
- }
- qunlock(ser);
- return 0;
- }
|