Browse Source

Plan 9 from Bell Labs 2012-10-02

David du Colombier 11 years ago
parent
commit
a3fb18aac6

+ 1 - 1
sys/src/9/pc/apic.c

@@ -234,7 +234,7 @@ lapicinit(Apic* apic)
 	/*
 	 * Do not allow acceptance of interrupts until all initialisation
 	 * for this processor is done. For the bootstrap processor this can be
-	 * early duing initialisation. For the application processors this should
+	 * early during initialisation. For the application processors this should
 	 * be after the bootstrap processor has lowered priority and is accepting
 	 * interrupts.
 	lapicw(LapicTPR, 0);

+ 47 - 1
sys/src/9/pc/i8253.c

@@ -55,6 +55,8 @@ enum
 	Tickshift=8,		/* extra accuracy */
 	MaxPeriod=Freq/HZ,
 	MinPeriod=Freq/(100*HZ),
+
+	Wdogms	= 200,		/* ms between strokes */
 };
 
 typedef struct I8253 I8253;
@@ -115,12 +117,42 @@ i8253init(void)
 	}
 }
 
+/*
+ * if the watchdog is running and we're on cpu 0 and ignoring (clock)
+ * interrupts, disable the watchdog temporarily so that the (presumed)
+ * long-running loop to follow will not trigger an NMI.
+ * wdogresume restarts the watchdog if wdogpause stopped it.
+ */
+static int
+wdogpause(void)
+{
+	int turndogoff;
+
+	turndogoff = watchdogon && m->machno == 0 && !islo();
+	if (turndogoff) {
+		watchdog->disable();
+		watchdogon = 0;
+	}
+	return turndogoff;
+}
+
+static void
+wdogresume(int resume)
+{
+	if (resume) {
+		watchdog->enable();
+		watchdogon = 1;
+	}
+}
+
 void
 guesscpuhz(int aalcycles)
 {
-	int loops, incr, x, y;
+	int loops, incr, x, y, dogwason;
 	uvlong a, b, cpufreq;
 
+	dogwason = wdogpause();		/* don't get NMI while busy looping */
+
 	/* find biggest loop that doesn't wrap */
 	incr = 16000000/(aalcycles*HZ*2);
 	x = 2000;
@@ -155,6 +187,7 @@ guesscpuhz(int aalcycles)
 		if(x > Freq/(3*HZ))
 			break;
 	}
+	wdogresume(dogwason);
 
 	/*
  	 *  figure out clock frequency and a loop multiplier for delay().
@@ -286,6 +319,14 @@ i8253read(uvlong *hz)
 void
 delay(int millisecs)
 {
+	if (millisecs > 10*1000)
+		iprint("delay(%d) from %#p\n", millisecs,
+			getcallerpc(&millisecs));
+	if (watchdogon && m->machno == 0 && !islo())
+		for (; millisecs > Wdogms; millisecs -= Wdogms) {
+			delay(Wdogms);
+			watchdog->restart();
+		}
 	millisecs *= m->loopconst;
 	if(millisecs <= 0)
 		millisecs = 1;
@@ -295,6 +336,11 @@ delay(int millisecs)
 void
 microdelay(int microsecs)
 {
+	if (watchdogon && m->machno == 0 && !islo())
+		for (; microsecs > Wdogms*1000; microsecs -= Wdogms*1000) {
+			delay(Wdogms);
+			watchdog->restart();
+		}
 	microsecs *= m->loopconst;
 	microsecs /= 1000;
 	if(microsecs <= 0)

+ 3 - 3
sys/src/9/port/devproc.c

@@ -843,9 +843,9 @@ procread(Chan *c, void *va, long n, vlong off)
 		if(sps == 0)
 			sps = statename[p->state];
 		memset(statbuf, ' ', sizeof statbuf);
-		memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
-		memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
-		memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
+		readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
+		readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
+		readstr(0, statbuf+2*KNAMELEN, 11, sps);
 		j = 2*KNAMELEN + 12;
 
 		for(i = 0; i < 6; i++) {

+ 36 - 15
sys/src/9/port/devwd.c

@@ -14,8 +14,16 @@ enum {
 	Qwdctl,
 };
 
+/*
+ * these are exposed so that delay() and the like can disable the watchdog
+ * before busy looping for a long time.
+ */
+Watchdog*watchdog;
+int	watchdogon;
+
 static Watchdog *wd;
 static int wdautopet;
