Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/cmd/usb/ether/asix.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * Asix USB ether adapters
3
 * I got no documentation for it, thus the bits
4
 * come from other systems; it's likely this is
5
 * doing more than needed in some places and
6
 * less than required in others.
7
 */
8
#include <u.h>
9
#include <libc.h>
10
#include <fcall.h>
11
#include <thread.h>
12
#include "usb.h"
13
#include "usbfs.h"
14
#include "ether.h"
15
 
16
enum
17
{
18
 
19
	/* Asix commands */
20
	Cswmii		= 0x06,		/* set sw mii */
21
	Crmii		= 0x07,		/* read mii reg */
22
	Cwmii		= 0x08,		/* write mii reg */
23
	Chwmii		= 0x0a,		/* set hw mii */
24
	Creeprom	= 0x0b,		/* read eeprom */
25
	Cwdis		= 0x0e,		/* write disable */
26
	Cwena		= 0x0d,		/* write enable */
27
	Crrxctl		= 0x0f,		/* read rx ctl */
28
	Cwrxctl		= 0x10,		/* write rx ctl */
29
	Cwipg		= 0x12,		/* write ipg */
30
	Crmac		= 0x13,		/* read mac addr */
31
	Crphy		= 0x19,		/* read phy id */
32
	Cwmedium		= 0x1b,		/* write medium mode */
33
	Crgpio		= 0x1e,		/* read gpio */
34
	Cwgpio		= 0x1f,		/* write gpios */
35
	Creset		= 0x20,		/* reset */
36
	Cwphy		= 0x22,		/* select phy */
37
 
38
	/* reset codes */
39
	Rclear		= 0x00,
40
	Rprte		= 0x04,
41
	Rprl		= 0x08,
42
	Riprl		= 0x20,
43
	Rippd		= 0x40,
44
 
45
	Gpiogpo1en	= 0x04,	/* gpio1 enable */,
46
	Gpiogpo1		= 0x08,	/* gpio1 value */
47
	Gpiogpo2en	= 0x10,	/* gpio2 enable */
48
	Gpiogpo2		= 0x20,	/* gpio2 value */
49
	Gpiorse		= 0x80,	/* gpio reload serial eeprom */
50
 
51
	Pmask		= 0x1F,
52
	Pembed		= 0x10,			/* embedded phy */
53
 
54
	Mfd		= 0x002,		/* media */
55
	Mac		= 0x004,
56
	Mrfc		= 0x010,
57
	Mtfc		= 0x020,
58
	Mjfe		= 0x040,
59
	Mre		= 0x100,
60
	Mps		= 0x200,
61
	Mall772		= Mfd|Mrfc|Mtfc|Mps|Mac|Mre,
62
	Mall178		= Mps|Mfd|Mac|Mrfc|Mtfc|Mjfe|Mre,
63
 
64
	Ipgdflt		= 0x15|0x0c|0x12,	/* default ipg0, 1, 2 */
65
	Rxctlso		= 0x80,
66
	Rxctlab		= 0x08,
67
	Rxctlsep	= 0x04,
68
	Rxctlamall	= 0x02,			/* all multicast */
69
	Rxctlprom	= 0x01,			/* promiscuous */
70
 
71
	/* MII */
72
	Miibmcr			= 0x00,		/* basic mode ctrl reg. */
73
		Bmcrreset	= 0x8000,	/* reset */
74
		Bmcranena	= 0x1000,	/* auto neg. enable */
75
		Bmcrar		= 0x0200,	/* announce restart */
76
 
77
	Miiad			= 0x04,		/* advertise reg. */
78
		Adcsma		= 0x0001,
79
		Ad1000f		= 0x0200,
80
		Ad1000h		= 0x0100,
81
		Ad10h		= 0x0020,
82
		Ad10f		= 0x0040,
83
		Ad100h		= 0x0080,
84
		Ad100f		= 0x0100,
85
		Adpause		= 0x0400,
86
		Adall		= Ad10h|Ad10f|Ad100h|Ad100f,
87
 
88
	Miimctl			= 0x14,		/* marvell ctl */
89
		Mtxdly		= 0x02,
90
		Mrxdly		= 0x80,
91
		Mtxrxdly	= 0x82,
92
 
93
	Miic1000			= 0x09,
94
 
95
};
96
 
97
static int
98
asixset(Dev *d, int c, int v)
99
{
100
	int r;
101
	int ec;
102
 
103
	r = Rh2d|Rvendor|Rdev;
104
	ec = usbcmd(d, r, c, v, 0, nil, 0);
105
	if(ec < 0)
106
		deprint(2, "%s: asixset %x %x: %r\n", argv0, c, v);
107
	return ec;
108
}
109
 
