diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-10-21 17:24:33 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-10-21 17:24:33 +0200 |
commit | 8dfff00e50652e1c0580c307374991b8cd3b864f (patch) | |
tree | ee35666fd949b5d0278956e6ca1568001157eff1 | |
parent | 21001d4294c0496a2fc8c23eead89df44bd85825 (diff) |
nusb/serial: add support for CH340 serial converter
-rw-r--r-- | sys/src/cmd/nusb/serial/ch340.c | 171 | ||||
-rw-r--r-- | sys/src/cmd/nusb/serial/mkfile | 2 | ||||
-rw-r--r-- | sys/src/cmd/nusb/serial/serial.c | 6 |
3 files changed, 176 insertions, 3 deletions
diff --git a/sys/src/cmd/nusb/serial/ch340.c b/sys/src/cmd/nusb/serial/ch340.c new file mode 100644 index 000000000..aef620494 --- /dev/null +++ b/sys/src/cmd/nusb/serial/ch340.c @@ -0,0 +1,171 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <fcall.h> +#include <9p.h> +#include "usb.h" +#include "serial.h" + +enum { + ReadVersion = 0x5F, + ReadReg = 0x95, + WriteReg = 0x9A, + SerialInit = 0xA1, + ModemCtrl = 0xA4, + + LcrEnableRx = 0x80, + LcrEnableTx = 0x40, + LcrMarkSpace = 0x20, + LcrParEven = 0x10, + LcrEnablePar = 0x08, + LcrStopBits2 = 0x04, + + LcrCS8 = 0x03, + LcrCS7 = 0x02, + LcrCS6 = 0x01, + LcrCS5 = 0x00, +}; + +static Cinfo chinfo[] = { + { 0x4348, 0x5523, }, + { 0x1a86, 0x7523, }, + { 0x1a86, 0x5523, }, + { 0, 0, }, +}; + +static Serialops chops; + +int +chprobe(Serial *ser) +{ + Usbdev *ud = ser->dev->usb; + + if(matchid(chinfo, ud->vid, ud->did) == nil) + return -1; + ser->Serialops = chops; + return 0; +} + +static int +chin(Serialport *p, uint req, uint val, uint index, void *buf, int len) +{ + Serial *ser; + + ser = p->s; + return usbcmd(ser->dev, Rd2h | Rvendor | Rdev, req, val, index, buf, len); +} + +static int +chout(Serialport *p, uint req, uint val, uint index) +{ + Serial *ser; + + ser = p->s; + return usbcmd(ser->dev, Rh2d | Rvendor | Rdev, req, val, index, nil, 0); +} + + +static int +chinit(Serialport *p) +{ + Serial *ser; + uchar ver[2]; + + ser = p->s; + dsprint(2, "chinit\n"); + + if(chin(p, ReadVersion, 0, 0, ver, sizeof(ver)) < 0) + return -1; + + dsprint(2, "ch340: chip version: %ux.%ux\n", ver[0], ver[1]); + + if(chout(p, SerialInit, 0, 0) < 0) + return -1; + + p->baud = 115200; + p->stop = 1; + p->bits = 8; + + chops.setparam(p); + + /* p gets freed by closedev, the process has a reference */ + incref(ser->dev); + return 0; +} + +static int +chsetbaud(Serialport *p) +{ + uint factor, divisor, a; + + factor = 1532620800 / p->baud; + divisor = 3; + + while((factor > 0xfff0) && divisor) { + factor /= 8; + divisor--; + } + + if(factor > 0xfff0) + return -1; + + factor = 0x10000 - factor; + a = (factor & 0xFF00) | divisor; + a |= 1<<7; + return chout(p, WriteReg, 0x1312, a); +} + +static int +chsetparam(Serialport *p) +{ + uint lcr; + + if(p->baud > 0) + chsetbaud(p); + + lcr = LcrEnableRx | LcrEnableTx; + + switch(p->bits){ + case 5: + lcr |= LcrCS5; + break; + case 6: + lcr |= LcrCS6; + break; + case 7: + lcr |= LcrCS7; + break; + case 8: + default: + lcr |= LcrCS8; + break; + } + + switch(p->parity){ + case 0: + default: + break; + case 1: + lcr |= LcrEnablePar; + break; + case 2: + lcr |= LcrEnablePar|LcrParEven; + break; + case 3: + lcr |= LcrEnablePar|LcrMarkSpace; + break; + case 4: + lcr |= LcrEnablePar|LcrParEven|LcrMarkSpace; + break; + }; + + if(p->stop == 2) + lcr |= LcrStopBits2; + + return chout(p, WriteReg, 0x2518, lcr); +} + +static Serialops chops = { + .init = chinit, + .setparam = chsetparam, +}; diff --git a/sys/src/cmd/nusb/serial/mkfile b/sys/src/cmd/nusb/serial/mkfile index 56c109106..f11df1dc5 100644 --- a/sys/src/cmd/nusb/serial/mkfile +++ b/sys/src/cmd/nusb/serial/mkfile @@ -1,7 +1,7 @@ </$objtype/mkfile TARG=serial -OFILES=ftdi.$O serial.$O prolific.$O ucons.$O silabs.$O +OFILES=ftdi.$O serial.$O prolific.$O ucons.$O silabs.$O ch340.$O HFILES=\ ../lib/usb.h\ serial.h\ diff --git a/sys/src/cmd/nusb/serial/serial.c b/sys/src/cmd/nusb/serial/serial.c index 9f37a57fe..5c52004c8 100644 --- a/sys/src/cmd/nusb/serial/serial.c +++ b/sys/src/cmd/nusb/serial/serial.c @@ -712,6 +712,7 @@ static Srv serialfs = { extern int ftprobe(Serial *ser); extern int plprobe(Serial *ser); extern int slprobe(Serial *ser); +extern int chprobe(Serial *ser); extern int uconsprobe(Serial *ser); void @@ -748,7 +749,8 @@ threadmain(int argc, char* argv[]) if(uconsprobe(ser) && ftprobe(ser) && slprobe(ser) - && plprobe(ser)) + && plprobe(ser) + && chprobe(ser)) sysfatal("no serial devices found"); for(i = 0; i < ser->nifcs; i++){ @@ -769,7 +771,7 @@ threadmain(int argc, char* argv[]) for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; if(serinit(p) < 0) - sysfatal("wserinit: %r"); + sysfatal("serinit: %r"); if(ser->nifcs == 1) snprint(p->name, sizeof p->name, "%s%s", p->isjtag ? "jtag" : "eiaU", dev->hname); else |