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