110
static int
111
asixget(Dev *d, int c, uchar *buf, int l)
112
{
113
	int r;
114
	int ec;
115
 
116
	r = Rd2h|Rvendor|Rdev;
117
	ec = usbcmd(d, r, c, 0, 0, buf, l);
118
	if(ec < 0)
119
		deprint(2, "%s: asixget %x: %r\n", argv0, c);
120
	return ec;
121
}
122
 
123
static int
124
getgpio(Dev *d)
125
{
126
	uchar c;
127
 
128
	if(asixget(d, Crgpio, &c, 1) < 0)
129
		return -1;
130
	return c;
131
}
132
 
133
static int
134
getphy(Dev *d)
135
{
136
	uchar buf[2];
137
 
138
	if(asixget(d, Crphy, buf, sizeof(buf)) < 0)
139
		return -1;
140
	deprint(2, "%s: phy addr %#ux\n", argv0, buf[1]);
141
	return buf[1];
142
}
143
 
144
static int
145
getrxctl(Dev *d)
146
{
147
	uchar buf[2];
148
	int r;
149
 
150
	memset(buf, 0, sizeof(buf));
151
	if(asixget(d, Crrxctl, buf, sizeof(buf)) < 0)
152
		return -1;
153
	r = GET2(buf);
154
	deprint(2, "%s: rxctl %#x\n", argv0, r);
155
	return r;
156
}
157
 
158
static int
159
getmac(Dev *d, uchar buf[])
160
{
161
	if(asixget(d, Crmac, buf, Eaddrlen) < 0)
162
		return -1;
163
	return Eaddrlen;
164
}
165
 
166
static int
167
miiread(Dev *d, int phy, int reg)
168
{
169
	int r;
170
	uchar v[2];
171
 
172
	r = Rd2h|Rvendor|Rdev;
173
	if(usbcmd(d, r, Crmii, phy, reg, v, 2) < 0){
174
		dprint(2, "%s: miiwrite: %r\n", argv0);
175
		return -1;
176
	}
177
	r = GET2(v);
178
	if(r == 0xFFFF)
179
		return -1;
180
	return r;
181
}
182
 
183
 
184
static int
185
miiwrite(Dev *d, int phy, int reg, int val)
186
{
187
	int r;
188
	uchar v[2];
189
 
190
	if(asixset(d, Cswmii, 0) < 0)
191
		return -1;
192
	r = Rh2d|Rvendor|Rdev;
193
	PUT2(v, val);
194
	if(usbcmd(d, r, Cwmii, phy, reg, v, 2) < 0){
195
		deprint(2, "%s: miiwrite: %#x %#x %r\n", argv0, reg, val);
196
		return -1;
197
	}
198
	if(asixset(d, Chwmii, 0) < 0)
199
		return -1;
200
	return 0;
201
}
202
 
203
static int
204
eepromread(Dev *d, int i)
205
{
206
	int r;
207
	int ec;
208
	uchar buf[2];
209
 
210
	r = Rd2h|Rvendor|Rdev;
211
	ec = usbcmd(d, r, Creeprom, i, 0, buf, sizeof(buf));
212
	if(ec < 0)
213
		deprint(2, "%s: eepromread %d: %r\n", argv0, i);
214
	ec = GET2(buf);
215
	deprint(2, "%s: eeprom %#x = %#x\n", argv0, i, ec);
216
	if(ec == 0xFFFF)
217
		ec = -1;
218
	return ec;
219
}
220
 
221
/*
222
 * No doc. we are doing what Linux does as closely
223
 * as we can.
224
 */
