Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "../port/error.h"
8
#include "../port/netif.h"
9
 
10
#include "etherif.h"
11
#include "ether8390.h"
12
 
13
/*
14
 * Western Digital/Standard Microsystems Corporation cards (WD80[01]3).
15
 * Also handles 8216 cards (Elite Ultra).
16
 * Configuration code based on that provided by SMC a long time ago.
17
 */
18
enum {					/* 83C584 Bus Interface Controller */
19
	Msr		= 0x00,		/* Memory Select Register */
20
	Icr		= 0x01,		/* Interface Configuration Register */
21
	Iar		= 0x02,		/* I/O Address Register */
22
	Bio		= 0x03,		/* BIOS ROM Address Register */
23
	Ear		= 0x03,		/* EEROM Address Register (shared with Bio) */
24
	Irr		= 0x04,		/* Interrupt Request Register */
25
	Hcr		= 0x04,		/* 8216 hardware control */
26
	Laar		= 0x05,		/* LA Address Register */
27
	Ijr		= 0x06,		/* Initialisation Jumpers */
28
	Gp2		= 0x07,		/* General Purpose Data Register */
29
	Lar		= 0x08,		/* LAN Address Registers */
30
	Id		= 0x0E,		/* Card ID byte */
31
	Cksum		= 0x0F,		/* Checksum */
32
};
33
 
34
enum {					/* Msr */
35
	Rst		= 0x80,		/* software reset */
36
	Menb		= 0x40,		/* memory enable */
37
};
38
 
39
enum {					/* Icr */
40
	Bit16		= 0x01,		/* 16-bit bus */
41
	Other		= 0x02,		/* other register access */
42
	Ir2		= 0x04,		/* IR2 */
43
	Msz		= 0x08,		/* SRAM size */
44
	Rla		= 0x10,		/* recall LAN address */
45
	Rx7		= 0x20,		/* recall all but I/O and LAN address */
46
	Rio		= 0x40,		/* recall I/O address from EEROM */
47
	Sto		= 0x80,		/* non-volatile EEROM store */
48
};
49
 
50
enum {					/* Laar */
51
	ZeroWS16	= 0x20,		/* zero wait states for 16-bit ops */
52
	L16en		= 0x40,		/* enable 16-bit LAN operation */
53
	M16en		= 0x80,		/* enable 16-bit memory access */
54
};
55
 
56
enum {					/* Ijr */
57
	Ienable		= 0x01,		/* 8216 interrupt enable */
58
};
59
 
60
/*
61
 * Mapping from configuration bits to interrupt level.
62
 */
63
static int irq8003[8] = {
64
	9, 3, 5, 7, 10, 11, 15, 4,
65
};
66
 
67
static int irq8216[8] = {
68
	0, 9, 3, 5, 7, 10, 11, 15,
69
};
70
 
71
static void
72
reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8])
73
{
74
	Dp8390 *ctlr;
75
	ulong port;
76
 
77
	ctlr = ether->ctlr;
78
	port = ether->port;
79
 
80
	/*
81
	 * Check for old, dumb 8003E, which doesn't have an interface
82
	 * chip. Only Msr exists out of the 1st eight registers, reads
83
	 * of the others just alias the 2nd eight registers, the LAN
84
	 * address ROM. Can check Icr, Irr and Laar against the ethernet
85
	 * address read above and if they match it's an 8003E (or an
86
	 * 8003EBT, 8003S, 8003SH or 8003WT, doesn't matter), in which
87
	 * case the default irq gets used.
88
	 */
89
	if(memcmp(&ea[1], &ic[1], 5) == 0){
90
		memset(ic, 0, sizeof(ic));
91
		ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
92
	}
93
	else{
94
		/*
95
		 * As a final sanity check for the 8013EBT, which doesn't have
96
		 * the 83C584 interface chip, but has 2 real registers, write Gp2
97
		 * and if it reads back the same, it's not an 8013EBT.
98
		 */
99
		outb(port+Gp2, 0xAA);
100
		inb(port+Msr);				/* wiggle bus */
101
		if(inb(port+Gp2) != 0xAA){
102
			memset(ic, 0, sizeof(ic));
103
			ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
104
		}
105
		else
106
			ether->irq = irq8003[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)];
107
 
108
		/*
109
		 * Check if 16-bit card.
110
		 * If Bit16 is read/write, then it's an 8-bit card.
111
		 * If Bit16 is set, it's in a 16-bit slot.
112
		 */
113
		outb(port+Icr, ic[Icr]^Bit16);
114
		inb(port+Msr);				/* wiggle bus */
115
		if((inb(port+Icr) & Bit16) == (ic[Icr] & Bit16)){
116
			ctlr->width = 2;
117
			ic[Icr] &= ~Bit16;
118
		}
119
		outb(port+Icr, ic[Icr]);
120
 
121
		if(ctlr->width == 2 && (inb(port+Icr) & Bit16) == 0)
122
			ctlr->width = 1;
123
	}
124
 
125
	ether->mem = (ulong)KADDR((ic[Msr] & 0x3F)<<13);
126
	if(ctlr->width == 2)
127
		ether->mem |= (ic[Laar] & 0x1F)<<19;
