Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
189
transmitcdc(Ctlr *ctlr, Block *b)
190
{
191
	transmit(ctlr, b);
192
}
193
 
194
static void
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
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
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
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
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
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
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
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
400
etherusbattach(Ether* edev)
401
{
402
	Ctlr *ctlr;
403
 
404
	ctlr = edev->ctlr;
405
	ctlr->edev = edev;
406
}
407
 
408
static int
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
437
etherusblink(void)
438
{
439
	addethercard("usb", etherusbpnp);
440
}