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