128
	else
129
		ether->mem |= 0x80000;
130
 
131
	if(ic[Icr] & (1<<3))
132
		ether->size = 32*1024;
133
	if(ctlr->width == 2)
134
		ether->size <<= 1;
135
 
136
	/*
137
	 * Enable interface RAM, set interface width.
138
	 */
139
	outb(port+Msr, ic[Msr]|Menb);
140
	if(ctlr->width == 2)
141
		outb(port+Laar, ic[Laar]|L16en|M16en|ZeroWS16);
142
}
143
 
144
static void
145
reset8216(Ether* ether, uchar[8])
146
{
147
	uchar hcr, irq, x;
148
	ulong addr, port;
149
	Dp8390 *ctlr;
150
 
151
	ctlr = ether->ctlr;
152
	port = ether->port;
153
 
154
	ctlr->width = 2;
155
 
156
	/*
157
	 * Switch to the alternate register set and retrieve the memory
158
	 * and irq information.
159
	 */
160
	hcr = inb(port+Hcr);
161
	outb(port+Hcr, 0x80|hcr);
162
	addr = inb(port+0x0B) & 0xFF;
163
	irq = inb(port+0x0D);
164
	outb(port+Hcr, hcr);
165
 
166
	ether->mem = (ulong)KADDR(0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13));
167
	ether->size = 8192*(1<<((addr>>4) & 0x03));
168
	ether->irq = irq8216[((irq>>4) & 0x04)|((irq>>2) & 0x03)];
169
 
170
	/*
171
	 * Enable interface RAM, set interface width, and enable interrupts.
172
	 */
173
	x = inb(port+Msr) & ~Rst;
174
	outb(port+Msr, Menb|x);
175
	x = inb(port+Laar);
176
	outb(port+Laar, M16en|x);
177
	outb(port+Ijr, Ienable);
178
}
179
 
180
/*
181
 * Get configuration parameters, enable memory.
182
 * There are opportunities here for buckets of code, try to resist.
183
 */
184
static int
185
reset(Ether* ether)
186
{
187
	int i;
188
	uchar ea[Eaddrlen], ic[8], id, nullea[Eaddrlen], sum;
189
	ulong port;
190
	Dp8390 *ctlr;
191
 
192
	/*
193
	 * Set up the software configuration.
194
	 * Use defaults for port, irq, mem and size if not specified.
195
	 * Defaults are set for the dumb 8003E which can't be
196
	 * autoconfigured.
197
	 */
198
	if(ether->port == 0)
199
		ether->port = 0x280;
200
	if(ether->irq == 0)
201
		ether->irq = 3;
202
	if(ether->mem == 0)
203
		ether->mem = 0xD0000;
204
	if(ether->size == 0)
205
		ether->size = 8*1024;
206
	if(ioalloc(ether->port, 0x20, 0, "wd8003") < 0)
207
		return -1;
208
 
209
	/*
210
	 * Look for the interface. Read the LAN address ROM
211
	 * and validate the checksum - the sum of all 8 bytes
212
	 * should be 0xFF.
213
	 * At the same time, get the (possible) interface chip
214
	 * registers, they'll be used later to check for aliasing.
215
	 */
216
	port = ether->port;
217
	sum = 0;
218
	for(i = 0; i < sizeof(ea); i++){
219
		ea[i] = inb(port+Lar+i);
220
		sum += ea[i];
221
		ic[i] = inb(port+i);
222
	}
223
	id = inb(port+Id);
224
	sum += id;
225
	sum += inb(port+Cksum);
226
	if(sum != 0xFF){
227
		iofree(ether->port);
228
		return -1;
229
	}
230
 
231
	ether->ctlr = malloc(sizeof(Dp8390));
232
	ctlr = ether->ctlr;
233
	if(ctlr == nil)
234
		error(Enomem);
235
	ctlr->ram = 1;
236
 
237
	if((id & 0xFE) == 0x2A)
238
		reset8216(ether, ic);
239
	else
240
		reset8003(ether, ea, ic);
241
 
242
	/*
243
	 * Set the DP8390 ring addresses.
244
	 */
245
	ctlr->port = port+0x10;
246
	ctlr->tstart = 0;
247
	ctlr->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
248
	ctlr->pstop = HOWMANY(ether->size, Dp8390BufSz);
249
 
250
	/*
251
	 * Finally, init the 8390, set the ethernet address
252
	 * and claim the memory used.
253
	 */
254
	dp8390reset(ether);
255
	memset(nullea, 0, Eaddrlen);
256
	if(memcmp(nullea, ether->ea, Eaddrlen) == 0){
257
		for(i = 0; i < sizeof(ether->ea); i++)
258
			ether->ea[i] = ea[i];
259
	}
260
	dp8390setea(ether);
261
 
262
	if(umbrwmalloc(PADDR(ether->mem), ether->size, 0) == 0)
263
		print("ether8003: warning - 0x%luX unavailable\n",
264
			PADDR(ether->mem));
265
 
266
	return 0;
267
}
268
 
269
void
270
ether8003link(void)
271
{
272
	addethercard("WD8003", reset);
273
}