shithub: riscv

Download patch

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,
 };