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
 * 3C589 and 3C562.
3
 * To do:
4
 *	check xcvr10Base2 still works (is GlobalReset necessary?).
5
 */
6
#include "u.h"
7
#include "../port/lib.h"
8
#include "mem.h"
9
#include "dat.h"
10
#include "fns.h"
11
#include "io.h"
12
#include "../port/error.h"
13
#include "../port/netif.h"
14
 
15
#include "etherif.h"
16
 
17
enum {						/* all windows */
18
	CommandR		= 0x000E,
19
	IntStatusR		= 0x000E,
20
};
21
 
22
enum {						/* Commands */
23
	GlobalReset		= 0x0000,
24
	SelectRegisterWindow	= 0x0001,
25
	RxReset			= 0x0005,
26
	TxReset			= 0x000B,
27
	AcknowledgeInterrupt	= 0x000D,
28
};
29
 
30
enum {						/* IntStatus bits */
31
	commandInProgress	= 0x1000,
32
};
33
 
34
#define COMMAND(port, cmd, a)	outs((port)+CommandR, ((cmd)<<11)|(a))
35
#define STATUS(port)		ins((port)+IntStatusR)
36
 
37
enum {						/* Window 0 - setup */
38
	Wsetup			= 0x0000,
39
						/* registers */
40
	ManufacturerID		= 0x0000,	/* 3C5[08]*, 3C59[27] */
41
	ProductID		= 0x0002,	/* 3C5[08]*, 3C59[27] */
42
	ConfigControl		= 0x0004,	/* 3C5[08]*, 3C59[27] */
43
	AddressConfig		= 0x0006,	/* 3C5[08]*, 3C59[27] */
44
	ResourceConfig		= 0x0008,	/* 3C5[08]*, 3C59[27] */
45
	EepromCommand		= 0x000A,
46
	EepromData		= 0x000C,
47
						/* AddressConfig Bits */
48
	autoSelect9		= 0x0080,
49
	xcvrMask9		= 0xC000,
50
						/* ConfigControl bits */
51
	Ena			= 0x0001,
52
	base10TAvailable9	= 0x0200,
53
	coaxAvailable9		= 0x1000,
54
	auiAvailable9		= 0x2000,
55
						/* EepromCommand bits */
56
	EepromReadRegister	= 0x0080,
57
	EepromBusy		= 0x8000,
58
};
59
 
60
enum {						/* Window 1 - operating set */
61
	Wop			= 0x0001,
62
};
63
 
64
enum {						/* Window 3 - FIFO management */
65
	Wfifo			= 0x0003,
66
						/* registers */
67
	InternalConfig		= 0x0000,	/* 3C509B, 3C589, 3C59[0257] */
68
						/* InternalConfig bits */
69
	xcvr10BaseT		= 0x00000000,
70
	xcvr10Base2		= 0x00300000,
71
};
72
 
73
enum {						/* Window 4 - diagnostic */
74
	Wdiagnostic		= 0x0004,
75
						/* registers */
76
	MediaStatus		= 0x000A,
77
						/* MediaStatus bits */
78
	linkBeatDetect		= 0x0800,
79
};
80
 
81
extern int etherelnk3reset(Ether*);
82
 
83
static char *tcmpcmcia[] = {
84
	"3C589",			/* 3COM 589[ABCD] */
85
	"3C562",			/* 3COM 562 */
86
	"589E",				/* 3COM Megahertz 589E */
87
	nil,
88
};
89
 
90
static int
91
configASIC(Ether* ether, int port, int xcvr)
92
{
93
	int x;
94
 
95
	/* set Window 0 configuration registers */
96
	COMMAND(port, SelectRegisterWindow, Wsetup);
97
	outs(port+ConfigControl, Ena);
98
 
99
	/* IRQ must be 3 on 3C589/3C562 */
100
	outs(port + ResourceConfig, 0x3F00);
101
 
102
	x = ins(port+AddressConfig) & ~xcvrMask9;
103
	x |= (xcvr>>20)<<14;
104
	outs(port+AddressConfig, x);
105
 
106
	COMMAND(port, TxReset, 0);
107
	while(STATUS(port) & commandInProgress)
108
		;
109
	COMMAND(port, RxReset, 0);
110
	while(STATUS(port) & commandInProgress)
111
		;
112
 
113
	return etherelnk3reset(ether);
114
}
115
 
116
static int
117
reset(Ether* ether)
118
{
119
	int i, t, slot;
120
	char *type;
121
	int port;
122
	enum { WantAny, Want10BT, Want10B2 };
123
	int want;
124
	uchar ea[6];
125
	char *p;
126
 
127
	if(ether->irq == 0)
128
		ether->irq = 10;
129
	if(ether->port == 0)
130
		ether->port = 0x240;
131
	port = ether->port;
132
 
133
	if(ioalloc(port, 0x10, 0, "3C589") < 0)
134
		return -1;
135
 
136
	type = nil;
137
	slot = -1;
138
	for(i = 0; tcmpcmcia[i] != nil; i++){
139
		type = tcmpcmcia[i];
140
		if((slot = pcmspecial(type, ether)) >= 0)
141
			break;
142
	}
143
	ether->type = type;	/* must be set before calling configASIC */
144
	if(slot < 0){
145
		iofree(port);
146
		return -1;
147
	}
148
 
149
	/*
150
	 * Read Ethernet address from card memory
151
	 * on 3C562, but only if the user has not 
152
	 * overridden it.
153
	 */
154
	memset(ea, 0, sizeof ea);
155
	if(memcmp(ea, ether->ea, 6) == 0 && strcmp(type, "3C562") == 0) {
156
		if(pcmcistuple(slot, 0x88, -1, ea, 6) == 6) {
157
			for(i = 0; i < 6; i += 2){
158
				t = ea[i];
159
				ea[i] = ea[i+1];
160
				ea[i+1] = t;
161
			}
162
			memmove(ether->ea, ea, 6);
163
		}
164
	}
165
	/*
166
	 * Allow user to specify desired media in plan9.ini
167
	 */
168
	want = WantAny;
169
	for(i = 0; i < ether->nopt; i++){
170
		if(cistrncmp(ether->opt[i], "media=", 6) != 0)
171
			continue;
172
		p = ether->opt[i]+6;
173
		if(cistrcmp(p, "10base2") == 0)
174
			want = Want10B2;
175
		else if(cistrcmp(p, "10baseT") == 0)
176
			want = Want10BT;
177
	}
178
 
179
	/* try configuring as a 10BaseT */
180
	if(want==WantAny || want==Want10BT){
181
		if(configASIC(ether, port, xcvr10BaseT) < 0){
182
			pcmspecialclose(slot);
183
			iofree(port);
184
			return -1;
185
		}
186
		delay(100);
187
		COMMAND(port, SelectRegisterWindow, Wdiagnostic);
188
		if((ins(port+MediaStatus)&linkBeatDetect) || want==Want10BT){
189
			COMMAND(port, SelectRegisterWindow, Wop);
190
			print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, type);
191
			return 0;
192
		}
193
	}
194
 
195
	/* try configuring as a 10base2 */
196
	if(want==WantAny || want==Want10B2){
197
		COMMAND(port, GlobalReset, 0);
198
		if(configASIC(ether, port, xcvr10Base2) < 0){
199
			pcmspecialclose(slot);
200
			iofree(port);
201
			return -1;
202
		}
203
		print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, type);
204
		return 0;
205
	}
206
	return -1;		/* not reached */
207
}
208
 
209
void
210
ether589link(void)
211
{
212
	addethercard("3C589", reset);
213
	addethercard("3C562", reset);
214
	addethercard("589E", reset);
215
}