diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-01-25 17:12:15 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-01-25 17:12:15 +0100 |
commit | 68c5dc801409a8a24cfe48977df62e040e92cc90 (patch) | |
tree | 12afffc3b91fdf86fde99f6b273bfdc30a290752 /sys | |
parent | 98dd0aebef1c3bbc05750d534582392695f801f5 (diff) |
nusb/serial: add silabs driver (from sources)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/src/cmd/nusb/serial/mkfile | 3 | ||||
-rw-r--r-- | sys/src/cmd/nusb/serial/serial.c | 23 | ||||
-rw-r--r-- | sys/src/cmd/nusb/serial/silabs.c | 147 | ||||
-rw-r--r-- | sys/src/cmd/nusb/serial/silabs.h | 3 |
4 files changed, 169 insertions, 7 deletions
diff --git a/sys/src/cmd/nusb/serial/mkfile b/sys/src/cmd/nusb/serial/mkfile index a1df868d4..c1c7673ff 100644 --- a/sys/src/cmd/nusb/serial/mkfile +++ b/sys/src/cmd/nusb/serial/mkfile @@ -1,13 +1,14 @@ </$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\ prolific.h\ serial.h\ ucons.h\ + silabs.h\ LIB=../lib/usb.a$O diff --git a/sys/src/cmd/nusb/serial/serial.c b/sys/src/cmd/nusb/serial/serial.c index 426d84bdf..2c41398f9 100644 --- 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 @@ openeps(Serialport *p, int epin, int epout, int epintr) 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 @@ openeps(Serialport *p, int epin, int epout, int epintr) 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 @@ findendpoints(Serial *ser, int ifc) 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 @@ threadmain(int argc, char* argv[]) 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"); } diff --git a/sys/src/cmd/nusb/serial/silabs.c b/sys/src/cmd/nusb/serial/silabs.c new file mode 100644 index 000000000..0753dd213 --- /dev/null +++ b/sys/src/cmd/nusb/serial/silabs.c @@ -0,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, +}; diff --git a/sys/src/cmd/nusb/serial/silabs.h b/sys/src/cmd/nusb/serial/silabs.h new file mode 100644 index 000000000..5ccc2aaba --- /dev/null +++ b/sys/src/cmd/nusb/serial/silabs.h @@ -0,0 +1,3 @@ +extern Serialops slops; + +int slmatch(char *info); |