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