1.1--- a/sys/src/cmd/nusb/ether/ether.c
1.2+++ b/sys/src/cmd/nusb/ether/ether.c
1.3@@ -886,6 +886,7 @@ extern int aueinit(Dev *);
1.4 extern int a88178init(Dev *);
1.5 extern int a88772init(Dev *);
1.6 extern int smscinit(Dev *);
1.7+extern int lan78xxinit(Dev *);
1.8 extern int cdcinit(Dev *);
1.9 extern int urlinit(Dev *);
1.10 extern int rndisinit(Dev *);
1.11@@ -896,6 +897,7 @@ static struct {
1.12 } ethertype[] = {
1.13 "cdc", cdcinit,
1.14 "smsc", smscinit,
1.15+ "lan78xx", lan78xxinit,
1.16 "a88178", a88178init,
1.17 "a88772", a88772init,
1.18 "aue", aueinit,
1.19@@ -921,7 +923,8 @@ threadmain(int argc, char **argv)
1.20 break;
1.21 case 'a':
1.22 setmac = 1;
1.23- parseether(macaddr, EARGF(usage()));
1.24+ if(parseether(macaddr, EARGF(usage())) != 0)
1.25+ usage();
1.26 break;
1.27 case 't':
1.28 t = EARGF(usage());
2.1new file mode 100644
2.2--- /dev/null
2.3+++ b/sys/src/cmd/nusb/ether/lan78xx.c
2.4@@ -0,0 +1,366 @@
2.5+/*
2.6+ * Microchip (ex SMSC) LAN78XX
2.7+ * Also used as ethernet core in LAN7515 usb hub + ethernet
2.8+ */
2.9+
2.10+#include <u.h>
2.11+#include <libc.h>
2.12+#include <thread.h>
2.13+
2.14+#include "usb.h"
2.15+#include "dat.h"
2.16+
2.17+enum {
2.18+ Doburst = 1,
2.19+ Resettime = 1000,
2.20+ E2pbusytime = 1000,
2.21+ Hsburst = 32,
2.22+ Defbulkdly = 1000,
2.23+ Rxfifosize = (12*1024),
2.24+ Txfifosize = (12*1024),
2.25+
2.26+ MACoffset = 1,
2.27+ PHYinternal = 1,
2.28+ Rxerror = 0x00400000,
2.29+ Txfcs = 1<<22,
2.30+
2.31+ /* USB vendor requests */
2.32+ Writereg = 0xA0,
2.33+ Readreg = 0xA1,
2.34+
2.35+ /* device registers */
2.36+ Idrev = 0x00,
2.37+ Intsts = 0x0C,
2.38+ Hwcfg = 0x10,
2.39+ Led0en = 1<<20,
2.40+ Led1en = 1<<21,
2.41+ Mef = 1<<4,
2.42+ Lrst = 1<<1,
2.43+ Pmctrl = 0x14,
2.44+ Ready = 1<<7,
2.45+ Phyrst = 1<<4,
2.46+ Gpiocfg0 = 0x18,
2.47+ Gpiocfg1 = 0x1C,
2.48+ E2pcmd = 0x40,
2.49+ Busy = 1<<31,
2.50+ Timeout = 1<<10,
2.51+ Loaded = 1<<9,
2.52+ Read = 0,
2.53+ E2pdata = 0x44,
2.54+ Burstcap = 0x90,
2.55+ Intepctl = 0x98,
2.56+ Phyint = 1<<17,
2.57+ Bulkdelay = 0x94,
2.58+ Rfectl = 0xB0,
2.59+ Rxcoe = 0xF<<11,
2.60+ Ab = 1<<10,
2.61+ Am = 1<<9,
2.62+ Au = 1<<8,
2.63+ Dpf = 1<<1,
2.64+ Usbcfg0 = 0x80,
2.65+ Bir = 1<<6,
2.66+ Bce = 1<<5,
2.67+ Usbcfg1 = 0x84,
2.68+ Rxfifoctl = 0xC0,
2.69+ Rxen = 1<<31,
2.70+ Txfifoctl = 0xC4,
2.71+ Txen = 1<<31,
2.72+ Rxfifo = 0xC8,
2.73+ Txfifo = 0xCc,
2.74+ Fctflow = 0xD0,
2.75+ Maccr = 0x100,
2.76+ Add = 1<<12,
2.77+ Asd = 1<<11,
2.78+ Macrx = 0x104,
2.79+ Macfcs = 1<<4,
2.80+ Macrxen = 1<<0,
2.81+ Mactx = 0x108,
2.82+ Mactxen = 1<<0,
2.83+ Addrh = 0x118,
2.84+ Addrl = 0x11C,
2.85+ MIIaddr = 0x120,
2.86+ MIIwrite= 1<<1,
2.87+ MIIread = 0<<1,
2.88+ MIIbusy = 1<<0,
2.89+ MIIdata = 0x124,
2.90+ Flow = 0x10C,
2.91+ Addrfilth = 0x400,
2.92+ Afvalid = 1<<31,
2.93+ Addrfiltl = 0x404,
2.94+
2.95+ /* MII registers */
2.96+ Bmcr = 0,
2.97+ Bmcrreset= 1<<15,
2.98+ Speed100= 1<<13,
2.99+ Anenable= 1<<12,
2.100+ Anrestart= 1<<9,
2.101+ Fulldpx = 1<<8,
2.102+ Speed1000= 1<<6,
2.103+ Bmsr = 1,
2.104+ Advertise = 4,
2.105+ Adcsma = 0x0001,
2.106+ Ad10h = 0x0020,
2.107+ Ad10f = 0x0040,
2.108+ Ad100h = 0x0080,
2.109+ Ad100f = 0x0100,
2.110+ Adpause = 0x0400,
2.111+ Adpauseasym= 0x0800,
2.112+ Adall = Ad10h|Ad10f|Ad100h|Ad100f,
2.113+ Lpa = 5,
2.114+ Ctrl1000 = 9,
2.115+ Ad1000h = 0x0400,
2.116+ Ad1000f = 0x0200,
2.117+ Ledmodes = 29,
2.118+ Led0shift = 0,
2.119+ Led1shift = 4,
2.120+ Linkact = 0x0,
2.121+ Link1000 = 0x1,
2.122+ Phyintmask = 25,
2.123+ Anegcomp= 1<<10,
2.124+ Linkchg = 1<<13,
2.125+};
2.126+
2.127+static int burstcap = Hsburst, bulkdelay = Defbulkdly;
2.128+
2.129+static int
2.130+wr(Dev *d, int reg, int val)
2.131+{
2.132+ int ret;
2.133+
2.134+ ret = usbcmd(d, Rh2d|Rvendor|Rdev, Writereg, 0, reg,
2.135+ (uchar*)&val, sizeof(val));
2.136+ if(ret < 0)
2.137+ fprint(2, "%s: wr(%x, %x): %r", argv0, reg, val);
2.138+ return ret;
2.139+}
2.140+
2.141+static int
2.142+rr(Dev *d, int reg)
2.143+{
2.144+ int ret, rval;
2.145+
2.146+ ret = usbcmd(d, Rd2h|Rvendor|Rdev, Readreg, 0, reg,
2.147+ (uchar*)&rval, sizeof(rval));
2.148+ if(ret < 0){
2.149+ fprint(2, "%s: rr(%x): %r", argv0, reg);
2.150+ return 0;
2.151+ }
2.152+ return rval;
2.153+}
2.154+
2.155+static int
2.156+miird(Dev *d, int idx)
2.157+{
2.158+ while(rr(d, MIIaddr) & MIIbusy)
2.159+ ;
2.160+ wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIread | MIIbusy);
2.161+ while(rr(d, MIIaddr) & MIIbusy)
2.162+ ;
2.163+ return rr(d, MIIdata);
2.164+}
2.165+
2.166+static void
2.167+miiwr(Dev *d, int idx, int val)
2.168+{
2.169+ while(rr(d, MIIaddr) & MIIbusy)
2.170+ ;
2.171+ wr(d, MIIdata, val);
2.172+ wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIwrite | MIIbusy);
2.173+ while(rr(d, MIIaddr) & MIIbusy)
2.174+ ;
2.175+}
2.176+
2.177+static int
2.178+eepromr(Dev *d, int off, uchar *buf, int len)
2.179+{
2.180+ int i, v;
2.181+
2.182+ for(i = 0; i < E2pbusytime; i++)
2.183+ if((rr(d, E2pcmd) & Busy) == 0)
2.184+ break;
2.185+ if(i == E2pbusytime)
2.186+ return -1;
2.187+ for(i = 0; i < len; i++){
2.188+ wr(d, E2pcmd, Busy|Read|(i+off));
2.189+ while((v = rr(d, E2pcmd) & (Busy|Timeout)) == Busy)
2.190+ ;
2.191+ if(v & Timeout)
2.192+ return -1;
2.193+ buf[i] = rr(d, E2pdata);
2.194+ }
2.195+ return 0;
2.196+}
2.197+
2.198+static void
2.199+phyinit(Dev *d)
2.200+{
2.201+ int i;
2.202+
2.203+ miiwr(d, Bmcr, Bmcrreset|Anenable);
2.204+ for(i = 0; i < Resettime/10; i++){
2.205+ if((miird(d, Bmcr) & Bmcrreset) == 0)
2.206+ break;
2.207+ sleep(10);
2.208+ }
2.209+ miiwr(d, Advertise, Adcsma|Adall|Adpause|Adpauseasym);
2.210+ miiwr(d, Ctrl1000, Ad1000f);
2.211+ miiwr(d, Phyintmask, 0);
2.212+ miiwr(d, Ledmodes, (Linkact<<Led1shift) | (Link1000<<Led0shift));
2.213+ miiwr(d, Bmcr, miird(d, Bmcr)|Anenable|Anrestart);
2.214+}
2.215+
2.216+
2.217+static int
2.218+doreset(Dev *d, int reg, int bit)
2.219+{
2.220+ int i;
2.221+
2.222+ if(wr(d, reg, bit) < 0)
2.223+ return -1;
2.224+ for(i = 0; i < Resettime/10; i++){
2.225+ if((rr(d, reg) & bit) == 0)
2.226+ return 1;
2.227+ sleep(10);
2.228+ }
2.229+ return 0;
2.230+}
2.231+
2.232+static int
2.233+lan78xxreceive(Dev *ep)
2.234+{
2.235+ Block *b;
2.236+ uint hd;
2.237+ int n;
2.238+
2.239+ n = Doburst? burstcap*512: Maxpkt;
2.240+ b = allocb(n);
2.241+ if((n = read(ep->dfd, b->wp, n)) < 10){
2.242+ freeb(b);
2.243+ return -1;
2.244+ }
2.245+ b->wp += n;
2.246+ while(BLEN(b) >= 10){
2.247+ hd = GET4(b->rp);
2.248+ b->rp += 10;
2.249+ n = hd & 0x3FFF;
2.250+ if(n > BLEN(b))
2.251+ break;
2.252+ if((hd & Rxerror) == 0){
2.253+ if(n == BLEN(b)){
2.254+ etheriq(b);
2.255+ return 0;
2.256+ }
2.257+ etheriq(copyblock(b, n));
2.258+ }
2.259+ b->rp = (uchar*)(((uintptr)b->rp + n + 3)&~3);
2.260+ }
2.261+ freeb(b);
2.262+ return 0;
2.263+}
2.264+
2.265+static void
2.266+lan78xxtransmit(Dev *ep, Block *b)
2.267+{
2.268+ int n = BLEN(b) & 0xFFFFF;
2.269+ b->rp -= 8;
2.270+ PUT4(b->rp, n | Txfcs);
2.271+ PUT4(b->rp+4, n);
2.272+ write(ep->dfd, b->rp, BLEN(b));
2.273+ freeb(b);
2.274+}
2.275+
2.276+static int
2.277+lan78xxpromiscuous(Dev *d, int on)
2.278+{
2.279+ int rxctl;
2.280+
2.281+ rxctl = rr(d, Rfectl);
2.282+ if(on)
2.283+ rxctl |= Am|Au;
2.284+ else {
2.285+ rxctl &= ~Au;
2.286+ if(nmulti == 0)
2.287+ rxctl &= ~Am;
2.288+ }
2.289+ return wr(d, Rfectl, rxctl);
2.290+}
2.291+
2.292+static int
2.293+lan78xxmulticast(Dev *d, uchar *, int)
2.294+{
2.295+ int rxctl;
2.296+
2.297+ rxctl = rr(d, Rfectl);
2.298+ if(nmulti != 0)
2.299+ rxctl |= Am;
2.300+ else
2.301+ rxctl &= ~Am;
2.302+ return wr(d, Rfectl, rxctl);
2.303+}
2.304+
2.305+int
2.306+lan78xxinit(Dev *d)
2.307+{
2.308+ u32int a;
2.309+ int i;
2.310+
2.311+ if(!doreset(d, Hwcfg, Lrst) || !doreset(d, Pmctrl, Phyrst))
2.312+ return -1;
2.313+ for(i = 0; i < Resettime/10; i++){
2.314+ if(rr(d, Pmctrl) & Ready)
2.315+ break;
2.316+ sleep(10);
2.317+ }
2.318+ if((rr(d, Pmctrl) & Ready) == 0){
2.319+ fprint(2, "%s: device not ready after reset\n", argv0);
2.320+ return -1;
2.321+ }
2.322+
2.323+ if(!setmac)
2.324+ if(eepromr(d, MACoffset, macaddr, Eaddrlen) < 0)
2.325+ fprint(2, "%s: can't read etheraddr from EEPROM\n", argv0);
2.326+
2.327+ a = GET4(macaddr);
2.328+ wr(d, Addrl, a);
2.329+ wr(d, Addrfiltl, a);
2.330+ a = GET2(macaddr+4);
2.331+ wr(d, Addrh, a);
2.332+ wr(d, Addrfilth, a|Afvalid);
2.333+
2.334+ wr(d, Usbcfg0, rr(d, Usbcfg0) | Bir);
2.335+ if(Doburst){
2.336+ wr(d, Hwcfg, rr(d, Hwcfg)|Mef);
2.337+ wr(d, Usbcfg0, rr(d, Usbcfg0)|Bce);
2.338+ wr(d, Burstcap, burstcap);
2.339+ wr(d, Bulkdelay, bulkdelay);
2.340+ }else{
2.341+ wr(d, Hwcfg, rr(d, Hwcfg)&~Mef);
2.342+ wr(d, Usbcfg0, rr(d, Usbcfg0)&~Bce);
2.343+ wr(d, Burstcap, 0);
2.344+ wr(d, Bulkdelay, 0);
2.345+ }
2.346+ wr(d, Rxfifo, (Rxfifosize-512)/512);
2.347+ wr(d, Txfifo, (Txfifosize-512)/512);
2.348+ wr(d, Intsts, ~0);
2.349+ wr(d, Hwcfg, rr(d, Hwcfg) | Led0en|Led1en);
2.350+ wr(d, Flow, 0);
2.351+ wr(d, Fctflow, 0);
2.352+ wr(d, Rfectl, (rr(d, Rfectl) & ~Rxcoe) | Ab|Dpf); /* TODO could offload checksums? */
2.353+
2.354+ phyinit(d);
2.355+
2.356+ wr(d, Maccr, rr(d,Maccr)|Add|Asd);
2.357+
2.358+ wr(d, Intepctl, rr(d, Intepctl)|Phyint);
2.359+ wr(d, Mactx, Mactxen);
2.360+ wr(d, Macrx, rr(d, Macrx) | Macfcs|Macrxen);
2.361+ wr(d, Txfifoctl, Txen);
2.362+ wr(d, Rxfifoctl, Rxen);
2.363+
2.364+ eptransmit = lan78xxtransmit;
2.365+ epreceive = lan78xxreceive;
2.366+ eppromiscuous = lan78xxpromiscuous;
2.367+ epmulticast = lan78xxmulticast;
2.368+
2.369+ return 0;
2.370+}
3.1--- a/sys/src/cmd/nusb/ether/mkfile
3.2+++ b/sys/src/cmd/nusb/ether/mkfile
3.3@@ -5,7 +5,7 @@ LIB=../lib/usb.a$O
3.4
3.5 TARG=ether
3.6 HFILES=../lib/usb.h dat.h
3.7-OFILES=ether.$O cdc.$O smsc.$O asix.$O aue.$O url.$O rndis.$O
3.8+OFILES=ether.$O cdc.$O smsc.$O lan78xx.$O asix.$O aue.$O url.$O rndis.$O
3.9
3.10 </sys/src/cmd/mkone
3.11