shithub: riscv

Download patch

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);