git: 9front

Download patch

ref: f8d145f1fd59dbf0d9da86465e8f8cabd259b771
parent: 2d6526b1a8b6b155c7e4b76efad124cbdd8d3c42
author: Arne <cgnarne@netcologne.de>
date: Sat Nov 22 11:35:55 EST 2025

nusb/serial: various fixes and improvements

ftdi:
Fix sendlines
Fix modemctl disable
ftreset clears flowcontrol, rts and dtr. Update flags accordingly

silabs:
Implement sendlines
Implement modemctl
Set ser->type, useful for support of  other cp210x devices

ch340:
Implement sendlines
Implement modemctl
Set ser->type to device version

serial:
make break and kn behave like devuart
set dev() to driver name when reading the ctl file

--- a/sys/src/cmd/nusb/serial/ch340.c
+++ b/sys/src/cmd/nusb/serial/ch340.c
@@ -24,6 +24,9 @@
 	LcrCS7		= 0x02,
 	LcrCS6		= 0x01,
 	LcrCS5		= 0x00,
+
+	DtrMask		= 0x20,
+	RtsMask		= 0x40,
 };
 
 static Cinfo chinfo[] = {
@@ -79,6 +82,9 @@
 
 	dsprint(2, "ch340: chip version: %ux.%ux\n", ver[0], ver[1]);
 
+	strncpy(ser->driver, "ch340", sizeof(ser->driver));
+	ser->type = ver[0];
+
 	if(chout(p, SerialInit, 0, 0) < 0)
 		return -1;
 
@@ -116,6 +122,31 @@
 }
 
 static int
+chsendlines(Serialport *p)
+{
+	uchar val;
+
+	val = 0;
+	if(p->rts)
+		val |= RtsMask;
+	if(p->dtr)
+		val |= DtrMask;
+
+	return chout(p, ModemCtrl, ~val, 0);
+}
+
+static int
+chmodemctl(Serialport *p, int set)
+{
+	/* XXX set dtr and rts for flow control?
+	   Linux does the same. do we even need flow control then? */
+	p->rts = p->dtr = set?1:0;
+	chsendlines(p);
+	p->mctl = p->rts;
+	return chout(p, WriteReg, 0x2727, (p->mctl<<8)|p->mctl);
+}
+
+static int
 chsetparam(Serialport *p)
 {
 	uint lcr;
@@ -162,6 +193,8 @@
 	if(p->stop == 2)
 		lcr |= LcrStopBits2;
 
+	chmodemctl(p, p->mctl);
+
 	return chout(p, WriteReg, 0x2518, lcr);
 }
 
@@ -168,5 +201,7 @@
 static Serialops chops = {
 	.init		= chinit,
 	.setparam	= chsetparam,
+	.sendlines	= chsendlines,
+	.modemctl	= chmodemctl,
 	.findeps	= findendpoints,
 };
--- a/sys/src/cmd/nusb/serial/ftdi.c
+++ b/sys/src/cmd/nusb/serial/ftdi.c
@@ -887,7 +887,7 @@
 {
 	if(set == 0){
 		p->mctl = 0;
-		ftdiwrite(p, 0, 0, FTSETMODEMCTRL);
+		ftdiwrite(p, 0, FTDISABLEFLOWCTRL, FTSETFLOWCTRL);
 		return 0;
 	}
 	p->mctl = 1;
@@ -1435,12 +1435,15 @@
 
 	if(p != nil){
 		ftdiwrite(p, FTRESETCTLVAL, 0, FTRESET);
+		p->mctl = p->rts = p->dtr = 0;
 		return 0;
 	}
 	p = ser->p;
 	for(i = 0; i < Maxifc; i++)
-		if(p[i].s != nil)
+		if(p[i].s != nil){
 			ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET);
+			p->mctl = p->rts = p->dtr = 0;
+		}
 	return 0;
 }
 
