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