FreeBSD/Linux Kernel Cross Reference
sys/pc/ether8003.c
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 ctlr->ram = 1;
234
235 if((id & 0xFE) == 0x2A)
236 reset8216(ether, ic);
237 else
238 reset8003(ether, ea, ic);
239
240 /*
241 * Set the DP8390 ring addresses.
242 */
243 ctlr->port = port+0x10;
244 ctlr->tstart = 0;
245 ctlr->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
246 ctlr->pstop = HOWMANY(ether->size, Dp8390BufSz);
247
248 /*
249 * Finally, init the 8390, set the ethernet address
250 * and claim the memory used.
251 */
252 dp8390reset(ether);
253 memset(nullea, 0, Eaddrlen);
254 if(memcmp(nullea, ether->ea, Eaddrlen) == 0){
255 for(i = 0; i < sizeof(ether->ea); i++)
256 ether->ea[i] = ea[i];
257 }
258 dp8390setea(ether);
259
260 if(umbrwmalloc(PADDR(ether->mem), ether->size, 0) == 0)
261 print("ether8003: warning - 0x%luX unavailable\n",
262 PADDR(ether->mem));
263
264 return 0;
265 }
266
267 void
268 ether8003link(void)
269 {
270 addethercard("WD8003", reset);
271 }
Cache object: 434a5b2d85ad58d15b8708742c194096
|