/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 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 voidserialfatal(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 voidserialdrain(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);} intserialreset(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 */intserialrecover(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 intserialctl(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 intserinit(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 intdwalk(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 voiddostat(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 intdstat(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 intdopen(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 voidfilldir(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 intdirgen(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 longdread(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:Lines 1–500 of 909. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 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: