This source file includes following definitions.
- wd_probe
- wdprobe1
- wd_open
- wd_reset_8390
- wd_block_input
- wd_block_output
- wd_close_card
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 static char *version =
18 "wd.c:v0.99-14 11/21/93 Donald Becker (becker@super.org)\n";
19
20 #include <linux/config.h>
21 #include <linux/kernel.h>
22 #include <linux/sched.h>
23 #include <linux/errno.h>
24 #include <linux/string.h>
25 #include <asm/io.h>
26 #include <asm/system.h>
27
28 #include <linux/netdevice.h>
29 #include "8390.h"
30
31
32 #ifndef HAVE_PORTRESERVE
33 #define check_region(ioaddr, size) 0
34 #define snarf_region(ioaddr, size) do ; while (0)
35 #endif
36
37 int wd_probe(struct device *dev);
38 int wdprobe1(int ioaddr, struct device *dev);
39
40 static int wd_open(struct device *dev);
41 static void wd_reset_8390(struct device *dev);
42 static int wd_block_input(struct device *dev, int count,
43 char *buf, int ring_offset);
44 static void wd_block_output(struct device *dev, int count,
45 const unsigned char *buf, const start_page);
46 static int wd_close_card(struct device *dev);
47
48
49 #define WD_START_PG 0x00
50 #define WD03_STOP_PG 0x20
51 #define WD13_STOP_PG 0x40
52
53 #define WD_CMDREG 0
54 #define WD_RESET 0x80
55 #define WD_MEMENB 0x40
56 #define WD_CMDREG5 5
57 #define ISA16 0x80
58 #define NIC16 0x40
59 #define WD_NIC_OFFSET 16
60
61
62
63
64
65
66
67
68
69 int wd_probe(struct device *dev)
70 {
71 int *port, ports[] = {0x300, 0x280, 0x380, 0x240, 0};
72 short ioaddr = dev->base_addr;
73
74 if (ioaddr < 0)
75 return ENXIO;
76 if (ioaddr > 0x100)
77 return ! wdprobe1(ioaddr, dev);
78
79 for (port = &ports[0]; *port; port++) {
80 if (check_region(*port, 32))
81 continue;
82 if (inb(*port + 8) != 0xff
83 && inb(*port + 9) != 0xff
84 && wdprobe1(*port, dev))
85 return 0;
86 }
87 dev->base_addr = ioaddr;
88 return ENODEV;
89 }
90
91 int wdprobe1(int ioaddr, struct device *dev)
92 {
93 int i;
94 unsigned char *station_addr = dev->dev_addr;
95 int checksum = 0;
96 int ancient = 0;
97 int word16 = 0;
98 char *model_name;
99
100 for (i = 0; i < 8; i++)
101 checksum += inb(ioaddr + 8 + i);
102 if ((checksum & 0xff) != 0xFF)
103 return 0;
104
105 printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
106 for (i = 0; i < 6; i++)
107 printk(" %2.2X", station_addr[i] = inb(ioaddr + 8 + i));
108
109
110
111
112
113
114 if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
115 unsigned char reg5 = inb(ioaddr+5);
116
117 switch (inb(ioaddr+2)) {
118 case 0x03: word16 = 0; model_name = "PDI8023-8"; break;
119 case 0x05: word16 = 0; model_name = "PDUC8023"; break;
120 case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
121
122 default: word16 = 0; model_name = "PDI8023"; break;
123 }
124 dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
125 dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
126 } else {
127
128
129
130
131
132
133 for (i = 0; i < 6; i++)
134 if (inb(ioaddr+i) != inb(ioaddr+8+i))
135 break;
136 if (i >= 6) {
137 ancient = 1;
138 model_name = "WD8003-old";
139 word16 = 0;
140 } else {
141 int tmp = inb(ioaddr+1);
142 outb( tmp ^ 0x01, ioaddr+1 );
143 if (((inb( ioaddr+1) & 0x01) == 0x01)
144 && (tmp & 0x01) == 0x01 ) {
145 int asic_reg5 = inb(ioaddr+WD_CMDREG5);
146
147 outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
148 outb(tmp, ioaddr+1);
149 model_name = "WD8013";
150 word16 = 1;
151 } else {
152 model_name = "WD8003";
153 word16 = 0;
154 }
155 outb(tmp, ioaddr+1);
156 }
157 #ifndef final_version
158 if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
159 printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
160 word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
161 #endif
162 }
163
164 #if defined(WD_SHMEM) && WD_SHMEM > 0x80000
165
166 dev->mem_start = WD_SHMEM;
167 #else
168 if (dev->mem_start == 0) {
169
170 int reg0 = inb(ioaddr);
171 if (reg0 == 0xff || reg0 == 0) {
172
173 dev->mem_start = 0xd0000;
174 printk(" assigning address %#lx", dev->mem_start);
175 } else {
176 int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
177
178 if (high_addr_bits == 0x1f || word16 == 0)
179 high_addr_bits = 0x01;
180 dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
181 }
182 }
183 #endif
184
185
186 dev->base_addr = ioaddr+WD_NIC_OFFSET;
187
188 if (dev->irq < 2) {
189 int irqmap[] = {9,3,5,7,10,11,15,4};
190 int reg1 = inb(ioaddr+1);
191 int reg4 = inb(ioaddr+4);
192 if (ancient || reg1 == 0xff) {
193 short nic_addr = ioaddr+WD_NIC_OFFSET;
194
195
196
197
198 outb_p(E8390_NODMA + E8390_STOP, nic_addr);
199 outb(0x00, nic_addr+EN0_IMR);
200 autoirq_setup(0);
201 outb_p(0xff, nic_addr + EN0_IMR);
202 outb_p(0x00, nic_addr + EN0_RCNTLO);
203 outb_p(0x00, nic_addr + EN0_RCNTHI);
204 outb(E8390_RREAD+E8390_START, nic_addr);
205 dev->irq = autoirq_report(2);
206 outb_p(0x00, nic_addr+EN0_IMR);
207
208 if (ei_debug > 2)
209 printk(" autoirq is %d", dev->irq);
210 if (dev->irq < 2)
211 dev->irq = word16 ? 10 : 5;
212 } else
213 dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
214 } else if (dev->irq == 2)
215 dev->irq = 9;
216
217
218
219 if (request_irq(dev->irq, ei_interrupt, 0, "wd")) {
220 printk (" unable to get IRQ %d.\n", dev->irq);
221 return 0;
222 }
223
224
225 snarf_region(ioaddr, 32);
226 ethdev_init(dev);
227
228 ei_status.name = model_name;
229 ei_status.word16 = word16;
230 ei_status.tx_start_page = WD_START_PG;
231 ei_status.rx_start_page = WD_START_PG + TX_PAGES;
232 ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
233
234
235 dev->rmem_start = dev->mem_start + TX_PAGES*256;
236 dev->mem_end = dev->rmem_end
237 = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
238
239 printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
240 model_name, dev->irq, dev->mem_start, dev->mem_end-1);
241 if (ei_debug > 0)
242 printk(version);
243
244 ei_status.reset_8390 = &wd_reset_8390;
245 ei_status.block_input = &wd_block_input;
246 ei_status.block_output = &wd_block_output;
247 dev->open = &wd_open;
248 dev->stop = &wd_close_card;
249 NS8390_init(dev, 0);
250
251 return dev->base_addr;
252 }
253
254 static int
255 wd_open(struct device *dev)
256 {
257 int ioaddr = dev->base_addr - WD_NIC_OFFSET;
258
259
260
261 ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
262 ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
263
264 if (ei_status.word16)
265 outb(ei_status.reg5, ioaddr+WD_CMDREG5);
266 outb(ei_status.reg0, ioaddr);
267
268 return ei_open(dev);
269 }
270
271 static void
272 wd_reset_8390(struct device *dev)
273 {
274 int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET;
275
276 outb(WD_RESET, wd_cmd_port);
277 if (ei_debug > 1) printk("resetting the WD80x3 t=%lu...", jiffies);
278 ei_status.txing = 0;
279
280
281 outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
282 if (ei_status.word16)
283 outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
284
285 if (ei_debug > 1) printk("reset done\n");
286 return;
287 }
288
289
290
291
292
293
294 static int
295 wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
296 {
297 int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET;
298 long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
299
300
301
302 if (count == 4) {
303 if (ei_status.word16)
304 outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
305 ((int*)buf)[0] = ((int*)xfer_start)[0];
306 return 0;
307 }
308
309 if (xfer_start + count > dev->rmem_end) {
310
311 int semi_count = dev->rmem_end - xfer_start;
312 memcpy(buf, (char *)xfer_start, semi_count);
313 count -= semi_count;
314 memcpy(buf + semi_count, (char *)dev->rmem_start, count);
315 } else
316 memcpy(buf, (char *)xfer_start, count);
317
318
319 if (ei_status.word16)
320 outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
321
322 return 0;
323 }
324
325 static void
326 wd_block_output(struct device *dev, int count, const unsigned char *buf,
327 int start_page)
328 {
329 int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET;
330 long shmem = dev->mem_start + ((start_page - WD_START_PG)<<8);
331
332
333 if (ei_status.word16) {
334
335 outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
336 memcpy((char *)shmem, buf, count);
337 outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
338 } else
339 memcpy((char *)shmem, buf, count);
340 }
341
342
343 static int
344 wd_close_card(struct device *dev)
345 {
346 int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET;
347
348 if (ei_debug > 1)
349 printk("%s: Shutting down ethercard.\n", dev->name);
350 NS8390_init(dev, 0);
351
352
353 outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
354
355
356 outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
357
358 return 0;
359 }
360
361
362
363
364
365
366
367
368
369