ref: 8677db333a11de80971df3e60f787b72b45a568c
parent: 502247bf92f380a642b8e17048466c18bb9efd24
author: cinap_lenrek <[email protected]>
date: Sat Jul 5 04:17:37 EDT 2014
nusb/serial: implement flushes handle reads and writes with 9pqueue(2) so they can be flushed and wont hang the filesystem. this also lets us get rid of the timeouts. ftdi is still full of braindamage that should be rewritten, but i dont have a device to test.
--- a/sys/src/cmd/nusb/serial/ftdi.c
+++ b/sys/src/cmd/nusb/serial/ftdi.c
@@ -1235,12 +1235,9 @@
count = p->ndata;
p->ndata = 0;
}
- assert(count >= 0);
- assert(p->ndata >= 0);
memmove(data, p->data, count);
if(p->ndata != 0)
memmove(p->data, p->data+count, p->ndata);
-
recvul(p->gotdata);
return count;
}
@@ -1313,7 +1310,6 @@
epreader(void *u)
{
int dfd, rcount, cl, ntries, recov;
- char err[40];
Areader *a;
Channel *c;
Packser *pk;
@@ -1333,7 +1329,7 @@
ntries = 0;
pk = nil;
- do {
+ for(;;) {
if (pk == nil)
pk = emallocz(sizeof(Packser), 1);
Eagain:
@@ -1374,7 +1370,7 @@
ntries = 0;
pk = nil;
}
- } while(rcount >= 0 || (rcount < 0 && strstr(err, "timed out") != nil));
+ }
if(rcount < 0)
fprint(2, "%s: error reading %s: %r\n", argv0, p->name);
@@ -1413,16 +1409,13 @@
memmove(p->data, pk->b, pk->nb);
p->ndata = pk->nb;
free(pk);
- dsprint(2, "serial %p: status reader %d \n", p, p->ndata);
/* consume it all */
while(p->ndata != 0){
- dsprint(2, "serial %p: status reader to consume: %d\n",
- p, p->ndata);
cl = recvul(p->w4data);
- if(cl < 0)
+ if(cl < 0)
break;
cl = sendul(p->gotdata, 1);
- if(cl < 0)
+ if(cl < 0)
break;
}
}
@@ -1473,9 +1466,6 @@
return -1;
dsprint(2, "serial: jtag latency timer set to %d\n", timerval);
- /* may be unnecessary */
- devctl(p->epin, "timeout 5000");
- devctl(p->epout, "timeout 5000");
/* 0xb is the mask for lines. plug dependant? */
ftdiwrite(p, BMMPSSE|0x0b, 0, FTSETBITMODE);
}
--- a/sys/src/cmd/nusb/serial/prolific.c
+++ b/sys/src/cmd/nusb/serial/prolific.c
@@ -446,12 +446,13 @@
plgetparam(p);
qunlock(ser);
free(buf);
- st = emallocz(255, 1);
qlock(ser);
- if(serialdebug)
+ if(serialdebug){
+ st = emallocz(255, 1);
serdumpst(p, st, 255);
- dsprint(2, st);
- free(st);
+ dsprint(2, "%s", st);
+ free(st);
+ }
/* p gets freed by closedev, the process has a reference */
incref(ser->dev);
proccreate(statusreader, p, 8*1024);
@@ -528,7 +529,7 @@
plreadstatus(Serialport *p)
{
int nr, dfd;
- char err[40];
+ char err[ERRMAX];
uchar buf[VendorReqSz];
Serial *ser;
@@ -535,17 +536,12 @@
ser = p->s;
qlock(ser);
- dsprint(2, "serial: reading from interrupt\n");
dfd = p->epintr->dfd;
-
qunlock(ser);
nr = read(dfd, buf, sizeof buf);
qlock(ser);
- snprint(err, sizeof err, "%r");
- dsprint(2, "serial: interrupt read %d %r\n", nr);
-
+ rerrstr(err, sizeof err);
if(nr < 0 && strstr(err, "timed out") == nil){
- dsprint(2, "serial: need to recover, status read %d %r\n", nr);
if(serialrecover(ser, nil, nil, err) < 0){
qunlock(ser);
return -1;
@@ -552,7 +548,7 @@
}
}
if(nr < 0)
- dsprint(2, "serial: reading status: %r");
+ dsprint(2, "serial: reading status: %r\n");
else if(nr >= sizeof buf - 1){
p->dcd = buf[8] & DcdStatus;
p->dsr = buf[8] & DsrStatus;
@@ -567,7 +563,6 @@
p->novererr++;
} else
dsprint(2, "serial: bad status read %d\n", nr);
- dsprint(2, "serial: finished read from interrupt %d\n", nr);
qunlock(ser);
return 0;
}
--- a/sys/src/cmd/nusb/serial/serial.c
+++ b/sys/src/cmd/nusb/serial/serial.c
@@ -414,92 +414,78 @@
respond(req, nil);
}
-enum {
- Serbufsize = 255,
-};
-
static void
-readproc(void *aux)
+procread(Req *req)
{
+ int count, rcount;
+ void *data;
+ Serial *ser;
+ Serialport *p;
+ char err[ERRMAX];
int dfd;
- Req *req;
- long count, rcount;
+
+ p = req->aux;
+ ser = p->s;
+ data = req->ofcall.data;
+ count = req->ifcall.count;
+Again:
+ qlock(ser);
+ if(count > ser->maxread)
+ count = ser->maxread;
+ if(ser->wait4data != nil) {
+ rcount = ser->wait4data(p, data, count);
+ qunlock(ser);
+ } else {
+ dfd = p->epin->dfd;
+ qunlock(ser);
+ rcount = read(dfd, data, count);
+ }
+ if(rcount < 0) {
+ err[0] = 0;
+ errstr(err, sizeof err);
+ if(p->rq->flush == 0 && strstr(err, "timed out") != nil)
+ goto Again;
+ respond(req, err);
+ } else {
+ req->ofcall.count = rcount;
+ respond(req, nil);
+ }
+}
+
+static void
+procwrite(Req *req)
+{
+ int count, wcount;
void *data;
Serial *ser;
Serialport *p;
- static int errrun, good;
- char err[Serbufsize];
+ char err[ERRMAX];
+ int dfd;
- p = aux;
+ p = req->aux;
ser = p->s;
- for(;;){
- qlock(&p->readq);
- while(p->readfirst == nil)
- rsleep(&p->readrend);
- req = p->readfirst;
- p->readfirst = req->aux;
- if(p->readlast == req)
- p->readlast = nil;
- req->aux = nil;
- qunlock(&p->readq);
+ data = req->ifcall.data;
+ count = req->ifcall.count;
+ qlock(ser);
+ if(ser->wait4data != nil) {
+ wcount = ser->wait4write(p, data, count);
+ qunlock(ser);
+ } else {
+ dfd = p->epout->dfd;
+ qunlock(ser);
+ wcount = write(dfd, data, count);
+ }
+ if(wcount != count) {
+ err[0] = 0;
+ errstr(err, sizeof err);
+ respond(req, err);
- count = req->ifcall.count;
- data = req->ofcall.data;
qlock(ser);
- 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->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);
- if(rcount >= 0){
- req->ofcall.count = rcount;
- respond(req, nil);
- } else
- responderror(req);
+ serialrecover(p->s, p, p->epout, err);
qunlock(ser);
+ } else {
+ req->ofcall.count = wcount;
+ respond(req, nil);
}
}
@@ -506,44 +492,31 @@
static void
dread(Req *req)
{
- char *e; /* change */
- Qid q;
Serial *ser;
- vlong offset;
Serialport *p;
- static char buf[Serbufsize];
+ ulong path;
- q = req->fid->qid;
-
- if(q.path == 0){
+ path = req->fid->qid.path;
+ if(path == 0){
dirread9p(req, dirgen, nil);
respond(req, nil);
return;
}
- p = ports[(q.path - 1) / 2];
+ p = ports[(path - 1) / 2];
ser = p->s;
- offset = req->ifcall.offset;
-
- memset(buf, 0, sizeof buf);
qlock(ser);
- switch((long)((q.path - 1) % 2)){
+ switch((path - 1) % 2){
case 0:
- qlock(&p->readq);
- if(p->readfirst == nil)
- p->readfirst = req;
- else
- p->readlast->aux = req;
- p->readlast = req;
- rwakeup(&p->readrend);
- qunlock(&p->readq);
+ req->aux = p;
+ reqqueuepush(p->rq, req, procread);
break;
case 1:
- if(offset == 0) {
- if(!p->isjtag){
- e = serdumpst(p, buf, Serbufsize);
- readbuf(req, buf, e - buf);
- }
+ req->ofcall.count = 0;
+ if(req->ifcall.offset == 0 && !p->isjtag){
+ char buf[256];
+ serdumpst(p, buf, sizeof buf);
+ readstr(req, buf);
}
respond(req, nil);
break;
@@ -551,85 +524,45 @@
qunlock(ser);
}
-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 void
dwrite(Req *req)
{
- ulong path;
- char *cmd;
Serial *ser;
- long count;
- void *buf;
Serialport *p;
+ ulong path;
+ int count;
path = req->fid->qid.path;
- p = ports[(path-1)/2];
+ p = ports[(path-1) / 2];
ser = p->s;
- count = req->ifcall.count;
- buf = req->ifcall.data;
-
qlock(ser);
- switch((long)((path-1)%2)){
+ switch((path-1) % 2){
case 0:
- count = altwrite(p, (uchar *)buf, count);
+ req->aux = p;
+ reqqueuepush(p->wq, req, procwrite);
break;
case 1:
- if(p->isjtag)
- break;
- cmd = emallocz(count+1, 1);
- memmove(cmd, buf, count);
- cmd[count] = 0;
- if(serialctl(p, cmd) < 0){
- qunlock(ser);
+ count = req->ifcall.count;
+ if(!p->isjtag){
+ char *cmd, *buf;
+
+ buf = (char*)req->ifcall.data;
+ cmd = emallocz(count+1, 1);
+ memmove(cmd, buf, count);
+ cmd[count] = 0;
+ if(serialctl(p, cmd) < 0){
+ qunlock(ser);
+ free(cmd);
+ respond(req, "bad control request");
+ return;
+ }
free(cmd);
- respond(req, "bad control request");
- return;
}
- free(cmd);
+ req->ofcall.count = count;
+ respond(req, nil);
break;
}
- if(count >= 0)
- ser->recover = 0;
- else
- serialrecover(ser, p, p->epout, "writing");
qunlock(ser);
- if(count >= 0){
- req->ofcall.count = count;
- respond(req, nil);
- } else
- responderror(req);
}
static int
@@ -653,12 +586,6 @@
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){
@@ -739,6 +666,27 @@
return 0;
}
+static void
+dflush(Req *req)
+{
+ Serialport *p;
+ Req *old;
+ ulong path;
+
+ old = req->oldreq;
+ path = old->fid->qid.path;
+ if(path != 0){
+ p = ports[(path - 1) / 2];
+ if(p != nil){
+ if(old->ifcall.type == Twrite)
+ reqqueueflush(p->wq, old);
+ else
+ reqqueueflush(p->rq, old);
+ }
+ }
+ respond(req, nil);
+}
+
/* keep in sync with main.c */
static void
usage(void)
@@ -759,6 +707,7 @@
.read = dread,
.write= dwrite,
.stat = dstat,
+ .flush = dflush,
.end = dend,
};
@@ -821,18 +770,14 @@
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)
sysfatal("wserinit: %r");
-
- dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p);
if(ser->nifcs == 1)
snprint(p->name, sizeof p->name, "%s%s", p->isjtag ? "jtag" : "eiaU", dev->hname);
else
snprint(p->name, sizeof p->name, "%s%s.%d", p->isjtag ? "jtag" : "eiaU", dev->hname, i);
- incref(dev);
- p->readrend.l = &p->readq;
- p->readpid = proccreate(readproc, p, mainstacksize);
+ p->rq = reqqueuecreate();
+ p->wq = reqqueuecreate();
ports = realloc(ports, (nports + 1) * sizeof(Serialport*));
ports[nports++] = p;
}
--- a/sys/src/cmd/nusb/serial/serial.h
+++ b/sys/src/cmd/nusb/serial/serial.h
@@ -65,11 +65,9 @@
Channel *readc; /* to uncouple reads, only used in ftdi... */
int ndata;
uchar data[DataBufSz];
-
- QLock readq;
- Req *readfirst, *readlast; /* read request queue */
- int readpid;
- Rendez readrend;
+
+ Reqqueue *rq;
+ Reqqueue *wq;
};
struct Serial {
--- a/sys/src/cmd/nusb/serial/silabs.c
+++ b/sys/src/cmd/nusb/serial/silabs.c
@@ -114,16 +114,6 @@
}
static int
-seteps(Serialport *p)
-{
- if(devctl(p->epin, "timeout 0") < 0){
- fprint(2, "can't set timeout on %s: %r\n", p->epin->dir);
- return -1;
- }
- return 0;
-}
-
-static int
wait4data(Serialport *p, uchar *data, int count)
{
int n;
@@ -139,6 +129,5 @@
.init = slinit,
.getparam = slgetparam,
.setparam = slsetparam,
- .seteps = seteps,
.wait4data = wait4data,
};