theoretical support for the rtl8150 usb ethernet chipset. untested due to no hardware. Reference: /n/atom/patch/applied2013/rtl8150 Date: Thu Oct 3 21:31:08 CES 2013 Signed-off-by: quanstro@quanstro.net --- /sys/src/cmd/usb/ether/ether.h Thu Oct 3 21:30:48 2013 +++ /sys/src/cmd/usb/ether/ether.h Thu Oct 3 21:30:48 2013 @@ -113,8 +113,9 @@ int ethermain(Dev *dev, int argc, char **argv); int asixreset(Ether*); -int smscreset(Ether*); +int smscreset(Ether*); int cdcreset(Ether*); +int rtl8150reset(Ether*); int parseaddr(uchar *m, char *s); void dumpframe(char *tag, void *p, int n); --- /sys/src/cmd/usb/ether/ether.c Thu Oct 3 21:30:50 2013 +++ /sys/src/cmd/usb/ether/ether.c Thu Oct 3 21:30:51 2013 @@ -121,6 +121,7 @@ { asixreset, smscreset, + rtl8150reset, cdcreset, /* keep last */ }; --- /sys/src/cmd/usb/ether/mkfile Thu Oct 3 21:30:52 2013 +++ /sys/src/cmd/usb/ether/mkfile Thu Oct 3 21:30:52 2013 @@ -9,6 +9,7 @@ asix.$O\ smsc.$O\ cdc.$O\ + rtl8150.$O\ HFILES=\ ether.h\ --- /sys/src/cmd/usb/ether/rtl8150.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/usb/ether/rtl8150.c Thu Oct 3 21:30:52 2013 @@ -0,0 +1,324 @@ +/* +* realtek rtl8150 10/100 usb ethernet device driver +* +* copy-pasted from shingo watanabe's openbsd rtl8150(4) driver +* and bill paul's and shunsuke akiyama's freebsd rue(4) driver +*/ +#include +#include +#include +#include +#include "usb.h" +#include "usbfs.h" +#include "ether.h" + +enum { + Timeout = 50, + Mfl = 60, /* min frame len */ +}; + +enum { /* requests */ + Rqm = 0x05, /* request mem */ + Crm = 1, /* command read mem */ + Cwm = 2, /* command write mem */ +}; + +enum { /* registers */ + Idr0 = 0x120, /* ether addr, load from 93c46 */ + Idr1 = 0x121, + Idr2 = 0x122, + Idr3 = 0x123, + Idr4 = 0x124, + Idr5 = 0x125, + + Mar0 = 0x126, /* multicast addr */ + Mar1 = 0x127, + Mar2 = 0x128, + Mar3 = 0x129, + Mar4 = 0x12a, + Mar5 = 0x12b, + Mar6 = 0x12c, + Mar7 = 0x12d, + + Cr = 0x12e, /* command */ + Tcr = 0x12f, /* transmit control */ + Rcr = 0x130, /* receive configuration */ + Tsr = 0x132, + Rsr = 0x133, + Con0 = 0x135, + Con1 = 0x136, + Msr = 0x137, /* media status */ + Phyar = 0x138, /* mii phy addr select */ + Phydr = 0x139, /* mii phy data */ + Phycr = 0x13b, /* mii phy control */ + Gppc = 0x13d, + Wcr = 0x13e, /* wake count */ + Bmcr = 0x140, /* basic mode control */ + Bmsr = 0x142, /* basic mode status */ + Anar = 0x144, /* an advertisement */ + Anlp = 0x146, /* an link partner ability */ + Aner = 0x148, + Nwtr = 0x14a, /* nway test */ + Cscr = 0x14c, + + Crc0 = 0x14e, + Crc1 = 0x150, + Crc2 = 0x152, + Crc3 = 0x154, + Crc4 = 0x156, + + Bm0 = 0x158, /* byte mask */ + Bm1 = 0x160, + Bm2 = 0x168, + Bm3 = 0x170, + Bm4 = 0x178, + + Phy1 = 0x180, + Phy2 = 0x184, + Tw1 = 0x186 +}; + +enum { /* Cr */ + We = 1 << 5, /* eeprom write enable */ + Sr = 1 << 4, /* software reset */ + Re = 1 << 3, /* ethernet receive enable */ + Te = 1 << 2, /* ethernet transmit enable */ + Ep3ce = 1 << 1, /* enable clr of perf counter */ + Al = 1 << 0 /* auto-load contents of 93c46 */ +}; + +enum { /* Tcr */ + Tr1 = 1 << 7, /* tx retry count */ + Tr0 = 1 << 6, + Ifg1 = 1 << 4, /* interframe gap time */ + Ifg0 = 1 << 3, + Nocrc = 1 << 0 /* no crc appended */ +}; + +enum { /* Rcr */ + Tail = 1 << 7, + Aer = 1 << 6, + Ar = 1 << 5, + Am = 1 << 4, + Ab = 1 << 3, + Ad = 1 << 2, + Aam = 1 << 1, + Aap = 1 << 0 +}; + +enum { /* Msr */ + Tfce = 1 << 7, + Rfce = 1 << 6, + Mdx = 1 << 4, /* duplex */ + S100 = 1 << 3, /* speed 100 */ + Lnk = 1 << 2, + Tpf = 1 << 1, + Rpf = 1 << 0 +}; + +enum { /* Phyar */ + Phyamsk = 0x1f +}; + +enum { /* Phycr */ + Phyown = 1 << 6, /* own bit */ + Rwcr = 1 << 5, /* mii mgmt data r/w control */ + Phyoffmsk = 0x1f /* phy register offset */ +}; + +enum { /* Bmcr */ + Spd = 0x2000, /* speed set */ + Bdx = 0x0100 /* duplex */ +}; + +enum { /* Anar */ + Ap = 0x0400 /* pause */ +}; + +enum { /* Anlp */ + Lpp = 0x0400 /* pause */ +}; + +enum { /* eeprom address declarations */ + Ebase = 0x1200, + Eidr0 = Ebase + 0x02, + Eidr1 = Ebase + 0x03, + Eidr2 = Ebase + 0x03, + Eidr3 = Ebase + 0x03, + Eidr4 = Ebase + 0x03, + Eidr5 = Ebase + 0x03, + Eint = Ebase + 0x17 /* interval */ +}; + +enum { /* receive header */ + Bcm = 0x0fff, /* rx bytes count mask */ + Vpm = 0x1000, /* valid packet mask */ + Rpm = 0x2000, /* runt packet mask */ + Ppm = 0x4000, /* physical match packet mask */ + Mpm = 0x8000 /* multicast packet mask */ +}; + +static int +mem(Dev *d, int cmd, int off, uchar *buf, int len) +{ + int r, rc; + + if(d == nil) + return 0; + r = Rvendor | Rdev; + if(cmd == Crm) + r |= Rd2h; + else + r |= Rh2d; + rc = usbcmd(d, r, Rqm, off, 0, buf, len); + if(rc < 0) { + fprint(2, "%s: mem(%d, %#.4x) failed\n", + argv0, cmd, off); + } + return rc; +} + +static int +csr8r(Dev *d, int reg) +{ + uchar v; + + v = 0; + if(mem(d, Crm, reg, &v, sizeof v) < 0) + return 0; + return v; +} + +static int +csr16r(Dev *d, int reg) +{ + uchar v[2]; + + PUT2(v, 0); + if(mem(d, Crm, reg, v, sizeof v) < 0) + return 0; + return GET2(v); +} + +static int +csr8w(Dev *d, int reg, int val) +{ + uchar v; + + v = val; + if(mem(d, Cwm, reg, &v, sizeof v) < 0) + return -1; + return 0; +} + +static int +csr16w(Dev *d, int reg, int val) +{ + uchar v[2]; + + PUT2(v, val); + if(mem(d, Cwm, reg, v, sizeof v) < 0) + return -1; + return 0; +} + +static int +csr32w(Dev *d, int reg, int val) +{ + uchar v[4]; + + PUT4(v, val); + if(mem(d, Cwm, reg, v, sizeof v) < 0) + return -1; + return 0; +} + +static void +reset(Dev *d) +{ + int i, r; + + r = csr8r(d, Cr) | Sr; + csr8w(d, Cr, r); + + for(i = 0; i < Timeout; i++) { + if((csr8r(d, Cr) & Sr) == 0) + break; + sleep(10); + } + if(i >= Timeout) + fprint(2, "%s: reset failed\n", argv0); + + sleep(100); +} + +static Buf sb; + +static long +rtl8150bread(Ether *e, Buf *bp) +{ + int n; + uint hd; + uchar *q; + + if(sb.rp == nil) + sb.rp = sb.data; + if(sb.ndata < 4) + sb.ndata += read(e->epin->dfd, sb.rp+sb.ndata, sizeof sb.data-sb.ndata); + if(sb.ndata < 0) + return -1; + if(sb.ndata < 4) + return 0; + n = sb.ndata - 4; + if(n < 6) { + sb.ndata = 0; + return 0; + } + q = sb.rp + n; + hd = GET2(q); + if((hd & Vpm) == 0) { + fprint(2, "rtl8150: rx error: %#.4ux\n", hd); + bp->ndata = 0; + } else{ + memcpy(bp, sb.rp, sb.ndata); + bp->ndata = sb.ndata; + sb.ndata = 0; + } + return bp->ndata; +} + +static long +rtl8150bwrite(Ether *e, Buf *bp) +{ + return write(e->epout->dfd, bp->rp, bp->ndata); +} + +int +rtl8150reset(Ether *e) +{ + int i, r; + Dev *d; + + d = e->dev; + reset(d); + if(mem(d, Crm, Idr0, e->addr, sizeof e->addr) < 0) + return -1; + + reset(d); + for(i = 0; i < sizeof e->addr; i++) + csr8w(d, Idr0+i, e->addr[i]); + + csr8w(d, Tcr, Tr1|Tr0|Ifg1|Ifg0); + csr16w(d, Rcr, Tail|Ad|Ab); + + r = csr16r(d, Rcr) & ~(Am | Aam | Aap); + csr16w(d, Rcr, r); + csr32w(d, Mar0, 0); + csr32w(d, Mar4, 0); + + csr8w(d, Cr, Te|Re); + + e->bwrite = rtl8150bwrite; + e->bread = rtl8150bread; + return 0; +}