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