1*e1c0af53SDavid du Colombier /*
2*e1c0af53SDavid du Colombier * Microchip (ex SMSC) LAN78XX
3*e1c0af53SDavid du Colombier * Also used as ethernet core in LAN7515 usb hub + ethernet
4*e1c0af53SDavid du Colombier */
5*e1c0af53SDavid du Colombier
6*e1c0af53SDavid du Colombier #include <u.h>
7*e1c0af53SDavid du Colombier #include <libc.h>
8*e1c0af53SDavid du Colombier #include <fcall.h>
9*e1c0af53SDavid du Colombier #include <thread.h>
10*e1c0af53SDavid du Colombier #include "usb.h"
11*e1c0af53SDavid du Colombier #include "usbfs.h"
12*e1c0af53SDavid du Colombier #include "ether.h"
13*e1c0af53SDavid du Colombier
14*e1c0af53SDavid du Colombier enum {
15*e1c0af53SDavid du Colombier Doburst = 1,
16*e1c0af53SDavid du Colombier Resettime = 1000,
17*e1c0af53SDavid du Colombier E2pbusytime = 1000,
18*e1c0af53SDavid du Colombier Hsburst = 32,
19*e1c0af53SDavid du Colombier Defbulkdly = 1000,
20*e1c0af53SDavid du Colombier Rxfifosize = (12*1024),
21*e1c0af53SDavid du Colombier Txfifosize = (12*1024),
22*e1c0af53SDavid du Colombier
23*e1c0af53SDavid du Colombier MACoffset = 1,
24*e1c0af53SDavid du Colombier PHYinternal = 1,
25*e1c0af53SDavid du Colombier Rxerror = 0x00400000,
26*e1c0af53SDavid du Colombier Txfcs = 1<<22,
27*e1c0af53SDavid du Colombier
28*e1c0af53SDavid du Colombier /* USB vendor requests */
29*e1c0af53SDavid du Colombier Writereg = 0xA0,
30*e1c0af53SDavid du Colombier Readreg = 0xA1,
31*e1c0af53SDavid du Colombier
32*e1c0af53SDavid du Colombier /* device registers */
33*e1c0af53SDavid du Colombier Idrev = 0x00,
34*e1c0af53SDavid du Colombier Intsts = 0x0C,
35*e1c0af53SDavid du Colombier Hwcfg = 0x10,
36*e1c0af53SDavid du Colombier Led0en = 1<<20,
37*e1c0af53SDavid du Colombier Led1en = 1<<21,
38*e1c0af53SDavid du Colombier Mef = 1<<4,
39*e1c0af53SDavid du Colombier Lrst = 1<<1,
40*e1c0af53SDavid du Colombier Pmctrl = 0x14,
41*e1c0af53SDavid du Colombier Ready = 1<<7,
42*e1c0af53SDavid du Colombier Phyrst = 1<<4,
43*e1c0af53SDavid du Colombier Gpiocfg0 = 0x18,
44*e1c0af53SDavid du Colombier Gpiocfg1 = 0x1C,
45*e1c0af53SDavid du Colombier E2pcmd = 0x40,
46*e1c0af53SDavid du Colombier Busy = 1<<31,
47*e1c0af53SDavid du Colombier Timeout = 1<<10,
48*e1c0af53SDavid du Colombier Loaded = 1<<9,
49*e1c0af53SDavid du Colombier Read = 0,
50*e1c0af53SDavid du Colombier E2pdata = 0x44,
51*e1c0af53SDavid du Colombier Burstcap = 0x90,
52*e1c0af53SDavid du Colombier Intepctl = 0x98,
53*e1c0af53SDavid du Colombier Phyint = 1<<17,
54*e1c0af53SDavid du Colombier Bulkdelay = 0x94,
55*e1c0af53SDavid du Colombier Rfectl = 0xB0,
56*e1c0af53SDavid du Colombier Rxcoe = 0xF<<11,
57*e1c0af53SDavid du Colombier Ab = 1<<10,
58*e1c0af53SDavid du Colombier Am = 1<<9,
59*e1c0af53SDavid du Colombier Au = 1<<8,
60*e1c0af53SDavid du Colombier Dpf = 1<<1,
61*e1c0af53SDavid du Colombier Usbcfg0 = 0x80,
62*e1c0af53SDavid du Colombier Bir = 1<<6,
63*e1c0af53SDavid du Colombier Bce = 1<<5,
64*e1c0af53SDavid du Colombier Usbcfg1 = 0x84,
65*e1c0af53SDavid du Colombier Rxfifoctl = 0xC0,
66*e1c0af53SDavid du Colombier Rxen = 1<<31,
67*e1c0af53SDavid du Colombier Txfifoctl = 0xC4,
68*e1c0af53SDavid du Colombier Txen = 1<<31,
69*e1c0af53SDavid du Colombier Rxfifo = 0xC8,
70*e1c0af53SDavid du Colombier Txfifo = 0xCc,
71*e1c0af53SDavid du Colombier Fctflow = 0xD0,
72*e1c0af53SDavid du Colombier Maccr = 0x100,
73*e1c0af53SDavid du Colombier Add = 1<<12,
74*e1c0af53SDavid du Colombier Asd = 1<<11,
75*e1c0af53SDavid du Colombier Macrx = 0x104,
76*e1c0af53SDavid du Colombier Macfcs = 1<<4,
77*e1c0af53SDavid du Colombier Macrxen = 1<<0,
78*e1c0af53SDavid du Colombier Mactx = 0x108,
79*e1c0af53SDavid du Colombier Mactxen = 1<<0,
80*e1c0af53SDavid du Colombier Addrh = 0x118,
81*e1c0af53SDavid du Colombier Addrl = 0x11C,
82*e1c0af53SDavid du Colombier MIIaddr = 0x120,
83*e1c0af53SDavid du Colombier MIIwrite= 1<<1,
84*e1c0af53SDavid du Colombier MIIread = 0<<1,
85*e1c0af53SDavid du Colombier MIIbusy = 1<<0,
86*e1c0af53SDavid du Colombier MIIdata = 0x124,
87*e1c0af53SDavid du Colombier Flow = 0x10C,
88*e1c0af53SDavid du Colombier Addrfilth = 0x400,
89*e1c0af53SDavid du Colombier Afvalid = 1<<31,
90*e1c0af53SDavid du Colombier Addrfiltl = 0x404,
91*e1c0af53SDavid du Colombier
92*e1c0af53SDavid du Colombier /* MII registers */
93*e1c0af53SDavid du Colombier Bmcr = 0,
94*e1c0af53SDavid du Colombier Bmcrreset= 1<<15,
95*e1c0af53SDavid du Colombier Speed100= 1<<13,
96*e1c0af53SDavid du Colombier Anenable= 1<<12,
97*e1c0af53SDavid du Colombier Anrestart= 1<<9,
98*e1c0af53SDavid du Colombier Fulldpx = 1<<8,
99*e1c0af53SDavid du Colombier Speed1000= 1<<6,
100*e1c0af53SDavid du Colombier Bmsr = 1,
101*e1c0af53SDavid du Colombier Advertise = 4,
102*e1c0af53SDavid du Colombier Adcsma = 0x0001,
103*e1c0af53SDavid du Colombier Ad10h = 0x0020,
104*e1c0af53SDavid du Colombier Ad10f = 0x0040,
105*e1c0af53SDavid du Colombier Ad100h = 0x0080,
106*e1c0af53SDavid du Colombier Ad100f = 0x0100,
107*e1c0af53SDavid du Colombier Adpause = 0x0400,
108*e1c0af53SDavid du Colombier Adpauseasym= 0x0800,
109*e1c0af53SDavid du Colombier Adall = Ad10h|Ad10f|Ad100h|Ad100f,
110*e1c0af53SDavid du Colombier Lpa = 5,
111*e1c0af53SDavid du Colombier Ctrl1000 = 9,
112*e1c0af53SDavid du Colombier Ad1000h = 0x0400,
113*e1c0af53SDavid du Colombier Ad1000f = 0x0200,
114*e1c0af53SDavid du Colombier Ledmodes = 29,
115*e1c0af53SDavid du Colombier Led0shift = 0,
116*e1c0af53SDavid du Colombier Led1shift = 4,
117*e1c0af53SDavid du Colombier Linkact = 0x0,
118*e1c0af53SDavid du Colombier Link1000 = 0x1,
119*e1c0af53SDavid du Colombier Phyintmask = 25,
120*e1c0af53SDavid du Colombier Anegcomp= 1<<10,
121*e1c0af53SDavid du Colombier Linkchg = 1<<13,
122*e1c0af53SDavid du Colombier };
123*e1c0af53SDavid du Colombier
124*e1c0af53SDavid du Colombier static int burstcap = Hsburst, bulkdelay = Defbulkdly;
125*e1c0af53SDavid du Colombier
126*e1c0af53SDavid du Colombier static int
wr(Dev * d,int reg,int val)127*e1c0af53SDavid du Colombier wr(Dev *d, int reg, int val)
128*e1c0af53SDavid du Colombier {
129*e1c0af53SDavid du Colombier int ret;
130*e1c0af53SDavid du Colombier
131*e1c0af53SDavid du Colombier ret = usbcmd(d, Rh2d|Rvendor|Rdev, Writereg, 0, reg,
132*e1c0af53SDavid du Colombier (uchar*)&val, sizeof(val));
133*e1c0af53SDavid du Colombier if(ret < 0)
134*e1c0af53SDavid du Colombier deprint(2, "%s: wr(%x, %x): %r", argv0, reg, val);
135*e1c0af53SDavid du Colombier return ret;
136*e1c0af53SDavid du Colombier }
137*e1c0af53SDavid du Colombier
138*e1c0af53SDavid du Colombier static int
rr(Dev * d,int reg)139*e1c0af53SDavid du Colombier rr(Dev *d, int reg)
140*e1c0af53SDavid du Colombier {
141*e1c0af53SDavid du Colombier int ret, rval;
142*e1c0af53SDavid du Colombier
143*e1c0af53SDavid du Colombier ret = usbcmd(d, Rd2h|Rvendor|Rdev, Readreg, 0, reg,
144*e1c0af53SDavid du Colombier (uchar*)&rval, sizeof(rval));
145*e1c0af53SDavid du Colombier if(ret < 0){
146*e1c0af53SDavid du Colombier fprint(2, "%s: rr(%x): %r", argv0, reg);
147*e1c0af53SDavid du Colombier return 0;
148*e1c0af53SDavid du Colombier }
149*e1c0af53SDavid du Colombier return rval;
150*e1c0af53SDavid du Colombier }
151*e1c0af53SDavid du Colombier
152*e1c0af53SDavid du Colombier static int
miird(Dev * d,int idx)153*e1c0af53SDavid du Colombier miird(Dev *d, int idx)
154*e1c0af53SDavid du Colombier {
155*e1c0af53SDavid du Colombier while(rr(d, MIIaddr) & MIIbusy)
156*e1c0af53SDavid du Colombier ;
157*e1c0af53SDavid du Colombier wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIread | MIIbusy);
158*e1c0af53SDavid du Colombier while(rr(d, MIIaddr) & MIIbusy)
159*e1c0af53SDavid du Colombier ;
160*e1c0af53SDavid du Colombier return rr(d, MIIdata);
161*e1c0af53SDavid du Colombier }
162*e1c0af53SDavid du Colombier
163*e1c0af53SDavid du Colombier static void
miiwr(Dev * d,int idx,int val)164*e1c0af53SDavid du Colombier miiwr(Dev *d, int idx, int val)
165*e1c0af53SDavid du Colombier {
166*e1c0af53SDavid du Colombier while(rr(d, MIIaddr) & MIIbusy)
167*e1c0af53SDavid du Colombier ;
168*e1c0af53SDavid du Colombier wr(d, MIIdata, val);
169*e1c0af53SDavid du Colombier wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIwrite | MIIbusy);
170*e1c0af53SDavid du Colombier while(rr(d, MIIaddr) & MIIbusy)
171*e1c0af53SDavid du Colombier ;
172*e1c0af53SDavid du Colombier }
173*e1c0af53SDavid du Colombier
174*e1c0af53SDavid du Colombier static int
eepromr(Dev * d,int off,uchar * buf,int len)175*e1c0af53SDavid du Colombier eepromr(Dev *d, int off, uchar *buf, int len)
176*e1c0af53SDavid du Colombier {
177*e1c0af53SDavid du Colombier int i, v;
178*e1c0af53SDavid du Colombier
179*e1c0af53SDavid du Colombier for(i = 0; i < E2pbusytime; i++)
180*e1c0af53SDavid du Colombier if((rr(d, E2pcmd) & Busy) == 0)
181*e1c0af53SDavid du Colombier break;
182*e1c0af53SDavid du Colombier if(i == E2pbusytime)
183*e1c0af53SDavid du Colombier return -1;
184*e1c0af53SDavid du Colombier for(i = 0; i < len; i++){
185*e1c0af53SDavid du Colombier wr(d, E2pcmd, Busy|Read|(i+off));
186*e1c0af53SDavid du Colombier while((v = rr(d, E2pcmd) & (Busy|Timeout)) == Busy)
187*e1c0af53SDavid du Colombier ;
188*e1c0af53SDavid du Colombier if(v & Timeout)
189*e1c0af53SDavid du Colombier return -1;
190*e1c0af53SDavid du Colombier buf[i] = rr(d, E2pdata);
191*e1c0af53SDavid du Colombier }
192*e1c0af53SDavid du Colombier return 0;
193*e1c0af53SDavid du Colombier }
194*e1c0af53SDavid du Colombier
195*e1c0af53SDavid du Colombier static void
phyinit(Dev * d)196*e1c0af53SDavid du Colombier phyinit(Dev *d)
197*e1c0af53SDavid du Colombier {
198*e1c0af53SDavid du Colombier int i;
199*e1c0af53SDavid du Colombier
200*e1c0af53SDavid du Colombier miiwr(d, Bmcr, Bmcrreset|Anenable);
201*e1c0af53SDavid du Colombier for(i = 0; i < Resettime/10; i++){
202*e1c0af53SDavid du Colombier if((miird(d, Bmcr) & Bmcrreset) == 0)
203*e1c0af53SDavid du Colombier break;
204*e1c0af53SDavid du Colombier sleep(10);
205*e1c0af53SDavid du Colombier }
206*e1c0af53SDavid du Colombier miiwr(d, Advertise, Adcsma|Adall|Adpause|Adpauseasym);
207*e1c0af53SDavid du Colombier miiwr(d, Ctrl1000, Ad1000f);
208*e1c0af53SDavid du Colombier miiwr(d, Phyintmask, 0);
209*e1c0af53SDavid du Colombier miiwr(d, Ledmodes, (Linkact<<Led1shift) | (Link1000<<Led0shift));
210*e1c0af53SDavid du Colombier miiwr(d, Bmcr, miird(d, Bmcr)|Anenable|Anrestart);
211*e1c0af53SDavid du Colombier }
212*e1c0af53SDavid du Colombier
213*e1c0af53SDavid du Colombier
214*e1c0af53SDavid du Colombier static int
doreset(Dev * d,int reg,int bit)215*e1c0af53SDavid du Colombier doreset(Dev *d, int reg, int bit)
216*e1c0af53SDavid du Colombier {
217*e1c0af53SDavid du Colombier int i;
218*e1c0af53SDavid du Colombier
219*e1c0af53SDavid du Colombier if(wr(d, reg, bit) < 0)
220*e1c0af53SDavid du Colombier return -1;
221*e1c0af53SDavid du Colombier for(i = 0; i < Resettime/10; i++){
222*e1c0af53SDavid du Colombier if((rr(d, reg) & bit) == 0)
223*e1c0af53SDavid du Colombier return 1;
224*e1c0af53SDavid du Colombier sleep(10);
225*e1c0af53SDavid du Colombier }
226*e1c0af53SDavid du Colombier return 0;
227*e1c0af53SDavid du Colombier }
228*e1c0af53SDavid du Colombier
229*e1c0af53SDavid du Colombier static int
getmac(Dev * d,uchar buf[])230*e1c0af53SDavid du Colombier getmac(Dev *d, uchar buf[])
231*e1c0af53SDavid du Colombier {
232*e1c0af53SDavid du Colombier int i;
233*e1c0af53SDavid du Colombier uchar ea[Eaddrlen];
234*e1c0af53SDavid du Colombier
235*e1c0af53SDavid du Colombier if(eepromr(d, MACoffset, ea, Eaddrlen) < 0)
236*e1c0af53SDavid du Colombier return -1;
237*e1c0af53SDavid du Colombier for(i = 0; i < Eaddrlen; i++)
238*e1c0af53SDavid du Colombier if(ea[i] != 0 && ea[i] != 0xFF){
239*e1c0af53SDavid du Colombier memmove(buf, ea, Eaddrlen);
240*e1c0af53SDavid du Colombier break;
241*e1c0af53SDavid du Colombier }
242*e1c0af53SDavid du Colombier return Eaddrlen;
243*e1c0af53SDavid du Colombier }
244*e1c0af53SDavid du Colombier
245*e1c0af53SDavid du Colombier static int
lan78xxinit(Ether * ether)246*e1c0af53SDavid du Colombier lan78xxinit(Ether *ether)
247*e1c0af53SDavid du Colombier {
248*e1c0af53SDavid du Colombier Dev *d;
249*e1c0af53SDavid du Colombier u32int a;
250*e1c0af53SDavid du Colombier int i;
251*e1c0af53SDavid du Colombier
252*e1c0af53SDavid du Colombier if(ether->cid != S78xx)
253*e1c0af53SDavid du Colombier return -1;
254*e1c0af53SDavid du Colombier d = ether->dev;
255*e1c0af53SDavid du Colombier deprint(2, "%s: setting up LAN78XX\n", argv0);
256*e1c0af53SDavid du Colombier deprint(2, "chip id/rev = %8.8ux\n", rr(d, Idrev));
257*e1c0af53SDavid du Colombier if(!doreset(d, Hwcfg, Lrst) || !doreset(d, Pmctrl, Phyrst))
258*e1c0af53SDavid du Colombier return -1;
259*e1c0af53SDavid du Colombier for(i = 0; i < Resettime/10; i++){
260*e1c0af53SDavid du Colombier if(rr(d, Pmctrl) & Ready)
261*e1c0af53SDavid du Colombier break;
262*e1c0af53SDavid du Colombier sleep(10);
263*e1c0af53SDavid du Colombier }
264*e1c0af53SDavid du Colombier if((rr(d, Pmctrl) & Ready) == 0){
265*e1c0af53SDavid du Colombier deprint(2, "%s: device not ready after reset\n", argv0);
266*e1c0af53SDavid du Colombier return -1;
267*e1c0af53SDavid du Colombier }
268*e1c0af53SDavid du Colombier if(getmac(d, ether->addr) < 0)
269*e1c0af53SDavid du Colombier deprint(2, "%s: can't read etheraddr from EEPROM\n", argv0);
270*e1c0af53SDavid du Colombier a = GET4(ether->addr);
271*e1c0af53SDavid du Colombier wr(d, Addrl, a);
272*e1c0af53SDavid du Colombier wr(d, Addrfiltl, a);
273*e1c0af53SDavid du Colombier a = GET2(ether->addr+4);
274*e1c0af53SDavid du Colombier wr(d, Addrh, a);
275*e1c0af53SDavid du Colombier wr(d, Addrfilth, a|Afvalid);
276*e1c0af53SDavid du Colombier deprint(2, "Address filter %8.8ux %8.8ux\n", rr(d, Addrfilth), rr(d, Addrfiltl));
277*e1c0af53SDavid du Colombier
278*e1c0af53SDavid du Colombier wr(d, Usbcfg0, rr(d, Usbcfg0) | Bir);
279*e1c0af53SDavid du Colombier if(Doburst){
280*e1c0af53SDavid du Colombier wr(d, Hwcfg, rr(d, Hwcfg)|Mef);
281*e1c0af53SDavid du Colombier wr(d, Usbcfg0, rr(d, Usbcfg0)|Bce);
282*e1c0af53SDavid du Colombier wr(d, Burstcap, burstcap);
283*e1c0af53SDavid du Colombier wr(d, Bulkdelay, bulkdelay);
284*e1c0af53SDavid du Colombier }else{
285*e1c0af53SDavid du Colombier wr(d, Hwcfg, rr(d, Hwcfg)&~Mef);
286*e1c0af53SDavid du Colombier wr(d, Usbcfg0, rr(d, Usbcfg0)&~Bce);
287*e1c0af53SDavid du Colombier wr(d, Burstcap, 0);
288*e1c0af53SDavid du Colombier wr(d, Bulkdelay, 0);
289*e1c0af53SDavid du Colombier }
290*e1c0af53SDavid du Colombier wr(d, Rxfifo, (Rxfifosize-512)/512);
291*e1c0af53SDavid du Colombier wr(d, Txfifo, (Txfifosize-512)/512);
292*e1c0af53SDavid du Colombier wr(d, Intsts, ~0);
293*e1c0af53SDavid du Colombier wr(d, Hwcfg, rr(d, Hwcfg) | Led0en|Led1en);
294*e1c0af53SDavid du Colombier wr(d, Flow, 0);
295*e1c0af53SDavid du Colombier wr(d, Fctflow, 0);
296*e1c0af53SDavid du Colombier wr(d, Rfectl, (rr(d, Rfectl) & ~Rxcoe) | Ab|Dpf); /* TODO could offload checksums? */
297*e1c0af53SDavid du Colombier
298*e1c0af53SDavid du Colombier phyinit(d);
299*e1c0af53SDavid du Colombier
300*e1c0af53SDavid du Colombier wr(d, Maccr, rr(d,Maccr)|Add|Asd);
301*e1c0af53SDavid du Colombier
302*e1c0af53SDavid du Colombier wr(d, Intepctl, rr(d, Intepctl)|Phyint);
303*e1c0af53SDavid du Colombier wr(d, Mactx, Mactxen);
304*e1c0af53SDavid du Colombier wr(d, Macrx, rr(d, Macrx) | Macfcs|Macrxen);
305*e1c0af53SDavid du Colombier wr(d, Txfifoctl, Txen);
306*e1c0af53SDavid du Colombier wr(d, Rxfifoctl, Rxen);
307*e1c0af53SDavid du Colombier
308*e1c0af53SDavid du Colombier return 0;
309*e1c0af53SDavid du Colombier }
310*e1c0af53SDavid du Colombier
311*e1c0af53SDavid du Colombier static long
lan78xxbread(Ether * e,Buf * bp)312*e1c0af53SDavid du Colombier lan78xxbread(Ether *e, Buf *bp)
313*e1c0af53SDavid du Colombier {
314*e1c0af53SDavid du Colombier uint hd;
315*e1c0af53SDavid du Colombier int n, m;
316*e1c0af53SDavid du Colombier Buf *rbp;
317*e1c0af53SDavid du Colombier
318*e1c0af53SDavid du Colombier rbp = e->aux;
319*e1c0af53SDavid du Colombier if(rbp->ndata < 10){
320*e1c0af53SDavid du Colombier rbp->rp = rbp->data;
321*e1c0af53SDavid du Colombier rbp->ndata = read(e->epin->dfd, rbp->rp, Doburst? burstcap*512:
322*e1c0af53SDavid du Colombier Maxpkt);
323*e1c0af53SDavid du Colombier if(rbp->ndata < 0)
324*e1c0af53SDavid du Colombier return -1;
325*e1c0af53SDavid du Colombier }
326*e1c0af53SDavid du Colombier if(rbp->ndata < 10){
327*e1c0af53SDavid du Colombier werrstr("short frame");
328*e1c0af53SDavid du Colombier fprint(2, "lan78xx short frame %d bytes\n", rbp->ndata);
329*e1c0af53SDavid du Colombier sleep(1000);
330*e1c0af53SDavid du Colombier return 0;
331*e1c0af53SDavid du Colombier }
332*e1c0af53SDavid du Colombier hd = GET4(rbp->rp);
333*e1c0af53SDavid du Colombier n = hd & 0x3FFF;
334*e1c0af53SDavid du Colombier rbp->rp += 10;
335*e1c0af53SDavid du Colombier rbp->ndata -= 10;
336*e1c0af53SDavid du Colombier if(n < 6 || n > rbp->ndata){
337*e1c0af53SDavid du Colombier werrstr("frame length");
338*e1c0af53SDavid du Colombier fprint(2, "lan78xx length error packet %d buf %d\n", n, rbp->ndata);
339*e1c0af53SDavid du Colombier rbp->ndata = 0;
340*e1c0af53SDavid du Colombier return 0;
341*e1c0af53SDavid du Colombier }
342*e1c0af53SDavid du Colombier if(hd & Rxerror){
343*e1c0af53SDavid du Colombier fprint(2, "lan78xx rx error %8.8ux\n", hd);
344*e1c0af53SDavid du Colombier n = 0;
345*e1c0af53SDavid du Colombier }else{
346*e1c0af53SDavid du Colombier bp->rp = bp->data + Hdrsize;
347*e1c0af53SDavid du Colombier memmove(bp->rp, rbp->rp, n);
348*e1c0af53SDavid du Colombier }
349*e1c0af53SDavid du Colombier bp->ndata = n;
350*e1c0af53SDavid du Colombier rbp->rp += n;
351*e1c0af53SDavid du Colombier rbp->ndata -= n;
352*e1c0af53SDavid du Colombier if(rbp->ndata > 0){
353*e1c0af53SDavid du Colombier m = rbp->rp - rbp->data;
354*e1c0af53SDavid du Colombier if(m&3){
355*e1c0af53SDavid du Colombier m = 4 - (m&3);
356*e1c0af53SDavid du Colombier rbp->rp += m;
357*e1c0af53SDavid du Colombier rbp->ndata -= m;
358*e1c0af53SDavid du Colombier }
359*e1c0af53SDavid du Colombier }
360*e1c0af53SDavid du Colombier return n;
361*e1c0af53SDavid du Colombier }
362*e1c0af53SDavid du Colombier
363*e1c0af53SDavid du Colombier static long
lan78xxbwrite(Ether * e,Buf * bp)364*e1c0af53SDavid du Colombier lan78xxbwrite(Ether *e, Buf *bp)
365*e1c0af53SDavid du Colombier {
366*e1c0af53SDavid du Colombier int n;
367*e1c0af53SDavid du Colombier
368*e1c0af53SDavid du Colombier n = bp->ndata & 0xFFFFF;
369*e1c0af53SDavid du Colombier bp->rp -= 8;
370*e1c0af53SDavid du Colombier bp->ndata += 8;
371*e1c0af53SDavid du Colombier PUT4(bp->rp, n | Txfcs);
372*e1c0af53SDavid du Colombier PUT4(bp->rp+4, 0);
373*e1c0af53SDavid du Colombier n = write(e->epout->dfd, bp->rp, bp->ndata);
374*e1c0af53SDavid du Colombier if(n != bp->ndata)
375*e1c0af53SDavid du Colombier deprint(2, "bwrite %d: %r\n", n);
376*e1c0af53SDavid du Colombier return n;
377*e1c0af53SDavid du Colombier }
378*e1c0af53SDavid du Colombier
379*e1c0af53SDavid du Colombier static int
lan78xxpromiscuous(Ether * e,int on)380*e1c0af53SDavid du Colombier lan78xxpromiscuous(Ether *e, int on)
381*e1c0af53SDavid du Colombier {
382*e1c0af53SDavid du Colombier Dev *d;
383*e1c0af53SDavid du Colombier int rxctl;
384*e1c0af53SDavid du Colombier
385*e1c0af53SDavid du Colombier d = e->dev;
386*e1c0af53SDavid du Colombier rxctl = rr(d, Rfectl);
387*e1c0af53SDavid du Colombier if(on)
388*e1c0af53SDavid du Colombier rxctl |= Am|Au;
389*e1c0af53SDavid du Colombier else
390*e1c0af53SDavid du Colombier rxctl &= ~(Am|Au);
391*e1c0af53SDavid du Colombier return wr(d, Rfectl, rxctl);
392*e1c0af53SDavid du Colombier }
393*e1c0af53SDavid du Colombier
394*e1c0af53SDavid du Colombier static int
lan78xxmulticast(Ether * e,uchar * addr,int on)395*e1c0af53SDavid du Colombier lan78xxmulticast(Ether *e, uchar *addr, int on)
396*e1c0af53SDavid du Colombier {
397*e1c0af53SDavid du Colombier int rxctl;
398*e1c0af53SDavid du Colombier Dev *d;
399*e1c0af53SDavid du Colombier
400*e1c0af53SDavid du Colombier USED(addr, on);
401*e1c0af53SDavid du Colombier /* BUG: should write multicast filter */
402*e1c0af53SDavid du Colombier d = e->dev;
403*e1c0af53SDavid du Colombier rxctl = rr(d, Rfectl);
404*e1c0af53SDavid du Colombier if(e->nmcasts != 0)
405*e1c0af53SDavid du Colombier rxctl |= Am;
406*e1c0af53SDavid du Colombier else
407*e1c0af53SDavid du Colombier rxctl &= ~Am;
408*e1c0af53SDavid du Colombier deprint(2, "%s: lan78xxmulticast %d\n", argv0, e->nmcasts);
409*e1c0af53SDavid du Colombier return wr(d, Rfectl, rxctl);
410*e1c0af53SDavid du Colombier }
411*e1c0af53SDavid du Colombier
412*e1c0af53SDavid du Colombier static void
lan78xxfree(Ether * ether)413*e1c0af53SDavid du Colombier lan78xxfree(Ether *ether)
414*e1c0af53SDavid du Colombier {
415*e1c0af53SDavid du Colombier free(ether->aux);
416*e1c0af53SDavid du Colombier ether->aux = nil;
417*e1c0af53SDavid du Colombier }
418*e1c0af53SDavid du Colombier
419*e1c0af53SDavid du Colombier int
lan78xxreset(Ether * ether)420*e1c0af53SDavid du Colombier lan78xxreset(Ether *ether)
421*e1c0af53SDavid du Colombier {
422*e1c0af53SDavid du Colombier Cinfo *ip;
423*e1c0af53SDavid du Colombier Dev *dev;
424*e1c0af53SDavid du Colombier
425*e1c0af53SDavid du Colombier dev = ether->dev;
426*e1c0af53SDavid du Colombier for(ip = cinfo; ip->vid != 0; ip++)
427*e1c0af53SDavid du Colombier if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
428*e1c0af53SDavid du Colombier ether->cid = ip->cid;
429*e1c0af53SDavid du Colombier if(lan78xxinit(ether) < 0){
430*e1c0af53SDavid du Colombier deprint(2, "%s: lan78xx init failed: %r\n", argv0);
431*e1c0af53SDavid du Colombier return -1;
432*e1c0af53SDavid du Colombier }
433*e1c0af53SDavid du Colombier deprint(2, "%s: lan78xx reset done\n", argv0);
434*e1c0af53SDavid du Colombier ether->name = "lan78xx";
435*e1c0af53SDavid du Colombier if(Doburst){
436*e1c0af53SDavid du Colombier ether->bufsize = burstcap*512;
437*e1c0af53SDavid du Colombier ether->aux = emallocz(sizeof(Buf) +
438*e1c0af53SDavid du Colombier ether->bufsize - Maxpkt, 1);
439*e1c0af53SDavid du Colombier }else{
440*e1c0af53SDavid du Colombier ether->bufsize = Maxpkt;
441*e1c0af53SDavid du Colombier ether->aux = emallocz(sizeof(Buf), 1);
442*e1c0af53SDavid du Colombier }
443*e1c0af53SDavid du Colombier ether->free = lan78xxfree;
444*e1c0af53SDavid du Colombier ether->bread = lan78xxbread;
445*e1c0af53SDavid du Colombier ether->bwrite = lan78xxbwrite;
446*e1c0af53SDavid du Colombier ether->promiscuous = lan78xxpromiscuous;
447*e1c0af53SDavid du Colombier ether->multicast = lan78xxmulticast;
448*e1c0af53SDavid du Colombier ether->mbps = 100; /* BUG */
449*e1c0af53SDavid du Colombier return 0;
450*e1c0af53SDavid du Colombier }
451*e1c0af53SDavid du Colombier return -1;
452*e1c0af53SDavid du Colombier }
453