@@ -1448,15 +1451,14 @@
 ftinit(Serialport *p)
 {
 	Serial *ser;
-	uint timerval;
+	uchar timerval;
 	int res;
 
 	ser = p->s;
+	strncpy(ser->driver, "ftdi", sizeof(ser->driver));
+	ftreset(ser, p);
 	if(p->isjtag){
-		res = ftdiwrite(p, FTSETFLOWCTRL, 0, FTDISABLEFLOWCTRL);
-		if(res < 0)
-			return -1;
-		res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
+		res = ftdiread(p, FTGETLATENCYTIMER, 0, &timerval,
 			FTLATENCYTIMERSZ);
 		if(res < 0)
 			return -1;
@@ -1463,7 +1465,7 @@
 		dsprint(2, "serial: jtag latency timer is %d\n", timerval);
 		timerval = 2;
 		ftdiwrite(p, FTLATENCYDEFAULT, 0, FTSETLATENCYTIMER);
-		res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
+		res = ftdiread(p, FTGETLATENCYTIMER, 0, &timerval,
 			FTLATENCYTIMERSZ);
 		if(res < 0)
 			return -1;
@@ -1492,23 +1494,21 @@
 	return 0;
 }
 
-static int
-setctlline(Serialport *p, uchar val)
-{
-	return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL);
-}
-
 static void
-updatectlst(Serialport *p, int val)
+composectl(Serialport *p)
 {
 	if(p->rts)
-		p->ctlstate |= val;
+		p->ctlstate |= CtlRTS;
 	else
-		p->ctlstate &= ~val;
+		p->ctlstate &= ~CtlRTS;
+	if(p->dtr)
+		p->ctlstate |= CtlDTR;
+	else
+		p->ctlstate &= ~CtlDTR;
 }
 
 static int
-setctl(Serialport *p)
+ftsendlines(Serialport *p)
 {
 	int res;
 	Serial *ser;
@@ -1515,35 +1515,21 @@
 
 	ser = p->s;
 
+	composectl(p);
 	if(ser->dev->usb->vid == FTVid && ser->dev->usb->did ==  FTHETIRA1Did){
 		fprint(2, "serial: cannot set lines for this device\n");
-		updatectlst(p, CtlRTS|CtlDTR);
-		p->rts = p->dtr = 1;
 		return -1;
 	}
 
 	/* NB: you can not set DTR and RTS with one control message */
-	updatectlst(p, CtlRTS);
-	res = setctlline(p, (CtlRTS<<8)|p->ctlstate);
+	res = ftdiwrite(p, (CtlRTS<<8)|p->ctlstate, 0, FTSETMODEMCTRL);
 	if(res < 0)
 		return res;
 
-	updatectlst(p, CtlDTR);
-	res = setctlline(p, (CtlDTR<<8)|p->ctlstate);
+	res = ftdiwrite(p, (CtlDTR<<8)|p->ctlstate, 0, FTSETMODEMCTRL);
 	if(res < 0)
 		return res;
 
-	return 0;
-}
-
-static int
-ftsendlines(Serialport *p)
-{
-	int res;
-
-	dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate);
-	res = setctl(p);
-	dsprint(2, "serial: sendlines res: %d\n", res);
 	return 0;
 }
 
--- a/sys/src/cmd/nusb/serial/serial.c
+++ b/sys/src/cmd/nusb/serial/serial.c
@@ -129,8 +129,11 @@
 	nf = tokenize(cmd, f, nelem(f));
 	for(i = 0; i < nf; i++){
 		if(strncmp(f[i], "break", 5) == 0){
-			if(ser->setbreak != nil)
+			if(ser->setbreak != nil){
 				ser->setbreak(p, 1);
+				sleep(200);
+				ser->setbreak(p, 0);
+			}
 			continue;
 		}
 
@@ -173,7 +176,7 @@
 		case 'k':
 			drain++;
 			ser->setbreak(p, 1);
-			sleep(n);
+			sleep(n<=0?200:n);
 			ser->setbreak(p, 0);
 			break;
 		case 'l':
@@ -291,7 +294,7 @@
 	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, "\ndev(%s) ", ser->driver);
 	s = seprint(s, e, "type(%d)  ", ser->type);
 	s = seprint(s, e, "framing(%d) ", p->nframeerr);
 	s = seprint(s, e, "overruns(%d) ", p->novererr);