225
static int
226
ctlrinit(Ether *ether)
227
{
228
	Dev *d;
229
	int i;
230
	int bmcr;
231
	int gpio;
232
	int ee17;
233
	int rc;
234
 
235
	d = ether->dev;
236
	switch(ether->cid){
237
	case A8817x:
238
	case A88179:
239
		fprint(2, "%s: card known but not implemented\n", argv0);
240
		/* fall through */
241
	default:
242
		return -1;
243
 
244
	case A88178:
245
		deprint(2, "%s: setting up A88178\n", argv0);
246
		gpio = getgpio(d);
247
		if(gpio < 0)
248
			return -1;
249
		deprint(2, "%s: gpio sts %#x\n", argv0, gpio);
250
		asixset(d, Cwena, 0);
251
		ee17 = eepromread(d, 0x0017);
252
		asixset(d, Cwdis, 0);
253
		asixset(d, Cwgpio, Gpiorse|Gpiogpo1|Gpiogpo1en);
254
		if((ee17 >> 8) != 1){
255
			asixset(d, Cwgpio, 0x003c);
256
			asixset(d, Cwgpio, 0x001c);
257
			asixset(d, Cwgpio, 0x003c);
258
		}else{
259
			asixset(d, Cwgpio, Gpiogpo1en);
260
			asixset(d, Cwgpio, Gpiogpo1|Gpiogpo1en);
261
		}
262
		asixset(d, Creset, Rclear);
263
		sleep(150);
264
		asixset(d, Creset, Rippd|Rprl);
265
		sleep(150);
266
		asixset(d, Cwrxctl, 0);
267
		if(getmac(d, ether->addr) < 0)
268
			return -1;
269
		ether->phy = getphy(d);
270
		if(ee17 < 0 || (ee17 & 0x7) == 0){
271
			miiwrite(d, ether->phy, Miimctl, Mtxrxdly);
272
			sleep(60);
273
		}
274
		miiwrite(d, ether->phy, Miibmcr, Bmcrreset|Bmcranena);
275
		miiwrite(d, ether->phy, Miiad, Adall|Adcsma|Adpause);
276
		miiwrite(d, ether->phy, Miic1000, Ad1000f);
277
		bmcr = miiread(d, ether->phy, Miibmcr);
278
		if((bmcr & Bmcranena) != 0){
279
			bmcr |= Bmcrar;
280
			miiwrite(d, ether->phy, Miibmcr, bmcr);
281
		}
282
		asixset(d, Cwmedium, Mall178);
283
		asixset(d, Cwrxctl, Rxctlso|Rxctlab);
284
		break;
285
 
286
	case A88772:
287
		deprint(2, "%s: setting up A88772\n", argv0);
288
		if(asixset(d, Cwgpio, Gpiorse|Gpiogpo2|Gpiogpo2en) < 0)
289
			return -1;
290
		ether->phy = getphy(d);
291
		dprint(2, "%s: phy %#x\n", argv0, ether->phy);
292
		if((ether->phy & Pmask) == Pembed){
293
			/* embedded 10/100 ethernet */
294
			rc = asixset(d, Cwphy, 1);
295
		}else
296
			rc = asixset(d, Cwphy, 0);
297
		if(rc < 0)
298
			return -1;
299
		if(asixset(d, Creset, Rippd|Rprl) < 0)
300
			return -1;
301
		sleep(150);
302
		if((ether->phy & Pmask) == Pembed)
303
			rc = asixset(d, Creset, Riprl);
304
		else
305
			rc = asixset(d, Creset, Rprte);
306
		if(rc < 0)
307
			return -1;
308
		sleep(150);
309
		rc = getrxctl(d);
310
		deprint(2, "%s: rxctl is %#x\n", argv0, rc);
311
		if(asixset(d, Cwrxctl, 0) < 0)
312
			return -1;
313
		if(getmac(d, ether->addr) < 0)
314
			return -1;
315
 
316
 
317
		if(asixset(d, Creset, Rprl) < 0)
318
			return -1;
319
		sleep(150);
320
		if(asixset(d, Creset, Riprl|Rprl) < 0)
321
			return -1;
322
		sleep(150);
323
 
324
		miiwrite(d, ether->phy, Miibmcr, Bmcrreset);
325
		miiwrite(d, ether->phy, Miiad, Adall|Adcsma);
326
		bmcr = miiread(d, ether->phy, Miibmcr);
327
		if((bmcr & Bmcranena) != 0){
328
			bmcr |= Bmcrar;
329
			miiwrite(d, ether->phy, Miibmcr, bmcr);
330
		}
331
		if(asixset(d, Cwmedium, Mall772) < 0)
332
			return -1;
333
		if(asixset(d, Cwipg, Ipgdflt) < 0)
334
			return -1;
335
		if(asixset(d, Cwrxctl, Rxctlso|Rxctlab) < 0)
336
			return -1;
337
		deprint(2, "%s: final rxctl: %#x\n", argv0, getrxctl(d));
338
		break;
339
	}
340
 
341
	if(etherdebug){
342
		fprint(2, "%s: ether: phy %#x addr ", argv0, ether->phy);
343
		for(i = 0; i < sizeof(ether->addr); i++)
344
			fprint(2, "%02x", ether->addr[i]);
345
		fprint(2, "\n");
346
	}
347
	return 0;
348
}
349
 
350
 
