xref: /plan9/sys/src/9/bcm/etherusb.c (revision 853458f38e7eb3a48cfa3a36aefdb799375e398a)
1 /*
2  * Kernel proxy for usb ethernet device
3  */
4 
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "../port/error.h"
12 #include "../port/netif.h"
13 
14 #include "etherif.h"
15 #include "../ip/ip.h"
16 
17 #define	GET4(p)		((p)[3]<<24 | (p)[2]<<16 | (p)[1]<<8  | (p)[0])
18 #define	PUT4(p, v)	((p)[0] = (v), (p)[1] = (v)>>8, \
19 			 (p)[2] = (v)>>16, (p)[3] = (v)>>24)
20 #define	dprint	if(debug) print
21 #define ddump	if(0) dump
22 
23 static int debug = 0;
24 
25 enum {
26 	Bind	= 0,
27 	Unbind,
28 
29 	SmscRxerror	= 0x8000,
30 	SmscTxfirst	= 0x2000,
31 	SmscTxlast	= 0x1000,
32 };
33 
34 typedef struct Ctlr Ctlr;
35 typedef struct Udev Udev;
36 
37 typedef int (Unpackfn)(Ether*, Block*);
38 typedef void (Transmitfn)(Ctlr*, Block*);
39 
40 struct Ctlr {
41 	Ether*	edev;
42 	Udev*	udev;
43 	Chan*	inchan;
44 	Chan*	outchan;
45 	char*	buf;
46 	int	bufsize;
47 	int	maxpkt;
48 	uint	rxbuf;
49 	uint	rxpkt;
50 	uint	txbuf;
51 	uint	txpkt;
52 	QLock;
53 };
54 
55 struct Udev {
56 	char	*name;
57 	Unpackfn *unpack;
58 	Transmitfn *transmit;
59 };
60 
61 static Cmdtab cmds[] = {
62 	{ Bind,		"bind",		7, },
63 	{ Unbind,	"unbind",	0, },
64 };
65 
66 static Unpackfn unpackcdc, unpackasix, unpacksmsc;
67 static Transmitfn transmitcdc, transmitasix, transmitsmsc;
68 
69 static Udev udevtab[] = {
70 	{ "cdc",	unpackcdc,	transmitcdc, },
71 	{ "asix",	unpackasix,	transmitasix, },
72 	{ "smsc",	unpacksmsc,	transmitsmsc, },
73 	{ nil },
74 };
75 
76 static void
dump(int c,Block * b)77 dump(int c, Block *b)
78 {
79 	int s, i;
80 
81 	s = splhi();
82 	print("%c%ld:", c, BLEN(b));
83 	for(i = 0; i < 32; i++)
84 		print(" %2.2ux", b->rp[i]);
85 	print("\n");
86 	splx(s);
87 }
88 
89 static int
unpack(Ether * edev,Block * b,int m)90 unpack(Ether *edev, Block *b, int m)
91 {
92 	Block *nb;
93 	Ctlr *ctlr;
94 
95 	ctlr = edev->ctlr;
96 	ddump('?', b);
97 	if(m == BLEN(b)){
98 		etheriq(edev, b, 1);
99 		ctlr->rxpkt++;
100 		return 1;
101 	}
102 	nb = iallocb(m);
103 	if(nb != nil){
104 		memmove(nb->wp, b->rp, m);
105 		nb->wp += m;
106 		etheriq(edev, nb, 1);
107 		ctlr->rxpkt++;
108 	}else
109 		edev->soverflows++;
110 	b->rp += m;
111 	return 0;
112 }
113 
114 static int
unpackcdc(Ether * edev,Block * b)115 unpackcdc(Ether *edev, Block *b)
116 {
117 	int m;
118 
119 	m = BLEN(b);
120 	if(m < 6)
121 		return -1;
122 	return unpack(edev, b, m);
123 }
124 
125 static int
unpackasix(Ether * edev,Block * b)126 unpackasix(Ether *edev, Block *b)
127 {
128 	ulong hd;
129 	int m;
130 	uchar *wp;
131 
132 	if(BLEN(b) < 4)
133 		return -1;
134 	hd = GET4(b->rp);
135 	b->rp += 4;
136 	m = hd & 0xFFFF;
137 	hd >>= 16;
138 	if(m != (~hd & 0xFFFF))
139 		return -1;
140 	m = ROUND(m, 2);
141 	if(m < 6 || m > BLEN(b))
142 		return -1;
143 	if((wp = b->rp + m) != b->wp && b->wp - wp < 4)
144 		b->wp = wp;
145 	return unpack(edev, b, m);
146 }
147 
148 static int
unpacksmsc(Ether * edev,Block * b)149 unpacksmsc(Ether *edev, Block *b)
150 {
151 	ulong hd;
152 	int m;
153 
154 	ddump('@', b);
155 	if(BLEN(b) < 4)
156 		return -1;
157 	hd = GET4(b->rp);
158 	b->rp += 4;
159 	m = hd >> 16;
160 	if(m < 6 || m > BLEN(b))
161 		return -1;
162 	if(BLEN(b) - m < 4)
163 		b->wp = b->rp + m;
164 	if(hd & SmscRxerror){
165 		edev->frames++;
166 		b->rp += m;
167 		if(BLEN(b) == 0){
168 			freeb(b);
169 			return 1;
170 		}
171 	}else if(unpack(edev, b, m) == 1)
172 		return 1;
173 	if((m &= 3) != 0)
174 		b->rp += 4 - m;
175 	return 0;
176 }
177 
178 static void
transmit(Ctlr * ctlr,Block * b)179 transmit(Ctlr *ctlr, Block *b)
180 {
181 	Chan *c;
182 
183 	ddump('!', b);
184 	c = ctlr->outchan;
185 	devtab[c->type]->bwrite(c, b, 0);
186 }
187 
188 static void
transmitcdc(Ctlr * ctlr,Block * b)189 transmitcdc(Ctlr *ctlr, Block *b)
190 {
191 	transmit(ctlr, b);
192 }
193 
194 static void
transmitasix(Ctlr * ctlr,Block * b)195 transmitasix(Ctlr *ctlr, Block *b)
196 {
197 	int n;
198 
199 	n = BLEN(b) & 0xFFFF;
200 	n |= ~n << 16;
201 	padblock(b, 4);
202 	PUT4(b->rp, n);
203 	if(BLEN(b) % ctlr->maxpkt == 0){
204 		padblock(b, -4);
205 		PUT4(b->wp, 0xFFFF0000);
206 		b->wp += 4;
207 	}
208 	transmit(ctlr, b);
209 }
210 
211 static void
transmitsmsc(Ctlr * ctlr,Block * b)212 transmitsmsc(Ctlr *ctlr, Block *b)
213 {
214 	int n;
215 
216 	n = BLEN(b) & 0x7FF;
217 	padblock(b, 8);
218 	PUT4(b->rp, n | SmscTxfirst | SmscTxlast);
219 	PUT4(b->rp+4, n);
220 	transmit(ctlr, b);
221 }
222 
223 static void
etherusbproc(void * a)224 etherusbproc(void *a)
225 {
226 	Ether *edev;
227 	Ctlr *ctlr;
228 	Chan *c;
229 	Block *b;
230 
231 	edev = a;
232 	ctlr = edev->ctlr;
233 	c = ctlr->inchan;
234 	b = nil;
235 	if(waserror()){
236 		print("etherusbproc: error exit %s\n", up->errstr);
237 		pexit(up->errstr, 1);
238 		return;
239 	}
240 	for(;;){
241 		if(b == nil){
242 			b = devtab[c->type]->bread(c, ctlr->bufsize, 0);
243 			ctlr->rxbuf++;
244 		}
245 		switch(ctlr->udev->unpack(edev, b)){
246 		case -1:
247 			edev->buffs++;
248 			freeb(b);
249 			/* fall through */
250 		case 1:
251 			b = nil;
252 			break;
253 		}
254 	}
255 }
256 
257 /*
258  * bind type indev outdev mac bufsize maxpkt
259  */
260 static void
bind(Ctlr * ctlr,Udev * udev,Cmdbuf * cb)261 bind(Ctlr *ctlr, Udev *udev, Cmdbuf *cb)
262 {
263 	Chan *inchan, *outchan;
264 	char *buf;
265 	uint bufsize, maxpkt;
266 
267 	qlock(ctlr);
268 	inchan = outchan = nil;
269 	buf = nil;
270 	if(waserror()){
271 		free(buf);
272 		if(inchan)
273 			cclose(inchan);
274 		if(outchan)
275 			cclose(outchan);
276 		qunlock(ctlr);
277 		nexterror();
278 	}
279 	if(ctlr->buf != nil)
280 		cmderror(cb, "already bound to a device");
281 	maxpkt = strtol(cb->f[6], 0, 0);
282 	if(maxpkt < 8 || maxpkt > 512)
283 		cmderror(cb, "bad maxpkt");
284 	bufsize = strtol(cb->f[5], 0, 0);
285 	if(bufsize < maxpkt || bufsize > 32*1024)
286 		cmderror(cb, "bad bufsize");
287 	buf = smalloc(bufsize);
288 	inchan = namec(cb->f[2], Aopen, OREAD, 0);
289 	outchan = namec(cb->f[3], Aopen, OWRITE, 0);
290 	assert(inchan != nil && outchan != nil);
291 	if(parsemac(ctlr->edev->ea, cb->f[4], Eaddrlen) != Eaddrlen)
292 		cmderror(cb, "bad etheraddr");
293 	memmove(ctlr->edev->addr, ctlr->edev->ea, Eaddrlen);
294 	print("\netherusb %s: %E\n", udev->name, ctlr->edev->addr);
295 	ctlr->buf = buf;
296 	ctlr->inchan = inchan;
297 	ctlr->outchan = outchan;
298 	ctlr->bufsize = bufsize;
299 	ctlr->maxpkt = maxpkt;
300 	ctlr->udev = udev;
301 	kproc("etherusb", etherusbproc, ctlr->edev);
302 	poperror();
303 	qunlock(ctlr);
304 }
305 
306 static void
unbind(Ctlr * ctlr)307 unbind(Ctlr *ctlr)
308 {
309 	qlock(ctlr);
310 	if(ctlr->buf != nil){
311 		free(ctlr->buf);
312 		ctlr->buf = nil;
313 		if(ctlr->inchan)
314 			cclose(ctlr->inchan);
315 		if(ctlr->outchan)
316 			cclose(ctlr->outchan);
317 		ctlr->inchan = ctlr->outchan = nil;
318 	}
319 	qunlock(ctlr);
320 }
321 
322 static long
etherusbifstat(Ether * edev,void * a,long n,ulong offset)323 etherusbifstat(Ether* edev, void* a, long n, ulong offset)
324 {
325 	Ctlr *ctlr;
326 	char *p;
327 	int l;
328 
329 	ctlr = edev->ctlr;
330 	p = malloc(READSTR);
331 	l = 0;
332 
333 	l += snprint(p+l, READSTR-l, "rxbuf: %ud\n", ctlr->rxbuf);
334 	l += snprint(p+l, READSTR-l, "rxpkt: %ud\n", ctlr->rxpkt);
335 	l += snprint(p+l, READSTR-l, "txbuf: %ud\n", ctlr->txbuf);
336 	l += snprint(p+l, READSTR-l, "txpkt: %ud\n", ctlr->txpkt);
337 	USED(l);
338 
339 	n = readstr(offset, a, n, p);
340 	free(p);
341 	return n;
342 }
343 
344 static void
etherusbtransmit(Ether * edev)345 etherusbtransmit(Ether *edev)
346 {
347 	Ctlr *ctlr;
348 	Block *b;
349 
350 	ctlr = edev->ctlr;
351 	while((b = qget(edev->oq)) != nil){
352 		ctlr->txpkt++;
353 		if(ctlr->buf == nil)
354 			freeb(b);
355 		else{
356 			ctlr->udev->transmit(ctlr, b);
357 			ctlr->txbuf++;
358 		}
359 	}
360 }
361 
362 static long
etherusbctl(Ether * edev,void * buf,long n)363 etherusbctl(Ether* edev, void* buf, long n)
364 {
365 	Ctlr *ctlr;
366 	Cmdbuf *cb;
367 	Cmdtab *ct;
368 	Udev *udev;
369 
370 	if((ctlr = edev->ctlr) == nil)
371 		error(Enonexist);
372 
373 	cb = parsecmd(buf, n);
374 	if(waserror()){
375 		free(cb);
376 		nexterror();
377 	}
378 	ct = lookupcmd(cb, cmds, nelem(cmds));
379 	switch(ct->index){
380 	case Bind:
381 		for(udev = udevtab; udev->name; udev++)
382 			if(strcmp(cb->f[1], udev->name) == 0)
383 				break;
384 		if(udev->name == nil)
385 			cmderror(cb, "unknown etherusb type");
386 		bind(ctlr, udev, cb);
387 		break;
388 	case Unbind:
389 		unbind(ctlr);
390 		break;
391 	default:
392 		cmderror(cb, "unknown etherusb control message");
393 	}
394 	poperror();
395 	free(cb);
396 	return n;
397 }
398 
399 static void
etherusbattach(Ether * edev)400 etherusbattach(Ether* edev)
401 {
402 	Ctlr *ctlr;
403 
404 	ctlr = edev->ctlr;
405 	ctlr->edev = edev;
406 }
407 
408 static int
etherusbpnp(Ether * edev)409 etherusbpnp(Ether* edev)
410 {
411 	Ctlr *ctlr;
412 
413 	ctlr = malloc(sizeof(Ctlr));
414 	edev->ctlr = ctlr;
415 	edev->irq = -1;
416 	edev->mbps = 100;	/* TODO: get this from usbether */
417 
418 	/*
419 	 * Linkage to the generic ethernet driver.
420 	 */
421 	edev->attach = etherusbattach;
422 	edev->transmit = etherusbtransmit;
423 	edev->interrupt = nil;
424 	edev->ifstat = etherusbifstat;
425 	edev->ctl = etherusbctl;
426 
427 	edev->arg = edev;
428 	/* TODO: promiscuous, multicast (for ipv6), shutdown (for reboot) */
429 //	edev->promiscuous = etherusbpromiscuous;
430 //	edev->shutdown = etherusbshutdown;
431 //	edev->multicast = etherusbmulticast;
432 
433 	return 0;
434 }
435 
436 void
etherusblink(void)437 etherusblink(void)
438 {
439 	addethercard("usb", etherusbpnp);
440 }
441