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