351
static long
352
asixbread(Ether *e, Buf *bp)
353
{
354
	ulong nr;
355
	ulong hd;
356
	Buf *rbp;
357
 
358
	rbp = e->aux;
359
	if(rbp == nil || rbp->ndata < 4){
360
		rbp->rp = rbp->data;
361
		rbp->ndata = read(e->epin->dfd, rbp->rp, sizeof(bp->data));
362
		if(rbp->ndata < 0)
363
			return -1;
364
	}
365
	if(rbp->ndata < 4){
366
		werrstr("short frame");
367
		deprint(2, "%s: asixbread got %d bytes\n", argv0, rbp->ndata);
368
		rbp->ndata = 0;
369
		return 0;
370
	}
371
	hd = GET4(rbp->rp);
372
	nr = hd & 0xFFFF;
373
	hd = (hd>>16) & 0xFFFF;
374
	if(nr != (~hd & 0xFFFF)){
375
		if(0)deprint(2, "%s: asixread: bad header %#ulx %#ulx\n",
376
			argv0, nr, (~hd & 0xFFFF));
377
		werrstr("bad usb packet header");
378
		rbp->ndata = 0;
379
		return 0;
380
	}
381
	rbp->rp += 4;
382
	if(nr < 6 || nr > Epktlen){
383
		if(nr < 6)
384
			werrstr("short frame");
385
		else
386
			werrstr("long frame");
387
		deprint(2, "%s: asixbread %r (%ld)\n", argv0, nr);
388
		rbp->ndata = 0;
389
		return 0;
390
	}
391
	bp->rp = bp->data + Hdrsize;
392
	memmove(bp->rp, rbp->rp, nr);
393
	bp->ndata = nr;
394
	rbp->rp += 4 + nr;
395
	rbp->ndata -= (4 + nr);
396
	return bp->ndata;
397
}
398
 
399
static long
400
asixbwrite(Ether *e, Buf *bp)
401
{
402
	ulong len;
403
	long n;
404
 
405
	deprint(2, "%s: asixbwrite %d bytes\n", argv0, bp->ndata);
406
	assert(bp->rp - bp->data >= Hdrsize);
407
	bp->ndata &= 0xFFFF;
408
	len = (0xFFFF0000 & ~(bp->ndata<<16))  | bp->ndata;
409
	bp->rp -= 4;
410
	PUT4(bp->rp, len);
411
	bp->ndata += 4;
412
	if((bp->ndata % e->epout->maxpkt) == 0){
413
		PUT4(bp->rp+bp->ndata, 0xFFFF0000);
414
		bp->ndata += 4;
415
	}
416
	n = write(e->epout->dfd, bp->rp, bp->ndata);
417
	deprint(2, "%s: asixbwrite wrote %ld bytes\n", argv0, n);
418
	if(n <= 0)
419
		return n;
420
	return n;
421
}
422
 
423
static int
424
asixpromiscuous(Ether *e, int on)
425
{
426
	int rxctl;
427
 
428
	deprint(2, "%s: asixpromiscuous %d\n", argv0, on);
429
	rxctl = getrxctl(e->dev);
430
	if(on != 0)
431
		rxctl |= Rxctlprom;
432
	else
433
		rxctl &= ~Rxctlprom;
434
	return asixset(e->dev, Cwrxctl, rxctl);
435
}
436
 
437
static int
438
asixmulticast(Ether *e, uchar *addr, int on)
439
{
440
	int rxctl;
441
 
442
	USED(addr);
443
	USED(on);
444
	/* BUG: should write multicast filter */
445
	rxctl = getrxctl(e->dev);
446
	if(e->nmcasts != 0)
447
		rxctl |= Rxctlamall;
448
	else
449
		rxctl &= ~Rxctlamall;
450
	deprint(2, "%s: asixmulticast %d\n", argv0, e->nmcasts);
451
	return asixset(e->dev, Cwrxctl, rxctl);
452
}
453
 
454
static void
455
asixfree(Ether *ether)
456
{
457
	deprint(2, "%s: aixfree %#p\n", argv0, ether);
458
	free(ether->aux);
459
	ether->aux = nil;
460
}
461
 
462
int
463
asixreset(Ether *ether)
464
{
465
	Cinfo *ip;
466
	Dev *dev;
467
 
468
	dev = ether->dev;
469
	for(ip = cinfo; ip->vid != 0; ip++)
470
		if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
471
			ether->cid = ip->cid;
472
			if(ctlrinit(ether) < 0){
473
				deprint(2, "%s: asix init failed: %r\n", argv0);
474
				return -1;
475
			}
476
			deprint(2, "%s: asix reset done\n", argv0);
477
			ether->name = "asix";
478
			ether->aux = emallocz(sizeof(Buf), 1);
479
			ether->bufsize = Hdrsize+Maxpkt;
480
			ether->bread = asixbread;
481
			ether->bwrite = asixbwrite;
482
			ether->free = asixfree;
483
			ether->promiscuous = asixpromiscuous;
484
			ether->multicast = asixmulticast;
485
			ether->mbps = 100;	/* BUG */
486
			return 0;
487
		}
488
	return -1;
489
}