Add support for Silicon Labs CP210x usb serial chips. I/O only - no modem control signals yet. Reference: /n/sources/patch/applied/usbserial-silabs Date: Fri Dec 14 10:23:30 CET 2012 Signed-off-by: miller@hamnavoe.com --- /sys/src/cmd/usb/serial/main.c Fri Dec 14 10:21:16 2012 +++ /sys/src/cmd/usb/serial/main.c Fri Dec 14 10:21:14 2012 @@ -7,6 +7,7 @@ #include "ucons.h" #include "prolific.h" #include "ftdi.h" +#include "silabs.h" enum { Arglen = 80, @@ -26,7 +27,7 @@ matchserial(char *info, void*) { if(uconsmatch(info) == 0 || plmatch(info) == 0 || - ftmatch(nil, info) == 0) + ftmatch(nil, info) == 0 || slmatch(info) == 0) return 0; return -1; } --- /sys/src/cmd/usb/serial/mkfile Fri Dec 14 10:21:20 2012 +++ /sys/src/cmd/usb/serial/mkfile Fri Dec 14 10:21:18 2012 @@ -2,7 +2,7 @@ TARG=serial OFILES=main.$O -LIBDOFILES=ftdi.$O serial.$O prolific.$O ucons.$O +LIBDOFILES=ftdi.$O serial.$O prolific.$O ucons.$O silabs.$O HFILES=\ ../lib/usb.h\ ftdi.h\ --- /sys/src/cmd/usb/serial/serial.c Fri Dec 14 10:21:25 2012 +++ /sys/src/cmd/usb/serial/serial.c Fri Dec 14 10:21:22 2012 @@ -13,6 +13,7 @@ #include "prolific.h" #include "ucons.h" #include "ftdi.h" +#include "silabs.h" int serialdebug; @@ -646,7 +647,11 @@ fprint(2, "serial: openep %d: %r\n", epin); return -1; } - p->epout = openep(ser->dev, epout); + if(epout == epin){ + 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); @@ -672,8 +677,12 @@ if(ser->seteps!= nil) ser->seteps(p); - opendevdata(p->epin, OREAD); - opendevdata(p->epout, OWRITE); + 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"); @@ -707,9 +716,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 == Ein || ep->dir == Eboth) && epout == -1) epout = ep->id; } } @@ -833,6 +842,8 @@ ser->Serialops = uconsops; else if(ftmatch(ser, buf) == 0) ser->Serialops = ftops; + else if(slmatch(buf) == 0) + ser->Serialops = slops; else { werrstr("serial: no serial devices found"); return -1; --- /sys/src/cmd/usb/serial/silabs.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/usb/serial/silabs.c Fri Dec 14 10:21:27 2012 @@ -0,0 +1,150 @@ +#include +#include +#include +#include "usb.h" +#include "usbfs.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; + int res; + + ser = p->s; + res = usbcmd(ser->dev, Rh2d | Rvendor | Riface, req, 0, p->interfc, buf, len); + return res; +} + +static int +slput(Serialport *p, uint op, uint val) +{ + Serial *ser; + int res; + + ser = p->s; + res = usbcmd(ser->dev, Rh2d | Rvendor | Riface, op, val, p->interfc, nil, 0); + return res; +} + +static int +slread(Serialport *p, int req, void *buf, int len) +{ + Serial *ser; + int res; + + ser = p->s; + res = usbcmd(ser->dev, Rd2h | Rvendor | Riface, req, 0, p->interfc, buf, len); + return res; +} + +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<parity<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); + do{ + n = read(p->epin->dfd, data, count); + }while(n == 0); + qlock(p->s); + return n; +} + +Serialops slops = { + .init = slinit, + .getparam = slgetparam, + .setparam = slsetparam, + .seteps = seteps, + .wait4data = wait4data, +}; --- /sys/src/cmd/usb/serial/silabs.h Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/usb/serial/silabs.h Fri Dec 14 10:21:29 2012 @@ -0,0 +1,2 @@ +extern Serialops slops; +int slmatch(char *info);