From: Eli Cohen <echoline@gmail.com>
To: 9front@9front.org
Subject: Re: CDC ACM nusb/serial driver
Date: Thu, 30 Jul 2020 14:48:34 -0700 [thread overview]
Message-ID: <CAHwi9by9PxkANrVwRY7ugW5QCmLne8T9eJtrMTNQHu+mB7azbQ@mail.gmail.com> (raw)
In-Reply-To: <CAHwi9bzvPoO-nqiTHetBO+CcRf40C5XVSm3DOrv=FbC-xZSyMg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 93 bytes --]
I already noticed a few tiny changes. these flags should be set to 1
or 0, not the bit value
[-- Attachment #2: serial.patch --]
[-- Type: text/x-patch, Size: 9571 bytes --]
diff -r 23bc1d0e2dd2 sys/src/cmd/nusb/serial/cdc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/nusb/serial/cdc.c Thu Jul 30 21:06:29 2020 -0700
@@ -0,0 +1,301 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <fcall.h>
+#include <9p.h>
+#include "usb.h"
+#include "serial.h"
+
+enum {
+ Kyocera = 0x0482,
+ AHK3001V = 0x0203,
+};
+
+enum {
+ ScACM = 2,
+ AT = 1,
+ None = 0,
+ LineCoding = 0x20,
+ SetBreak = 0x23,
+ ControlState = 0x22,
+};
+
+enum {
+ ClassCDCData = 0x0a,
+ SubclassData = 0,
+};
+
+enum {
+ SubCDCCM = 1,
+ SubCDCACM = 2,
+ SubCDCUnion = 6,
+};
+
+typedef struct raw_desc {
+ uchar bLength;
+ uchar bDescriptorType;
+ uchar bDescriptorSubtype;
+ uchar bbytes[1];
+} raw_desc;
+
+typedef struct cm_desc {
+ uchar bLength;
+ uchar bDescriptorType;
+ uchar bDescriptorSubtype;
+ uchar bmCapabilities;
+ uchar bDataInterface;
+} cm_desc;
+
+enum {
+ CMDoesCM = 1,
+ CMOverData = 2,
+};
+
+typedef struct acm_desc {
+ uchar bLength;
+ uchar bDescriptorType;
+ uchar bDescriptorSubtype;
+ uchar bmCapabilities;
+} acm_desc;
+
+enum {
+ ACMHasFeature = 1,
+ ACMHasLine = 2,
+ ACMHasBreak = 4,
+ ACMHasNetwork = 8,
+};
+
+typedef struct union_desc {
+ uchar bLength;
+ uchar bDescriptorType;
+ uchar bDescriptorSubtype;
+ uchar bMasterInterface;
+ uchar bSlaveInterface[1];
+} union_desc;
+
+typedef struct cdc_notify {
+ uchar bmRequestType;
+ uchar bNotification;
+ ushort wValue;
+ ushort wIndex;
+ ushort wLength;
+ uchar data[16];
+} cdc_notify;
+
+enum {
+ Notification = 0xa1,
+ SerialState = 0x20,
+};
+
+enum {
+ DcdStatus = 0x01,
+ DsrStatus = 0x02,
+ RingStatus = 0x08,
+};
+
+static int
+cdcsetparam(Serialport *p)
+{
+ int res;
+ uchar vals[7];
+
+ PUT4(vals, p->baud);
+
+ vals[4] = 0;
+ if(p->stop == 1)
+ vals[4] = 0;
+ if(p->stop == 15)
+ vals[4] = 1;
+ if(p->stop == 2)
+ vals[4] = 2;
+
+ vals[5] = p->parity;
+
+ vals[6] = p->bits;
+
+ res = usbcmd(p->s->dev, Rh2d | Rclass | Riface, LineCoding, 0, 0, vals, 7);
+
+ return res;
+}
+
+void
+getcaps(Serialport *p)
+{
+ int i, j;
+ Desc *desc;
+ Iface *iface;
+ raw_desc ddesc;
+ cm_desc dcm;
+ acm_desc dacm;
+ union_desc dunion;
+ int cur_ifc;
+
+ for (i = 0; i < Niface; i++) {
+ iface = p->s->dev->usb->conf[0]->iface[i];
+ if (iface == nil)
+ continue;
+
+ cur_ifc = iface->id;
+ if (cur_ifc != p->ctl_ifc && Class(iface->csp) == ClassCDCData && Subclass(iface->csp) == SubclassData && p->data_ifc == -1)
+ p->data_ifc = cur_ifc;
+
+ if (cur_ifc == p->ctl_ifc)
+ for (j = 0; j < Nddesc; j++) {
+ desc = p->s->dev->usb->ddesc[j];
+ if (desc == nil)
+ continue;
+
+ ddesc = (raw_desc)desc->data;
+ if (ddesc.bDescriptorType == Dfunction) {
+ switch (ddesc.bDescriptorSubtype) {
+ case SubCDCCM:
+ dcm = (cm_desc)ddesc;
+ p->data_ifc = dcm.bDataInterface;
+ break;
+ case SubCDCACM:
+ dacm = (acm_desc)ddesc;
+ p->hasbreak = dacm.bmCapabilities & ACMHasBreak? 1: 0;
+ break;
+ case SubCDCUnion:
+ dunion = (union_desc)ddesc;
+ p->data_ifc = dunion.bSlaveInterface[0];
+ break;
+ }
+ }
+ }
+ }
+}
+
+void
+statusreader(void *u)
+{
+ Serialport *p = u;
+ uchar buf[sizeof(cdc_notify)];
+ cdc_notify *notify;
+
+ notify = (cdc_notify*)buf;
+ threadsetname("statusreaderproc");
+
+ while(read(p->epintr->dfd, buf, sizeof(cdc_notify)) > 0) {
+ if (notify->bmRequestType == Notification && notify->bNotification == SerialState && notify->wLength == 2) {
+ p->dcd = notify->data[0] & DcdStatus? 1: 0;
+ p->dsr = notify->data[0] & DsrStatus? 1: 0;
+ p->ring = notify->data[0] & RingStatus? 1: 0;
+ } else {
+ fprint(2, "serial: unknown intr message: reqtype:%02x notify:%02x len:%d state:%02x\n", notify->bmRequestType, notify->bNotification, notify->wLength, notify->data[0]);
+ }
+ }
+
+ fprint(2, "serial: statusreader exiting: %r\n");
+ closedev(p->s->dev);
+}
+
+static int
+cdcinit(Serialport *p)
+{
+ p->baud = 115200;
+ p->bits = 8;
+ p->parity = 0;
+ p->stop = 1;
+ cdcsetparam(p);
+
+ incref(p->s->dev);
+ proccreate(statusreader, p, 8*1024);
+
+ return 0;
+}
+
+static int
+cdcsetbreak(Serialport *p, int val)
+{
+ if(p->hasbreak == 0)
+ return 0;
+
+ return usbcmd(p->s->dev, Rh2d | Rclass | Riface, SetBreak, (val != 0? 0xffff: 0x0000), 0, nil, 0);
+}
+
+static int
+cdcsendlines(Serialport *p)
+{
+ if(p->rts)
+ p->ctlstate |= CtlRTS;
+ else
+ p->ctlstate &= ~CtlRTS;
+ if(p->dtr)
+ p->ctlstate |= CtlDTR;
+ else
+ p->ctlstate &= ~CtlDTR;
+
+ return usbcmd(p->s->dev, Rh2d | Rclass | Riface, ControlState, p->ctlstate, 0, nil, 0);
+}
+
+static int
+cdcclearpipes(Serialport *p)
+{
+ if(unstall(p->s->dev, p->epout, Eout) < 0)
+ dprint(2, "serial: unstall epout: %r\n");
+ if(unstall(p->s->dev, p->epin, Ein) < 0)
+ dprint(2, "serial: unstall epin: %r\n");
+ if(unstall(p->s->dev, p->epintr, Ein) < 0)
+ dprint(2, "serial: unstall epintr: %r\n");
+
+ return 0;
+}
+
+static int
+cdcwait4data(Serialport *p, uchar *data, int count)
+{
+ int n;
+
+ qunlock(p->s);
+ while ((n = read(p->epin->dfd, data, count)) == 0)
+ ;
+ qlock(p->s);
+
+ return n;
+}
+
+static Serialops cdcops = {
+ .init = cdcinit,
+ .setparam = cdcsetparam,
+ .setbreak = cdcsetbreak,
+ .sendlines = cdcsendlines,
+ .clearpipes = cdcclearpipes,
+ .wait4data = cdcwait4data,
+};
+
+int
+cdcprobe(Serial *ser)
+{
+ int i, ifcs;
+ Usbdev *ud = ser->dev->usb;
+ Iface *iface;
+ ulong csp;
+
+ ifcs = 0;
+ if (ud->vid == Kyocera || ud->did == AHK3001V)
+ ifcs++;
+ else for (i = 0; i < Niface; i++) {
+ iface = ud->conf[0]->iface[i];
+ if (iface == nil)
+ continue;
+
+ csp = iface->csp;
+ if (Class(csp) == Clcomms && Subclass(csp) == ScACM && (Proto(csp) == AT || Proto(csp) == None)) {
+ ser->p[ifcs].ctl_ifc = i;
+ ser->p[ifcs].s = ser;
+ getcaps(&ser->p[ifcs]);
+ ifcs++;
+ }
+ }
+
+ if (ifcs == 0)
+ return -1;
+
+ ser->nifcs = ifcs;
+ ser->isacm = 1;
+ ser->outhdrsz = 0;
+ ser->hasepintr = 1;
+ ser->Serialops = cdcops;
+ return 0;
+}
diff -r 23bc1d0e2dd2 sys/src/cmd/nusb/serial/mkfile
--- a/sys/src/cmd/nusb/serial/mkfile Tue Jun 09 12:23:24 2020 -0700
+++ b/sys/src/cmd/nusb/serial/mkfile Thu Jul 30 21:06:29 2020 -0700
@@ -1,7 +1,7 @@
</$objtype/mkfile
TARG=serial
-OFILES=ftdi.$O serial.$O prolific.$O ucons.$O silabs.$O ch340.$O
+OFILES=ftdi.$O serial.$O prolific.$O ucons.$O silabs.$O ch340.$O cdc.$O
HFILES=\
../lib/usb.h\
serial.h\
diff -r 23bc1d0e2dd2 sys/src/cmd/nusb/serial/serial.c
--- a/sys/src/cmd/nusb/serial/serial.c Tue Jun 09 12:23:24 2020 -0700
+++ b/sys/src/cmd/nusb/serial/serial.c Thu Jul 30 21:06:29 2020 -0700
@@ -624,23 +624,46 @@
epintr = epin = epout = -1;
- /*
- * interfc 0 means start from the start which is equiv to
- * iterate through endpoints probably, could be done better
- */
- eps = ser->dev->usb->conf[0]->iface[ifc]->ep;
+ if(ser->isacm){
+ eps = ser->dev->usb->conf[0]->iface[ser->p[ifc].ctl_ifc]->ep;
- for(i = 0; i < Nep; i++){
- if((ep = eps[i]) == nil)
- continue;
- if(ser->hasepintr && ep->type == Eintr &&
- ep->dir == Ein && epintr == -1)
- epintr = ep->id;
- if(ep->type == Ebulk){
- if((ep->dir == Ein || ep->dir == Eboth) && epin == -1)
- epin = ep->id;
- if((ep->dir == Eout || ep->dir == Eboth) && epout == -1)
- epout = ep->id;
+ for(i = 0; i < Nep; i++){
+ if((ep = eps[i]) == nil)
+ continue;
+ if(ep->type == Eintr && ep->dir == Ein && epintr == -1)
+ epintr = ep->id;
+ }
+
+ eps = ser->dev->usb->conf[0]->iface[ser->p[ifc].data_ifc]->ep;
+ for(i = 0; i < Nep; i++){
+ if((ep = eps[i]) == nil)
+ continue;
+ if(ep->type == Ebulk){
+ if((ep->dir == Ein || ep->dir == Eboth) && epin == -1)
+ epin = ep->id;
+ if((ep->dir == Eout || ep->dir == Eboth) && epout == -1)
+ epout = ep->id;
+ }
+ }
+ } else {
+ /*
+ * interfc 0 means start from the start which is equiv to
+ * iterate through endpoints probably, could be done better
+ */
+ eps = ser->dev->usb->conf[0]->iface[ifc]->ep;
+
+ for(i = 0; i < Nep; i++){
+ if((ep = eps[i]) == nil)
+ continue;
+ if(ser->hasepintr && ep->type == Eintr &&
+ ep->dir == Ein && epintr == -1)
+ epintr = ep->id;
+ if(ep->type == Ebulk){
+ if((ep->dir == Ein || ep->dir == Eboth) && epin == -1)
+ epin = ep->id;
+ if((ep->dir == Eout || ep->dir == Eboth) && epout == -1)
+ epout = ep->id;
+ }
}
}
dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr);
@@ -714,6 +737,7 @@
extern int slprobe(Serial *ser);
extern int chprobe(Serial *ser);
extern int uconsprobe(Serial *ser);
+extern int cdcprobe(Serial *ser);
void
threadmain(int argc, char* argv[])
@@ -750,7 +774,8 @@
&& ftprobe(ser)
&& slprobe(ser)
&& plprobe(ser)
- && chprobe(ser))
+ && chprobe(ser)
+ && cdcprobe(ser))
sysfatal("no serial devices found");
for(i = 0; i < ser->nifcs; i++){
diff -r 23bc1d0e2dd2 sys/src/cmd/nusb/serial/serial.h
--- a/sys/src/cmd/nusb/serial/serial.h Tue Jun 09 12:23:24 2020 -0700
+++ b/sys/src/cmd/nusb/serial/serial.h Thu Jul 30 21:06:29 2020 -0700
@@ -60,6 +60,10 @@
int interfc; /* interfc on the device for ftdi */
+ int hasbreak; /* CDC ACM may not have break */
+ int ctl_ifc; /* epintr iface for CDC ACM */
+ int data_ifc; /* epin/out iface for CDC ACM */
+
Channel *w4data;
Channel *gotdata;
int ndata;
@@ -81,6 +85,7 @@
int jtag; /* index of jtag interface, -1 none */
int nifcs; /* # of serial interfaces, including JTAG */
+ int isacm; /* CDC ACM interfaces handled differently */
Serialport p[Maxifc];
int maxrtrans;
int maxwtrans;
next prev parent reply other threads:[~2020-07-30 21:48 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-30 21:18 Eli Cohen
2020-07-30 21:48 ` Eli Cohen [this message]
2020-07-31 15:38 ` [9front] " ori
2020-07-31 11:18 ` [9front] " Ethan Gardener
2020-08-01 5:35 ` Anthony Martin
2020-08-01 15:34 ` Ethan Gardener
2020-08-01 16:45 ` Eli Cohen
2020-08-01 20:32 ` Ethan Gardener
2020-08-02 13:34 ` cinap_lenrek
2020-08-03 6:27 ` Eli Cohen
2020-10-05 21:53 ` Eli Cohen
2020-08-01 15:34 ` cinap_lenrek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAHwi9by9PxkANrVwRY7ugW5QCmLne8T9eJtrMTNQHu+mB7azbQ@mail.gmail.com \
--to=echoline@gmail.com \
--cc=9front@9front.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).