xref: /plan9-contrib/sys/src/cmd/usb/ether/smsc.c (revision e1c0af539adcc53c770ef6e067291d1d2730e221)
1a650be7dSDavid du Colombier /*
2a650be7dSDavid du Colombier  * SMSC LAN95XX
3a650be7dSDavid du Colombier  */
4a650be7dSDavid du Colombier 
5a650be7dSDavid du Colombier #include <u.h>
6a650be7dSDavid du Colombier #include <libc.h>
7a650be7dSDavid du Colombier #include <fcall.h>
8a650be7dSDavid du Colombier #include <thread.h>
9a650be7dSDavid du Colombier #include "usb.h"
10a650be7dSDavid du Colombier #include "usbfs.h"
11a650be7dSDavid du Colombier #include "ether.h"
12a650be7dSDavid du Colombier 
13a650be7dSDavid du Colombier enum {
14a650be7dSDavid du Colombier 	Doburst		= 1,
15a650be7dSDavid du Colombier 	Resettime	= 1000,
16a650be7dSDavid du Colombier 	E2pbusytime	= 1000,
17a650be7dSDavid du Colombier 	Afcdefault	= 0xF830A1,
18*e1c0af53SDavid du Colombier 	Hsburst		= 24,
19a650be7dSDavid du Colombier 	Fsburst		= 129,
20*e1c0af53SDavid du Colombier 	Defbulkdly	= 1000,
21a650be7dSDavid du Colombier 
22a650be7dSDavid du Colombier 	Ethp8021q	= 0x8100,
23a650be7dSDavid du Colombier 	MACoffset 	= 1,
24a650be7dSDavid du Colombier 	PHYinternal	= 1,
25a650be7dSDavid du Colombier 	Rxerror		= 0x8000,
26a650be7dSDavid du Colombier 	Txfirst		= 0x2000,
27a650be7dSDavid du Colombier 	Txlast		= 0x1000,
28a650be7dSDavid du Colombier 
29a650be7dSDavid du Colombier 	/* USB vendor requests */
30a650be7dSDavid du Colombier 	Writereg	= 0xA0,
31a650be7dSDavid du Colombier 	Readreg		= 0xA1,
32a650be7dSDavid du Colombier 
33a650be7dSDavid du Colombier 	/* device registers */
34a650be7dSDavid du Colombier 	Intsts		= 0x08,
35a650be7dSDavid du Colombier 	Txcfg		= 0x10,
36a650be7dSDavid du Colombier 		Txon	= 1<<2,
37a650be7dSDavid du Colombier 	Hwcfg		= 0x14,
38a650be7dSDavid du Colombier 		Bir	= 1<<12,
39a650be7dSDavid du Colombier 		Rxdoff	= 3<<9,
40a650be7dSDavid du Colombier 		Mef	= 1<<5,
41a650be7dSDavid du Colombier 		Lrst	= 1<<3,
42a650be7dSDavid du Colombier 		Bce	= 1<<1,
43a650be7dSDavid du Colombier 	Pmctrl		= 0x20,
44a650be7dSDavid du Colombier 		Phyrst	= 1<<4,
45a650be7dSDavid du Colombier 	Ledgpio		= 0x24,
46a650be7dSDavid du Colombier 		Ledspd	= 1<<24,
47a650be7dSDavid du Colombier 		Ledlnk	= 1<<20,
48a650be7dSDavid du Colombier 		Ledfdx	= 1<<16,
49a650be7dSDavid du Colombier 	Afccfg		= 0x2C,
50a650be7dSDavid du Colombier 	E2pcmd		= 0x30,
51a650be7dSDavid du Colombier 		Busy	= 1<<31,
52a650be7dSDavid du Colombier 		Timeout	= 1<<10,
53a650be7dSDavid du Colombier 		Read	= 0,
54a650be7dSDavid du Colombier 	E2pdata		= 0x34,
55a650be7dSDavid du Colombier 	Burstcap	= 0x38,
56a650be7dSDavid du Colombier 	Intepctl	= 0x68,
57a650be7dSDavid du Colombier 		Phyint	= 1<<15,
58a650be7dSDavid du Colombier 	Bulkdelay	= 0x6C,
59a650be7dSDavid du Colombier 	Maccr		= 0x100,
60a650be7dSDavid du Colombier 		Mcpas	= 1<<19,
61a650be7dSDavid du Colombier 		Prms	= 1<<18,
62a650be7dSDavid du Colombier 		Hpfilt	= 1<<13,
63a650be7dSDavid du Colombier 		Txen	= 1<<3,
64a650be7dSDavid du Colombier 		Rxen	= 1<<2,
65a650be7dSDavid du Colombier 	Addrh		= 0x104,
66a650be7dSDavid du Colombier 	Addrl		= 0x108,
67a650be7dSDavid du Colombier 	Hashh		= 0x10C,
68a650be7dSDavid du Colombier 	Hashl		= 0x110,
69a650be7dSDavid du Colombier 	MIIaddr		= 0x114,
70a650be7dSDavid du Colombier 		MIIwrite= 1<<1,
71a650be7dSDavid du Colombier 		MIIread	= 0<<1,
72a650be7dSDavid du Colombier 		MIIbusy	= 1<<0,
73a650be7dSDavid du Colombier 	MIIdata		= 0x118,
74a650be7dSDavid du Colombier 	Flow		= 0x11C,
75a650be7dSDavid du Colombier 	Vlan1		= 0x120,
76a650be7dSDavid du Colombier 	Coecr		= 0x130,
77a650be7dSDavid du Colombier 		Txcoe	= 1<<16,
78a650be7dSDavid du Colombier 		Rxcoemd	= 1<<1,
79a650be7dSDavid du Colombier 		Rxcoe	= 1<<0,
80a650be7dSDavid du Colombier 
81a650be7dSDavid du Colombier 	/* MII registers */
82a650be7dSDavid du Colombier 	Bmcr		= 0,
83a650be7dSDavid du Colombier 		Bmcrreset= 1<<15,
84a650be7dSDavid du Colombier 		Speed100= 1<<13,
85a650be7dSDavid du Colombier 		Anenable= 1<<12,
86a650be7dSDavid du Colombier 		Anrestart= 1<<9,
87a650be7dSDavid du Colombier 		Fulldpx	= 1<<8,
88a650be7dSDavid du Colombier 	Bmsr		= 1,
89a650be7dSDavid du Colombier 	Advertise	= 4,
90a650be7dSDavid du Colombier 		Adcsma	= 0x0001,
91a650be7dSDavid du Colombier 		Ad10h	= 0x0020,
92a650be7dSDavid du Colombier 		Ad10f	= 0x0040,
93a650be7dSDavid du Colombier 		Ad100h	= 0x0080,
94a650be7dSDavid du Colombier 		Ad100f	= 0x0100,
95a650be7dSDavid du Colombier 		Adpause	= 0x0400,
96a650be7dSDavid du Colombier 		Adpauseasym= 0x0800,
97a650be7dSDavid du Colombier 		Adall	= Ad10h|Ad10f|Ad100h|Ad100f,
98a650be7dSDavid du Colombier 	Phyintsrc	= 29,
99a650be7dSDavid du Colombier 	Phyintmask	= 30,
100a650be7dSDavid du Colombier 		Anegcomp= 1<<6,
101a650be7dSDavid du Colombier 		Linkdown= 1<<4,
102a650be7dSDavid du Colombier };
103a650be7dSDavid du Colombier 
104*e1c0af53SDavid du Colombier static int burstcap = Hsburst, bulkdelay = Defbulkdly;
105*e1c0af53SDavid du Colombier 
106a650be7dSDavid du Colombier static int
wr(Dev * d,int reg,int val)107a650be7dSDavid du Colombier wr(Dev *d, int reg, int val)
108a650be7dSDavid du Colombier {
109a650be7dSDavid du Colombier 	int ret;
110a650be7dSDavid du Colombier 
111a650be7dSDavid du Colombier 	ret = usbcmd(d, Rh2d|Rvendor|Rdev, Writereg, 0, reg,
112a650be7dSDavid du Colombier 		(uchar*)&val, sizeof(val));
113a650be7dSDavid du Colombier 	if(ret < 0)
114a650be7dSDavid du Colombier 		deprint(2, "%s: wr(%x, %x): %r", argv0, reg, val);
115a650be7dSDavid du Colombier 	return ret;
116a650be7dSDavid du Colombier }
117a650be7dSDavid du Colombier 
118a650be7dSDavid du Colombier static int
rr(Dev * d,int reg)119a650be7dSDavid du Colombier rr(Dev *d, int reg)
120a650be7dSDavid du Colombier {
121a650be7dSDavid du Colombier 	int ret, rval;
122a650be7dSDavid du Colombier 
123a650be7dSDavid du Colombier 	ret = usbcmd(d, Rd2h|Rvendor|Rdev, Readreg, 0, reg,
124a650be7dSDavid du Colombier 		(uchar*)&rval, sizeof(rval));
125a650be7dSDavid du Colombier 	if(ret < 0){
126a650be7dSDavid du Colombier 		fprint(2, "%s: rr(%x): %r", argv0, reg);
127a650be7dSDavid du Colombier 		return 0;
128a650be7dSDavid du Colombier 	}
129a650be7dSDavid du Colombier 	return rval;
130a650be7dSDavid du Colombier }
131a650be7dSDavid du Colombier 
132a650be7dSDavid du Colombier static int
miird(Dev * d,int idx)133a650be7dSDavid du Colombier miird(Dev *d, int idx)
134a650be7dSDavid du Colombier {
135a650be7dSDavid du Colombier 	while(rr(d, MIIaddr) & MIIbusy)
136a650be7dSDavid du Colombier 		;
137a650be7dSDavid du Colombier 	wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIread);
138a650be7dSDavid du Colombier 	while(rr(d, MIIaddr) & MIIbusy)
139a650be7dSDavid du Colombier 		;
140a650be7dSDavid du Colombier 	return rr(d, MIIdata);
141a650be7dSDavid du Colombier }
142a650be7dSDavid du Colombier 
143a650be7dSDavid du Colombier static void
miiwr(Dev * d,int idx,int val)144a650be7dSDavid du Colombier miiwr(Dev *d, int idx, int val)
145a650be7dSDavid du Colombier {
146a650be7dSDavid du Colombier 	while(rr(d, MIIaddr) & MIIbusy)
147a650be7dSDavid du Colombier 		;
148a650be7dSDavid du Colombier 	wr(d, MIIdata, val);
149a650be7dSDavid du Colombier 	wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIwrite);
150a650be7dSDavid du Colombier 	while(rr(d, MIIaddr) & MIIbusy)
151a650be7dSDavid du Colombier 		;
152a650be7dSDavid du Colombier }
153a650be7dSDavid du Colombier 
154a650be7dSDavid du Colombier static int
eepromr(Dev * d,int off,uchar * buf,int len)155a650be7dSDavid du Colombier eepromr(Dev *d, int off, uchar *buf, int len)
156a650be7dSDavid du Colombier {
157a650be7dSDavid du Colombier 	int i, v;
158a650be7dSDavid du Colombier 
159a650be7dSDavid du Colombier 	for(i = 0; i < E2pbusytime; i++)
160a650be7dSDavid du Colombier 		if((rr(d, E2pcmd) & Busy) == 0)
161a650be7dSDavid du Colombier 			break;
162a650be7dSDavid du Colombier 	if(i == E2pbusytime)
163a650be7dSDavid du Colombier 		return -1;
164a650be7dSDavid du Colombier 	for(i = 0; i < len; i++){
165a650be7dSDavid du Colombier 		wr(d, E2pcmd, Busy|Read|(i+off));
166a650be7dSDavid du Colombier 		while((v = rr(d, E2pcmd) & (Busy|Timeout)) == Busy)
167a650be7dSDavid du Colombier 			;
168a650be7dSDavid du Colombier 		if(v & Timeout)
169a650be7dSDavid du Colombier 			return -1;
170a650be7dSDavid du Colombier 		buf[i] = rr(d, E2pdata);
171a650be7dSDavid du Colombier 	}
172a650be7dSDavid du Colombier 	return 0;
173a650be7dSDavid du Colombier }
174a650be7dSDavid du Colombier 
175a650be7dSDavid du Colombier static void
phyinit(Dev * d)176a650be7dSDavid du Colombier phyinit(Dev *d)
177a650be7dSDavid du Colombier {
178a650be7dSDavid du Colombier 	int i;
179a650be7dSDavid du Colombier 
180a650be7dSDavid du Colombier 	miiwr(d, Bmcr, Bmcrreset|Anenable);
181a650be7dSDavid du Colombier 	for(i = 0; i < Resettime/10; i++){
182a650be7dSDavid du Colombier 		if((miird(d, Bmcr) & Bmcrreset) == 0)
183a650be7dSDavid du Colombier 			break;
184a650be7dSDavid du Colombier 		sleep(10);
185a650be7dSDavid du Colombier 	}
186a650be7dSDavid du Colombier 	miiwr(d, Advertise, Adcsma|Adall|Adpause|Adpauseasym);
187a650be7dSDavid du Colombier //	miiwr(d, Advertise, Adcsma|Ad10f|Ad10h|Adpause|Adpauseasym);
188a650be7dSDavid du Colombier 	miird(d, Phyintsrc);
189a650be7dSDavid du Colombier 	miiwr(d, Phyintmask, Anegcomp|Linkdown);
190a650be7dSDavid du Colombier 	miiwr(d, Bmcr, miird(d, Bmcr)|Anenable|Anrestart);
191a650be7dSDavid du Colombier }
192a650be7dSDavid du Colombier 
193a650be7dSDavid du Colombier 
194a650be7dSDavid du Colombier static int
doreset(Dev * d,int reg,int bit)195a650be7dSDavid du Colombier doreset(Dev *d, int reg, int bit)
196a650be7dSDavid du Colombier {
197a650be7dSDavid du Colombier 	int i;
198a650be7dSDavid du Colombier 
199a650be7dSDavid du Colombier 	if(wr(d, reg, bit) < 0)
200a650be7dSDavid du Colombier 		return -1;
201a650be7dSDavid du Colombier 	for(i = 0; i < Resettime/10; i++){
202a650be7dSDavid du Colombier 		 if((rr(d, reg) & bit) == 0)
203a650be7dSDavid du Colombier 			return 1;
204a650be7dSDavid du Colombier 		sleep(10);
205a650be7dSDavid du Colombier 	}
206a650be7dSDavid du Colombier 	return 0;
207a650be7dSDavid du Colombier }
208a650be7dSDavid du Colombier 
209a650be7dSDavid du Colombier static int
getmac(Dev * d,uchar buf[])210a650be7dSDavid du Colombier getmac(Dev *d, uchar buf[])
211a650be7dSDavid du Colombier {
212a650be7dSDavid du Colombier 	int i;
213a650be7dSDavid du Colombier 	uchar ea[Eaddrlen];
214a650be7dSDavid du Colombier 
215a650be7dSDavid du Colombier 	if(eepromr(d, MACoffset, ea, Eaddrlen) < 0)
216a650be7dSDavid du Colombier 		return -1;
217a650be7dSDavid du Colombier 	for(i = 0; i < Eaddrlen; i++)
2180cc6832dSDavid du Colombier 		if(ea[i] != 0 && ea[i] != 0xFF){
219a650be7dSDavid du Colombier 			memmove(buf, ea, Eaddrlen);
220a650be7dSDavid du Colombier 			break;
221a650be7dSDavid du Colombier 		}
222a650be7dSDavid du Colombier 	return Eaddrlen;
223a650be7dSDavid du Colombier }
224a650be7dSDavid du Colombier 
225a650be7dSDavid du Colombier static int
smscinit(Ether * ether)226a650be7dSDavid du Colombier smscinit(Ether *ether)
227a650be7dSDavid du Colombier {
228a650be7dSDavid du Colombier 	Dev *d;
229a650be7dSDavid du Colombier 
230a650be7dSDavid du Colombier 	if(ether->cid != S95xx)
231a650be7dSDavid du Colombier 		return -1;
232a650be7dSDavid du Colombier 	d = ether->dev;
233a650be7dSDavid du Colombier 	deprint(2, "%s: setting up SMSC95XX\n", argv0);
234a650be7dSDavid du Colombier 	if(!doreset(d, Hwcfg, Lrst) || !doreset(d, Pmctrl, Phyrst))
235a650be7dSDavid du Colombier 		return -1;
236a650be7dSDavid du Colombier 	if(getmac(d, ether->addr) < 0)
237a650be7dSDavid du Colombier 		return -1;
238a650be7dSDavid du Colombier 	wr(d, Addrl, GET4(ether->addr));
239a650be7dSDavid du Colombier 	wr(d, Addrh, GET2(ether->addr+4));
240a650be7dSDavid du Colombier 	if(Doburst){
241a650be7dSDavid du Colombier 		wr(d, Hwcfg, (rr(d,Hwcfg)&~Rxdoff)|Bir|Mef|Bce);
242*e1c0af53SDavid du Colombier 		wr(d, Burstcap, burstcap);
243*e1c0af53SDavid du Colombier 		wr(d, Bulkdelay, bulkdelay);
244a650be7dSDavid du Colombier 	}else{
245a650be7dSDavid du Colombier 		wr(d, Hwcfg, (rr(d,Hwcfg)&~(Rxdoff|Mef|Bce))|Bir);
246a650be7dSDavid du Colombier 		wr(d, Burstcap, 0);
247*e1c0af53SDavid du Colombier 		wr(d, Bulkdelay, 0);
248a650be7dSDavid du Colombier 	}
249a650be7dSDavid du Colombier 	wr(d, Intsts, ~0);
250a650be7dSDavid du Colombier 	wr(d, Ledgpio, Ledspd|Ledlnk|Ledfdx);
251a650be7dSDavid du Colombier 	wr(d, Flow, 0);
252a650be7dSDavid du Colombier 	wr(d, Afccfg, Afcdefault);
253a650be7dSDavid du Colombier 	wr(d, Vlan1, Ethp8021q);
254a650be7dSDavid du Colombier 	wr(d, Coecr, rr(d,Coecr)&~(Txcoe|Rxcoe)); /* TODO could offload checksums? */
255a650be7dSDavid du Colombier 
256a650be7dSDavid du Colombier 	wr(d, Hashh, 0);
257a650be7dSDavid du Colombier 	wr(d, Hashl, 0);
258a650be7dSDavid du Colombier 	wr(d, Maccr, rr(d,Maccr)&~(Prms|Mcpas|Hpfilt));
259a650be7dSDavid du Colombier 
260a650be7dSDavid du Colombier 	phyinit(d);
261a650be7dSDavid du Colombier 
262a650be7dSDavid du Colombier 	wr(d, Intepctl, rr(d, Intepctl)|Phyint);
263a650be7dSDavid du Colombier 	wr(d, Maccr, rr(d, Maccr)|Txen|Rxen);
264a650be7dSDavid du Colombier 	wr(d, Txcfg, Txon);
265a650be7dSDavid du Colombier 
266a650be7dSDavid du Colombier 	return 0;
267a650be7dSDavid du Colombier }
268a650be7dSDavid du Colombier 
269a650be7dSDavid du Colombier static long
smscbread(Ether * e,Buf * bp)270a650be7dSDavid du Colombier smscbread(Ether *e, Buf *bp)
271a650be7dSDavid du Colombier {
272a650be7dSDavid du Colombier 	uint hd;
273a650be7dSDavid du Colombier 	int n, m;
274a650be7dSDavid du Colombier 	Buf *rbp;
275a650be7dSDavid du Colombier 
276a650be7dSDavid du Colombier 	rbp = e->aux;
277a650be7dSDavid du Colombier 	if(rbp->ndata < 4){
278a650be7dSDavid du Colombier 		rbp->rp = rbp->data;
279*e1c0af53SDavid du Colombier 		rbp->ndata = read(e->epin->dfd, rbp->rp, Doburst? burstcap*512:
2800cc6832dSDavid du Colombier 			Maxpkt);
281a650be7dSDavid du Colombier 		if(rbp->ndata < 0)
282a650be7dSDavid du Colombier 			return -1;
283a650be7dSDavid du Colombier 	}
284a650be7dSDavid du Colombier 	if(rbp->ndata < 4){
285a650be7dSDavid du Colombier 		werrstr("short frame");
286a650be7dSDavid du Colombier 		fprint(2, "smsc short frame %d bytes\n", rbp->ndata);
287a650be7dSDavid du Colombier 		return 0;
288a650be7dSDavid du Colombier 	}
289a650be7dSDavid du Colombier 	hd = GET4(rbp->rp);
290*e1c0af53SDavid du Colombier 	rbp->rp += 4;
291*e1c0af53SDavid du Colombier 	rbp->ndata -= 4;
292a650be7dSDavid du Colombier 	n = hd >> 16;
293*e1c0af53SDavid du Colombier 	if(n < 6 || n > rbp->ndata){
294a650be7dSDavid du Colombier 		werrstr("frame length");
295a650be7dSDavid du Colombier 		fprint(2, "smsc length error packet %d buf %d\n", n, rbp->ndata);
296a650be7dSDavid du Colombier 		rbp->ndata = 0;
297a650be7dSDavid du Colombier 		return 0;
298a650be7dSDavid du Colombier 	}
299*e1c0af53SDavid du Colombier 	m = n;
300*e1c0af53SDavid du Colombier 	if(rbp->ndata - m < 4)
301*e1c0af53SDavid du Colombier 		m = rbp->ndata;
302a650be7dSDavid du Colombier 	if(hd & Rxerror){
303a650be7dSDavid du Colombier 		fprint(2, "smsc rx error %8.8ux\n", hd);
304a650be7dSDavid du Colombier 		n = 0;
305a650be7dSDavid du Colombier 	}else{
306a650be7dSDavid du Colombier 		bp->rp = bp->data + Hdrsize;
307*e1c0af53SDavid du Colombier 		memmove(bp->rp, rbp->rp, n);
308a650be7dSDavid du Colombier 	}
309a650be7dSDavid du Colombier 	bp->ndata = n;
310a650be7dSDavid du Colombier 	rbp->rp += m;
311a650be7dSDavid du Colombier 	rbp->ndata -= m;
312a650be7dSDavid du Colombier 	return n;
313a650be7dSDavid du Colombier }
314a650be7dSDavid du Colombier 
315a650be7dSDavid du Colombier static long
smscbwrite(Ether * e,Buf * bp)316a650be7dSDavid du Colombier smscbwrite(Ether *e, Buf *bp)
317a650be7dSDavid du Colombier {
318a650be7dSDavid du Colombier 	int n;
319a650be7dSDavid du Colombier 
320a650be7dSDavid du Colombier 	n = bp->ndata & 0x7FF;
321a650be7dSDavid du Colombier 	bp->rp -= 8;
322a650be7dSDavid du Colombier 	bp->ndata += 8;
323a650be7dSDavid du Colombier 	PUT4(bp->rp, n | Txfirst | Txlast);
324a650be7dSDavid du Colombier 	PUT4(bp->rp+4, n);
325a650be7dSDavid du Colombier 	n = write(e->epout->dfd, bp->rp, bp->ndata);
326a650be7dSDavid du Colombier 	return n;
327a650be7dSDavid du Colombier }
328a650be7dSDavid du Colombier 
329853458f3SDavid du Colombier static int
smscpromiscuous(Ether * e,int on)330853458f3SDavid du Colombier smscpromiscuous(Ether *e, int on)
331853458f3SDavid du Colombier {
33219c1d8dfSDavid du Colombier 	Dev *d;
333853458f3SDavid du Colombier 	int rxctl;
334853458f3SDavid du Colombier 
33519c1d8dfSDavid du Colombier 	d = e->dev;
33619c1d8dfSDavid du Colombier 	rxctl = rr(d, Maccr);
33719c1d8dfSDavid du Colombier 	if(on)
33819c1d8dfSDavid du Colombier 		rxctl |= Prms;
339853458f3SDavid du Colombier 	else
34019c1d8dfSDavid du Colombier 		rxctl &= ~Prms;
34119c1d8dfSDavid du Colombier 	return wr(d, Maccr, rxctl);
342853458f3SDavid du Colombier }
343853458f3SDavid du Colombier 
344853458f3SDavid du Colombier static int
smscmulticast(Ether * e,uchar * addr,int on)345853458f3SDavid du Colombier smscmulticast(Ether *e, uchar *addr, int on)
346853458f3SDavid du Colombier {
347853458f3SDavid du Colombier 	int rxctl;
34819c1d8dfSDavid du Colombier 	Dev *d;
349853458f3SDavid du Colombier 
35019c1d8dfSDavid du Colombier 	USED(addr, on);
351853458f3SDavid du Colombier 	/* BUG: should write multicast filter */
35219c1d8dfSDavid du Colombier 	d = e->dev;
35319c1d8dfSDavid du Colombier 	rxctl = rr(d, Maccr);
354853458f3SDavid du Colombier 	if(e->nmcasts != 0)
35519c1d8dfSDavid du Colombier 		rxctl |= Mcpas;
356853458f3SDavid du Colombier 	else
35719c1d8dfSDavid du Colombier 		rxctl &= ~Mcpas;
358853458f3SDavid du Colombier 	deprint(2, "%s: smscmulticast %d\n", argv0, e->nmcasts);
35919c1d8dfSDavid du Colombier 	return wr(d, Maccr, rxctl);
360853458f3SDavid du Colombier }
361853458f3SDavid du Colombier 
362a650be7dSDavid du Colombier static void
smscfree(Ether * ether)363a650be7dSDavid du Colombier smscfree(Ether *ether)
364a650be7dSDavid du Colombier {
365a650be7dSDavid du Colombier 	free(ether->aux);
366a650be7dSDavid du Colombier 	ether->aux = nil;
367a650be7dSDavid du Colombier }
368a650be7dSDavid du Colombier 
369a650be7dSDavid du Colombier int
smscreset(Ether * ether)370a650be7dSDavid du Colombier smscreset(Ether *ether)
371a650be7dSDavid du Colombier {
372a650be7dSDavid du Colombier 	Cinfo *ip;
373a650be7dSDavid du Colombier 	Dev *dev;
374a650be7dSDavid du Colombier 
375a650be7dSDavid du Colombier 	dev = ether->dev;
376a650be7dSDavid du Colombier 	for(ip = cinfo; ip->vid != 0; ip++)
377a650be7dSDavid du Colombier 		if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
378a650be7dSDavid du Colombier 			ether->cid = ip->cid;
379a650be7dSDavid du Colombier 			if(smscinit(ether) < 0){
380a650be7dSDavid du Colombier 				deprint(2, "%s: smsc init failed: %r\n", argv0);
381a650be7dSDavid du Colombier 				return -1;
382a650be7dSDavid du Colombier 			}
383a650be7dSDavid du Colombier 			deprint(2, "%s: smsc reset done\n", argv0);
3840cc6832dSDavid du Colombier 			ether->name = "smsc";
3850cc6832dSDavid du Colombier 			if(Doburst){
386*e1c0af53SDavid du Colombier 				ether->bufsize = burstcap*512;
3870cc6832dSDavid du Colombier 				ether->aux = emallocz(sizeof(Buf) +
3880cc6832dSDavid du Colombier 					ether->bufsize - Maxpkt, 1);
3890cc6832dSDavid du Colombier 			}else{
3900cc6832dSDavid du Colombier 				ether->bufsize = Maxpkt;
3910cc6832dSDavid du Colombier 				ether->aux = emallocz(sizeof(Buf), 1);
3920cc6832dSDavid du Colombier 			}
393a650be7dSDavid du Colombier 			ether->free = smscfree;
394a650be7dSDavid du Colombier 			ether->bread = smscbread;
395a650be7dSDavid du Colombier 			ether->bwrite = smscbwrite;
396853458f3SDavid du Colombier 			ether->promiscuous = smscpromiscuous;
397853458f3SDavid du Colombier 			ether->multicast = smscmulticast;
398a650be7dSDavid du Colombier 			ether->mbps = 100;	/* BUG */
399a650be7dSDavid du Colombier 			return 0;
400a650be7dSDavid du Colombier 		}
401a650be7dSDavid du Colombier 	return -1;
402a650be7dSDavid du Colombier }
403