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