xref: /plan9/sys/src/cmd/usb/ether/ether.c (revision 0cc6832d7c845a6250c7353daab06d4af2dfe5cb)
1906943f9SDavid du Colombier /*
2906943f9SDavid du Colombier  * usb/ether - usb ethernet adapter.
3906943f9SDavid du Colombier  * BUG: This should use /dev/etherfile to
4906943f9SDavid du Colombier  * use the kernel ether device code.
5906943f9SDavid du Colombier  */
6906943f9SDavid du Colombier #include <u.h>
7906943f9SDavid du Colombier #include <libc.h>
8906943f9SDavid du Colombier #include <fcall.h>
9906943f9SDavid du Colombier #include <thread.h>
10906943f9SDavid du Colombier #include "usb.h"
11906943f9SDavid du Colombier #include "usbfs.h"
12906943f9SDavid du Colombier #include "ether.h"
13906943f9SDavid du Colombier 
14906943f9SDavid du Colombier typedef struct Dirtab Dirtab;
15906943f9SDavid du Colombier 
16906943f9SDavid du Colombier enum
17906943f9SDavid du Colombier {
18906943f9SDavid du Colombier 	/* Qids. Maintain order (relative to dirtabs structs) */
19906943f9SDavid du Colombier 	Qroot	= 0,
20906943f9SDavid du Colombier 	Qclone,
21906943f9SDavid du Colombier 	Qaddr,
22906943f9SDavid du Colombier 	Qifstats,
23906943f9SDavid du Colombier 	Qstats,
24906943f9SDavid du Colombier 	Qndir,
25906943f9SDavid du Colombier 	Qndata,
26906943f9SDavid du Colombier 	Qnctl,
27906943f9SDavid du Colombier 	Qnifstats,
28906943f9SDavid du Colombier 	Qnstats,
29906943f9SDavid du Colombier 	Qntype,
30906943f9SDavid du Colombier 	Qmax,
31906943f9SDavid du Colombier };
32906943f9SDavid du Colombier 
33906943f9SDavid du Colombier struct Dirtab
34906943f9SDavid du Colombier {
35906943f9SDavid du Colombier 	char	*name;
36906943f9SDavid du Colombier 	int	qid;
37906943f9SDavid du Colombier 	int	mode;
38906943f9SDavid du Colombier };
39906943f9SDavid du Colombier 
40906943f9SDavid du Colombier typedef int (*Resetf)(Ether*);
41906943f9SDavid du Colombier 
42906943f9SDavid du Colombier /*
43906943f9SDavid du Colombier  * Controllers by vid/vid. Used to locate
44906943f9SDavid du Colombier  * specific adapters that do not implement cdc ethernet
45906943f9SDavid du Colombier  * Keep null terminated.
46906943f9SDavid du Colombier  */
47906943f9SDavid du Colombier Cinfo cinfo[] =
48906943f9SDavid du Colombier {
49906943f9SDavid du Colombier 	/* Asix controllers.
50a1c7250fSDavid du Colombier 	 * Only A88178 and A88772 are implemented.
51906943f9SDavid du Colombier 	 * Others are easy to add by borrowing code
52906943f9SDavid du Colombier 	 * from other systems.
53906943f9SDavid du Colombier 	 */
54a1c7250fSDavid du Colombier 	{0x0411, 0x003d, A8817x},	/* buffalo */
55906943f9SDavid du Colombier 	{0x0411, 0x006e, A88178},
56906943f9SDavid du Colombier 	{0x04f1, 0x3008, A8817x},
57906943f9SDavid du Colombier 	{0x050d, 0x5055, A88178},
58a1c7250fSDavid du Colombier 	{0x0557, 0x2009, A8817x},
59906943f9SDavid du Colombier 	{0x05ac, 0x1402, A88772},	/* Apple */
60a1c7250fSDavid du Colombier 	{0x077b, 0x2226, A8817x},
61a1c7250fSDavid du Colombier 	{0x07aa, 0x0017, A8817x},
62a1c7250fSDavid du Colombier 	{0x07d1, 0x3c05, A88772},
63a1c7250fSDavid du Colombier 	{0x0b95, 0x1720, A8817x},	/* asix */
64a1c7250fSDavid du Colombier 	{0x0b95, 0x1780, A88178},	/* Geoff */
65a1c7250fSDavid du Colombier 	{0x0b95, 0x7720, A88772},
66906943f9SDavid du Colombier 	{0x0b95, 0x772a, A88772},
67906943f9SDavid du Colombier 	{0x0db0, 0xa877, A88772},
68a1c7250fSDavid du Colombier 	{0x1189, 0x0893, A8817x},
69a1c7250fSDavid du Colombier 	{0x13b1, 0x0018, A88772},
70a1c7250fSDavid du Colombier 	{0x14ea, 0xab11, A88178},
71a1c7250fSDavid du Colombier 	{0x1557, 0x7720, A88772},
72a1c7250fSDavid du Colombier 	{0x1631, 0x6200, A8817x},
73a1c7250fSDavid du Colombier 	{0x1737, 0x0039, A88178},
74a1c7250fSDavid du Colombier 	{0x2001, 0x3c05, A88772},
75a1c7250fSDavid du Colombier 	{0x6189, 0x182d, A8817x},
76a650be7dSDavid du Colombier 
77a650be7dSDavid du Colombier 	/* SMSC controllers.
78a650be7dSDavid du Colombier 	 * LAN95xx family
79a650be7dSDavid du Colombier 	 */
80a650be7dSDavid du Colombier 	{0x0424, 0xec00, S95xx},	/* LAN9512 (as in raspberry pi) */
81a650be7dSDavid du Colombier 	{0x0424, 0x9500, S95xx},
82a650be7dSDavid du Colombier 	{0x0424, 0x9505, S95xx},
83a650be7dSDavid du Colombier 	{0x0424, 0x9E00, S95xx},
84a650be7dSDavid du Colombier 	{0x0424, 0x9E01, S95xx},
85906943f9SDavid du Colombier 	{0, 0, 0},
86906943f9SDavid du Colombier };
87906943f9SDavid du Colombier 
88906943f9SDavid du Colombier /*
89906943f9SDavid du Colombier  * Each etherU%d is the root of our file system,
90906943f9SDavid du Colombier  * which is added to the usb root directory. We only
91906943f9SDavid du Colombier  * have to concern ourselfs with each /etherU%d subtree.
92906943f9SDavid du Colombier  *
93906943f9SDavid du Colombier  * NB: Maintain order in dirtabs, relative to the Qids enum.
94906943f9SDavid du Colombier  */
95906943f9SDavid du Colombier 
96906943f9SDavid du Colombier static Dirtab rootdirtab[] =
97906943f9SDavid du Colombier {
98906943f9SDavid du Colombier 	"/",		Qroot,		DMDIR|0555,	/* etherU%d */
99906943f9SDavid du Colombier 	"clone",	Qclone,		0666,
100906943f9SDavid du Colombier 	"addr",		Qaddr,		0444,
101906943f9SDavid du Colombier 	"ifstats",	Qifstats,	0444,
102906943f9SDavid du Colombier 	"stats",	Qstats,		0444,
103906943f9SDavid du Colombier 	/* one dir per connection here */
104906943f9SDavid du Colombier 	nil, 0, 0,
105906943f9SDavid du Colombier };
106906943f9SDavid du Colombier 
107906943f9SDavid du Colombier static Dirtab conndirtab[] =
108906943f9SDavid du Colombier {
109906943f9SDavid du Colombier 	"%d",		Qndir,		DMDIR|0555,
110906943f9SDavid du Colombier 	"data",		Qndata,		0666,
111906943f9SDavid du Colombier 	"ctl",		Qnctl,		0666,
112906943f9SDavid du Colombier 	"ifstats",	Qnifstats,	0444,
113906943f9SDavid du Colombier 	"stats",	Qnstats,	0444,
114906943f9SDavid du Colombier 	"type",		Qntype,		0444,
115906943f9SDavid du Colombier 	nil, 0,
116906943f9SDavid du Colombier };
117906943f9SDavid du Colombier 
118906943f9SDavid du Colombier int etherdebug;
119906943f9SDavid du Colombier 
120906943f9SDavid du Colombier Resetf ethers[] =
121906943f9SDavid du Colombier {
122906943f9SDavid du Colombier 	asixreset,
123a650be7dSDavid du Colombier 	smscreset,
124906943f9SDavid du Colombier 	cdcreset,	/* keep last */
125906943f9SDavid du Colombier };
126906943f9SDavid du Colombier 
127906943f9SDavid du Colombier static int
qtype(vlong q)128906943f9SDavid du Colombier qtype(vlong q)
129906943f9SDavid du Colombier {
130906943f9SDavid du Colombier 	return q&0xFF;
131906943f9SDavid du Colombier }
132906943f9SDavid du Colombier 
133906943f9SDavid du Colombier static int
qnum(vlong q)134906943f9SDavid du Colombier qnum(vlong q)
135906943f9SDavid du Colombier {
136906943f9SDavid du Colombier 	return (q >> 8) & 0xFFFFFF;
137906943f9SDavid du Colombier }
138906943f9SDavid du Colombier 
139906943f9SDavid du Colombier static uvlong
mkqid(int n,int t)140906943f9SDavid du Colombier mkqid(int n, int t)
141906943f9SDavid du Colombier {
142906943f9SDavid du Colombier 	uvlong q;
143906943f9SDavid du Colombier 
144906943f9SDavid du Colombier 	q = (n&0xFFFFFF) << 8 | t&0xFF;
145906943f9SDavid du Colombier 	return q;
146906943f9SDavid du Colombier }
147906943f9SDavid du Colombier 
148906943f9SDavid du Colombier static void
freebuf(Ether * e,Buf * bp)149906943f9SDavid du Colombier freebuf(Ether *e, Buf *bp)
150906943f9SDavid du Colombier {
151906943f9SDavid du Colombier 	if(0)deprint(2, "%s: freebuf %#p\n", argv0, bp);
152906943f9SDavid du Colombier 	if(bp != nil){
153906943f9SDavid du Colombier 		qlock(e);
154906943f9SDavid du Colombier 		e->nbufs--;
155906943f9SDavid du Colombier 		qunlock(e);
156906943f9SDavid du Colombier 		sendp(e->bc, bp);
157906943f9SDavid du Colombier 	}
158906943f9SDavid du Colombier }
159906943f9SDavid du Colombier 
160906943f9SDavid du Colombier static Buf*
allocbuf(Ether * e)161906943f9SDavid du Colombier allocbuf(Ether *e)
162906943f9SDavid du Colombier {
163906943f9SDavid du Colombier 	Buf *bp;
164906943f9SDavid du Colombier 
165906943f9SDavid du Colombier 	bp = nbrecvp(e->bc);
166906943f9SDavid du Colombier 	if(bp == nil){
167906943f9SDavid du Colombier 		qlock(e);
168a650be7dSDavid du Colombier 		if(e->nabufs < Nbufs){
169906943f9SDavid du Colombier 			bp = emallocz(sizeof(Buf), 1);
170906943f9SDavid du Colombier 			e->nabufs++;
171906943f9SDavid du Colombier 			setmalloctag(bp, getcallerpc(&e));
172906943f9SDavid du Colombier 			deprint(2, "%s: %d buffers\n", argv0, e->nabufs);
173906943f9SDavid du Colombier 		}
174906943f9SDavid du Colombier 		qunlock(e);
175906943f9SDavid du Colombier 	}
176a650be7dSDavid du Colombier 	if(bp == nil){
177*0cc6832dSDavid du Colombier 		deprint(2, "%s: blocked waiting for allocbuf\n", argv0);
178906943f9SDavid du Colombier 		bp = recvp(e->bc);
179a650be7dSDavid du Colombier 	}
180906943f9SDavid du Colombier 	bp->rp = bp->data + Hdrsize;
181906943f9SDavid du Colombier 	bp->ndata = 0;
182906943f9SDavid du Colombier 	if(0)deprint(2, "%s: allocbuf %#p\n", argv0, bp);
183906943f9SDavid du Colombier 	qlock(e);
184906943f9SDavid du Colombier 	e->nbufs++;
185906943f9SDavid du Colombier 	qunlock(e);
186906943f9SDavid du Colombier 	return bp;
187906943f9SDavid du Colombier }
188906943f9SDavid du Colombier 
189906943f9SDavid du Colombier static Conn*
newconn(Ether * e)190906943f9SDavid du Colombier newconn(Ether *e)
191906943f9SDavid du Colombier {
192906943f9SDavid du Colombier 	int i;
193906943f9SDavid du Colombier 	Conn *c;
194906943f9SDavid du Colombier 
195906943f9SDavid du Colombier 	qlock(e);
196906943f9SDavid du Colombier 	for(i = 0; i < nelem(e->conns); i++){
197906943f9SDavid du Colombier 		c = e->conns[i];
198906943f9SDavid du Colombier 		if(c == nil || c->ref == 0){
199906943f9SDavid du Colombier 			if(c == nil){
200906943f9SDavid du Colombier 				c = emallocz(sizeof(Conn), 1);
201a650be7dSDavid du Colombier 				c->rc = chancreate(sizeof(Buf*), 16);
202906943f9SDavid du Colombier 				c->nb = i;
203906943f9SDavid du Colombier 			}
204906943f9SDavid du Colombier 			c->ref = 1;
205906943f9SDavid du Colombier 			if(i == e->nconns)
206906943f9SDavid du Colombier 				e->nconns++;
207906943f9SDavid du Colombier 			e->conns[i] = c;
208906943f9SDavid du Colombier 			deprint(2, "%s: newconn %d\n", argv0, i);
209906943f9SDavid du Colombier 			qunlock(e);
210906943f9SDavid du Colombier 			return c;
211906943f9SDavid du Colombier 		}
212906943f9SDavid du Colombier 	}
213906943f9SDavid du Colombier 	qunlock(e);
214906943f9SDavid du Colombier 	return nil;
215906943f9SDavid du Colombier }
216906943f9SDavid du Colombier 
217906943f9SDavid du Colombier static char*
seprintaddr(char * s,char * se,uchar * addr)218906943f9SDavid du Colombier seprintaddr(char *s, char *se, uchar *addr)
219906943f9SDavid du Colombier {
220906943f9SDavid du Colombier 	int i;
221906943f9SDavid du Colombier 
222906943f9SDavid du Colombier 	for(i = 0; i < Eaddrlen; i++)
223906943f9SDavid du Colombier 		s = seprint(s, se, "%02x", addr[i]);
224906943f9SDavid du Colombier 	return s;
225906943f9SDavid du Colombier }
226906943f9SDavid du Colombier 
227906943f9SDavid du Colombier void
dumpframe(char * tag,void * p,int n)228906943f9SDavid du Colombier dumpframe(char *tag, void *p, int n)
229906943f9SDavid du Colombier {
230906943f9SDavid du Colombier 	Etherpkt *ep;
231906943f9SDavid du Colombier 	char buf[128];
232906943f9SDavid du Colombier 	char *s, *se;
233906943f9SDavid du Colombier 	int i;
234906943f9SDavid du Colombier 
235906943f9SDavid du Colombier 	ep = p;
236906943f9SDavid du Colombier 	if(n < Eaddrlen * 2 + 2){
237906943f9SDavid du Colombier 		fprint(2, "short packet (%d bytes)\n", n);
238906943f9SDavid du Colombier 		return;
239906943f9SDavid du Colombier 	}
240906943f9SDavid du Colombier 	se = buf+sizeof(buf);
241906943f9SDavid du Colombier 	s = seprint(buf, se, "%s [%d]: ", tag, n);
242906943f9SDavid du Colombier 	s = seprintaddr(s, se, ep->s);
243906943f9SDavid du Colombier 	s = seprint(s, se, " -> ");
244906943f9SDavid du Colombier 	s = seprintaddr(s, se, ep->d);
245906943f9SDavid du Colombier 	s = seprint(s, se, " type 0x%02ux%02ux ", ep->type[0], ep->type[1]);
246906943f9SDavid du Colombier 	n -= Eaddrlen * 2 + 2;
247906943f9SDavid du Colombier 	for(i = 0; i < n && i < 16; i++)
248906943f9SDavid du Colombier 		s = seprint(s, se, "%02x", ep->data[i]);
249906943f9SDavid du Colombier 	if(n >= 16)
250906943f9SDavid du Colombier 		fprint(2, "%s...\n", buf);
251906943f9SDavid du Colombier 	else
252906943f9SDavid du Colombier 		fprint(2, "%s\n", buf);
253906943f9SDavid du Colombier }
254906943f9SDavid du Colombier 
255906943f9SDavid du Colombier static char*
seprintstats(char * s,char * se,Ether * e)256906943f9SDavid du Colombier seprintstats(char *s, char *se, Ether *e)
257906943f9SDavid du Colombier {
258906943f9SDavid du Colombier 	qlock(e);
259906943f9SDavid du Colombier 	s = seprint(s, se, "in: %ld\n", e->nin);
260906943f9SDavid du Colombier 	s = seprint(s, se, "out: %ld\n", e->nout);
261906943f9SDavid du Colombier 	s = seprint(s, se, "input errs: %ld\n", e->nierrs);
262906943f9SDavid du Colombier 	s = seprint(s, se, "output errs: %ld\n", e->noerrs);
263906943f9SDavid du Colombier 	s = seprint(s, se, "mbps: %d\n", e->mbps);
264906943f9SDavid du Colombier 	s = seprint(s, se, "prom: %ld\n", e->prom.ref);
265906943f9SDavid du Colombier 	s = seprint(s, se, "addr: ");
266906943f9SDavid du Colombier 	s = seprintaddr(s, se, e->addr);
267906943f9SDavid du Colombier 	s = seprint(s, se, "\n");
268906943f9SDavid du Colombier 	qunlock(e);
269906943f9SDavid du Colombier 	return s;
270906943f9SDavid du Colombier }
271906943f9SDavid du Colombier 
272906943f9SDavid du Colombier static char*
seprintifstats(char * s,char * se,Ether * e)273906943f9SDavid du Colombier seprintifstats(char *s, char *se, Ether *e)
274906943f9SDavid du Colombier {
275906943f9SDavid du Colombier 	int i;
276906943f9SDavid du Colombier 	Conn *c;
277906943f9SDavid du Colombier 
278906943f9SDavid du Colombier 	qlock(e);
279906943f9SDavid du Colombier 	s = seprint(s, se, "ctlr id: %#x\n", e->cid);
280906943f9SDavid du Colombier 	s = seprint(s, se, "phy: %#x\n", e->phy);
281d37e33ffSDavid du Colombier 	s = seprint(s, se, "exiting: %s\n", e->exiting ? "y" : "n");
282906943f9SDavid du Colombier 	s = seprint(s, se, "conns: %d\n", e->nconns);
283906943f9SDavid du Colombier 	s = seprint(s, se, "allocated bufs: %d\n", e->nabufs);
284906943f9SDavid du Colombier 	s = seprint(s, se, "used bufs: %d\n", e->nbufs);
285906943f9SDavid du Colombier 	for(i = 0; i < nelem(e->conns); i++){
286906943f9SDavid du Colombier 		c = e->conns[i];
287906943f9SDavid du Colombier 		if(c == nil)
288906943f9SDavid du Colombier 			continue;
289906943f9SDavid du Colombier 		if(c->ref == 0)
290906943f9SDavid du Colombier 			s = seprint(s, se, "c[%d]: free\n", i);
291906943f9SDavid du Colombier 		else{
292906943f9SDavid du Colombier 			s = seprint(s, se, "c[%d]: refs %ld t %#x h %d p %d\n",
293906943f9SDavid du Colombier 				c->nb, c->ref, c->type, c->headersonly, c->prom);
294906943f9SDavid du Colombier 		}
295906943f9SDavid du Colombier 	}
296906943f9SDavid du Colombier 	qunlock(e);
297906943f9SDavid du Colombier 	return s;
298906943f9SDavid du Colombier }
299906943f9SDavid du Colombier 
300906943f9SDavid du Colombier static void
etherdump(Ether * e)301906943f9SDavid du Colombier etherdump(Ether *e)
302906943f9SDavid du Colombier {
303906943f9SDavid du Colombier 	char buf[256];
304906943f9SDavid du Colombier 
305906943f9SDavid du Colombier 	if(etherdebug == 0)
306906943f9SDavid du Colombier 		return;
307906943f9SDavid du Colombier 	seprintifstats(buf, buf+sizeof(buf), e);
308906943f9SDavid du Colombier 	fprint(2, "%s: ether %#p:\n%s\n", argv0, e, buf);
309906943f9SDavid du Colombier }
310906943f9SDavid du Colombier 
311906943f9SDavid du Colombier static Conn*
getconn(Ether * e,int i,int idleok)312906943f9SDavid du Colombier getconn(Ether *e, int i, int idleok)
313906943f9SDavid du Colombier {
314906943f9SDavid du Colombier 	Conn *c;
315906943f9SDavid du Colombier 
316906943f9SDavid du Colombier 	qlock(e);
317906943f9SDavid du Colombier 	if(i < 0 || i >= e->nconns)
318906943f9SDavid du Colombier 		c = nil;
319906943f9SDavid du Colombier 	else{
320906943f9SDavid du Colombier 		c = e->conns[i];
321906943f9SDavid du Colombier 		if(idleok == 0 && c != nil && c->ref == 0)
322906943f9SDavid du Colombier 			c = nil;
323906943f9SDavid du Colombier 	}
324906943f9SDavid du Colombier 	qunlock(e);
325906943f9SDavid du Colombier 	return c;
326906943f9SDavid du Colombier }
327906943f9SDavid du Colombier 
328906943f9SDavid du Colombier static void
filldir(Usbfs * fs,Dir * d,Dirtab * tab,int cn)329906943f9SDavid du Colombier filldir(Usbfs *fs, Dir *d, Dirtab *tab, int cn)
330906943f9SDavid du Colombier {
331906943f9SDavid du Colombier 	d->qid.path = mkqid(cn, tab->qid);
332906943f9SDavid du Colombier 	d->qid.path |= fs->qid;
333906943f9SDavid du Colombier 	d->mode = tab->mode;
334906943f9SDavid du Colombier 	if((d->mode & DMDIR) != 0)
335906943f9SDavid du Colombier 		d->qid.type = QTDIR;
336906943f9SDavid du Colombier 	else
337906943f9SDavid du Colombier 		d->qid.type = QTFILE;
338906943f9SDavid du Colombier 	if(tab->qid == Qndir)
339e9b54818SDavid du Colombier 		snprint(d->name, Namesz, "%d", cn);
340906943f9SDavid du Colombier 	else
341906943f9SDavid du Colombier 		d->name = tab->name;
342906943f9SDavid du Colombier }
343906943f9SDavid du Colombier 
344906943f9SDavid du Colombier static int
rootdirgen(Usbfs * fs,Qid,int i,Dir * d,void *)345906943f9SDavid du Colombier rootdirgen(Usbfs *fs, Qid, int i, Dir *d, void *)
346906943f9SDavid du Colombier {
347906943f9SDavid du Colombier 	Ether *e;
348906943f9SDavid du Colombier 	Dirtab *tab;
349906943f9SDavid du Colombier 	int cn;
350906943f9SDavid du Colombier 
351906943f9SDavid du Colombier 	e = fs->aux;
352906943f9SDavid du Colombier 	i++;				/* skip root */
353906943f9SDavid du Colombier 	cn = 0;
354906943f9SDavid du Colombier 	if(i < nelem(rootdirtab) - 1)	/* null terminated */
355906943f9SDavid du Colombier 		tab = &rootdirtab[i];
356906943f9SDavid du Colombier 	else{
357906943f9SDavid du Colombier 		cn = i - nelem(rootdirtab) + 1;
358906943f9SDavid du Colombier 		if(cn < e->nconns)
359906943f9SDavid du Colombier 			tab = &conndirtab[0];
360906943f9SDavid du Colombier 		else
361906943f9SDavid du Colombier 			return -1;
362906943f9SDavid du Colombier 	}
363906943f9SDavid du Colombier 	filldir(fs, d, tab, cn);
364906943f9SDavid du Colombier 	return 0;
365906943f9SDavid du Colombier }
366906943f9SDavid du Colombier 
367906943f9SDavid du Colombier static int
conndirgen(Usbfs * fs,Qid q,int i,Dir * d,void *)368906943f9SDavid du Colombier conndirgen(Usbfs *fs, Qid q, int i, Dir *d, void *)
369906943f9SDavid du Colombier {
370906943f9SDavid du Colombier 	Dirtab *tab;
371906943f9SDavid du Colombier 
372906943f9SDavid du Colombier 	i++;				/* skip root */
373906943f9SDavid du Colombier 	if(i < nelem(conndirtab) - 1)	/* null terminated */
374906943f9SDavid du Colombier 		tab = &conndirtab[i];
375906943f9SDavid du Colombier 	else
376906943f9SDavid du Colombier 		return -1;
377906943f9SDavid du Colombier 	filldir(fs, d, tab, qnum(q.path));
378906943f9SDavid du Colombier 	return 0;
379906943f9SDavid du Colombier }
380906943f9SDavid du Colombier 
381906943f9SDavid du Colombier static int
fswalk(Usbfs * fs,Fid * fid,char * name)382906943f9SDavid du Colombier fswalk(Usbfs *fs, Fid *fid, char *name)
383906943f9SDavid du Colombier {
384d37e33ffSDavid du Colombier 	int cn, i;
385906943f9SDavid du Colombier 	char *es;
386906943f9SDavid du Colombier 	Dirtab *tab;
387d37e33ffSDavid du Colombier 	Ether *e;
388d37e33ffSDavid du Colombier 	Qid qid;
389906943f9SDavid du Colombier 
390906943f9SDavid du Colombier 	e = fs->aux;
391906943f9SDavid du Colombier 	qid = fid->qid;
392906943f9SDavid du Colombier 	qid.path &= ~fs->qid;
393906943f9SDavid du Colombier 	if((qid.type & QTDIR) == 0){
394906943f9SDavid du Colombier 		werrstr("walk in non-directory");
395906943f9SDavid du Colombier 		return -1;
396906943f9SDavid du Colombier 	}
397906943f9SDavid du Colombier 
398906943f9SDavid du Colombier 	if(strcmp(name, "..") == 0){
399906943f9SDavid du Colombier 		/* must be /etherU%d; i.e. our root dir. */
400906943f9SDavid du Colombier 		fid->qid.path = mkqid(0, Qroot) | fs->qid;
401906943f9SDavid du Colombier 		fid->qid.vers = 0;
402906943f9SDavid du Colombier 		fid->qid.type = QTDIR;
403906943f9SDavid du Colombier 		return 0;
404906943f9SDavid du Colombier 	}
405906943f9SDavid du Colombier 	switch(qtype(qid.path)){
406906943f9SDavid du Colombier 	case Qroot:
407906943f9SDavid du Colombier 		if(name[0] >= '0' && name[0] <= '9'){
408906943f9SDavid du Colombier 			es = name;
409906943f9SDavid du Colombier 			cn = strtoul(name, &es, 10);
410906943f9SDavid du Colombier 			if(cn >= e->nconns || *es != 0){
411906943f9SDavid du Colombier 				werrstr(Enotfound);
412906943f9SDavid du Colombier 				return -1;
413906943f9SDavid du Colombier 			}
414906943f9SDavid du Colombier 			fid->qid.path = mkqid(cn, Qndir) | fs->qid;
415906943f9SDavid du Colombier 			fid->qid.vers = 0;
416906943f9SDavid du Colombier 			return 0;
417906943f9SDavid du Colombier 		}
418906943f9SDavid du Colombier 		/* fall */
419906943f9SDavid du Colombier 	case Qndir:
420906943f9SDavid du Colombier 		if(qtype(qid.path) == Qroot)
421906943f9SDavid du Colombier 			tab = rootdirtab;
422906943f9SDavid du Colombier 		else
423906943f9SDavid du Colombier 			tab = conndirtab;
424906943f9SDavid du Colombier 		cn = qnum(qid.path);
425906943f9SDavid du Colombier 		for(i = 0; tab[i].name != nil; tab++)
426906943f9SDavid du Colombier 			if(strcmp(tab[i].name, name) == 0){
427906943f9SDavid du Colombier 				fid->qid.path = mkqid(cn, tab[i].qid)|fs->qid;
428906943f9SDavid du Colombier 				fid->qid.vers = 0;
429906943f9SDavid du Colombier 				if((tab[i].mode & DMDIR) != 0)
430906943f9SDavid du Colombier 					fid->qid.type = QTDIR;
431906943f9SDavid du Colombier 				else
432906943f9SDavid du Colombier 					fid->qid.type = QTFILE;
433906943f9SDavid du Colombier 				return 0;
434906943f9SDavid du Colombier 			}
435906943f9SDavid du Colombier 		break;
436906943f9SDavid du Colombier 	default:
437906943f9SDavid du Colombier 		sysfatal("usb: ether: fswalk bug");
438906943f9SDavid du Colombier 	}
439906943f9SDavid du Colombier 	return -1;
440906943f9SDavid du Colombier }
441906943f9SDavid du Colombier 
442906943f9SDavid du Colombier static Dirtab*
qdirtab(vlong q)443906943f9SDavid du Colombier qdirtab(vlong q)
444906943f9SDavid du Colombier {
445d37e33ffSDavid du Colombier 	int i, qt;
446906943f9SDavid du Colombier 	Dirtab *tab;
447906943f9SDavid du Colombier 
448906943f9SDavid du Colombier 	qt = qtype(q);
449906943f9SDavid du Colombier 	if(qt < nelem(rootdirtab) - 1){	/* null terminated */
450906943f9SDavid du Colombier 		tab = rootdirtab;
451906943f9SDavid du Colombier 		i = qt;
452906943f9SDavid du Colombier 	}else{
453906943f9SDavid du Colombier 		tab = conndirtab;
454906943f9SDavid du Colombier 		i = qt - (nelem(rootdirtab) - 1);
455906943f9SDavid du Colombier 		assert(i < nelem(conndirtab) - 1);
456906943f9SDavid du Colombier 	}
457906943f9SDavid du Colombier 	return &tab[i];
458906943f9SDavid du Colombier }
459906943f9SDavid du Colombier 
460906943f9SDavid du Colombier static int
fsstat(Usbfs * fs,Qid qid,Dir * d)461906943f9SDavid du Colombier fsstat(Usbfs *fs, Qid qid, Dir *d)
462906943f9SDavid du Colombier {
463906943f9SDavid du Colombier 	filldir(fs, d, qdirtab(qid.path), qnum(qid.path));
464906943f9SDavid du Colombier 	return 0;
465906943f9SDavid du Colombier }
466906943f9SDavid du Colombier 
467906943f9SDavid du Colombier static int
fsopen(Usbfs * fs,Fid * fid,int omode)468906943f9SDavid du Colombier fsopen(Usbfs *fs, Fid *fid, int omode)
469906943f9SDavid du Colombier {
470906943f9SDavid du Colombier 	int qt;
471906943f9SDavid du Colombier 	vlong qid;
472d37e33ffSDavid du Colombier 	Conn *c;
473d37e33ffSDavid du Colombier 	Dirtab *tab;
474d37e33ffSDavid du Colombier 	Ether *e;
475906943f9SDavid du Colombier 
476906943f9SDavid du Colombier 	qid = fid->qid.path & ~fs->qid;
477906943f9SDavid du Colombier 	e = fs->aux;
478906943f9SDavid du Colombier 	qt = qtype(qid);
479906943f9SDavid du Colombier 	tab = qdirtab(qid);
480906943f9SDavid du Colombier 	omode &= 3;
481906943f9SDavid du Colombier 	if(omode != OREAD && (tab->mode&0222) == 0){
482906943f9SDavid du Colombier 		werrstr(Eperm);
483906943f9SDavid du Colombier 		return -1;
484906943f9SDavid du Colombier 	}
485906943f9SDavid du Colombier 	switch(qt){
486906943f9SDavid du Colombier 	case Qclone:
487906943f9SDavid du Colombier 		c = newconn(e);
488906943f9SDavid du Colombier 		if(c == nil){
489906943f9SDavid du Colombier 			werrstr("no more connections");
490906943f9SDavid du Colombier 			return -1;
491906943f9SDavid du Colombier 		}
492906943f9SDavid du Colombier 		fid->qid.type = QTFILE;
493906943f9SDavid du Colombier 		fid->qid.path = mkqid(c->nb, Qnctl)|fs->qid;
494906943f9SDavid du Colombier 		fid->qid.vers = 0;
495906943f9SDavid du Colombier 		break;
496906943f9SDavid du Colombier 	case Qndata:
497906943f9SDavid du Colombier 	case Qnctl:
498906943f9SDavid du Colombier 	case Qnifstats:
499906943f9SDavid du Colombier 	case Qnstats:
500906943f9SDavid du Colombier 	case Qntype:
501906943f9SDavid du Colombier 		c = getconn(e, qnum(qid), 1);
502906943f9SDavid du Colombier 		if(c == nil)
503906943f9SDavid du Colombier 			sysfatal("usb: ether: fsopen bug");
504906943f9SDavid du Colombier 		incref(c);
505906943f9SDavid du Colombier 		break;
506906943f9SDavid du Colombier 	}
507906943f9SDavid du Colombier 	etherdump(e);
508906943f9SDavid du Colombier 	return 0;
509906943f9SDavid du Colombier }
510906943f9SDavid du Colombier 
511906943f9SDavid du Colombier static int
prom(Ether * e,int set)512906943f9SDavid du Colombier prom(Ether *e, int set)
513906943f9SDavid du Colombier {
514906943f9SDavid du Colombier 	if(e->promiscuous != nil)
515906943f9SDavid du Colombier 		return e->promiscuous(e, set);
516906943f9SDavid du Colombier 	return 0;
517906943f9SDavid du Colombier }
518906943f9SDavid du Colombier 
519906943f9SDavid du Colombier static void
fsclunk(Usbfs * fs,Fid * fid)520906943f9SDavid du Colombier fsclunk(Usbfs *fs, Fid *fid)
521906943f9SDavid du Colombier {
522906943f9SDavid du Colombier 	int qt;
523906943f9SDavid du Colombier 	vlong qid;
524906943f9SDavid du Colombier 	Buf *bp;
525d37e33ffSDavid du Colombier 	Conn *c;
526d37e33ffSDavid du Colombier 	Ether *e;
527906943f9SDavid du Colombier 
528906943f9SDavid du Colombier 	e = fs->aux;
529906943f9SDavid du Colombier 	qid = fid->qid.path & ~fs->qid;
530906943f9SDavid du Colombier 	qt = qtype(qid);
531906943f9SDavid du Colombier 	switch(qt){
532906943f9SDavid du Colombier 	case Qndata:
533906943f9SDavid du Colombier 	case Qnctl:
534906943f9SDavid du Colombier 	case Qnifstats:
535906943f9SDavid du Colombier 	case Qnstats:
536906943f9SDavid du Colombier 	case Qntype:
537906943f9SDavid du Colombier 		if(fid->omode != ONONE){
538906943f9SDavid du Colombier 			c = getconn(e, qnum(qid), 0);
539906943f9SDavid du Colombier 			if(c == nil)
540906943f9SDavid du Colombier 				sysfatal("usb: ether: fsopen bug");
541906943f9SDavid du Colombier 			if(decref(c) == 0){
542906943f9SDavid du Colombier 				while((bp = nbrecvp(c->rc)) != nil)
543906943f9SDavid du Colombier 					freebuf(e, bp);
544906943f9SDavid du Colombier 				qlock(e);
545906943f9SDavid du Colombier 				if(c->prom != 0)
546906943f9SDavid du Colombier 					if(decref(&e->prom) == 0)
547906943f9SDavid du Colombier 						prom(e, 0);
548906943f9SDavid du Colombier 				c->prom = c->type = 0;
549906943f9SDavid du Colombier 				qunlock(e);
550906943f9SDavid du Colombier 			}
551906943f9SDavid du Colombier 		}
552906943f9SDavid du Colombier 		break;
553906943f9SDavid du Colombier 	}
554906943f9SDavid du Colombier 	etherdump(e);
555906943f9SDavid du Colombier }
556906943f9SDavid du Colombier 
557906943f9SDavid du Colombier int
parseaddr(uchar * m,char * s)558906943f9SDavid du Colombier parseaddr(uchar *m, char *s)
559906943f9SDavid du Colombier {
560d37e33ffSDavid du Colombier 	int i, n;
561906943f9SDavid du Colombier 	uchar v;
562906943f9SDavid du Colombier 
563906943f9SDavid du Colombier 	if(strlen(s) < 12)
564906943f9SDavid du Colombier 		return -1;
565906943f9SDavid du Colombier 	if(strlen(s) > 12 && strlen(s) < 17)
566906943f9SDavid du Colombier 		return -1;
567906943f9SDavid du Colombier 	for(i = n = 0; i < strlen(s); i++){
568906943f9SDavid du Colombier 		if(s[i] == ':')
569906943f9SDavid du Colombier 			continue;
570906943f9SDavid du Colombier 		if(s[i] >= 'A' && s[i] <= 'F')
571906943f9SDavid du Colombier 			v = 10 + s[i] - 'A';
572906943f9SDavid du Colombier 		else if(s[i] >= 'a' && s[i] <= 'f')
573906943f9SDavid du Colombier 			v = 10 + s[i] - 'a';
574906943f9SDavid du Colombier 		else if(s[i] >= '0' && s[i] <= '9')
575906943f9SDavid du Colombier 			v = s[i] - '0';
576906943f9SDavid du Colombier 		else
577906943f9SDavid du Colombier 			return -1;
578906943f9SDavid du Colombier 		if(n&1)
579906943f9SDavid du Colombier 			m[n/2] |= v;
580906943f9SDavid du Colombier 		else
581906943f9SDavid du Colombier 			m[n/2] = v<<4;
582906943f9SDavid du Colombier 		n++;
583906943f9SDavid du Colombier 	}
584906943f9SDavid du Colombier 	return 0;
585906943f9SDavid du Colombier }
586906943f9SDavid du Colombier 
587906943f9SDavid du Colombier static long
fsread(Usbfs * fs,Fid * fid,void * data,long count,vlong offset)588906943f9SDavid du Colombier fsread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
589906943f9SDavid du Colombier {
590d37e33ffSDavid du Colombier 	int cn, qt;
591d37e33ffSDavid du Colombier 	char *s, *se;
592ed868a7cSDavid du Colombier 	char buf[2048];		/* keep this large for ifstats */
593d37e33ffSDavid du Colombier 	Buf *bp;
594906943f9SDavid du Colombier 	Conn *c;
595d37e33ffSDavid du Colombier 	Ether *e;
596d37e33ffSDavid du Colombier 	Qid q;
597906943f9SDavid du Colombier 
598906943f9SDavid du Colombier 	q = fid->qid;
599906943f9SDavid du Colombier 	q.path &= ~fs->qid;
600906943f9SDavid du Colombier 	e = fs->aux;
601906943f9SDavid du Colombier 	s = buf;
602906943f9SDavid du Colombier 	se = buf+sizeof(buf);
603906943f9SDavid du Colombier 	qt = qtype(q.path);
604906943f9SDavid du Colombier 	cn = qnum(q.path);
605906943f9SDavid du Colombier 	switch(qt){
606906943f9SDavid du Colombier 	case Qroot:
607906943f9SDavid du Colombier 		count = usbdirread(fs, q, data, count, offset, rootdirgen, nil);
608906943f9SDavid du Colombier 		break;
609906943f9SDavid du Colombier 	case Qaddr:
610906943f9SDavid du Colombier 		s = seprintaddr(s, se, e->addr);
611906943f9SDavid du Colombier 		count = usbreadbuf(data, count, offset, buf, s - buf);
612906943f9SDavid du Colombier 		break;
613906943f9SDavid du Colombier 	case Qnifstats:
614906943f9SDavid du Colombier 		/* BUG */
615906943f9SDavid du Colombier 	case Qifstats:
616906943f9SDavid du Colombier 		s = seprintifstats(s, se, e);
617906943f9SDavid du Colombier 		if(e->seprintstats != nil)
618906943f9SDavid du Colombier 			s = e->seprintstats(s, se, e);
619906943f9SDavid du Colombier 		count = usbreadbuf(data, count, offset, buf, s - buf);
620906943f9SDavid du Colombier 		break;
621906943f9SDavid du Colombier 	case Qnstats:
622906943f9SDavid du Colombier 		/* BUG */
623906943f9SDavid du Colombier 	case Qstats:
624906943f9SDavid du Colombier 		s = seprintstats(s, se, e);
625906943f9SDavid du Colombier 		count = usbreadbuf(data, count, offset, buf, s - buf);
626906943f9SDavid du Colombier 		break;
627906943f9SDavid du Colombier 
628906943f9SDavid du Colombier 	case Qndir:
629906943f9SDavid du Colombier 		count = usbdirread(fs, q, data, count, offset, conndirgen, nil);
630906943f9SDavid du Colombier 		break;
631906943f9SDavid du Colombier 	case Qndata:
632906943f9SDavid du Colombier 		c = getconn(e, cn, 0);
633906943f9SDavid du Colombier 		if(c == nil){
634906943f9SDavid du Colombier 			werrstr(Eio);
635906943f9SDavid du Colombier 			return -1;
636906943f9SDavid du Colombier 		}
637906943f9SDavid du Colombier 		bp = recvp(c->rc);
638906943f9SDavid du Colombier 		if(bp == nil)
639906943f9SDavid du Colombier 			return -1;
640906943f9SDavid du Colombier 		if(etherdebug > 1)
641906943f9SDavid du Colombier 			dumpframe("etherin", bp->rp, bp->ndata);
642906943f9SDavid du Colombier 		count = usbreadbuf(data, count, 0LL, bp->rp, bp->ndata);
643906943f9SDavid du Colombier 		freebuf(e, bp);
644906943f9SDavid du Colombier 		break;
645906943f9SDavid du Colombier 	case Qnctl:
646906943f9SDavid du Colombier 		s = seprint(s, se, "%11d ", cn);
647906943f9SDavid du Colombier 		count = usbreadbuf(data, count, offset, buf, s - buf);
648906943f9SDavid du Colombier 		break;
649906943f9SDavid du Colombier 	case Qntype:
650906943f9SDavid du Colombier 		c = getconn(e, cn, 0);
651906943f9SDavid du Colombier 		if(c == nil)
652906943f9SDavid du Colombier 			s = seprint(s, se, "%11d ", 0);
653906943f9SDavid du Colombier 		else
654906943f9SDavid du Colombier 			s = seprint(s, se, "%11d ", c->type);
655906943f9SDavid du Colombier 		count = usbreadbuf(data, count, offset, buf, s - buf);
656906943f9SDavid du Colombier 		break;
657906943f9SDavid du Colombier 	default:
658906943f9SDavid du Colombier 		sysfatal("usb: ether: fsread bug");
659906943f9SDavid du Colombier 	}
660906943f9SDavid du Colombier 	return count;
661906943f9SDavid du Colombier }
662906943f9SDavid du Colombier 
663906943f9SDavid du Colombier static int
typeinuse(Ether * e,int t)664906943f9SDavid du Colombier typeinuse(Ether *e, int t)
665906943f9SDavid du Colombier {
666906943f9SDavid du Colombier 	int i;
667906943f9SDavid du Colombier 
668906943f9SDavid du Colombier 	for(i = 0; i < e->nconns; i++)
669906943f9SDavid du Colombier 		if(e->conns[i]->ref > 0 && e->conns[i]->type == t)
670906943f9SDavid du Colombier 			return 1;
671906943f9SDavid du Colombier 	return 0;
672906943f9SDavid du Colombier }
673906943f9SDavid du Colombier 
674906943f9SDavid du Colombier static int
isloopback(Ether * e,Buf *)675906943f9SDavid du Colombier isloopback(Ether *e, Buf *)
676906943f9SDavid du Colombier {
677906943f9SDavid du Colombier 	return e->prom.ref > 0; /* BUG: also loopbacks and broadcasts */
678906943f9SDavid du Colombier }
679906943f9SDavid du Colombier 
680906943f9SDavid du Colombier static int
etherctl(Ether * e,Conn * c,char * buf)681906943f9SDavid du Colombier etherctl(Ether *e, Conn *c, char *buf)
682906943f9SDavid du Colombier {
683906943f9SDavid du Colombier 	uchar addr[Eaddrlen];
684906943f9SDavid du Colombier 	int t;
685906943f9SDavid du Colombier 
686906943f9SDavid du Colombier 	deprint(2, "%s: etherctl: %s\n", argv0, buf);
687906943f9SDavid du Colombier 	if(strncmp(buf, "connect ", 8) == 0){
688906943f9SDavid du Colombier 		t = atoi(buf+8);
689906943f9SDavid du Colombier 		qlock(e);
690906943f9SDavid du Colombier 		if(typeinuse(e, t)){
691906943f9SDavid du Colombier 			werrstr("type already in use");
692906943f9SDavid du Colombier 			qunlock(e);
693906943f9SDavid du Colombier 			return -1;
694906943f9SDavid du Colombier 		}
695906943f9SDavid du Colombier 		c->type = atoi(buf+8);
696906943f9SDavid du Colombier 		qunlock(e);
697906943f9SDavid du Colombier 		return 0;
698906943f9SDavid du Colombier 	}
699906943f9SDavid du Colombier 	if(strncmp(buf, "nonblocking", 11) == 0){
700906943f9SDavid du Colombier 		if(buf[11] == '\n' || buf[11] == 0)
701906943f9SDavid du Colombier 			e->nblock = 1;
702906943f9SDavid du Colombier 		else
703906943f9SDavid du Colombier 			e->nblock = atoi(buf + 12);
704906943f9SDavid du Colombier 		deprint(2, "%s: nblock %d\n", argv0, e->nblock);
705906943f9SDavid du Colombier 		return 0;
706906943f9SDavid du Colombier 	}
707906943f9SDavid du Colombier 	if(strncmp(buf, "promiscuous", 11) == 0){
708906943f9SDavid du Colombier 		if(c->prom == 0)
709906943f9SDavid du Colombier 			incref(&e->prom);
710906943f9SDavid du Colombier 		c->prom = 1;
711906943f9SDavid du Colombier 		return prom(e, 1);
712906943f9SDavid du Colombier 	}
713906943f9SDavid du Colombier 	if(strncmp(buf, "headersonly", 11) == 0){
714906943f9SDavid du Colombier 		c->headersonly = 1;
715906943f9SDavid du Colombier 		return 0;
716906943f9SDavid du Colombier 	}
717d37e33ffSDavid du Colombier 	if(strncmp(buf, "addmulti ", 9) == 0 || strncmp(buf, "remmulti ", 9) == 0){
718906943f9SDavid du Colombier 		if(parseaddr(addr, buf+9) < 0){
719906943f9SDavid du Colombier 			werrstr("bad address");
720906943f9SDavid du Colombier 			return -1;
721906943f9SDavid du Colombier 		}
722906943f9SDavid du Colombier 		if(e->multicast == nil)
723906943f9SDavid du Colombier 			return 0;
724906943f9SDavid du Colombier 		if(strncmp(buf, "add", 3) == 0){
725906943f9SDavid du Colombier 			e->nmcasts++;
726906943f9SDavid du Colombier 			return e->multicast(e, addr, 1);
727906943f9SDavid du Colombier 		}else{
728906943f9SDavid du Colombier 			e->nmcasts--;
729906943f9SDavid du Colombier 			return e->multicast(e, addr, 0);
730906943f9SDavid du Colombier 		}
731906943f9SDavid du Colombier 	}
732906943f9SDavid du Colombier 
733906943f9SDavid du Colombier 	if(e->ctl != nil)
734906943f9SDavid du Colombier 		return e->ctl(e, buf);
735906943f9SDavid du Colombier 	werrstr(Ebadctl);
736906943f9SDavid du Colombier 	return -1;
737906943f9SDavid du Colombier }
738906943f9SDavid du Colombier 
739906943f9SDavid du Colombier static long
etherbread(Ether * e,Buf * bp)740906943f9SDavid du Colombier etherbread(Ether *e, Buf *bp)
741906943f9SDavid du Colombier {
742906943f9SDavid du Colombier 	deprint(2, "%s: etherbread\n", argv0);
743906943f9SDavid du Colombier 	bp->rp = bp->data + Hdrsize;
744d37e33ffSDavid du Colombier 	bp->ndata = -1;
745906943f9SDavid du Colombier 	bp->ndata = read(e->epin->dfd, bp->rp, sizeof(bp->data)-Hdrsize);
746a23bc242SDavid du Colombier 	if(bp->ndata < 0){
747a23bc242SDavid du Colombier 		deprint(2, "%s: etherbread: %r\n", argv0);	/* keep { and }  */
748a23bc242SDavid du Colombier 	}else
749d37e33ffSDavid du Colombier 		deprint(2, "%s: etherbread: got %d bytes\n", argv0, bp->ndata);
750906943f9SDavid du Colombier 	return bp->ndata;
751906943f9SDavid du Colombier }
752906943f9SDavid du Colombier 
753906943f9SDavid du Colombier static long
etherbwrite(Ether * e,Buf * bp)754906943f9SDavid du Colombier etherbwrite(Ether *e, Buf *bp)
755906943f9SDavid du Colombier {
756906943f9SDavid du Colombier 	long n;
757906943f9SDavid du Colombier 
758906943f9SDavid du Colombier 	deprint(2, "%s: etherbwrite %d bytes\n", argv0, bp->ndata);
759906943f9SDavid du Colombier 	n = write(e->epout->dfd, bp->rp, bp->ndata);
760a23bc242SDavid du Colombier 	if(n < 0){
761a23bc242SDavid du Colombier 		deprint(2, "%s: etherbwrite: %r\n", argv0);	/* keep { and }  */
762a23bc242SDavid du Colombier 	}else
763906943f9SDavid du Colombier 		deprint(2, "%s: etherbwrite wrote %ld bytes\n", argv0, n);
764906943f9SDavid du Colombier 	if(n <= 0)
765906943f9SDavid du Colombier 		return n;
766906943f9SDavid du Colombier 	if((bp->ndata % e->epout->maxpkt) == 0){
767906943f9SDavid du Colombier 		deprint(2, "%s: short pkt write\n", argv0);
768d37e33ffSDavid du Colombier 		write(e->epout->dfd, "", 1);
769906943f9SDavid du Colombier 	}
770906943f9SDavid du Colombier 	return n;
771906943f9SDavid du Colombier }
772906943f9SDavid du Colombier 
773906943f9SDavid du Colombier static long
fswrite(Usbfs * fs,Fid * fid,void * data,long count,vlong)774906943f9SDavid du Colombier fswrite(Usbfs *fs, Fid *fid, void *data, long count, vlong)
775906943f9SDavid du Colombier {
776d37e33ffSDavid du Colombier 	int cn, qt;
777906943f9SDavid du Colombier 	char buf[128];
778906943f9SDavid du Colombier 	Buf *bp;
779d37e33ffSDavid du Colombier 	Conn *c;
780d37e33ffSDavid du Colombier 	Ether *e;
781d37e33ffSDavid du Colombier 	Qid q;
782906943f9SDavid du Colombier 
783906943f9SDavid du Colombier 	q = fid->qid;
784906943f9SDavid du Colombier 	q.path &= ~fs->qid;
785906943f9SDavid du Colombier 	e = fs->aux;
786906943f9SDavid du Colombier 	qt = qtype(q.path);
787906943f9SDavid du Colombier 	cn = qnum(q.path);
788906943f9SDavid du Colombier 	switch(qt){
789906943f9SDavid du Colombier 	case Qndata:
790906943f9SDavid du Colombier 		c = getconn(e, cn, 0);
791906943f9SDavid du Colombier 		if(c == nil){
792906943f9SDavid du Colombier 			werrstr(Eio);
793906943f9SDavid du Colombier 			return -1;
794906943f9SDavid du Colombier 		}
795906943f9SDavid du Colombier 		bp = allocbuf(e);
796906943f9SDavid du Colombier 		if(count > sizeof(bp->data)-Hdrsize)
797906943f9SDavid du Colombier 			count = sizeof(bp->data)-Hdrsize;
798906943f9SDavid du Colombier 		memmove(bp->rp, data, count);
799906943f9SDavid du Colombier 		bp->ndata = count;
800906943f9SDavid du Colombier 		if(etherdebug > 1)
801906943f9SDavid du Colombier 			dumpframe("etherout", bp->rp, bp->ndata);
802906943f9SDavid du Colombier 		if(e->nblock == 0)
803906943f9SDavid du Colombier 			sendp(e->wc, bp);
804a23bc242SDavid du Colombier 		else if(nbsendp(e->wc, bp) == 0){
805*0cc6832dSDavid du Colombier 			deprint(2, "%s: (out) packet lost\n", argv0);
806a650be7dSDavid du Colombier 			e->noerrs++;
807906943f9SDavid du Colombier 			freebuf(e, bp);
808906943f9SDavid du Colombier 		}
809906943f9SDavid du Colombier 		break;
810906943f9SDavid du Colombier 	case Qnctl:
811906943f9SDavid du Colombier 		c = getconn(e, cn, 0);
812906943f9SDavid du Colombier 		if(c == nil){
813906943f9SDavid du Colombier 			werrstr(Eio);
814906943f9SDavid du Colombier 			return -1;
815906943f9SDavid du Colombier 		}
816906943f9SDavid du Colombier 		if(count > sizeof(buf) - 1)
817906943f9SDavid du Colombier 			count = sizeof(buf) - 1;
818906943f9SDavid du Colombier 		memmove(buf, data, count);
819906943f9SDavid du Colombier 		buf[count] = 0;
820906943f9SDavid du Colombier 		if(etherctl(e, c, buf) < 0)
821906943f9SDavid du Colombier 			return -1;
822906943f9SDavid du Colombier 		break;
823906943f9SDavid du Colombier 	default:
824906943f9SDavid du Colombier 		sysfatal("usb: ether: fsread bug");
825906943f9SDavid du Colombier 	}
826906943f9SDavid du Colombier 	return count;
827906943f9SDavid du Colombier }
828906943f9SDavid du Colombier 
829906943f9SDavid du Colombier static int
openeps(Ether * e,int epin,int epout)830906943f9SDavid du Colombier openeps(Ether *e, int epin, int epout)
831906943f9SDavid du Colombier {
832906943f9SDavid du Colombier 	e->epin = openep(e->dev, epin);
833906943f9SDavid du Colombier 	if(e->epin == nil){
834906943f9SDavid du Colombier 		fprint(2, "ether: in: openep %d: %r\n", epin);
835906943f9SDavid du Colombier 		return -1;
836906943f9SDavid du Colombier 	}
837906943f9SDavid du Colombier 	if(epout == epin){
838906943f9SDavid du Colombier 		incref(e->epin);
839906943f9SDavid du Colombier 		e->epout = e->epin;
840906943f9SDavid du Colombier 	}else
841906943f9SDavid du Colombier 		e->epout = openep(e->dev, epout);
842906943f9SDavid du Colombier 	if(e->epout == nil){
843906943f9SDavid du Colombier 		fprint(2, "ether: out: openep %d: %r\n", epout);
844906943f9SDavid du Colombier 		closedev(e->epin);
845906943f9SDavid du Colombier 		return -1;
846906943f9SDavid du Colombier 	}
847906943f9SDavid du Colombier 	if(e->epin == e->epout)
848906943f9SDavid du Colombier 		opendevdata(e->epin, ORDWR);
849906943f9SDavid du Colombier 	else{
850906943f9SDavid du Colombier 		opendevdata(e->epin, OREAD);
851906943f9SDavid du Colombier 		opendevdata(e->epout, OWRITE);
852906943f9SDavid du Colombier 	}
853906943f9SDavid du Colombier 	if(e->epin->dfd < 0 || e->epout->dfd < 0){
854906943f9SDavid du Colombier 		fprint(2, "ether: open i/o ep data: %r\n");
855906943f9SDavid du Colombier 		closedev(e->epin);
856906943f9SDavid du Colombier 		closedev(e->epout);
857906943f9SDavid du Colombier 		return -1;
858906943f9SDavid du Colombier 	}
859d37e33ffSDavid du Colombier 	dprint(2, "ether: ep in %s maxpkt %d; ep out %s maxpkt %d\n",
860d37e33ffSDavid du Colombier 		e->epin->dir, e->epin->maxpkt, e->epout->dir, e->epout->maxpkt);
861d37e33ffSDavid du Colombier 
862d37e33ffSDavid du Colombier 	/* time outs are not activated for I/O endpoints */
863906943f9SDavid du Colombier 
864906943f9SDavid du Colombier 	if(usbdebug > 2 || etherdebug > 2){
865906943f9SDavid du Colombier 		devctl(e->epin, "debug 1");
866906943f9SDavid du Colombier 		devctl(e->epout, "debug 1");
867906943f9SDavid du Colombier 		devctl(e->dev, "debug 1");
868906943f9SDavid du Colombier 	}
869d37e33ffSDavid du Colombier 
870906943f9SDavid du Colombier 	return 0;
871906943f9SDavid du Colombier }
872906943f9SDavid du Colombier 
873906943f9SDavid du Colombier static int
usage(void)874906943f9SDavid du Colombier usage(void)
875906943f9SDavid du Colombier {
876a650be7dSDavid du Colombier 	werrstr("usage: usb/ether [-a addr] [-d] [-N nb]");
877906943f9SDavid du Colombier 	return -1;
878906943f9SDavid du Colombier }
879906943f9SDavid du Colombier 
880906943f9SDavid du Colombier static Usbfs etherfs = {
881906943f9SDavid du Colombier 	.walk = fswalk,
882906943f9SDavid du Colombier 	.open =	 fsopen,
883906943f9SDavid du Colombier 	.read =	 fsread,
884906943f9SDavid du Colombier 	.write = fswrite,
885906943f9SDavid du Colombier 	.stat =	 fsstat,
886906943f9SDavid du Colombier 	.clunk = fsclunk,
887906943f9SDavid du Colombier };
888906943f9SDavid du Colombier 
889906943f9SDavid du Colombier static void
shutdownchan(Channel * c)890d37e33ffSDavid du Colombier shutdownchan(Channel *c)
891d37e33ffSDavid du Colombier {
892d37e33ffSDavid du Colombier 	Buf *bp;
893d37e33ffSDavid du Colombier 
894d37e33ffSDavid du Colombier 	while((bp=nbrecvp(c)) != nil)
895d37e33ffSDavid du Colombier 		free(bp);
896d37e33ffSDavid du Colombier 	chanfree(c);
897d37e33ffSDavid du Colombier }
898d37e33ffSDavid du Colombier 
899d37e33ffSDavid du Colombier static void
etherfree(Ether * e)900906943f9SDavid du Colombier etherfree(Ether *e)
901906943f9SDavid du Colombier {
902906943f9SDavid du Colombier 	int i;
903906943f9SDavid du Colombier 	Buf *bp;
904906943f9SDavid du Colombier 
905906943f9SDavid du Colombier 	if(e->free != nil)
906906943f9SDavid du Colombier 		e->free(e);
907906943f9SDavid du Colombier 	closedev(e->epin);
908906943f9SDavid du Colombier 	closedev(e->epout);
909d37e33ffSDavid du Colombier 	if(e->rc == nil){	/* not really started */
910906943f9SDavid du Colombier 		free(e);
911906943f9SDavid du Colombier 		return;
912906943f9SDavid du Colombier 	}
913906943f9SDavid du Colombier 	for(i = 0; i < e->nconns; i++)
914906943f9SDavid du Colombier 		if(e->conns[i] != nil){
915906943f9SDavid du Colombier 			while((bp = nbrecvp(e->conns[i]->rc)) != nil)
916906943f9SDavid du Colombier 				free(bp);
917906943f9SDavid du Colombier 			chanfree(e->conns[i]->rc);
918906943f9SDavid du Colombier 			free(e->conns[i]);
919906943f9SDavid du Colombier 		}
920d37e33ffSDavid du Colombier 	shutdownchan(e->bc);
921d37e33ffSDavid du Colombier 	shutdownchan(e->rc);
922d37e33ffSDavid du Colombier 	shutdownchan(e->wc);
923906943f9SDavid du Colombier 	e->epin = e->epout = nil;
924d5789509SDavid du Colombier 	devctl(e->dev, "detach");
925906943f9SDavid du Colombier 	free(e);
926906943f9SDavid du Colombier }
927906943f9SDavid du Colombier 
928d37e33ffSDavid du Colombier static void
etherdevfree(void * a)929d37e33ffSDavid du Colombier etherdevfree(void *a)
930d37e33ffSDavid du Colombier {
931d37e33ffSDavid du Colombier 	Ether *e = a;
932d37e33ffSDavid du Colombier 
933d37e33ffSDavid du Colombier 	if(e != nil)
934d37e33ffSDavid du Colombier 		etherfree(e);
935d37e33ffSDavid du Colombier }
936d37e33ffSDavid du Colombier 
937906943f9SDavid du Colombier /* must return 1 if c wants bp; 0 if not */
938906943f9SDavid du Colombier static int
cwantsbp(Conn * c,Buf * bp)939906943f9SDavid du Colombier cwantsbp(Conn *c, Buf *bp)
940906943f9SDavid du Colombier {
941906943f9SDavid du Colombier 	if(c->ref != 0 && (c->prom != 0 || c->type < 0 || c->type == bp->type))
942906943f9SDavid du Colombier 		return 1;
943906943f9SDavid du Colombier 	return 0;
944906943f9SDavid du Colombier }
945906943f9SDavid du Colombier 
946906943f9SDavid du Colombier static void
etherwriteproc(void * a)947906943f9SDavid du Colombier etherwriteproc(void *a)
948906943f9SDavid du Colombier {
949906943f9SDavid du Colombier 	Ether *e = a;
950906943f9SDavid du Colombier 	Buf *bp;
951906943f9SDavid du Colombier 	Channel *wc;
952906943f9SDavid du Colombier 
953a650be7dSDavid du Colombier 	threadsetname("etherwrite");
954906943f9SDavid du Colombier 	wc = e->wc;
955906943f9SDavid du Colombier 	while(e->exiting == 0){
956906943f9SDavid du Colombier 		bp = recvp(wc);
957a23bc242SDavid du Colombier 		if(bp == nil || e->exiting != 0){
958a23bc242SDavid du Colombier 			free(bp);
959906943f9SDavid du Colombier 			break;
960a23bc242SDavid du Colombier 		}
961906943f9SDavid du Colombier 		e->nout++;
962906943f9SDavid du Colombier 		if(e->bwrite(e, bp) < 0)
963906943f9SDavid du Colombier 			e->noerrs++;
964d37e33ffSDavid du Colombier 		if(isloopback(e, bp) && e->exiting == 0)
965906943f9SDavid du Colombier 			sendp(e->rc, bp); /* send to input queue */
966906943f9SDavid du Colombier 		else
967906943f9SDavid du Colombier 			freebuf(e, bp);
968906943f9SDavid du Colombier 	}
969906943f9SDavid du Colombier 	deprint(2, "%s: writeproc exiting\n", argv0);
970d37e33ffSDavid du Colombier 	closedev(e->dev);
971d37e33ffSDavid du Colombier }
972d37e33ffSDavid du Colombier 
973d37e33ffSDavid du Colombier static void
setbuftype(Buf * bp)974d37e33ffSDavid du Colombier setbuftype(Buf *bp)
975d37e33ffSDavid du Colombier {
976d37e33ffSDavid du Colombier 	uchar *p;
977d37e33ffSDavid du Colombier 
978d37e33ffSDavid du Colombier 	bp->type = 0;
979d37e33ffSDavid du Colombier 	if(bp->ndata >= Ehdrsize){
980d37e33ffSDavid du Colombier 		p = bp->rp + Eaddrlen*2;
981d37e33ffSDavid du Colombier 		bp->type = p[0]<<8 | p[1];
982d37e33ffSDavid du Colombier 	}
983d37e33ffSDavid du Colombier }
984d37e33ffSDavid du Colombier 
985d37e33ffSDavid du Colombier static void
etherexiting(Ether * e)986d37e33ffSDavid du Colombier etherexiting(Ether *e)
987d37e33ffSDavid du Colombier {
988d37e33ffSDavid du Colombier 	devctl(e->dev, "detach");
989d37e33ffSDavid du Colombier 	e->exiting = 1;
990d37e33ffSDavid du Colombier 	close(e->epin->dfd);
991d37e33ffSDavid du Colombier 	e->epin->dfd = -1;
992d37e33ffSDavid du Colombier 	close(e->epout->dfd);
993d37e33ffSDavid du Colombier 	e->epout->dfd = -1;
994d37e33ffSDavid du Colombier 	nbsend(e->wc, nil);
995906943f9SDavid du Colombier }
996906943f9SDavid du Colombier 
997906943f9SDavid du Colombier static void
etherreadproc(void * a)998906943f9SDavid du Colombier etherreadproc(void *a)
999906943f9SDavid du Colombier {
1000d37e33ffSDavid du Colombier 	int i, n, nwants;
1001d37e33ffSDavid du Colombier 	Buf *bp, *dbp;
1002906943f9SDavid du Colombier 	Ether *e = a;
1003906943f9SDavid du Colombier 
1004a650be7dSDavid du Colombier 	threadsetname("etherread");
1005906943f9SDavid du Colombier 	while(e->exiting == 0){
1006906943f9SDavid du Colombier 		bp = nbrecvp(e->rc);
1007906943f9SDavid du Colombier 		if(bp == nil){
1008d37e33ffSDavid du Colombier 			bp = allocbuf(e);	/* leak() may think we leak */
1009906943f9SDavid du Colombier 			if(e->bread(e, bp) < 0){
1010906943f9SDavid du Colombier 				freebuf(e, bp);
1011906943f9SDavid du Colombier 				break;
1012906943f9SDavid du Colombier 			}
1013906943f9SDavid du Colombier 			if(bp->ndata == 0){
1014906943f9SDavid du Colombier 				/* may be a short packet; continue */
1015906943f9SDavid du Colombier 				if(0)dprint(2, "%s: read: short\n", argv0);
1016906943f9SDavid du Colombier 				freebuf(e, bp);
1017906943f9SDavid du Colombier 				continue;
1018d37e33ffSDavid du Colombier 			}else
1019d37e33ffSDavid du Colombier 				setbuftype(bp);
1020906943f9SDavid du Colombier 		}
1021906943f9SDavid du Colombier 		e->nin++;
1022906943f9SDavid du Colombier 		nwants = 0;
1023906943f9SDavid du Colombier 		for(i = 0; i < e->nconns; i++)
1024906943f9SDavid du Colombier 			nwants += cwantsbp(e->conns[i], bp);
1025906943f9SDavid du Colombier 		for(i = 0; nwants > 0 && i < e->nconns; i++)
1026906943f9SDavid du Colombier 			if(cwantsbp(e->conns[i], bp)){
1027906943f9SDavid du Colombier 				n = bp->ndata;
1028906943f9SDavid du Colombier 				if(e->conns[i]->type == -2 && n > 64)
1029906943f9SDavid du Colombier 					n = 64;
1030906943f9SDavid du Colombier 				if(nwants-- == 1){
1031906943f9SDavid du Colombier 					bp->ndata = n;
1032906943f9SDavid du Colombier 					dbp = bp;
1033906943f9SDavid du Colombier 					bp = nil;
1034906943f9SDavid du Colombier 				}else{
1035906943f9SDavid du Colombier 					dbp = allocbuf(e);
1036906943f9SDavid du Colombier 					memmove(dbp->rp, bp->rp, n);
1037906943f9SDavid du Colombier 					dbp->ndata = n;
1038d37e33ffSDavid du Colombier 					dbp->type = bp->type;
1039906943f9SDavid du Colombier 				}
1040a23bc242SDavid du Colombier 				if(nbsendp(e->conns[i]->rc, dbp) == 0){
1041*0cc6832dSDavid du Colombier 					deprint(2, "%s: (in) packet lost\n", argv0);
1042906943f9SDavid du Colombier 					e->nierrs++;
1043906943f9SDavid du Colombier 					freebuf(e, dbp);
1044906943f9SDavid du Colombier 				}
1045906943f9SDavid du Colombier 			}
1046906943f9SDavid du Colombier 		freebuf(e, bp);
1047906943f9SDavid du Colombier 	}
1048906943f9SDavid du Colombier 	deprint(2, "%s: writeproc exiting\n", argv0);
1049d37e33ffSDavid du Colombier 	etherexiting(e);
1050d37e33ffSDavid du Colombier 	closedev(e->dev);
1051d5789509SDavid du Colombier 	usbfsdel(&e->fs);
1052906943f9SDavid du Colombier }
1053906943f9SDavid du Colombier 
1054906943f9SDavid du Colombier static void
setalt(Dev * d,int ifcid,int altid)1055906943f9SDavid du Colombier setalt(Dev *d, int ifcid, int altid)
1056906943f9SDavid du Colombier {
1057d37e33ffSDavid du Colombier 	if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, altid, ifcid, nil, 0) < 0)
1058906943f9SDavid du Colombier 		dprint(2, "%s: setalt ifc %d alt %d: %r\n", argv0, ifcid, altid);
1059906943f9SDavid du Colombier }
1060906943f9SDavid du Colombier 
1061906943f9SDavid du Colombier static int
ifaceinit(Ether * e,Iface * ifc,int * ei,int * eo)1062906943f9SDavid du Colombier ifaceinit(Ether *e, Iface *ifc, int *ei, int *eo)
1063906943f9SDavid du Colombier {
1064906943f9SDavid du Colombier 	Ep *ep;
1065d37e33ffSDavid du Colombier 	int epin, epout, i;
1066906943f9SDavid du Colombier 
1067906943f9SDavid du Colombier 	if(ifc == nil)
1068906943f9SDavid du Colombier 		return -1;
1069906943f9SDavid du Colombier 
1070d37e33ffSDavid du Colombier 	epin = epout = -1;
1071906943f9SDavid du Colombier 	for(i = 0; (epin < 0 || epout < 0) && i < nelem(ifc->ep); i++)
1072906943f9SDavid du Colombier 		if((ep = ifc->ep[i]) != nil && ep->type == Ebulk){
1073906943f9SDavid du Colombier 			if(ep->dir == Eboth || ep->dir == Ein)
1074906943f9SDavid du Colombier 				if(epin == -1)
1075906943f9SDavid du Colombier 					epin =  ep->id;
1076906943f9SDavid du Colombier 			if(ep->dir == Eboth || ep->dir == Eout)
1077906943f9SDavid du Colombier 				if(epout == -1)
1078906943f9SDavid du Colombier 					epout = ep->id;
1079906943f9SDavid du Colombier 		}
1080906943f9SDavid du Colombier 	if(epin == -1 || epout == -1)
1081906943f9SDavid du Colombier 		return -1;
1082d37e33ffSDavid du Colombier 
1083906943f9SDavid du Colombier 	dprint(2, "ether: ep ids: in %d out %d\n", epin, epout);
1084906943f9SDavid du Colombier 	for(i = 0; i < nelem(ifc->altc); i++)
1085d37e33ffSDavid du Colombier 		if(ifc->altc[i] != nil)
1086d37e33ffSDavid du Colombier 			setalt(e->dev, ifc->id, i);
1087906943f9SDavid du Colombier 
1088906943f9SDavid du Colombier 	*ei = epin;
1089906943f9SDavid du Colombier 	*eo = epout;
1090906943f9SDavid du Colombier 	return 0;
1091906943f9SDavid du Colombier }
1092906943f9SDavid du Colombier 
1093906943f9SDavid du Colombier static int
etherinit(Ether * e,int * ei,int * eo)1094906943f9SDavid du Colombier etherinit(Ether *e, int *ei, int *eo)
1095906943f9SDavid du Colombier {
1096d37e33ffSDavid du Colombier 	int ctlid, datid, i, j;
1097906943f9SDavid du Colombier 	Conf *c;
1098d37e33ffSDavid du Colombier 	Desc *desc;
1099d37e33ffSDavid du Colombier 	Iface *ctlif, *datif;
1100d37e33ffSDavid du Colombier 	Usbdev *ud;
1101906943f9SDavid du Colombier 
1102906943f9SDavid du Colombier 	*ei = *eo = -1;
1103906943f9SDavid du Colombier 	ud = e->dev->usb;
1104d37e33ffSDavid du Colombier 
1105d37e33ffSDavid du Colombier 	/* look for union descriptor with ethernet ctrl interface */
1106d37e33ffSDavid du Colombier 	for(i = 0; i < nelem(ud->ddesc); i++){
1107d37e33ffSDavid du Colombier 		if((desc = ud->ddesc[i]) == nil)
1108d37e33ffSDavid du Colombier 			continue;
1109d37e33ffSDavid du Colombier 		if(desc->data.bLength < 5 || desc->data.bbytes[0] != Cdcunion)
1110d37e33ffSDavid du Colombier 			continue;
1111d37e33ffSDavid du Colombier 
1112d37e33ffSDavid du Colombier 		ctlid = desc->data.bbytes[1];
1113d37e33ffSDavid du Colombier 		datid = desc->data.bbytes[2];
1114d37e33ffSDavid du Colombier 
1115d37e33ffSDavid du Colombier 		if((c = desc->conf) == nil)
1116d37e33ffSDavid du Colombier 			continue;
1117d37e33ffSDavid du Colombier 
1118d37e33ffSDavid du Colombier 		ctlif = datif = nil;
1119d37e33ffSDavid du Colombier 		for(j = 0; j < nelem(c->iface); j++){
1120d37e33ffSDavid du Colombier 			if(c->iface[j] == nil)
1121d37e33ffSDavid du Colombier 				continue;
1122d37e33ffSDavid du Colombier 			if(c->iface[j]->id == ctlid)
1123d37e33ffSDavid du Colombier 				ctlif = c->iface[j];
1124d37e33ffSDavid du Colombier 			if(c->iface[j]->id == datid)
1125d37e33ffSDavid du Colombier 				datif = c->iface[j];
1126d37e33ffSDavid du Colombier 
1127d37e33ffSDavid du Colombier 			if(datif != nil && ctlif != nil){
1128d37e33ffSDavid du Colombier 				if(Subclass(ctlif->csp) == Scether &&
1129d37e33ffSDavid du Colombier 				    ifaceinit(e, datif, ei, eo) != -1)
1130d37e33ffSDavid du Colombier 					return 0;
1131d37e33ffSDavid du Colombier 				break;
1132d37e33ffSDavid du Colombier 			}
1133d37e33ffSDavid du Colombier 		}
1134d37e33ffSDavid du Colombier 	}
1135d37e33ffSDavid du Colombier 	/* try any other one that seems to be ok */
1136906943f9SDavid du Colombier 	for(i = 0; i < nelem(ud->conf); i++)
1137906943f9SDavid du Colombier 		if((c = ud->conf[i]) != nil)
1138906943f9SDavid du Colombier 			for(j = 0; j < nelem(c->iface); j++)
1139906943f9SDavid du Colombier 				if(ifaceinit(e, c->iface[j], ei, eo) != -1)
1140906943f9SDavid du Colombier 					return 0;
1141906943f9SDavid du Colombier 	dprint(2, "%s: no valid endpoints", argv0);
1142906943f9SDavid du Colombier 	return -1;
1143906943f9SDavid du Colombier }
1144906943f9SDavid du Colombier 
1145*0cc6832dSDavid du Colombier static int
kernelproxy(Ether * e)1146*0cc6832dSDavid du Colombier kernelproxy(Ether *e)
1147*0cc6832dSDavid du Colombier {
1148*0cc6832dSDavid du Colombier 	int ctlfd, n;
1149*0cc6832dSDavid du Colombier 	char eaddr[13];
1150*0cc6832dSDavid du Colombier 
1151*0cc6832dSDavid du Colombier 	ctlfd = open("#l0/ether0/clone", ORDWR);
1152*0cc6832dSDavid du Colombier 	if(ctlfd < 0){
1153*0cc6832dSDavid du Colombier 		deprint(2, "%s: etherusb bind #l0: %r\n", argv0);
1154*0cc6832dSDavid du Colombier 		return -1;
1155*0cc6832dSDavid du Colombier 	}
1156*0cc6832dSDavid du Colombier 	close(e->epin->dfd);
1157*0cc6832dSDavid du Colombier 	close(e->epout->dfd);
1158*0cc6832dSDavid du Colombier 	seprintaddr(eaddr, eaddr+sizeof(eaddr), e->addr);
1159*0cc6832dSDavid du Colombier 	n = fprint(ctlfd, "bind %s #u/usb/ep%d.%d/data #u/usb/ep%d.%d/data %s %d %d",
1160*0cc6832dSDavid du Colombier 		e->name, e->dev->id, e->epin->id, e->dev->id, e->epout->id,
1161*0cc6832dSDavid du Colombier 		eaddr, e->bufsize, e->epout->maxpkt);
1162*0cc6832dSDavid du Colombier 	if(n < 0){
1163*0cc6832dSDavid du Colombier 		deprint(2, "%s: etherusb bind #l0: %r\n", argv0);
1164*0cc6832dSDavid du Colombier 		opendevdata(e->epin, OREAD);
1165*0cc6832dSDavid du Colombier 		opendevdata(e->epout, OWRITE);
1166*0cc6832dSDavid du Colombier 		close(ctlfd);
1167*0cc6832dSDavid du Colombier 		return -1;
1168*0cc6832dSDavid du Colombier 	}
1169*0cc6832dSDavid du Colombier 	close(ctlfd);
1170*0cc6832dSDavid du Colombier 	return 0;
1171*0cc6832dSDavid du Colombier }
1172*0cc6832dSDavid du Colombier 
1173906943f9SDavid du Colombier int
ethermain(Dev * dev,int argc,char ** argv)1174906943f9SDavid du Colombier ethermain(Dev *dev, int argc, char **argv)
1175906943f9SDavid du Colombier {
1176ed868a7cSDavid du Colombier 	int epin, epout, i, devid;
1177906943f9SDavid du Colombier 	Ether *e;
1178a650be7dSDavid du Colombier 	uchar ea[Eaddrlen];
1179906943f9SDavid du Colombier 
1180ed868a7cSDavid du Colombier 	devid = dev->id;
1181a650be7dSDavid du Colombier 	memset(ea, 0, Eaddrlen);
1182906943f9SDavid du Colombier 	ARGBEGIN{
1183a650be7dSDavid du Colombier 	case 'a':
1184a650be7dSDavid du Colombier 		if(parseaddr(ea, EARGF(usage())) < 0)
1185a650be7dSDavid du Colombier 			return usage();
1186a650be7dSDavid du Colombier 		break;
1187906943f9SDavid du Colombier 	case 'd':
1188906943f9SDavid du Colombier 		if(etherdebug == 0)
1189906943f9SDavid du Colombier 			fprint(2, "ether debug on\n");
1190906943f9SDavid du Colombier 		etherdebug++;
1191906943f9SDavid du Colombier 		break;
1192ed868a7cSDavid du Colombier 	case 'N':
1193ed868a7cSDavid du Colombier 		devid = atoi(EARGF(usage()));
1194ed868a7cSDavid du Colombier 		break;
1195906943f9SDavid du Colombier 	default:
1196906943f9SDavid du Colombier 		return usage();
1197906943f9SDavid du Colombier 	}ARGEND
1198ed868a7cSDavid du Colombier 	if(argc != 0) {
1199906943f9SDavid du Colombier 		return usage();
1200ed868a7cSDavid du Colombier 	}
1201906943f9SDavid du Colombier 	e = dev->aux = emallocz(sizeof(Ether), 1);
1202906943f9SDavid du Colombier 	e->dev = dev;
1203906943f9SDavid du Colombier 	dev->free = etherdevfree;
1204a650be7dSDavid du Colombier 	memmove(e->addr, ea, Eaddrlen);
1205*0cc6832dSDavid du Colombier 	e->name = "cdc";
1206906943f9SDavid du Colombier 
1207906943f9SDavid du Colombier 	for(i = 0; i < nelem(ethers); i++)
1208906943f9SDavid du Colombier 		if(ethers[i](e) == 0)
1209906943f9SDavid du Colombier 			break;
1210906943f9SDavid du Colombier 	if(i == nelem(ethers))
1211906943f9SDavid du Colombier 		return -1;
1212906943f9SDavid du Colombier 	if(e->init == nil)
1213906943f9SDavid du Colombier 		e->init = etherinit;
1214906943f9SDavid du Colombier 	if(e->init(e, &epin, &epout) < 0)
1215906943f9SDavid du Colombier 		return -1;
1216906943f9SDavid du Colombier 	if(e->bwrite == nil)
1217906943f9SDavid du Colombier 		e->bwrite = etherbwrite;
1218906943f9SDavid du Colombier 	if(e->bread == nil)
1219906943f9SDavid du Colombier 		e->bread = etherbread;
1220*0cc6832dSDavid du Colombier 	if(e->bufsize == 0)
1221*0cc6832dSDavid du Colombier 		e->bufsize = Maxpkt;
1222906943f9SDavid du Colombier 
1223906943f9SDavid du Colombier 	if(openeps(e, epin, epout) < 0)
1224906943f9SDavid du Colombier 		return -1;
1225*0cc6832dSDavid du Colombier 	if(kernelproxy(e) == 0)
1226*0cc6832dSDavid du Colombier 		return 0;
1227906943f9SDavid du Colombier 	e->fs = etherfs;
1228ed868a7cSDavid du Colombier 	snprint(e->fs.name, sizeof(e->fs.name), "etherU%d", devid);
1229906943f9SDavid du Colombier 	e->fs.dev = dev;
1230906943f9SDavid du Colombier 	e->fs.aux = e;
1231a650be7dSDavid du Colombier 	e->bc = chancreate(sizeof(Buf*), Nbufs);
1232906943f9SDavid du Colombier 	e->rc = chancreate(sizeof(Buf*), Nconns/2);
1233906943f9SDavid du Colombier 	e->wc = chancreate(sizeof(Buf*), Nconns*2);
1234d37e33ffSDavid du Colombier 	incref(e->dev);
1235906943f9SDavid du Colombier 	proccreate(etherwriteproc, e, 16*1024);
1236d37e33ffSDavid du Colombier 	incref(e->dev);
1237906943f9SDavid du Colombier 	proccreate(etherreadproc, e, 16*1024);
1238906943f9SDavid du Colombier 	deprint(2, "%s: dev ref %ld\n", argv0, dev->ref);
1239d5789509SDavid du Colombier 	incref(e->dev);
1240906943f9SDavid du Colombier 	usbfsadd(&e->fs);
1241906943f9SDavid du Colombier 	return 0;
1242906943f9SDavid du Colombier }
1243