ref: 68c5dc801409a8a24cfe48977df62e040e92cc90
parent: 98dd0aebef1c3bbc05750d534582392695f801f5
author: cinap_lenrek <[email protected]>
date: Fri Jan 25 12:12:15 EST 2013
nusb/serial: add silabs driver (from sources)
--- 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
+OFILES=ftdi.$O serial.$O prolific.$O ucons.$O silabs.$O
HFILES=\
../lib/usb.h\
ftdi.h\
@@ -8,6 +8,7 @@
prolific.h\
serial.h\
ucons.h\
+ silabs.h\
LIB=../lib/usb.a$O
--- a/sys/src/cmd/nusb/serial/serial.c
+++ b/sys/src/cmd/nusb/serial/serial.c
@@ -14,6 +14,7 @@
#include "prolific.h"
#include "ucons.h"
#include "ftdi.h"
+#include "silabs.h"
int serialdebug;
static int sdebug;
@@ -637,7 +638,11 @@
fprint(2, "serial: openep %d: %r\n", epin);
return -1;
}
- p->epout = openep(ser->dev, epout);
+ if(epin == epout){
+ incref(p->epin);
+ p->epout = p->epin;
+ } else
+ p->epout = openep(ser->dev, epout);
if(p->epout == nil){
fprint(2, "serial: openep %d: %r\n", epout);
closedev(p->epin);
@@ -663,9 +668,13 @@
if(ser->seteps!= nil)
ser->seteps(p);
- opendevdata(p->epin, OREAD);
- opendevdata(p->epout, OWRITE);
- if(p->epin->dfd < 0 ||p->epout->dfd < 0 ||
+ if(p->epin == p->epout)
+ opendevdata(p->epin, ORDWR);
+ else {
+ opendevdata(p->epin, OREAD);
+ opendevdata(p->epout, OWRITE);
+ }
+ if(p->epin->dfd < 0 || p->epout->dfd < 0 ||
(ser->hasepintr && p->epintr->dfd < 0)){
fprint(2, "serial: open i/o ep data: %r\n");
closedev(p->epin);
@@ -698,9 +707,9 @@
ep->dir == Ein && epintr == -1)
epintr = ep->id;
if(ep->type == Ebulk){
- if(ep->dir == Ein && epin == -1)
+ if((ep->dir == Ein || ep->dir == Eboth) && epin == -1)
epin = ep->id;
- if(ep->dir == Eout && epout == -1)
+ if((ep->dir == Eout || ep->dir == Eboth) && epout == -1)
epout = ep->id;
}
}
@@ -822,6 +831,8 @@
ser->Serialops = uconsops;
else if(ftmatch(ser, buf) == 0)
ser->Serialops = ftops;
+ else if(slmatch(buf) == 0)
+ ser->Serialops = slops;
else {
sysfatal("no serial devices found");
}
--- /dev/null
+++ b/sys/src/cmd/nusb/serial/silabs.c
@@ -1,0 +1,147 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <fcall.h>
+#include <9p.h>
+#include "usb.h"
+#include "serial.h"
+#include "silabs.h"
+
+static Cinfo slinfo[] = {
+ { 0x10c4, 0xea60, }, /* CP210x */
+ { 0x10c4, 0xea61, }, /* CP210x */
+ { 0, 0, },
+};
+
+enum {
+ Enable = 0x00,
+
+ Getbaud = 0x1D,
+ Setbaud = 0x1E,
+ Setlcr = 0x03,
+ Getlcr = 0x04,
+ Bitsmask = 0x0F00,
+ Bitsshift = 8,
+ Parmask = 0x00F0,
+ Parshift = 4,
+ Stopmask = 0x000F,
+ Stop1 = 0x0000,
+ Stop1_5 = 0x0001,
+ Stop2 = 0x0002,
+};
+
+slmatch(char *info)
+{
+ Cinfo *ip;
+ char buf[50];
+
+ for(ip = slinfo; ip->vid != 0; ip++){
+ snprint(buf, sizeof buf, "vid %#06x did %#06x",
+ ip->vid, ip->did);
+ if(strstr(info, buf) != nil)
+ return 0;
+ }
+ return -1;
+}
+
+static int
+slwrite(Serialport *p, int req, void *buf, int len)
+{
+ Serial *ser;
+
+ ser = p->s;
+ return usbcmd(ser->dev, Rh2d | Rvendor | Riface, req, 0, p->interfc,
+ buf, len);
+}
+
+static int
+slput(Serialport *p, uint op, uint val)
+{
+ Serial *ser;
+
+ ser = p->s;
+ return usbcmd(ser->dev, Rh2d | Rvendor | Riface, op, val, p->interfc,
+ nil, 0);
+}
+
+static int
+slread(Serialport *p, int req, void *buf, int len)
+{
+ Serial *ser;
+
+ ser = p->s;
+ return usbcmd(ser->dev, Rd2h | Rvendor | Riface, req, 0, p->interfc,
+ buf, len);
+}
+
+static int
+slinit(Serialport *p)
+{
+ Serial *ser;
+
+ ser = p->s;
+ dsprint(2, "slinit\n");
+
+ slput(p, Enable, 1);
+
+ slops.getparam(p);
+
+ /* p gets freed by closedev, the process has a reference */
+ incref(ser->dev);
+ return 0;
+}
+
+static int
+slgetparam(Serialport *p)
+{
+ u16int lcr;
+
+ slread(p, Getbaud, &p->baud, sizeof(p->baud));
+ slread(p, Getlcr, &lcr, sizeof(lcr));
+ p->bits = (lcr&Bitsmask)>>Bitsshift;
+ p->parity = (lcr&Parmask)>>Parshift;
+ p->stop = (lcr&Stopmask) == Stop1? 1 : 2;
+ return 0;
+}
+
+static int
+slsetparam(Serialport *p)
+{
+ u16int lcr;
+
+ lcr = p->stop == 1? Stop1 : Stop2;
+ lcr |= (p->bits<<Bitsshift) | (p->parity<<Parshift);
+ slput(p, Setlcr, lcr);
+ slwrite(p, Setbaud, &p->baud, sizeof(p->baud));
+ return 0;
+}
+
+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;
+
+ qunlock(p->s);
+ while ((n = read(p->epin->dfd, data, count)) == 0)
+ ;
+ qlock(p->s);
+ return n;
+}
+
+Serialops slops = {
+ .init = slinit,
+ .getparam = slgetparam,
+ .setparam = slsetparam,
+ .seteps = seteps,
+ .wait4data = wait4data,
+};
--- /dev/null
+++ b/sys/src/cmd/nusb/serial/silabs.h
@@ -1,0 +1,3 @@
+extern Serialops slops;
+
+int slmatch(char *info);