+static int wdclock0called;
 static Ref refs;
 static Dirtab wddir[] = {
 	".",		{ Qdir, 0, QTDIR },	0,		0555,
@@ -24,21 +32,28 @@ static Dirtab wddir[] = {
 
 
 void
-addwatchdog(Watchdog *watchdog)
+addwatchdog(Watchdog *wdog)
 {
 	if(wd){
 		print("addwatchdog: watchdog already installed\n");
 		return;
 	}
-	wd = watchdog;
+	wd = watchdog = wdog;
 	if(wd)
 		wd->disable();
 }
 
+static int
+wdallowed(void)
+{
+	return getconf("*nowatchdog") == nil;
+}
+
 static void
 wdpet(void)
 {
-	if (wdautopet)
+	/* watchdog could be paused; if so, don't restart */
+	if (wdautopet && watchdogon)
 		wd->restart();
 }
 
@@ -49,12 +64,15 @@ wdpet(void)
 static void
 wdautostart(void)
 {
-	if (wdautopet || !wd)
+	if (wdautopet || !wd || !wdallowed())
 		return;
 	iprint("watchdog: on with clock strokes\n");
 	wd->enable();
-	wdautopet = 1;
-	addclock0link(wdpet, 200);
+	wdautopet = watchdogon = 1;
+	if (!wdclock0called) {
+		addclock0link(wdpet, 200);
+		wdclock0called = 1;
+	}
 }
 
 static void
@@ -62,7 +80,7 @@ wdautostop(void)
 {
 	if (!wdautopet)
 		return;
-	wdautopet = 0;
+	wdautopet = watchdogon = 0;
 	wd->disable();
 	iprint("watchdog: off\n");
 }
@@ -102,17 +120,19 @@ wdopen(Chan* c, int omode)
 }
 
 static void
-wdclose(Chan *c)
+wdshutdown(void)
 {
-	if(c->qid.path == Qwdctl && c->flag&COPEN && decref(&refs) <= 0 && wd)
+	if (wd) {
 		wd->disable();
+		watchdogon = 0;
+	}
 }
 
 static void
-wdshutdown(void)
+wdclose(Chan *c)
 {
-	if (wd)
-		wd->disable();
+	if(c->qid.path == Qwdctl && c->flag&COPEN && decref(&refs) <= 0)
+		wdshutdown();
 }
 
 static long
@@ -170,10 +190,11 @@ wdwrite(Chan* c, void* a, long n, vlong off)
 		if((p = strchr(a, '\n')) != nil)
 			*p = 0;
 
-		if(strncmp(a, "enable", n) == 0)
+		if(strncmp(a, "enable", n) == 0) {
 			wd->enable();
-		else if(strncmp(a, "disable", n) == 0)
-			wd->disable();
+			watchdogon = 1;
+		} else if(strncmp(a, "disable", n) == 0)
+			wdshutdown();
 		else if(strncmp(a, "restart", n) == 0)
 			wd->restart();
 		else

+ 3 - 0
sys/src/9/port/portdat.h

@@ -792,6 +792,9 @@ extern	char*	sysname;
 extern	uint	qiomaxatomic;
 extern	char*	sysctab[];
 
+	Watchdog*watchdog;
+	int	watchdogon;
+
 enum
 {
 	LRESPROF	= 3,

+ 5 - 2
sys/src/cmd/usb/ether/asix.c

@@ -234,8 +234,11 @@ ctlrinit(Ether *ether)
 
 	d = ether->dev;
 	switch(ether->cid){
-	default:
+	case A8817x:
+	case A88179:
 		fprint(2, "%s: card known but not implemented\n", argv0);
+		/* fall through */
+	default:
 		return -1;
 
 	case A88178:
@@ -467,7 +470,7 @@ asixreset(Ether *ether)
 		if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
 			ether->cid = ip->cid;
 			if(ctlrinit(ether) < 0){
-				deprint(2, "%s: init failed: %r\n", argv0);
+				deprint(2, "%s: asix init failed: %r\n", argv0);
 				return -1;
 			}
 			deprint(2, "%s: asix reset done\n", argv0);

+ 29 - 6
sys/src/cmd/usb/ether/ether.c

@@ -73,6 +73,15 @@ Cinfo cinfo[] =
 	{0x1737, 0x0039, A88178},
 	{0x2001, 0x3c05, A88772},
 	{0x6189, 0x182d, A8817x},
+
+	/* SMSC controllers.
+	 * LAN95xx family
+	 */
+	{0x0424, 0xec00, S95xx},	/* LAN9512 (as in raspberry pi) */
+	{0x0424, 0x9500, S95xx},
+	{0x0424, 0x9505, S95xx},
+	{0x0424, 0x9E00, S95xx},
+	{0x0424, 0x9E01, S95xx},
 	{0, 0, 0},
 };
 
@@ -111,6 +120,7 @@ int etherdebug;
 Resetf ethers[] =
 {
 	asixreset,
+	smscreset,
 	cdcreset,	/* keep last */
 };
 
@@ -155,7 +165,7 @@ allocbuf(Ether *e)
 	bp = nbrecvp(e->bc);
 	if(bp == nil){
 		qlock(e);
-		if(e->nabufs < Nconns){
+		if(e->nabufs < Nbufs){
 			bp = emallocz(sizeof(Buf), 1);
 			e->nabufs++;
 			setmalloctag(bp, getcallerpc(&e));
@@ -163,8 +173,10 @@ allocbuf(Ether *e)
 		}
 		qunlock(e);
 	}
-	if(bp == nil)
+	if(bp == nil){
+		fprint(2, "%s: blocked waiting for allocbuf\n", argv0);
 		bp = recvp(e->bc);
+	}
 	bp->rp = bp->data + Hdrsize;
 	bp->ndata = 0;
 	if(0)deprint(2, "%s: allocbuf %#p\n", argv0, bp);
@@ -186,7 +198,7 @@ newconn(Ether *e)
 		if(c == nil || c->ref == 0){
 			if(c == nil){
 				c = emallocz(sizeof(Conn), 1);
-				c->rc = chancreate(sizeof(Buf*), 2);
+				c->rc = chancreate(sizeof(Buf*), 16);
 				c->nb = i;
 			}
 			c->ref = 1;
@@ -790,7 +802,8 @@ fswrite(Usbfs *fs, Fid *fid, void *data, long count, vlong)
 		if(e->nblock == 0)
 			sendp(e->wc, bp);
 		else if(nbsendp(e->wc, bp) == 0){
-			deprint(2, "%s: (out) packet lost\n", argv0);
+			fprint(2, "%s: (out) packet lost\n", argv0);
+			e->noerrs++;
 			freebuf(e, bp);
 		}
 		break;
@@ -860,7 +873,7 @@ openeps(Ether *e, int epin, int epout)
 static int
 usage(void)
 {
-	werrstr("usage: usb/ether [-d] [-N nb]");
+	werrstr("usage: usb/ether [-a addr] [-d] [-N nb]");
 	return -1;
 }
 
@@ -937,6 +950,7 @@ etherwriteproc(void *a)
 	Buf *bp;
 	Channel *wc;
 
+	threadsetname("etherwrite");
 	wc = e->wc;
 	while(e->exiting == 0){
 		bp = recvp(wc);
@@ -987,6 +1001,7 @@ etherreadproc(void *a)
 	Buf *bp, *dbp;
 	Ether *e = a;
 
+	threadsetname("etherread");
 	while(e->exiting == 0){
 		bp = nbrecvp(e->rc);
 		if(bp == nil){
@@ -1023,6 +1038,7 @@ etherreadproc(void *a)
 					dbp->type = bp->type;
 				}
 				if(nbsendp(e->conns[i]->rc, dbp) == 0){
+					fprint(2, "%s: (in) packet lost\n", argv0);
 					e->nierrs++;
 					freebuf(e, dbp);
 				}
@@ -1131,9 +1147,15 @@ ethermain(Dev *dev, int argc, char **argv)
 {
 	int epin, epout, i, devid;
 	Ether *e;
+	uchar ea[Eaddrlen];
 
 	devid = dev->id;
+	memset(ea, 0, Eaddrlen);
 	ARGBEGIN{
+	case 'a':
+		if(parseaddr(ea, EARGF(usage())) < 0)
+			return usage();
+		break;
 	case 'd':
 		if(etherdebug == 0)
 			fprint(2, "ether debug on\n");
@@ -1151,6 +1173,7 @@ ethermain(Dev *dev, int argc, char **argv)
 	e = dev->aux = emallocz(sizeof(Ether), 1);
 	e->dev = dev;
 	dev->free = etherdevfree;
+	memmove(e->addr, ea, Eaddrlen);
 
 	for(i = 0; i < nelem(ethers); i++)
 		if(ethers[i](e) == 0)
@@ -1172,7 +1195,7 @@ ethermain(Dev *dev, int argc, char **argv)
 	snprint(e->fs.name, sizeof(e->fs.name), "etherU%d", devid);
 	e->fs.dev = dev;
 	e->fs.aux = e;
-	e->bc = chancreate(sizeof(Buf*), Nconns);
+	e->bc = chancreate(sizeof(Buf*), Nbufs);
 	e->rc = chancreate(sizeof(Buf*), Nconns/2);
 	e->wc = chancreate(sizeof(Buf*), Nconns*2);
 	incref(e->dev);

+ 3 - 1
sys/src/cmd/usb/ether/ether.h

@@ -13,6 +13,7 @@ enum
 	A88178,
 	A88179,
 	A88772,
+	S95xx,		/* SMSC */
 
 	Eaddrlen = 6,
 	Epktlen = 1514,
@@ -20,7 +21,7 @@ enum
 
 	Maxpkt	= 2000,	/* no jumbo packets here */
 	Nconns	= 8,	/* max number of connections */
-	Nbufs	= 8,	/* max number of buffers */
+	Nbufs	= 32,	/* max number of buffers */
 	Scether = 6,	/* ethernet cdc subclass */
 	Fnheader = 0,	/* Functions */
 	Fnunion = 6,
@@ -110,6 +111,7 @@ struct Etherpkt
 
 int	ethermain(Dev *dev, int argc, char **argv);
 int	asixreset(Ether*);
+int smscreset(Ether*);
 int	cdcreset(Ether*);
 int	parseaddr(uchar *m, char *s);
 void	dumpframe(char *tag, void *p, int n);

+ 4 - 1
sys/src/cmd/usb/ether/main.c

@@ -19,7 +19,7 @@ enum
 static void
 usage(void)
 {
-	fprint(2, "usage: %s [-Dd] [-N nb] [-m mnt] [-s srv] [dev...]\n", argv0);
+	fprint(2, "usage: %s [-a addr] [-Dd] [-N nb] [-m mnt] [-s srv] [dev...]\n", argv0);
 	threadexitsall("usage");
 }
 
@@ -61,6 +61,9 @@ threadmain(int argc, char **argv)
 	ae = args+sizeof(args);
 	as = seprint(args, ae, "ether");
 	ARGBEGIN{
+	case 'a':
+		as = seprint(as, ae, " -a %s", EARGF(usage()));
+		break;
 	case 'D':
 		usbfsdebug++;
 		break;

+ 1 - 0
sys/src/cmd/usb/ether/mkfile

@@ -7,6 +7,7 @@ OFILES=\
 LIBDOFILES=\
 	ether.$O\
 	asix.$O\
+	smsc.$O\
 	cdc.$O\
 
 HFILES=\

+ 353 - 0
sys/src/cmd/usb/ether/smsc.c

@@ -0,0 +1,353 @@
+/*
+ * SMSC LAN95XX
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include "usb.h"
+#include "usbfs.h"
+#include "ether.h"
+
+enum {
+	Doburst		= 1,
+	Resettime	= 1000,
+	E2pbusytime	= 1000,
+	Afcdefault	= 0xF830A1,
+//	Hsburst		= 37,
+	Hsburst		= 8,
+	Fsburst		= 129,
+	Defbulkdly	= 0x2000,
+
+	Ethp8021q	= 0x8100,
+	MACoffset 	= 1,
+	PHYinternal	= 1,
+	Rxerror		= 0x8000,
+	Txfirst		= 0x2000,
+	Txlast		= 0x1000,
+
+	/* USB vendor requests */
+	Writereg	= 0xA0,
+	Readreg		= 0xA1,
+
+	/* device registers */
+	Intsts		= 0x08,
+	Txcfg		= 0x10,
+		Txon	= 1<<2,
+	Hwcfg		= 0x14,
+		Bir	= 1<<12,
+		Rxdoff	= 3<<9,
+		Mef	= 1<<5,
+		Lrst	= 1<<3,
+		Bce	= 1<<1,
+	Pmctrl		= 0x20,
+		Phyrst	= 1<<4,
+	Ledgpio		= 0x24,
+		Ledspd	= 1<<24,
+		Ledlnk	= 1<<20,
+		Ledfdx	= 1<<16,
+	Afccfg		= 0x2C,
+	E2pcmd		= 0x30,
+		Busy	= 1<<31,
+		Timeout	= 1<<10,
+		Read	= 0,
+	E2pdata		= 0x34,
+	Burstcap	= 0x38,
+	Intepctl	= 0x68,
+		Phyint	= 1<<15,
+	Bulkdelay	= 0x6C,
+	Maccr		= 0x100,
+		Mcpas	= 1<<19,
+		Prms	= 1<<18,
+		Hpfilt	= 1<<13,
+		Txen	= 1<<3,
+		Rxen	= 1<<2,
+	Addrh		= 0x104,
+	Addrl		= 0x108,
+	Hashh		= 0x10C,
+	Hashl		= 0x110,
+	MIIaddr		= 0x114,
+		MIIwrite= 1<<1,
+		MIIread	= 0<<1,
+		MIIbusy	= 1<<0,
+	MIIdata		= 0x118,
+	Flow		= 0x11C,
+	Vlan1		= 0x120,
+	Coecr		= 0x130,
+		Txcoe	= 1<<16,
+		Rxcoemd	= 1<<1,
+		Rxcoe	= 1<<0,
+
+	/* MII registers */
+	Bmcr		= 0,
+		Bmcrreset= 1<<15,
+		Speed100= 1<<13,
+		Anenable= 1<<12,
+		Anrestart= 1<<9,
+		Fulldpx	= 1<<8,
+	Bmsr		= 1,
+	Advertise	= 4,
+		Adcsma	= 0x0001,
+		Ad10h	= 0x0020,
+		Ad10f	= 0x0040,
+		Ad100h	= 0x0080,
+		Ad100f	= 0x0100,
+		Adpause	= 0x0400,
+		Adpauseasym= 0x0800,
+		Adall	= Ad10h|Ad10f|Ad100h|Ad100f,
+	Phyintsrc	= 29,
+	Phyintmask	= 30,
+		Anegcomp= 1<<6,
+		Linkdown= 1<<4,
+};
+
+static int
+wr(Dev *d, int reg, int val)
+{
+	int ret;
+
+	ret = usbcmd(d, Rh2d|Rvendor|Rdev, Writereg, 0, reg,
+		(uchar*)&val, sizeof(val));
+	if(ret < 0)
+		deprint(2, "%s: wr(%x, %x): %r", argv0, reg, val);
+	return ret;
+}
+
+static int
+rr(Dev *d, int reg)
+{
+	int ret, rval;
+
+	ret = usbcmd(d, Rd2h|Rvendor|Rdev, Readreg, 0, reg,
+		(uchar*)&rval, sizeof(rval));
+	if(ret < 0){
+		fprint(2, "%s: rr(%x): %r", argv0, reg);
+		return 0;
+	}
+	return rval;
+}
+
+static int
+miird(Dev *d, int idx)
+{
+	while(rr(d, MIIaddr) & MIIbusy)
+		;
+	wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIread);
+	while(rr(d, MIIaddr) & MIIbusy)
+		;
+	return rr(d, MIIdata);
+}
+
+static void
+miiwr(Dev *d, int idx, int val)
+{
+	while(rr(d, MIIaddr) & MIIbusy)
+		;
+	wr(d, MIIdata, val);
+	wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIwrite);
+	while(rr(d, MIIaddr) & MIIbusy)
+		;
+}
+
+static int
+eepromr(Dev *d, int off, uchar *buf, int len)
+{
+	int i, v;
+
+	for(i = 0; i < E2pbusytime; i++)
+		if((rr(d, E2pcmd) & Busy) == 0)
+			break;
+	if(i == E2pbusytime)
+		return -1;
+	for(i = 0; i < len; i++){
+		wr(d, E2pcmd, Busy|Read|(i+off));
+		while((v = rr(d, E2pcmd) & (Busy|Timeout)) == Busy)
+			;
+		if(v & Timeout)
+			return -1;
+		buf[i] = rr(d, E2pdata);
+	}
+	return 0;
+}
+
+static void
+phyinit(Dev *d)
+{
+	int i;
+
+	miiwr(d, Bmcr, Bmcrreset|Anenable);
+	for(i = 0; i < Resettime/10; i++){
+		if((miird(d, Bmcr) & Bmcrreset) == 0)
+			break;
+		sleep(10);
+	}
+	miiwr(d, Advertise, Adcsma|Adall|Adpause|Adpauseasym);
+//	miiwr(d, Advertise, Adcsma|Ad10f|Ad10h|Adpause|Adpauseasym);
+	miird(d, Phyintsrc);
+	miiwr(d, Phyintmask, Anegcomp|Linkdown);
+	miiwr(d, Bmcr, miird(d, Bmcr)|Anenable|Anrestart);
+}
+
+
+static int
+doreset(Dev *d, int reg, int bit)
+{
+	int i;
+
+	if(wr(d, reg, bit) < 0)
+		return -1;
+	for(i = 0; i < Resettime/10; i++){
+		 if((rr(d, reg) & bit) == 0)
+			return 1;
+		sleep(10);
+	}
+	return 0;
+}
+
+static int
+getmac(Dev *d, uchar buf[])
+{
+	int i;
+	uchar ea[Eaddrlen];
+
+	if(eepromr(d, MACoffset, ea, Eaddrlen) < 0)
+		return -1;
+	for(i = 0; i < Eaddrlen; i++)
+		if(ea[i] != 0){
+			memmove(buf, ea, Eaddrlen);
+			break;
+		}
+	return Eaddrlen;
+}
+
+static int
+smscinit(Ether *ether)
+{
+	Dev *d;
+
+	if(ether->cid != S95xx)
+		return -1;
+	d = ether->dev;
+	deprint(2, "%s: setting up SMSC95XX\n", argv0);
+	if(!doreset(d, Hwcfg, Lrst) || !doreset(d, Pmctrl, Phyrst))
+		return -1;
+	if(getmac(d, ether->addr) < 0)
+		return -1;
+	wr(d, Addrl, GET4(ether->addr));
+	wr(d, Addrh, GET2(ether->addr+4));
+	if(Doburst){
+		wr(d, Hwcfg, (rr(d,Hwcfg)&~Rxdoff)|Bir|Mef|Bce);
+		wr(d, Burstcap, Hsburst);
+	}else{
+		wr(d, Hwcfg, (rr(d,Hwcfg)&~(Rxdoff|Mef|Bce))|Bir);
+		wr(d, Burstcap, 0);
+	}
+	wr(d, Bulkdelay, Defbulkdly);
+	wr(d, Intsts, ~0);
+	wr(d, Ledgpio, Ledspd|Ledlnk|Ledfdx);
+	wr(d, Flow, 0);
+	wr(d, Afccfg, Afcdefault);
+	wr(d, Vlan1, Ethp8021q);
+	wr(d, Coecr, rr(d,Coecr)&~(Txcoe|Rxcoe)); /* TODO could offload checksums? */
+
+	wr(d, Hashh, 0);
+	wr(d, Hashl, 0);
+	wr(d, Maccr, rr(d,Maccr)&~(Prms|Mcpas|Hpfilt));
+
+	phyinit(d);
+
+	wr(d, Intepctl, rr(d, Intepctl)|Phyint);
+	wr(d, Maccr, rr(d, Maccr)|Txen|Rxen);
+	wr(d, Txcfg, Txon);
+
+	return 0;
+}
+
+static long
+smscbread(Ether *e, Buf *bp)
+{
+	uint hd;
+	int n, m;
+	Buf *rbp;
+
+	rbp = e->aux;
+	if(rbp->ndata < 4){
+		rbp->rp = rbp->data;
+		rbp->ndata = read(e->epin->dfd, rbp->rp, Doburst? Hsburst*512:
+			sizeof(rbp->data));
+		if(rbp->ndata < 0)
+			return -1;
+	}
+	if(rbp->ndata < 4){
+		werrstr("short frame");
+		fprint(2, "smsc short frame %d bytes\n", rbp->ndata);
+		return 0;
+	}
+	hd = GET4(rbp->rp);
+	n = hd >> 16;
+	m = (n + 4 + 3) & ~3;
+	if(n < 6 || m > rbp->ndata){
+		werrstr("frame length");
+		fprint(2, "smsc length error packet %d buf %d\n", n, rbp->ndata);
+		rbp->ndata = 0;
+		return 0;
+	}
+	if(hd & Rxerror){
+		fprint(2, "smsc rx error %8.8ux\n", hd);
+		n = 0;
+	}else{
+		bp->rp = bp->data + Hdrsize;
+		memmove(bp->rp, rbp->rp+4, n);
+	}
+	bp->ndata = n;
+	rbp->rp += m;
+	rbp->ndata -= m;
+	return n;
+}
+
+static long
+smscbwrite(Ether *e, Buf *bp)
+{
+	int n;
+
+	n = bp->ndata & 0x7FF;
+	bp->rp -= 8;
+	bp->ndata += 8;
+	PUT4(bp->rp, n | Txfirst | Txlast);
+	PUT4(bp->rp+4, n);
+	n = write(e->epout->dfd, bp->rp, bp->ndata);
+	return n;
+}
+
+static void
+smscfree(Ether *ether)
+{
+	free(ether->aux);
+	ether->aux = nil;
+}
+
+int
+smscreset(Ether *ether)
+{
+	Cinfo *ip;
+	Dev *dev;
+
+	dev = ether->dev;
+	for(ip = cinfo; ip->vid != 0; ip++)
+		if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
+			ether->cid = ip->cid;
+			if(smscinit(ether) < 0){
+				deprint(2, "%s: smsc init failed: %r\n", argv0);
+				return -1;
+			}
+			deprint(2, "%s: smsc reset done\n", argv0);
+			ether->aux = emallocz(sizeof(Buf) + Hsburst*512 - Maxpkt, 1);
+			ether->free = smscfree;
+			ether->bread = smscbread;
+			ether->bwrite = smscbwrite;
+			ether->mbps = 100;	/* BUG */
+			return 0;
+		}
+	return -1;
+}

+ 54 - 29
sys/src/cmd/usb/usbd/usbd.c

@@ -711,9 +711,21 @@ setdrvargs(char *name, char *args)
 			dt->args = estrdup(args);
 }
 
+static void
+setdrvauto(char *name, int on)
+{
+	Devtab *dt;
+	extern Devtab devtab[];
+
+	for(dt = devtab; dt->name != nil; dt++)
+		if(strstr(dt->name, name) != nil)
+			dt->noauto = !on;
+}
+
 static long
 cfswrite(Usbfs*, Fid *, void *data, long cnt, vlong )
 {
+	char *cmd, *arg;
 	char buf[80];
 	char *toks[4];
 
@@ -736,17 +748,25 @@ cfswrite(Usbfs*, Fid *, void *data, long cnt, vlong )
 		return cnt;
 	}
 	if(tokenize(buf, toks, nelem(toks)) != 2){
-		werrstr("usage: debug|fsdebug n");
+		werrstr("usage: auto|debug|diskargs|fsdebug|kbargs|noauto n");
 		return -1;
 	}
-	if(strcmp(toks[0], "debug") == 0)
-		usbdebug = atoi(toks[1]);
-	else if(strcmp(toks[0], "fsdebug") == 0)
-		usbfsdebug = atoi(toks[1]);
-	else if(strcmp(toks[0], "kbargs") == 0)
-		setdrvargs("kb", toks[1]);
-	else if(strcmp(toks[0], "diskargs") == 0)
-		setdrvargs("disk", toks[1]);
+	cmd = toks[0];
+	arg = toks[1];
+	if(strcmp(cmd, "auto") == 0)
+		setdrvauto(arg, 1);
+	else if(strcmp(cmd, "debug") == 0)
+		usbdebug = atoi(arg);
+	else if(strcmp(cmd, "diskargs") == 0)
+		setdrvargs("disk", arg);
+	else if(strcmp(cmd, "etherargs") == 0)
+		setdrvargs("ether", arg);
+	else if(strcmp(cmd, "fsdebug") == 0)
+		usbfsdebug = atoi(arg);
+	else if(strcmp(cmd, "kbargs") == 0)
+		setdrvargs("kb", arg);
+	else if(strcmp(cmd, "noauto") == 0)
+		setdrvauto(arg, 0);
 	else{
 		werrstr("unknown ctl '%s'", buf);
 		return -1;
@@ -778,28 +798,37 @@ static Usbfs ctlfs =
 };
 
 static void
-args(void)
+getenvint(char *env, int *lp)
 {
 	char *s;
 
-	s = getenv("usbdebug");
-	if(s != nil)
-		usbdebug = atoi(s);
+	s = getenv(env);
+	if (s != nil)
+		*lp = atoi(s);
 	free(s);
-	s = getenv("usbfsdebug");
-	if(s != nil)
-		usbfsdebug = atoi(s);
-	free(s);
-	s = getenv("kbargs");
-	if(s != nil)
-		setdrvargs("kb", s);
-	free(s);
-	s = getenv("diskargs");
+}
+
+static void
+getenvdrvargs(char *env, char *argname)
+{
+	char *s;
+
+	s = getenv(env);
 	if(s != nil)
-		setdrvargs("disk", s);
+		setdrvargs(argname, s);
 	free(s);
 }
 
+static void
+args(void)
+{
+	getenvint("usbdebug",	&usbdebug);
+	getenvint("usbfsdebug",	&usbfsdebug);
+	getenvdrvargs("kbargs",    "kb");
+	getenvdrvargs("diskargs",  "disk");
+	getenvdrvargs("etherargs", "ether");
+}
+
 static void
 usage(void)
 {
@@ -812,13 +841,9 @@ extern void usbfsexits(int);
 void
 threadmain(int argc, char **argv)
 {
-	int i;
+	int fd, i, nd;
+	char *err, *mnt, *srv;
 	Dir *d;
-	int fd;
-	int nd;
-	char *err;
-	char *srv;
-	char *mnt;
 
 	srv = "usb";
 	mnt = "/dev";

+ 1 - 0
sys/src/cmd/usb/usbd/usbd.h

@@ -122,6 +122,7 @@ struct Devtab
 	int	did;
 	char	*args;
 	uvlong	devmask;
+	int	noauto;
 };
 
 

+ 2 - 0
sys/src/cmd/usb/usbd/usbdb

@@ -4,8 +4,10 @@ embed
 	kb	csp=0x010103 csp=0x020103	args=
 	disk	class=storage			args=
 	ether	class=255 csp=0x00ffff vid=0x0b95		args=
+	ether	class=255 csp=0xff00ff vid=0x0424 did=0xec00	args=
 	serial	class=255 csp=0xffffff vid=0x9e88 did=0x9e8f	args=
 	serial	class=255 csp=0xffffff vid=0x0403		args=
+	serial	class=255 csp=0x0000ff vid=0x10c4	args=
 #	wifi	class=0 csp=0 vid=0x0bda did=0x8192		args=
 #	wifi	class=0 csp=0 vid=0x148f did=0x2870		args=
 auto