xref: /plan9/sys/src/cmd/usb/ether/asix.c (revision 906943f9f6b8411972abb5e3a03ed19f74be7ccc)
1*906943f9SDavid du Colombier /*
2*906943f9SDavid du Colombier  * Asix USB ether adapters
3*906943f9SDavid du Colombier  * I got no documentation for it, thus the bits
4*906943f9SDavid du Colombier  * come from other systems; it's likely this is
5*906943f9SDavid du Colombier  * doing more than needed in some places and
6*906943f9SDavid du Colombier  * less than required in others.
7*906943f9SDavid du Colombier  */
8*906943f9SDavid du Colombier #include <u.h>
9*906943f9SDavid du Colombier #include <libc.h>
10*906943f9SDavid du Colombier #include <fcall.h>
11*906943f9SDavid du Colombier #include <thread.h>
12*906943f9SDavid du Colombier #include "usb.h"
13*906943f9SDavid du Colombier #include "usbfs.h"
14*906943f9SDavid du Colombier #include "ether.h"
15*906943f9SDavid du Colombier 
16*906943f9SDavid du Colombier enum
17*906943f9SDavid du Colombier {
18*906943f9SDavid du Colombier 
19*906943f9SDavid du Colombier 	/* Asix commands */
20*906943f9SDavid du Colombier 	Cswmii		= 0x06,		/* set sw mii */
21*906943f9SDavid du Colombier 	Crmii		= 0x07,		/* read mii reg */
22*906943f9SDavid du Colombier 	Cwmii		= 0x08,		/* write mii reg */
23*906943f9SDavid du Colombier 	Chwmii		= 0x0a,		/* set hw mii */
24*906943f9SDavid du Colombier 	Creeprom	= 0x0b,		/* read eeprom */
25*906943f9SDavid du Colombier 	Cwdis		= 0x0e,		/* write disable */
26*906943f9SDavid du Colombier 	Cwena		= 0x0d,		/* write enable */
27*906943f9SDavid du Colombier 	Crrxctl		= 0x0f,		/* read rx ctl */
28*906943f9SDavid du Colombier 	Cwrxctl		= 0x10,		/* write rx ctl */
29*906943f9SDavid du Colombier 	Cwipg		= 0x12,		/* write ipg */
30*906943f9SDavid du Colombier 	Crmac		= 0x13,		/* read mac addr */
31*906943f9SDavid du Colombier 	Crphy		= 0x19,		/* read phy id */
32*906943f9SDavid du Colombier 	Cwmedium		= 0x1b,		/* write medium mode */
33*906943f9SDavid du Colombier 	Crgpio		= 0x1e,		/* read gpio */
34*906943f9SDavid du Colombier 	Cwgpio		= 0x1f,		/* write gpios */
35*906943f9SDavid du Colombier 	Creset		= 0x20,		/* reset */
36*906943f9SDavid du Colombier 	Cwphy		= 0x22,		/* select phy */
37*906943f9SDavid du Colombier 
38*906943f9SDavid du Colombier 	/* reset codes */
39*906943f9SDavid du Colombier 	Rclear		= 0x00,
40*906943f9SDavid du Colombier 	Rprte		= 0x04,
41*906943f9SDavid du Colombier 	Rprl		= 0x08,
42*906943f9SDavid du Colombier 	Riprl		= 0x20,
43*906943f9SDavid du Colombier 	Rippd		= 0x40,
44*906943f9SDavid du Colombier 
45*906943f9SDavid du Colombier 	Gpiogpo1en	= 0x04,	/* gpio1 enable */,
46*906943f9SDavid du Colombier 	Gpiogpo1		= 0x08,	/* gpio1 value */
47*906943f9SDavid du Colombier 	Gpiogpo2en	= 0x10,	/* gpio2 enable */
48*906943f9SDavid du Colombier 	Gpiogpo2		= 0x20,	/* gpio2 value */
49*906943f9SDavid du Colombier 	Gpiorse		= 0x80,	/* gpio reload serial eeprom */
50*906943f9SDavid du Colombier 
51*906943f9SDavid du Colombier 	Pmask		= 0x1F,
52*906943f9SDavid du Colombier 	Pembed		= 0x10,			/* embedded phy */
53*906943f9SDavid du Colombier 
54*906943f9SDavid du Colombier 	Mfd		= 0x002,		/* media */
55*906943f9SDavid du Colombier 	Mac		= 0x004,
56*906943f9SDavid du Colombier 	Mrfc		= 0x010,
57*906943f9SDavid du Colombier 	Mtfc		= 0x020,
58*906943f9SDavid du Colombier 	Mjfe		= 0x040,
59*906943f9SDavid du Colombier 	Mre		= 0x100,
60*906943f9SDavid du Colombier 	Mps		= 0x200,
61*906943f9SDavid du Colombier 	Mall772		= Mfd|Mrfc|Mtfc|Mps|Mac|Mre,
62*906943f9SDavid du Colombier 	Mall178		= Mps|Mfd|Mac|Mrfc|Mtfc|Mjfe|Mre,
63*906943f9SDavid du Colombier 
64*906943f9SDavid du Colombier 	Ipgdflt		= 0x15|0x0c|0x12,	/* default ipg0, 1, 2 */
65*906943f9SDavid du Colombier 	Rxctlso		= 0x80,
66*906943f9SDavid du Colombier 	Rxctlab		= 0x08,
67*906943f9SDavid du Colombier 	Rxctlsep	= 0x04,
68*906943f9SDavid du Colombier 	Rxctlamall	= 0x02,			/* all multicast */
69*906943f9SDavid du Colombier 	Rxctlprom	= 0x01,			/* promiscuous */
70*906943f9SDavid du Colombier 
71*906943f9SDavid du Colombier 	/* MII */
72*906943f9SDavid du Colombier 	Miibmcr			= 0x00,		/* basic mode ctrl reg. */
73*906943f9SDavid du Colombier 		Bmcrreset	= 0x8000,	/* reset */
74*906943f9SDavid du Colombier 		Bmcranena	= 0x1000,	/* auto neg. enable */
75*906943f9SDavid du Colombier 		Bmcrar		= 0x0200,	/* announce restart */
76*906943f9SDavid du Colombier 
77*906943f9SDavid du Colombier 	Miiad			= 0x04,		/* advertise reg. */
78*906943f9SDavid du Colombier 		Adcsma		= 0x0001,
79*906943f9SDavid du Colombier 		Ad1000f		= 0x0200,
80*906943f9SDavid du Colombier 		Ad1000h		= 0x0100,
81*906943f9SDavid du Colombier 		Ad10h		= 0x0020,
82*906943f9SDavid du Colombier 		Ad10f		= 0x0040,
83*906943f9SDavid du Colombier 		Ad100h		= 0x0080,
84*906943f9SDavid du Colombier 		Ad100f		= 0x0100,
85*906943f9SDavid du Colombier 		Adpause		= 0x0400,
86*906943f9SDavid du Colombier 		Adall		= Ad10h|Ad10f|Ad100h|Ad100f,
87*906943f9SDavid du Colombier 
88*906943f9SDavid du Colombier 	Miimctl			= 0x14,		/* marvell ctl */
89*906943f9SDavid du Colombier 		Mtxdly		= 0x02,
90*906943f9SDavid du Colombier 		Mrxdly		= 0x80,
91*906943f9SDavid du Colombier 		Mtxrxdly	= 0x82,
92*906943f9SDavid du Colombier 
93*906943f9SDavid du Colombier 	Miic1000			= 0x09,
94*906943f9SDavid du Colombier 
95*906943f9SDavid du Colombier };
96*906943f9SDavid du Colombier 
97*906943f9SDavid du Colombier static int
98*906943f9SDavid du Colombier asixset(Dev *d, int c, int v)
99*906943f9SDavid du Colombier {
100*906943f9SDavid du Colombier 	int r;
101*906943f9SDavid du Colombier 	int ec;
102*906943f9SDavid du Colombier 
103*906943f9SDavid du Colombier 	r = Rh2d|Rvendor|Rdev;
104*906943f9SDavid du Colombier 	ec = usbcmd(d, r, c, v, 0, nil, 0);
105*906943f9SDavid du Colombier 	if(ec < 0)
106*906943f9SDavid du Colombier 		deprint(2, "%s: asixset %x %x: %r\n", argv0, c, v);
107*906943f9SDavid du Colombier 	return ec;
108*906943f9SDavid du Colombier }
109*906943f9SDavid du Colombier 
110*906943f9SDavid du Colombier static int
111*906943f9SDavid du Colombier asixget(Dev *d, int c, uchar *buf, int l)
112*906943f9SDavid du Colombier {
113*906943f9SDavid du Colombier 	int r;
114*906943f9SDavid du Colombier 	int ec;
115*906943f9SDavid du Colombier 
116*906943f9SDavid du Colombier 	r = Rd2h|Rvendor|Rdev;
117*906943f9SDavid du Colombier 	ec = usbcmd(d, r, c, 0, 0, buf, l);
118*906943f9SDavid du Colombier 	if(ec < 0)
119*906943f9SDavid du Colombier 		deprint(2, "%s: asixget %x: %r\n", argv0, c);
120*906943f9SDavid du Colombier 	return ec;
121*906943f9SDavid du Colombier }
122*906943f9SDavid du Colombier 
123*906943f9SDavid du Colombier static int
124*906943f9SDavid du Colombier getgpio(Dev *d)
125*906943f9SDavid du Colombier {
126*906943f9SDavid du Colombier 	uchar c;
127*906943f9SDavid du Colombier 
128*906943f9SDavid du Colombier 	if(asixget(d, Crgpio, &c, 1) < 0)
129*906943f9SDavid du Colombier 		return -1;
130*906943f9SDavid du Colombier 	return c;
131*906943f9SDavid du Colombier }
132*906943f9SDavid du Colombier 
133*906943f9SDavid du Colombier static int
134*906943f9SDavid du Colombier getphy(Dev *d)
135*906943f9SDavid du Colombier {
136*906943f9SDavid du Colombier 	uchar buf[2];
137*906943f9SDavid du Colombier 
138*906943f9SDavid du Colombier 	if(asixget(d, Crphy, buf, sizeof(buf)) < 0)
139*906943f9SDavid du Colombier 		return -1;
140*906943f9SDavid du Colombier 	deprint(2, "%s: phy addr %#ux\n", argv0, buf[1]);
141*906943f9SDavid du Colombier 	return buf[1];
142*906943f9SDavid du Colombier }
143*906943f9SDavid du Colombier 
144*906943f9SDavid du Colombier static int
145*906943f9SDavid du Colombier getrxctl(Dev *d)
146*906943f9SDavid du Colombier {
147*906943f9SDavid du Colombier 	uchar buf[2];
148*906943f9SDavid du Colombier 	int r;
149*906943f9SDavid du Colombier 
150*906943f9SDavid du Colombier 	memset(buf, 0, sizeof(buf));
151*906943f9SDavid du Colombier 	if(asixget(d, Crrxctl, buf, sizeof(buf)) < 0)
152*906943f9SDavid du Colombier 		return -1;
153*906943f9SDavid du Colombier 	r = GET2(buf);
154*906943f9SDavid du Colombier 	deprint(2, "%s: rxctl %#x\n", argv0, r);
155*906943f9SDavid du Colombier 	return r;
156*906943f9SDavid du Colombier }
157*906943f9SDavid du Colombier 
158*906943f9SDavid du Colombier static int
159*906943f9SDavid du Colombier getmac(Dev *d, uchar buf[])
160*906943f9SDavid du Colombier {
161*906943f9SDavid du Colombier 	if(asixget(d, Crmac, buf, Eaddrlen) < 0)
162*906943f9SDavid du Colombier 		return -1;
163*906943f9SDavid du Colombier 	return Eaddrlen;
164*906943f9SDavid du Colombier }
165*906943f9SDavid du Colombier 
166*906943f9SDavid du Colombier static int
167*906943f9SDavid du Colombier miiread(Dev *d, int phy, int reg)
168*906943f9SDavid du Colombier {
169*906943f9SDavid du Colombier 	int r;
170*906943f9SDavid du Colombier 	uchar v[2];
171*906943f9SDavid du Colombier 
172*906943f9SDavid du Colombier 	r = Rd2h|Rvendor|Rdev;
173*906943f9SDavid du Colombier 	if(usbcmd(d, r, Crmii, phy, reg, v, 2) < 0){
174*906943f9SDavid du Colombier 		dprint(2, "%s: miiwrite: %r\n", argv0);
175*906943f9SDavid du Colombier 		return -1;
176*906943f9SDavid du Colombier 	}
177*906943f9SDavid du Colombier 	r = GET2(v);
178*906943f9SDavid du Colombier 	if(r == 0xFFFF)
179*906943f9SDavid du Colombier 		return -1;
180*906943f9SDavid du Colombier 	return r;
181*906943f9SDavid du Colombier }
182*906943f9SDavid du Colombier 
183*906943f9SDavid du Colombier 
184*906943f9SDavid du Colombier static int
185*906943f9SDavid du Colombier miiwrite(Dev *d, int phy, int reg, int val)
186*906943f9SDavid du Colombier {
187*906943f9SDavid du Colombier 	int r;
188*906943f9SDavid du Colombier 	uchar v[2];
189*906943f9SDavid du Colombier 
190*906943f9SDavid du Colombier 	if(asixset(d, Cswmii, 0) < 0)
191*906943f9SDavid du Colombier 		return -1;
192*906943f9SDavid du Colombier 	r = Rh2d|Rvendor|Rdev;
193*906943f9SDavid du Colombier 	PUT2(v, val);
194*906943f9SDavid du Colombier 	if(usbcmd(d, r, Cwmii, phy, reg, v, 2) < 0){
195*906943f9SDavid du Colombier 		deprint(2, "%s: miiwrite: %#x %#x %r\n", argv0, reg, val);
196*906943f9SDavid du Colombier 		return -1;
197*906943f9SDavid du Colombier 	}
198*906943f9SDavid du Colombier 	if(asixset(d, Chwmii, 0) < 0)
199*906943f9SDavid du Colombier 		return -1;
200*906943f9SDavid du Colombier 	return 0;
201*906943f9SDavid du Colombier }
202*906943f9SDavid du Colombier 
203*906943f9SDavid du Colombier static int
204*906943f9SDavid du Colombier eepromread(Dev *d, int i)
205*906943f9SDavid du Colombier {
206*906943f9SDavid du Colombier 	int r;
207*906943f9SDavid du Colombier 	int ec;
208*906943f9SDavid du Colombier 	uchar buf[2];
209*906943f9SDavid du Colombier 
210*906943f9SDavid du Colombier 	r = Rd2h|Rvendor|Rdev;
211*906943f9SDavid du Colombier 	ec = usbcmd(d, r, Creeprom, i, 0, buf, sizeof(buf));
212*906943f9SDavid du Colombier 	if(ec < 0)
213*906943f9SDavid du Colombier 		deprint(2, "%s: eepromread %d: %r\n", argv0, i);
214*906943f9SDavid du Colombier 	ec = GET2(buf);
215*906943f9SDavid du Colombier 	deprint(2, "%s: eeprom %#x = %#x\n", argv0, i, ec);
216*906943f9SDavid du Colombier 	if(ec == 0xFFFF)
217*906943f9SDavid du Colombier 		ec = -1;
218*906943f9SDavid du Colombier 	return ec;
219*906943f9SDavid du Colombier }
220*906943f9SDavid du Colombier 
221*906943f9SDavid du Colombier /*
222*906943f9SDavid du Colombier  * No doc. we are doing what Linux does as closely
223*906943f9SDavid du Colombier  * as we can.
224*906943f9SDavid du Colombier  */
225*906943f9SDavid du Colombier static int
226*906943f9SDavid du Colombier ctlrinit(Ether *ether)
227*906943f9SDavid du Colombier {
228*906943f9SDavid du Colombier 	Dev *d;
229*906943f9SDavid du Colombier 	int i;
230*906943f9SDavid du Colombier 	int bmcr;
231*906943f9SDavid du Colombier 	int gpio;
232*906943f9SDavid du Colombier 	int ee17;
233*906943f9SDavid du Colombier 	int rc;
234*906943f9SDavid du Colombier 
235*906943f9SDavid du Colombier 	d = ether->dev;
236*906943f9SDavid du Colombier 	switch(ether->cid){
237*906943f9SDavid du Colombier 	default:
238*906943f9SDavid du Colombier 		fprint(2, "%s: card known but not implemented\n", argv0);
239*906943f9SDavid du Colombier 		return -1;
240*906943f9SDavid du Colombier 
241*906943f9SDavid du Colombier 	case A88178:
242*906943f9SDavid du Colombier 		deprint(2, "%s: setting up A88178\n", argv0);
243*906943f9SDavid du Colombier 		gpio = getgpio(d);
244*906943f9SDavid du Colombier 		if(gpio < 0)
245*906943f9SDavid du Colombier 			return -1;
246*906943f9SDavid du Colombier 		deprint(2, "%s: gpio sts %#x\n", argv0, gpio);
247*906943f9SDavid du Colombier 		asixset(d, Cwena, 0);
248*906943f9SDavid du Colombier 		ee17 = eepromread(d, 0x0017);
249*906943f9SDavid du Colombier 		asixset(d, Cwdis, 0);
250*906943f9SDavid du Colombier 		asixset(d, Cwgpio, Gpiorse|Gpiogpo1|Gpiogpo1en);
251*906943f9SDavid du Colombier 		if((ee17 >> 8) != 1){
252*906943f9SDavid du Colombier 			asixset(d, Cwgpio, 0x003c);
253*906943f9SDavid du Colombier 			asixset(d, Cwgpio, 0x001c);
254*906943f9SDavid du Colombier 			asixset(d, Cwgpio, 0x003c);
255*906943f9SDavid du Colombier 		}else{
256*906943f9SDavid du Colombier 			asixset(d, Cwgpio, Gpiogpo1en);
257*906943f9SDavid du Colombier 			asixset(d, Cwgpio, Gpiogpo1|Gpiogpo1en);
258*906943f9SDavid du Colombier 		}
259*906943f9SDavid du Colombier 		asixset(d, Creset, Rclear);
260*906943f9SDavid du Colombier 		sleep(150);
261*906943f9SDavid du Colombier 		asixset(d, Creset, Rippd|Rprl);
262*906943f9SDavid du Colombier 		sleep(150);
263*906943f9SDavid du Colombier 		asixset(d, Cwrxctl, 0);
264*906943f9SDavid du Colombier 		if(getmac(d, ether->addr) < 0)
265*906943f9SDavid du Colombier 			return -1;
266*906943f9SDavid du Colombier 		ether->phy = getphy(d);
267*906943f9SDavid du Colombier 		if(ee17 < 0 || (ee17 & 0x7) == 0){
268*906943f9SDavid du Colombier 			miiwrite(d, ether->phy, Miimctl, Mtxrxdly);
269*906943f9SDavid du Colombier 			sleep(60);
270*906943f9SDavid du Colombier 		}
271*906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miibmcr, Bmcrreset|Bmcranena);
272*906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miiad, Adall|Adcsma|Adpause);
273*906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miic1000, Ad1000f);
274*906943f9SDavid du Colombier 		bmcr = miiread(d, ether->phy, Miibmcr);
275*906943f9SDavid du Colombier 		if((bmcr & Bmcranena) != 0){
276*906943f9SDavid du Colombier 			bmcr |= Bmcrar;
277*906943f9SDavid du Colombier 			miiwrite(d, ether->phy, Miibmcr, bmcr);
278*906943f9SDavid du Colombier 		}
279*906943f9SDavid du Colombier 		asixset(d, Cwmedium, Mall178);
280*906943f9SDavid du Colombier 		asixset(d, Cwrxctl, Rxctlso|Rxctlab);
281*906943f9SDavid du Colombier 		break;
282*906943f9SDavid du Colombier 
283*906943f9SDavid du Colombier 	case A88772:
284*906943f9SDavid du Colombier 		deprint(2, "%s: setting up A88772\n", argv0);
285*906943f9SDavid du Colombier 		if(asixset(d, Cwgpio, Gpiorse|Gpiogpo2|Gpiogpo2en) < 0)
286*906943f9SDavid du Colombier 			return -1;
287*906943f9SDavid du Colombier 		ether->phy = getphy(d);
288*906943f9SDavid du Colombier 		dprint(2, "%s: phy %#x\n", argv0, ether->phy);
289*906943f9SDavid du Colombier 		if((ether->phy & Pmask) == Pembed){
290*906943f9SDavid du Colombier 			/* embedded 10/100 ethernet */
291*906943f9SDavid du Colombier 			rc = asixset(d, Cwphy, 1);
292*906943f9SDavid du Colombier 		}else
293*906943f9SDavid du Colombier 			rc = asixset(d, Cwphy, 0);
294*906943f9SDavid du Colombier 		if(rc < 0)
295*906943f9SDavid du Colombier 			return -1;
296*906943f9SDavid du Colombier 		if(asixset(d, Creset, Rippd|Rprl) < 0)
297*906943f9SDavid du Colombier 			return -1;
298*906943f9SDavid du Colombier 		sleep(150);
299*906943f9SDavid du Colombier 		if((ether->phy & Pmask) == Pembed)
300*906943f9SDavid du Colombier 			rc = asixset(d, Creset, Riprl);
301*906943f9SDavid du Colombier 		else
302*906943f9SDavid du Colombier 			rc = asixset(d, Creset, Rprte);
303*906943f9SDavid du Colombier 		if(rc < 0)
304*906943f9SDavid du Colombier 			return -1;
305*906943f9SDavid du Colombier 		sleep(150);
306*906943f9SDavid du Colombier 		rc = getrxctl(d);
307*906943f9SDavid du Colombier 		deprint(2, "%s: rxctl is %#x\n", argv0, rc);
308*906943f9SDavid du Colombier 		if(asixset(d, Cwrxctl, 0) < 0)
309*906943f9SDavid du Colombier 			return -1;
310*906943f9SDavid du Colombier 		if(getmac(d, ether->addr) < 0)
311*906943f9SDavid du Colombier 			return -1;
312*906943f9SDavid du Colombier 
313*906943f9SDavid du Colombier 
314*906943f9SDavid du Colombier 		if(asixset(d, Creset, Rprl) < 0)
315*906943f9SDavid du Colombier 			return -1;
316*906943f9SDavid du Colombier 		sleep(150);
317*906943f9SDavid du Colombier 		if(asixset(d, Creset, Riprl|Rprl) < 0)
318*906943f9SDavid du Colombier 			return -1;
319*906943f9SDavid du Colombier 		sleep(150);
320*906943f9SDavid du Colombier 
321*906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miibmcr, Bmcrreset);
322*906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miiad, Adall|Adcsma);
323*906943f9SDavid du Colombier 		bmcr = miiread(d, ether->phy, Miibmcr);
324*906943f9SDavid du Colombier 		if((bmcr & Bmcranena) != 0){
325*906943f9SDavid du Colombier 			bmcr |= Bmcrar;
326*906943f9SDavid du Colombier 			miiwrite(d, ether->phy, Miibmcr, bmcr);
327*906943f9SDavid du Colombier 		}
328*906943f9SDavid du Colombier 		if(asixset(d, Cwmedium, Mall772) < 0)
329*906943f9SDavid du Colombier 			return -1;
330*906943f9SDavid du Colombier 		if(asixset(d, Cwipg, Ipgdflt) < 0)
331*906943f9SDavid du Colombier 			return -1;
332*906943f9SDavid du Colombier 		if(asixset(d, Cwrxctl, Rxctlso|Rxctlab) < 0)
333*906943f9SDavid du Colombier 			return -1;
334*906943f9SDavid du Colombier 		deprint(2, "%s: final rxctl: %#x\n", argv0, getrxctl(d));
335*906943f9SDavid du Colombier 		break;
336*906943f9SDavid du Colombier 	}
337*906943f9SDavid du Colombier 
338*906943f9SDavid du Colombier 	if(etherdebug){
339*906943f9SDavid du Colombier 		fprint(2, "%s: ether: phy %#x addr ", argv0, ether->phy);
340*906943f9SDavid du Colombier 		for(i = 0; i < sizeof(ether->addr); i++)
341*906943f9SDavid du Colombier 			fprint(2, "%02x", ether->addr[i]);
342*906943f9SDavid du Colombier 		fprint(2, "\n");
343*906943f9SDavid du Colombier 	}
344*906943f9SDavid du Colombier 	return 0;
345*906943f9SDavid du Colombier }
346*906943f9SDavid du Colombier 
347*906943f9SDavid du Colombier 
348*906943f9SDavid du Colombier static long
349*906943f9SDavid du Colombier asixbread(Ether *e, Buf *bp)
350*906943f9SDavid du Colombier {
351*906943f9SDavid du Colombier 	ulong nr;
352*906943f9SDavid du Colombier 	ulong hd;
353*906943f9SDavid du Colombier 	Buf *rbp;
354*906943f9SDavid du Colombier 
355*906943f9SDavid du Colombier 	rbp = e->aux;
356*906943f9SDavid du Colombier 	if(rbp == nil || rbp->ndata < 4){
357*906943f9SDavid du Colombier 		rbp->rp = rbp->data;
358*906943f9SDavid du Colombier 		rbp->ndata = read(e->epin->dfd, rbp->rp, sizeof(bp->data));
359*906943f9SDavid du Colombier 		if(rbp->ndata < 0)
360*906943f9SDavid du Colombier 			return -1;
361*906943f9SDavid du Colombier 	}
362*906943f9SDavid du Colombier 	if(rbp->ndata < 4){
363*906943f9SDavid du Colombier 		werrstr("short frame");
364*906943f9SDavid du Colombier 		deprint(2, "%s: asixbread got %d bytes\n", argv0, rbp->ndata);
365*906943f9SDavid du Colombier 		rbp->ndata = 0;
366*906943f9SDavid du Colombier 		return 0;
367*906943f9SDavid du Colombier 	}
368*906943f9SDavid du Colombier 	hd = GET4(rbp->rp);
369*906943f9SDavid du Colombier 	nr = hd & 0xFFFF;
370*906943f9SDavid du Colombier 	hd = (hd>>16) & 0xFFFF;
371*906943f9SDavid du Colombier 	if(nr != (~hd & 0xFFFF)){
372*906943f9SDavid du Colombier 		if(0)deprint(2, "%s: asixread: bad header %#ulx %#ulx\n",
373*906943f9SDavid du Colombier 			argv0, nr, (~hd & 0xFFFF));
374*906943f9SDavid du Colombier 		werrstr("bad usb packet header");
375*906943f9SDavid du Colombier 		rbp->ndata = 0;
376*906943f9SDavid du Colombier 		return 0;
377*906943f9SDavid du Colombier 	}
378*906943f9SDavid du Colombier 	rbp->rp += 4;
379*906943f9SDavid du Colombier 	if(nr < 6 || nr > Epktlen){
380*906943f9SDavid du Colombier 		if(nr < 6)
381*906943f9SDavid du Colombier 			werrstr("short frame");
382*906943f9SDavid du Colombier 		else
383*906943f9SDavid du Colombier 			werrstr("long frame");
384*906943f9SDavid du Colombier 		deprint(2, "%s: asixbread %r (%ld)\n", argv0, nr);
385*906943f9SDavid du Colombier 		rbp->ndata = 0;
386*906943f9SDavid du Colombier 		return 0;
387*906943f9SDavid du Colombier 	}
388*906943f9SDavid du Colombier 	bp->rp = bp->data + Hdrsize;
389*906943f9SDavid du Colombier 	memmove(bp->rp, rbp->rp, nr);
390*906943f9SDavid du Colombier 	bp->ndata = nr;
391*906943f9SDavid du Colombier 	rbp->rp += 4 + nr;
392*906943f9SDavid du Colombier 	rbp->ndata -= (4 + nr);
393*906943f9SDavid du Colombier 	return bp->ndata;
394*906943f9SDavid du Colombier }
395*906943f9SDavid du Colombier 
396*906943f9SDavid du Colombier static long
397*906943f9SDavid du Colombier asixbwrite(Ether *e, Buf *bp)
398*906943f9SDavid du Colombier {
399*906943f9SDavid du Colombier 	ulong len;
400*906943f9SDavid du Colombier 	long n;
401*906943f9SDavid du Colombier 
402*906943f9SDavid du Colombier 	deprint(2, "%s: asixbwrite %d bytes\n", argv0, bp->ndata);
403*906943f9SDavid du Colombier 	assert(bp->rp - bp->data >= Hdrsize);
404*906943f9SDavid du Colombier 	bp->ndata &= 0xFFFF;
405*906943f9SDavid du Colombier 	len = (0xFFFF0000 & ~(bp->ndata<<16))  | bp->ndata;
406*906943f9SDavid du Colombier 	bp->rp -= 4;
407*906943f9SDavid du Colombier 	PUT4(bp->rp, len);
408*906943f9SDavid du Colombier 	bp->ndata += 4;
409*906943f9SDavid du Colombier 	if((bp->ndata % e->epout->maxpkt) == 0){
410*906943f9SDavid du Colombier 		PUT4(bp->rp+bp->ndata, 0xFFFF0000);
411*906943f9SDavid du Colombier 		bp->ndata += 4;
412*906943f9SDavid du Colombier 	}
413*906943f9SDavid du Colombier 	n = write(e->epout->dfd, bp->rp, bp->ndata);
414*906943f9SDavid du Colombier 	deprint(2, "%s: asixbwrite wrote %ld bytes\n", argv0, n);
415*906943f9SDavid du Colombier 	if(n <= 0)
416*906943f9SDavid du Colombier 		return n;
417*906943f9SDavid du Colombier 	return n;
418*906943f9SDavid du Colombier }
419*906943f9SDavid du Colombier 
420*906943f9SDavid du Colombier static int
421*906943f9SDavid du Colombier asixpromiscuous(Ether *e, int on)
422*906943f9SDavid du Colombier {
423*906943f9SDavid du Colombier 	int rxctl;
424*906943f9SDavid du Colombier 
425*906943f9SDavid du Colombier 	deprint(2, "%s: aixprompiscuous %d\n", argv0, on);
426*906943f9SDavid du Colombier 	rxctl = getrxctl(e->dev);
427*906943f9SDavid du Colombier 	if(on != 0)
428*906943f9SDavid du Colombier 		rxctl |= Rxctlprom;
429*906943f9SDavid du Colombier 	else
430*906943f9SDavid du Colombier 		rxctl &= ~Rxctlprom;
431*906943f9SDavid du Colombier 	return asixset(e->dev, Cwrxctl, rxctl);
432*906943f9SDavid du Colombier }
433*906943f9SDavid du Colombier 
434*906943f9SDavid du Colombier static int
435*906943f9SDavid du Colombier asixmulticast(Ether *e, uchar *addr, int on)
436*906943f9SDavid du Colombier {
437*906943f9SDavid du Colombier 	int rxctl;
438*906943f9SDavid du Colombier 
439*906943f9SDavid du Colombier 	USED(addr);
440*906943f9SDavid du Colombier 	USED(on);
441*906943f9SDavid du Colombier 	/* BUG: should write multicast filter */
442*906943f9SDavid du Colombier 	rxctl = getrxctl(e->dev);
443*906943f9SDavid du Colombier 	if(e->nmcasts != 0)
444*906943f9SDavid du Colombier 		rxctl |= Rxctlamall;
445*906943f9SDavid du Colombier 	else
446*906943f9SDavid du Colombier 		rxctl &= ~Rxctlamall;
447*906943f9SDavid du Colombier 	deprint(2, "%s: asixmulticast %d\n", argv0, e->nmcasts);
448*906943f9SDavid du Colombier 	return asixset(e->dev, Cwrxctl, rxctl);
449*906943f9SDavid du Colombier }
450*906943f9SDavid du Colombier 
451*906943f9SDavid du Colombier static void
452*906943f9SDavid du Colombier asixfree(Ether *ether)
453*906943f9SDavid du Colombier {
454*906943f9SDavid du Colombier 	deprint(2, "%s: aixfree %#p\n", argv0, ether);
455*906943f9SDavid du Colombier 	free(ether->aux);
456*906943f9SDavid du Colombier 	ether->aux = nil;
457*906943f9SDavid du Colombier }
458*906943f9SDavid du Colombier 
459*906943f9SDavid du Colombier int
460*906943f9SDavid du Colombier asixreset(Ether *ether)
461*906943f9SDavid du Colombier {
462*906943f9SDavid du Colombier 	Cinfo *ip;
463*906943f9SDavid du Colombier 	Dev *dev;
464*906943f9SDavid du Colombier 
465*906943f9SDavid du Colombier 	dev = ether->dev;
466*906943f9SDavid du Colombier 	for(ip = cinfo; ip->vid != 0; ip++)
467*906943f9SDavid du Colombier 		if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
468*906943f9SDavid du Colombier 			ether->cid = ip->cid;
469*906943f9SDavid du Colombier 			if(ctlrinit(ether) < 0){
470*906943f9SDavid du Colombier 				deprint(2, "%s: init failed: %r\n", argv0);
471*906943f9SDavid du Colombier 				return -1;
472*906943f9SDavid du Colombier 			}
473*906943f9SDavid du Colombier 			deprint(2, "%s: asix reset done\n", argv0);
474*906943f9SDavid du Colombier 			ether->aux = emallocz(sizeof(Buf), 1);
475*906943f9SDavid du Colombier 			ether->bread = asixbread;
476*906943f9SDavid du Colombier 			ether->bwrite = asixbwrite;
477*906943f9SDavid du Colombier 			ether->free = asixfree;
478*906943f9SDavid du Colombier 			ether->promiscuous = asixpromiscuous;
479*906943f9SDavid du Colombier 			ether->multicast = asixmulticast;
480*906943f9SDavid du Colombier 			ether->mbps = 100;	/* BUG */
481*906943f9SDavid du Colombier 			return 0;
482*906943f9SDavid du Colombier 		}
483*906943f9SDavid du Colombier 	return -1;
484*906943f9SDavid du Colombier }
485