--- a/sys/src/cmd/nusb/serial/serial.h
+++ b/sys/src/cmd/nusb/serial/serial.h
@@ -74,6 +74,7 @@
 	QLock;
 	Dev	*dev;		/* usb device*/
 
+	char	driver[8];	/* driver name, e.g. ch340 */
 	int	type;		/* serial model subtype */
 	int	recover;	/* # of non-fatal recovery tries */
 	Serialops;
--- a/sys/src/cmd/nusb/serial/silabs.c
+++ b/sys/src/cmd/nusb/serial/silabs.c
@@ -11,6 +11,11 @@
 
 	Getbaud		= 0x1D,
 	Setbaud		= 0x1E,
+	Setflow		= 0x13,
+		Flowdtron = 0x01,
+		Flowctshs = 0x08,
+		Flowrtson = 0x40,
+		Flowrtshs = 0x80,
 	Setlcr		= 0x03,
 	Getlcr		= 0x04,
 		Bitsmask	= 0x0F00,
@@ -21,6 +26,9 @@
 		Stop1		= 0x0000,
 		Stop1_5		= 0x0001,
 		Stop2		= 0x0002,
+	Setctrl		= 0x07,
+		Dtron		= 0x0001,
+		Rtson		= 0x0002,
 };
 
 static Cinfo slinfo[] = {
@@ -72,6 +80,23 @@
 }
 
 static int
+slgettype(Serialport *p)
+{
+	Serial *ser;
+	uchar buf;
+	int res;
+
+	ser = p->s;
+	res = usbcmd(ser->dev, Rd2h | Rvendor | Riface, 0xff, 0x370B, p->interfc,
+		&buf, 1);
+
+	if(res < 0)
+		return 0xff;
+
+	return buf;
+}
+
+static int
 slinit(Serialport *p)
 {
 	Serial *ser;
@@ -79,6 +104,9 @@
 	ser = p->s;
 	dsprint(2, "slinit\n");
 
+	strncpy(ser->driver, "silabs", sizeof(ser->driver));
+	ser->type = slgettype(p);
+
 	slput(p, Enable, 1);
 
 	slops.getparam(p);
@@ -114,6 +142,38 @@
 }
 
 static int
+slsendlines(Serialport *p)
+{
+	u16int ctrl;
+	
+	ctrl = (p->dtr? Dtron : 0) | Dtron << 8;
+	ctrl |= (p->rts? Rtson : 0) | Rtson << 8;
+
+	slput(p, Setctrl, ctrl);
+	return 0;
+}
+
+static
+slmodemctl(Serialport *p, int set)
+{
+	uchar flow[4*4];
+
+	memset(flow, 0, sizeof flow);
+
+	if(set){
+		p->mctl = 1;
+		PUT4(flow, (p->dtr?Flowdtron:0) | Flowctshs);
+		PUT4(flow+4, Flowrtshs);
+	}else{
+		p->mctl = 0;
+		PUT4(flow, (p->dtr)?Flowdtron:0);
+		PUT4(flow+4, (p->rts)?Flowrtson:0);
+	}
+	slwrite(p, Setflow, flow, sizeof flow);
+	return 0;
+}
+
+static int
 wait4data(Serialport *p, uchar *data, int count)
 {
 	int n;
@@ -129,6 +189,8 @@
 	.init		= slinit,
 	.getparam	= slgetparam,
 	.setparam	= slsetparam,
+	.sendlines	= slsendlines,
+	.modemctl	= slmodemctl,
 	.wait4data	= wait4data,
 	.findeps	= findendpoints,
 };
--