xref: /plan9/sys/src/cmd/usb/ether/asix.c (revision 853458f38e7eb3a48cfa3a36aefdb799375e398a)
1906943f9SDavid du Colombier /*
2906943f9SDavid du Colombier  * Asix USB ether adapters
3906943f9SDavid du Colombier  * I got no documentation for it, thus the bits
4906943f9SDavid du Colombier  * come from other systems; it's likely this is
5906943f9SDavid du Colombier  * doing more than needed in some places and
6906943f9SDavid du Colombier  * less than required in others.
7906943f9SDavid du Colombier  */
8906943f9SDavid du Colombier #include <u.h>
9906943f9SDavid du Colombier #include <libc.h>
10906943f9SDavid du Colombier #include <fcall.h>
11906943f9SDavid du Colombier #include <thread.h>
12906943f9SDavid du Colombier #include "usb.h"
13906943f9SDavid du Colombier #include "usbfs.h"
14906943f9SDavid du Colombier #include "ether.h"
15906943f9SDavid du Colombier 
16906943f9SDavid du Colombier enum
17906943f9SDavid du Colombier {
18906943f9SDavid du Colombier 
19906943f9SDavid du Colombier 	/* Asix commands */
20906943f9SDavid du Colombier 	Cswmii		= 0x06,		/* set sw mii */
21906943f9SDavid du Colombier 	Crmii		= 0x07,		/* read mii reg */
22906943f9SDavid du Colombier 	Cwmii		= 0x08,		/* write mii reg */
23906943f9SDavid du Colombier 	Chwmii		= 0x0a,		/* set hw mii */
24906943f9SDavid du Colombier 	Creeprom	= 0x0b,		/* read eeprom */
25906943f9SDavid du Colombier 	Cwdis		= 0x0e,		/* write disable */
26906943f9SDavid du Colombier 	Cwena		= 0x0d,		/* write enable */
27906943f9SDavid du Colombier 	Crrxctl		= 0x0f,		/* read rx ctl */
28906943f9SDavid du Colombier 	Cwrxctl		= 0x10,		/* write rx ctl */
29906943f9SDavid du Colombier 	Cwipg		= 0x12,		/* write ipg */
30906943f9SDavid du Colombier 	Crmac		= 0x13,		/* read mac addr */
31906943f9SDavid du Colombier 	Crphy		= 0x19,		/* read phy id */
32906943f9SDavid du Colombier 	Cwmedium		= 0x1b,		/* write medium mode */
33906943f9SDavid du Colombier 	Crgpio		= 0x1e,		/* read gpio */
34906943f9SDavid du Colombier 	Cwgpio		= 0x1f,		/* write gpios */
35906943f9SDavid du Colombier 	Creset		= 0x20,		/* reset */
36906943f9SDavid du Colombier 	Cwphy		= 0x22,		/* select phy */
37906943f9SDavid du Colombier 
38906943f9SDavid du Colombier 	/* reset codes */
39906943f9SDavid du Colombier 	Rclear		= 0x00,
40906943f9SDavid du Colombier 	Rprte		= 0x04,
41906943f9SDavid du Colombier 	Rprl		= 0x08,
42906943f9SDavid du Colombier 	Riprl		= 0x20,
43906943f9SDavid du Colombier 	Rippd		= 0x40,
44906943f9SDavid du Colombier 
45906943f9SDavid du Colombier 	Gpiogpo1en	= 0x04,	/* gpio1 enable */,
46906943f9SDavid du Colombier 	Gpiogpo1		= 0x08,	/* gpio1 value */
47906943f9SDavid du Colombier 	Gpiogpo2en	= 0x10,	/* gpio2 enable */
48906943f9SDavid du Colombier 	Gpiogpo2		= 0x20,	/* gpio2 value */
49906943f9SDavid du Colombier 	Gpiorse		= 0x80,	/* gpio reload serial eeprom */
50906943f9SDavid du Colombier 
51906943f9SDavid du Colombier 	Pmask		= 0x1F,
52906943f9SDavid du Colombier 	Pembed		= 0x10,			/* embedded phy */
53906943f9SDavid du Colombier 
54906943f9SDavid du Colombier 	Mfd		= 0x002,		/* media */
55906943f9SDavid du Colombier 	Mac		= 0x004,
56906943f9SDavid du Colombier 	Mrfc		= 0x010,
57906943f9SDavid du Colombier 	Mtfc		= 0x020,
58906943f9SDavid du Colombier 	Mjfe		= 0x040,
59906943f9SDavid du Colombier 	Mre		= 0x100,
60906943f9SDavid du Colombier 	Mps		= 0x200,
61906943f9SDavid du Colombier 	Mall772		= Mfd|Mrfc|Mtfc|Mps|Mac|Mre,
62906943f9SDavid du Colombier 	Mall178		= Mps|Mfd|Mac|Mrfc|Mtfc|Mjfe|Mre,
63906943f9SDavid du Colombier 
64906943f9SDavid du Colombier 	Ipgdflt		= 0x15|0x0c|0x12,	/* default ipg0, 1, 2 */
65906943f9SDavid du Colombier 	Rxctlso		= 0x80,
66906943f9SDavid du Colombier 	Rxctlab		= 0x08,
67906943f9SDavid du Colombier 	Rxctlsep	= 0x04,
68906943f9SDavid du Colombier 	Rxctlamall	= 0x02,			/* all multicast */
69906943f9SDavid du Colombier 	Rxctlprom	= 0x01,			/* promiscuous */
70906943f9SDavid du Colombier 
71906943f9SDavid du Colombier 	/* MII */
72906943f9SDavid du Colombier 	Miibmcr			= 0x00,		/* basic mode ctrl reg. */
73906943f9SDavid du Colombier 		Bmcrreset	= 0x8000,	/* reset */
74906943f9SDavid du Colombier 		Bmcranena	= 0x1000,	/* auto neg. enable */
75906943f9SDavid du Colombier 		Bmcrar		= 0x0200,	/* announce restart */
76906943f9SDavid du Colombier 
77906943f9SDavid du Colombier 	Miiad			= 0x04,		/* advertise reg. */
78906943f9SDavid du Colombier 		Adcsma		= 0x0001,
79906943f9SDavid du Colombier 		Ad1000f		= 0x0200,
80906943f9SDavid du Colombier 		Ad1000h		= 0x0100,
81906943f9SDavid du Colombier 		Ad10h		= 0x0020,
82906943f9SDavid du Colombier 		Ad10f		= 0x0040,
83906943f9SDavid du Colombier 		Ad100h		= 0x0080,
84906943f9SDavid du Colombier 		Ad100f		= 0x0100,
85906943f9SDavid du Colombier 		Adpause		= 0x0400,
86906943f9SDavid du Colombier 		Adall		= Ad10h|Ad10f|Ad100h|Ad100f,
87906943f9SDavid du Colombier 
88906943f9SDavid du Colombier 	Miimctl			= 0x14,		/* marvell ctl */
89906943f9SDavid du Colombier 		Mtxdly		= 0x02,
90906943f9SDavid du Colombier 		Mrxdly		= 0x80,
91906943f9SDavid du Colombier 		Mtxrxdly	= 0x82,
92906943f9SDavid du Colombier 
93906943f9SDavid du Colombier 	Miic1000			= 0x09,
94906943f9SDavid du Colombier 
95906943f9SDavid du Colombier };
96906943f9SDavid du Colombier 
97906943f9SDavid du Colombier static int
asixset(Dev * d,int c,int v)98906943f9SDavid du Colombier asixset(Dev *d, int c, int v)
99906943f9SDavid du Colombier {
100906943f9SDavid du Colombier 	int r;
101906943f9SDavid du Colombier 	int ec;
102906943f9SDavid du Colombier 
103906943f9SDavid du Colombier 	r = Rh2d|Rvendor|Rdev;
104906943f9SDavid du Colombier 	ec = usbcmd(d, r, c, v, 0, nil, 0);
105906943f9SDavid du Colombier 	if(ec < 0)
106906943f9SDavid du Colombier 		deprint(2, "%s: asixset %x %x: %r\n", argv0, c, v);
107906943f9SDavid du Colombier 	return ec;
108906943f9SDavid du Colombier }
109906943f9SDavid du Colombier 
110906943f9SDavid du Colombier static int
asixget(Dev * d,int c,uchar * buf,int l)111906943f9SDavid du Colombier asixget(Dev *d, int c, uchar *buf, int l)
112906943f9SDavid du Colombier {
113906943f9SDavid du Colombier 	int r;
114906943f9SDavid du Colombier 	int ec;
115906943f9SDavid du Colombier 
116906943f9SDavid du Colombier 	r = Rd2h|Rvendor|Rdev;
117906943f9SDavid du Colombier 	ec = usbcmd(d, r, c, 0, 0, buf, l);
118906943f9SDavid du Colombier 	if(ec < 0)
119906943f9SDavid du Colombier 		deprint(2, "%s: asixget %x: %r\n", argv0, c);
120906943f9SDavid du Colombier 	return ec;
121906943f9SDavid du Colombier }
122906943f9SDavid du Colombier 
123906943f9SDavid du Colombier static int
getgpio(Dev * d)124906943f9SDavid du Colombier getgpio(Dev *d)
125906943f9SDavid du Colombier {
126906943f9SDavid du Colombier 	uchar c;
127906943f9SDavid du Colombier 
128906943f9SDavid du Colombier 	if(asixget(d, Crgpio, &c, 1) < 0)
129906943f9SDavid du Colombier 		return -1;
130906943f9SDavid du Colombier 	return c;
131906943f9SDavid du Colombier }
132906943f9SDavid du Colombier 
133906943f9SDavid du Colombier static int
getphy(Dev * d)134906943f9SDavid du Colombier getphy(Dev *d)
135906943f9SDavid du Colombier {
136906943f9SDavid du Colombier 	uchar buf[2];
137906943f9SDavid du Colombier 
138906943f9SDavid du Colombier 	if(asixget(d, Crphy, buf, sizeof(buf)) < 0)
139906943f9SDavid du Colombier 		return -1;
140906943f9SDavid du Colombier 	deprint(2, "%s: phy addr %#ux\n", argv0, buf[1]);
141906943f9SDavid du Colombier 	return buf[1];
142906943f9SDavid du Colombier }
143906943f9SDavid du Colombier 
144906943f9SDavid du Colombier static int
getrxctl(Dev * d)145906943f9SDavid du Colombier getrxctl(Dev *d)
146906943f9SDavid du Colombier {
147906943f9SDavid du Colombier 	uchar buf[2];
148906943f9SDavid du Colombier 	int r;
149906943f9SDavid du Colombier 
150906943f9SDavid du Colombier 	memset(buf, 0, sizeof(buf));
151906943f9SDavid du Colombier 	if(asixget(d, Crrxctl, buf, sizeof(buf)) < 0)
152906943f9SDavid du Colombier 		return -1;
153906943f9SDavid du Colombier 	r = GET2(buf);
154906943f9SDavid du Colombier 	deprint(2, "%s: rxctl %#x\n", argv0, r);
155906943f9SDavid du Colombier 	return r;
156906943f9SDavid du Colombier }
157906943f9SDavid du Colombier 
158906943f9SDavid du Colombier static int
getmac(Dev * d,uchar buf[])159906943f9SDavid du Colombier getmac(Dev *d, uchar buf[])
160906943f9SDavid du Colombier {
161906943f9SDavid du Colombier 	if(asixget(d, Crmac, buf, Eaddrlen) < 0)
162906943f9SDavid du Colombier 		return -1;
163906943f9SDavid du Colombier 	return Eaddrlen;
164906943f9SDavid du Colombier }
165906943f9SDavid du Colombier 
166906943f9SDavid du Colombier static int
miiread(Dev * d,int phy,int reg)167906943f9SDavid du Colombier miiread(Dev *d, int phy, int reg)
168906943f9SDavid du Colombier {
169906943f9SDavid du Colombier 	int r;
170906943f9SDavid du Colombier 	uchar v[2];
171906943f9SDavid du Colombier 
172906943f9SDavid du Colombier 	r = Rd2h|Rvendor|Rdev;
173906943f9SDavid du Colombier 	if(usbcmd(d, r, Crmii, phy, reg, v, 2) < 0){
174906943f9SDavid du Colombier 		dprint(2, "%s: miiwrite: %r\n", argv0);
175906943f9SDavid du Colombier 		return -1;
176906943f9SDavid du Colombier 	}
177906943f9SDavid du Colombier 	r = GET2(v);
178906943f9SDavid du Colombier 	if(r == 0xFFFF)
179906943f9SDavid du Colombier 		return -1;
180906943f9SDavid du Colombier 	return r;
181906943f9SDavid du Colombier }
182906943f9SDavid du Colombier 
183906943f9SDavid du Colombier 
184906943f9SDavid du Colombier static int
miiwrite(Dev * d,int phy,int reg,int val)185906943f9SDavid du Colombier miiwrite(Dev *d, int phy, int reg, int val)
186906943f9SDavid du Colombier {
187906943f9SDavid du Colombier 	int r;
188906943f9SDavid du Colombier 	uchar v[2];
189906943f9SDavid du Colombier 
190906943f9SDavid du Colombier 	if(asixset(d, Cswmii, 0) < 0)
191906943f9SDavid du Colombier 		return -1;
192906943f9SDavid du Colombier 	r = Rh2d|Rvendor|Rdev;
193906943f9SDavid du Colombier 	PUT2(v, val);
194906943f9SDavid du Colombier 	if(usbcmd(d, r, Cwmii, phy, reg, v, 2) < 0){
195906943f9SDavid du Colombier 		deprint(2, "%s: miiwrite: %#x %#x %r\n", argv0, reg, val);
196906943f9SDavid du Colombier 		return -1;
197906943f9SDavid du Colombier 	}
198906943f9SDavid du Colombier 	if(asixset(d, Chwmii, 0) < 0)
199906943f9SDavid du Colombier 		return -1;
200906943f9SDavid du Colombier 	return 0;
201906943f9SDavid du Colombier }
202906943f9SDavid du Colombier 
203906943f9SDavid du Colombier static int
eepromread(Dev * d,int i)204906943f9SDavid du Colombier eepromread(Dev *d, int i)
205906943f9SDavid du Colombier {
206906943f9SDavid du Colombier 	int r;
207906943f9SDavid du Colombier 	int ec;
208906943f9SDavid du Colombier 	uchar buf[2];
209906943f9SDavid du Colombier 
210906943f9SDavid du Colombier 	r = Rd2h|Rvendor|Rdev;
211906943f9SDavid du Colombier 	ec = usbcmd(d, r, Creeprom, i, 0, buf, sizeof(buf));
212906943f9SDavid du Colombier 	if(ec < 0)
213906943f9SDavid du Colombier 		deprint(2, "%s: eepromread %d: %r\n", argv0, i);
214906943f9SDavid du Colombier 	ec = GET2(buf);
215906943f9SDavid du Colombier 	deprint(2, "%s: eeprom %#x = %#x\n", argv0, i, ec);
216906943f9SDavid du Colombier 	if(ec == 0xFFFF)
217906943f9SDavid du Colombier 		ec = -1;
218906943f9SDavid du Colombier 	return ec;
219906943f9SDavid du Colombier }
220906943f9SDavid du Colombier 
221906943f9SDavid du Colombier /*
222906943f9SDavid du Colombier  * No doc. we are doing what Linux does as closely
223906943f9SDavid du Colombier  * as we can.
224906943f9SDavid du Colombier  */
225906943f9SDavid du Colombier static int
ctlrinit(Ether * ether)226906943f9SDavid du Colombier ctlrinit(Ether *ether)
227906943f9SDavid du Colombier {
228906943f9SDavid du Colombier 	Dev *d;
229906943f9SDavid du Colombier 	int i;
230906943f9SDavid du Colombier 	int bmcr;
231906943f9SDavid du Colombier 	int gpio;
232906943f9SDavid du Colombier 	int ee17;
233906943f9SDavid du Colombier 	int rc;
234906943f9SDavid du Colombier 
235906943f9SDavid du Colombier 	d = ether->dev;
236906943f9SDavid du Colombier 	switch(ether->cid){
237a650be7dSDavid du Colombier 	case A8817x:
238a650be7dSDavid du Colombier 	case A88179:
239906943f9SDavid du Colombier 		fprint(2, "%s: card known but not implemented\n", argv0);
240a650be7dSDavid du Colombier 		/* fall through */
241a650be7dSDavid du Colombier 	default:
242906943f9SDavid du Colombier 		return -1;
243906943f9SDavid du Colombier 
244906943f9SDavid du Colombier 	case A88178:
245906943f9SDavid du Colombier 		deprint(2, "%s: setting up A88178\n", argv0);
246906943f9SDavid du Colombier 		gpio = getgpio(d);
247906943f9SDavid du Colombier 		if(gpio < 0)
248906943f9SDavid du Colombier 			return -1;
249906943f9SDavid du Colombier 		deprint(2, "%s: gpio sts %#x\n", argv0, gpio);
250906943f9SDavid du Colombier 		asixset(d, Cwena, 0);
251906943f9SDavid du Colombier 		ee17 = eepromread(d, 0x0017);
252906943f9SDavid du Colombier 		asixset(d, Cwdis, 0);
253906943f9SDavid du Colombier 		asixset(d, Cwgpio, Gpiorse|Gpiogpo1|Gpiogpo1en);
254906943f9SDavid du Colombier 		if((ee17 >> 8) != 1){
255906943f9SDavid du Colombier 			asixset(d, Cwgpio, 0x003c);
256906943f9SDavid du Colombier 			asixset(d, Cwgpio, 0x001c);
257906943f9SDavid du Colombier 			asixset(d, Cwgpio, 0x003c);
258906943f9SDavid du Colombier 		}else{
259906943f9SDavid du Colombier 			asixset(d, Cwgpio, Gpiogpo1en);
260906943f9SDavid du Colombier 			asixset(d, Cwgpio, Gpiogpo1|Gpiogpo1en);
261906943f9SDavid du Colombier 		}
262906943f9SDavid du Colombier 		asixset(d, Creset, Rclear);
263906943f9SDavid du Colombier 		sleep(150);
264906943f9SDavid du Colombier 		asixset(d, Creset, Rippd|Rprl);
265906943f9SDavid du Colombier 		sleep(150);
266906943f9SDavid du Colombier 		asixset(d, Cwrxctl, 0);
267906943f9SDavid du Colombier 		if(getmac(d, ether->addr) < 0)
268906943f9SDavid du Colombier 			return -1;
269906943f9SDavid du Colombier 		ether->phy = getphy(d);
270906943f9SDavid du Colombier 		if(ee17 < 0 || (ee17 & 0x7) == 0){
271906943f9SDavid du Colombier 			miiwrite(d, ether->phy, Miimctl, Mtxrxdly);
272906943f9SDavid du Colombier 			sleep(60);
273906943f9SDavid du Colombier 		}
274906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miibmcr, Bmcrreset|Bmcranena);
275906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miiad, Adall|Adcsma|Adpause);
276906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miic1000, Ad1000f);
277906943f9SDavid du Colombier 		bmcr = miiread(d, ether->phy, Miibmcr);
278906943f9SDavid du Colombier 		if((bmcr & Bmcranena) != 0){
279906943f9SDavid du Colombier 			bmcr |= Bmcrar;
280906943f9SDavid du Colombier 			miiwrite(d, ether->phy, Miibmcr, bmcr);
281906943f9SDavid du Colombier 		}
282906943f9SDavid du Colombier 		asixset(d, Cwmedium, Mall178);
283906943f9SDavid du Colombier 		asixset(d, Cwrxctl, Rxctlso|Rxctlab);
284906943f9SDavid du Colombier 		break;
285906943f9SDavid du Colombier 
286906943f9SDavid du Colombier 	case A88772:
287906943f9SDavid du Colombier 		deprint(2, "%s: setting up A88772\n", argv0);
288906943f9SDavid du Colombier 		if(asixset(d, Cwgpio, Gpiorse|Gpiogpo2|Gpiogpo2en) < 0)
289906943f9SDavid du Colombier 			return -1;
290906943f9SDavid du Colombier 		ether->phy = getphy(d);
291906943f9SDavid du Colombier 		dprint(2, "%s: phy %#x\n", argv0, ether->phy);
292906943f9SDavid du Colombier 		if((ether->phy & Pmask) == Pembed){
293906943f9SDavid du Colombier 			/* embedded 10/100 ethernet */
294906943f9SDavid du Colombier 			rc = asixset(d, Cwphy, 1);
295906943f9SDavid du Colombier 		}else
296906943f9SDavid du Colombier 			rc = asixset(d, Cwphy, 0);
297906943f9SDavid du Colombier 		if(rc < 0)
298906943f9SDavid du Colombier 			return -1;
299906943f9SDavid du Colombier 		if(asixset(d, Creset, Rippd|Rprl) < 0)
300906943f9SDavid du Colombier 			return -1;
301906943f9SDavid du Colombier 		sleep(150);
302906943f9SDavid du Colombier 		if((ether->phy & Pmask) == Pembed)
303906943f9SDavid du Colombier 			rc = asixset(d, Creset, Riprl);
304906943f9SDavid du Colombier 		else
305906943f9SDavid du Colombier 			rc = asixset(d, Creset, Rprte);
306906943f9SDavid du Colombier 		if(rc < 0)
307906943f9SDavid du Colombier 			return -1;
308906943f9SDavid du Colombier 		sleep(150);
309906943f9SDavid du Colombier 		rc = getrxctl(d);
310906943f9SDavid du Colombier 		deprint(2, "%s: rxctl is %#x\n", argv0, rc);
311906943f9SDavid du Colombier 		if(asixset(d, Cwrxctl, 0) < 0)
312906943f9SDavid du Colombier 			return -1;
313906943f9SDavid du Colombier 		if(getmac(d, ether->addr) < 0)
314906943f9SDavid du Colombier 			return -1;
315906943f9SDavid du Colombier 
316906943f9SDavid du Colombier 
317906943f9SDavid du Colombier 		if(asixset(d, Creset, Rprl) < 0)
318906943f9SDavid du Colombier 			return -1;
319906943f9SDavid du Colombier 		sleep(150);
320906943f9SDavid du Colombier 		if(asixset(d, Creset, Riprl|Rprl) < 0)
321906943f9SDavid du Colombier 			return -1;
322906943f9SDavid du Colombier 		sleep(150);
323906943f9SDavid du Colombier 
324906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miibmcr, Bmcrreset);
325906943f9SDavid du Colombier 		miiwrite(d, ether->phy, Miiad, Adall|Adcsma);
326906943f9SDavid du Colombier 		bmcr = miiread(d, ether->phy, Miibmcr);
327906943f9SDavid du Colombier 		if((bmcr & Bmcranena) != 0){
328906943f9SDavid du Colombier 			bmcr |= Bmcrar;
329906943f9SDavid du Colombier 			miiwrite(d, ether->phy, Miibmcr, bmcr);
330906943f9SDavid du Colombier 		}
331906943f9SDavid du Colombier 		if(asixset(d, Cwmedium, Mall772) < 0)
332906943f9SDavid du Colombier 			return -1;
333906943f9SDavid du Colombier 		if(asixset(d, Cwipg, Ipgdflt) < 0)
334906943f9SDavid du Colombier 			return -1;
335906943f9SDavid du Colombier 		if(asixset(d, Cwrxctl, Rxctlso|Rxctlab) < 0)
336906943f9SDavid du Colombier 			return -1;
337906943f9SDavid du Colombier 		deprint(2, "%s: final rxctl: %#x\n", argv0, getrxctl(d));
338906943f9SDavid du Colombier 		break;
339906943f9SDavid du Colombier 	}
340906943f9SDavid du Colombier 
341906943f9SDavid du Colombier 	if(etherdebug){
342906943f9SDavid du Colombier 		fprint(2, "%s: ether: phy %#x addr ", argv0, ether->phy);
343906943f9SDavid du Colombier 		for(i = 0; i < sizeof(ether->addr); i++)
344906943f9SDavid du Colombier 			fprint(2, "%02x", ether->addr[i]);
345906943f9SDavid du Colombier 		fprint(2, "\n");
346906943f9SDavid du Colombier 	}
347906943f9SDavid du Colombier 	return 0;
348906943f9SDavid du Colombier }
349906943f9SDavid du Colombier 
350906943f9SDavid du Colombier 
351906943f9SDavid du Colombier static long
asixbread(Ether * e,Buf * bp)352906943f9SDavid du Colombier asixbread(Ether *e, Buf *bp)
353906943f9SDavid du Colombier {
354906943f9SDavid du Colombier 	ulong nr;
355906943f9SDavid du Colombier 	ulong hd;
356906943f9SDavid du Colombier 	Buf *rbp;
357906943f9SDavid du Colombier 
358906943f9SDavid du Colombier 	rbp = e->aux;
359906943f9SDavid du Colombier 	if(rbp == nil || rbp->ndata < 4){
360906943f9SDavid du Colombier 		rbp->rp = rbp->data;
361906943f9SDavid du Colombier 		rbp->ndata = read(e->epin->dfd, rbp->rp, sizeof(bp->data));
362906943f9SDavid du Colombier 		if(rbp->ndata < 0)
363906943f9SDavid du Colombier 			return -1;
364906943f9SDavid du Colombier 	}
365906943f9SDavid du Colombier 	if(rbp->ndata < 4){
366906943f9SDavid du Colombier 		werrstr("short frame");
367906943f9SDavid du Colombier 		deprint(2, "%s: asixbread got %d bytes\n", argv0, rbp->ndata);
368906943f9SDavid du Colombier 		rbp->ndata = 0;
369906943f9SDavid du Colombier 		return 0;
370906943f9SDavid du Colombier 	}
371906943f9SDavid du Colombier 	hd = GET4(rbp->rp);
372906943f9SDavid du Colombier 	nr = hd & 0xFFFF;
373906943f9SDavid du Colombier 	hd = (hd>>16) & 0xFFFF;
374906943f9SDavid du Colombier 	if(nr != (~hd & 0xFFFF)){
375906943f9SDavid du Colombier 		if(0)deprint(2, "%s: asixread: bad header %#ulx %#ulx\n",
376906943f9SDavid du Colombier 			argv0, nr, (~hd & 0xFFFF));
377906943f9SDavid du Colombier 		werrstr("bad usb packet header");
378906943f9SDavid du Colombier 		rbp->ndata = 0;
379906943f9SDavid du Colombier 		return 0;
380906943f9SDavid du Colombier 	}
381906943f9SDavid du Colombier 	rbp->rp += 4;
382906943f9SDavid du Colombier 	if(nr < 6 || nr > Epktlen){
383906943f9SDavid du Colombier 		if(nr < 6)
384906943f9SDavid du Colombier 			werrstr("short frame");
385906943f9SDavid du Colombier 		else
386906943f9SDavid du Colombier 			werrstr("long frame");
387906943f9SDavid du Colombier 		deprint(2, "%s: asixbread %r (%ld)\n", argv0, nr);
388906943f9SDavid du Colombier 		rbp->ndata = 0;
389906943f9SDavid du Colombier 		return 0;
390906943f9SDavid du Colombier 	}
391906943f9SDavid du Colombier 	bp->rp = bp->data + Hdrsize;
392906943f9SDavid du Colombier 	memmove(bp->rp, rbp->rp, nr);
393906943f9SDavid du Colombier 	bp->ndata = nr;
394906943f9SDavid du Colombier 	rbp->rp += 4 + nr;
395906943f9SDavid du Colombier 	rbp->ndata -= (4 + nr);
396906943f9SDavid du Colombier 	return bp->ndata;
397906943f9SDavid du Colombier }
398906943f9SDavid du Colombier 
399906943f9SDavid du Colombier static long
asixbwrite(Ether * e,Buf * bp)400906943f9SDavid du Colombier asixbwrite(Ether *e, Buf *bp)
401906943f9SDavid du Colombier {
402906943f9SDavid du Colombier 	ulong len;
403906943f9SDavid du Colombier 	long n;
404906943f9SDavid du Colombier 
405906943f9SDavid du Colombier 	deprint(2, "%s: asixbwrite %d bytes\n", argv0, bp->ndata);
406906943f9SDavid du Colombier 	assert(bp->rp - bp->data >= Hdrsize);
407906943f9SDavid du Colombier 	bp->ndata &= 0xFFFF;
408906943f9SDavid du Colombier 	len = (0xFFFF0000 & ~(bp->ndata<<16))  | bp->ndata;
409906943f9SDavid du Colombier 	bp->rp -= 4;
410906943f9SDavid du Colombier 	PUT4(bp->rp, len);
411906943f9SDavid du Colombier 	bp->ndata += 4;
412906943f9SDavid du Colombier 	if((bp->ndata % e->epout->maxpkt) == 0){
413906943f9SDavid du Colombier 		PUT4(bp->rp+bp->ndata, 0xFFFF0000);
414906943f9SDavid du Colombier 		bp->ndata += 4;
415906943f9SDavid du Colombier 	}
416906943f9SDavid du Colombier 	n = write(e->epout->dfd, bp->rp, bp->ndata);
417906943f9SDavid du Colombier 	deprint(2, "%s: asixbwrite wrote %ld bytes\n", argv0, n);
418906943f9SDavid du Colombier 	if(n <= 0)
419906943f9SDavid du Colombier 		return n;
420906943f9SDavid du Colombier 	return n;
421906943f9SDavid du Colombier }
422906943f9SDavid du Colombier 
423906943f9SDavid du Colombier static int
asixpromiscuous(Ether * e,int on)424906943f9SDavid du Colombier asixpromiscuous(Ether *e, int on)
425906943f9SDavid du Colombier {
426906943f9SDavid du Colombier 	int rxctl;
427906943f9SDavid du Colombier 
428*853458f3SDavid du Colombier 	deprint(2, "%s: asixpromiscuous %d\n", argv0, on);
429906943f9SDavid du Colombier 	rxctl = getrxctl(e->dev);
430906943f9SDavid du Colombier 	if(on != 0)
431906943f9SDavid du Colombier 		rxctl |= Rxctlprom;
432906943f9SDavid du Colombier 	else
433906943f9SDavid du Colombier 		rxctl &= ~Rxctlprom;
434906943f9SDavid du Colombier 	return asixset(e->dev, Cwrxctl, rxctl);
435906943f9SDavid du Colombier }
436906943f9SDavid du Colombier 
437906943f9SDavid du Colombier static int
asixmulticast(Ether * e,uchar * addr,int on)438906943f9SDavid du Colombier asixmulticast(Ether *e, uchar *addr, int on)
439906943f9SDavid du Colombier {
440906943f9SDavid du Colombier 	int rxctl;
441906943f9SDavid du Colombier 
442906943f9SDavid du Colombier 	USED(addr);
443906943f9SDavid du Colombier 	USED(on);
444906943f9SDavid du Colombier 	/* BUG: should write multicast filter */
445906943f9SDavid du Colombier 	rxctl = getrxctl(e->dev);
446906943f9SDavid du Colombier 	if(e->nmcasts != 0)
447906943f9SDavid du Colombier 		rxctl |= Rxctlamall;
448906943f9SDavid du Colombier 	else
449906943f9SDavid du Colombier 		rxctl &= ~Rxctlamall;
450906943f9SDavid du Colombier 	deprint(2, "%s: asixmulticast %d\n", argv0, e->nmcasts);
451906943f9SDavid du Colombier 	return asixset(e->dev, Cwrxctl, rxctl);
452906943f9SDavid du Colombier }
453906943f9SDavid du Colombier 
454906943f9SDavid du Colombier static void
asixfree(Ether * ether)455906943f9SDavid du Colombier asixfree(Ether *ether)
456906943f9SDavid du Colombier {
457906943f9SDavid du Colombier 	deprint(2, "%s: aixfree %#p\n", argv0, ether);
458906943f9SDavid du Colombier 	free(ether->aux);
459906943f9SDavid du Colombier 	ether->aux = nil;
460906943f9SDavid du Colombier }
461906943f9SDavid du Colombier 
462906943f9SDavid du Colombier int
asixreset(Ether * ether)463906943f9SDavid du Colombier asixreset(Ether *ether)
464906943f9SDavid du Colombier {
465906943f9SDavid du Colombier 	Cinfo *ip;
466906943f9SDavid du Colombier 	Dev *dev;
467906943f9SDavid du Colombier 
468906943f9SDavid du Colombier 	dev = ether->dev;
469906943f9SDavid du Colombier 	for(ip = cinfo; ip->vid != 0; ip++)
470906943f9SDavid du Colombier 		if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
471906943f9SDavid du Colombier 			ether->cid = ip->cid;
472906943f9SDavid du Colombier 			if(ctlrinit(ether) < 0){
473a650be7dSDavid du Colombier 				deprint(2, "%s: asix init failed: %r\n", argv0);
474906943f9SDavid du Colombier 				return -1;
475906943f9SDavid du Colombier 			}
476906943f9SDavid du Colombier 			deprint(2, "%s: asix reset done\n", argv0);
4770cc6832dSDavid du Colombier 			ether->name = "asix";
478906943f9SDavid du Colombier 			ether->aux = emallocz(sizeof(Buf), 1);
4790cc6832dSDavid du Colombier 			ether->bufsize = Hdrsize+Maxpkt;
480906943f9SDavid du Colombier 			ether->bread = asixbread;
481906943f9SDavid du Colombier 			ether->bwrite = asixbwrite;
482906943f9SDavid du Colombier 			ether->free = asixfree;
483906943f9SDavid du Colombier 			ether->promiscuous = asixpromiscuous;
484906943f9SDavid du Colombier 			ether->multicast = asixmulticast;
485906943f9SDavid du Colombier 			ether->mbps = 100;	/* BUG */
486906943f9SDavid du Colombier 			return 0;
487906943f9SDavid du Colombier 		}
488906943f9SDavid du Colombier 	return -1;
489906943f9SDavid du Colombier }
490