OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [net/] [wd.c] - Blame information for rev 1765

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/* wd.c: A WD80x3 ethernet driver for linux. */
2
/*
3
        Written 1993-94 by Donald Becker.
4
 
5
        Copyright 1993 United States Government as represented by the
6
        Director, National Security Agency.
7
 
8
        This software may be used and distributed according to the terms
9
        of the GNU Public License, incorporated herein by reference.
10
 
11
        The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
12
        Center of Excellence in Space Data and Information Sciences
13
           Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
14
 
15
        This is a driver for WD8003 and WD8013 "compatible" ethercards.
16
 
17
        Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
18
 
19
        Changelog:
20
 
21
        Paul Gortmaker  : multiple card support for module users, support
22
                          for non-standard memory sizes.
23
 
24
 
25
*/
26
 
27
static const char *version =
28
        "wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
29
 
30
#include <linux/module.h>
31
 
32
#include <linux/kernel.h>
33
#include <linux/sched.h>
34
#include <linux/errno.h>
35
#include <linux/string.h>
36
#include <asm/io.h>
37
#include <asm/system.h>
38
 
39
#include <linux/netdevice.h>
40
#include <linux/etherdevice.h>
41
#include "8390.h"
42
 
43
/* A zero-terminated list of I/O addresses to be probed. */
44
static unsigned int wd_portlist[] =
45
{0x300, 0x280, 0x380, 0x240, 0};
46
 
47
int wd_probe(struct device *dev);
48
int wd_probe1(struct device *dev, int ioaddr);
49
 
50
static int wd_open(struct device *dev);
51
static void wd_reset_8390(struct device *dev);
52
static void wd_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
53
                                                int ring_page);
54
static void wd_block_input(struct device *dev, int count,
55
                                                  struct sk_buff *skb, int ring_offset);
56
static void wd_block_output(struct device *dev, int count,
57
                                                        const unsigned char *buf, const int start_page);
58
static int wd_close_card(struct device *dev);
59
 
60
 
61
#define WD_START_PG             0x00    /* First page of TX buffer */
62
#define WD03_STOP_PG    0x20    /* Last page +1 of RX ring */
63
#define WD13_STOP_PG    0x40    /* Last page +1 of RX ring */
64
 
65
#define WD_CMDREG               0                /* Offset to ASIC command register. */
66
#define  WD_RESET               0x80    /* Board reset, in WD_CMDREG. */
67
#define  WD_MEMENB              0x40    /* Enable the shared memory. */
68
#define WD_CMDREG5              5               /* Offset to 16-bit-only ASIC register 5. */
69
#define  ISA16                  0x80    /* Enable 16 bit access from the ISA bus. */
70
#define  NIC16                  0x40    /* Enable 16 bit access from the 8390. */
71
#define WD_NIC_OFFSET   16              /* Offset to the 8390 from the base_addr. */
72
#define WD_IO_EXTENT    32
73
 
74
 
75
/*      Probe for the WD8003 and WD8013.  These cards have the station
76
        address PROM at I/O ports <base>+8 to <base>+13, with a checksum
77
        following. A Soundblaster can have the same checksum as an WDethercard,
78
        so we have an extra exclusionary check for it.
79
 
80
        The wd_probe1() routine initializes the card and fills the
81
        station address field. */
82
 
83
#ifdef HAVE_DEVLIST
84
struct netdev_entry wd_drv =
85
{"wd", wd_probe1, WD_IO_EXTENT, wd_portlist};
86
#else
87
 
88
int wd_probe(struct device *dev)
89
{
90
        int i;
91
        int base_addr = dev ? dev->base_addr : 0;
92
 
93
        if (base_addr > 0x1ff)          /* Check a single specified location. */
94
                return wd_probe1(dev, base_addr);
95
        else if (base_addr != 0) /* Don't probe at all. */
96
                return ENXIO;
97
 
98
        for (i = 0; wd_portlist[i]; i++) {
99
                int ioaddr = wd_portlist[i];
100
                if (check_region(ioaddr, WD_IO_EXTENT))
101
                        continue;
102
                if (wd_probe1(dev, ioaddr) == 0)
103
                        return 0;
104
        }
105
 
106
        return ENODEV;
107
}
108
#endif
109
 
110
int wd_probe1(struct device *dev, int ioaddr)
111
{
112
        int i;
113
        int checksum = 0;
114
        int ancient = 0;                 /* An old card without config registers. */
115
        int word16 = 0;                          /* 0 = 8 bit, 1 = 16 bit */
116
        const char *model_name;
117
        static unsigned version_printed = 0;
118
 
119
        for (i = 0; i < 8; i++)
120
                checksum += inb(ioaddr + 8 + i);
121
        if (inb(ioaddr + 8) == 0xff     /* Extra check to avoid soundcard. */
122
                || inb(ioaddr + 9) == 0xff
123
                || (checksum & 0xff) != 0xFF)
124
                return ENODEV;
125
 
126
        /* We should have a "dev" from Space.c or the static module table. */
127
        if (dev == NULL) {
128
                printk("wd.c: Passed a NULL device.\n");
129
                dev = init_etherdev(0, 0);
130
        }
131
 
132
        /* Check for semi-valid mem_start/end values if supplied. */
133
        if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) {
134
                printk(KERN_WARNING "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n");
135
                dev->mem_start = 0;
136
                dev->mem_end = 0;
137
        }
138
 
139
        if (ei_debug  &&  version_printed++ == 0)
140
                printk(version);
141
 
142
        printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
143
        for (i = 0; i < 6; i++)
144
                printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
145
 
146
        /* The following PureData probe code was contributed by
147
           Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
148
           configuration differently from others so we have to check for them.
149
           This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
150
           */
151
        if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
152
                unsigned char reg5 = inb(ioaddr+5);
153
 
154
                switch (inb(ioaddr+2)) {
155
                case 0x03: word16 = 0; model_name = "PDI8023-8"; break;
156
                case 0x05: word16 = 0; model_name = "PDUC8023";  break;
157
                case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
158
                        /* Either 0x01 (dumb) or they've released a new version. */
159
                default:         word16 = 0; model_name = "PDI8023";     break;
160
                }
161
                dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
162
                dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
163
        } else {                                                                /* End of PureData probe */
164
                /* This method of checking for a 16-bit board is borrowed from the
165
                   we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
166
                   I'm comparing the two method in alpha test to make certain they
167
                   return the same result. */
168
                /* Check for the old 8 bit board - it has register 0/8 aliasing.
169
                   Do NOT check i>=6 here -- it hangs the old 8003 boards! */
170
                for (i = 0; i < 6; i++)
171
                        if (inb(ioaddr+i) != inb(ioaddr+8+i))
172
                                break;
173
                if (i >= 6) {
174
                        ancient = 1;
175
                        model_name = "WD8003-old";
176
                        word16 = 0;
177
                } else {
178
                        int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
179
                        outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
180
                        if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
181
                                && (tmp & 0x01) == 0x01 ) {                             /* In a 16 slot. */
182
                                int asic_reg5 = inb(ioaddr+WD_CMDREG5);
183
                                /* Magic to set ASIC to word-wide mode. */
184
                                outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
185
                                outb(tmp, ioaddr+1);
186
                                model_name = "WD8013";
187
                                word16 = 1;             /* We have a 16bit board here! */
188
                        } else {
189
                                model_name = "WD8003";
190
                                word16 = 0;
191
                        }
192
                        outb(tmp, ioaddr+1);                    /* Restore original reg1 value. */
193
                }
194
#ifndef final_version
195
                if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
196
                        printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
197
                                   word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
198
#endif
199
        }
200
 
201
#if defined(WD_SHMEM) && WD_SHMEM > 0x80000
202
        /* Allow a compile-time override.        */
203
        dev->mem_start = WD_SHMEM;
204
#else
205
        if (dev->mem_start == 0) {
206
                /* Sanity and old 8003 check */
207
                int reg0 = inb(ioaddr);
208
                if (reg0 == 0xff || reg0 == 0) {
209
                        /* Future plan: this could check a few likely locations first. */
210
                        dev->mem_start = 0xd0000;
211
                        printk(" assigning address %#lx", dev->mem_start);
212
                } else {
213
                        int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
214
                        /* Some boards don't have the register 5 -- it returns 0xff. */
215
                        if (high_addr_bits == 0x1f || word16 == 0)
216
                                high_addr_bits = 0x01;
217
                        dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
218
                }
219
        }
220
#endif
221
 
222
        /* The 8390 isn't at the base address -- the ASIC regs are there! */
223
        dev->base_addr = ioaddr+WD_NIC_OFFSET;
224
 
225
        if (dev->irq < 2) {
226
                int irqmap[] = {9,3,5,7,10,11,15,4};
227
                int reg1 = inb(ioaddr+1);
228
                int reg4 = inb(ioaddr+4);
229
                if (ancient || reg1 == 0xff) {  /* Ack!! No way to read the IRQ! */
230
                        short nic_addr = ioaddr+WD_NIC_OFFSET;
231
 
232
                        /* We have an old-style ethercard that doesn't report its IRQ
233
                           line.  Do autoirq to find the IRQ line. Note that this IS NOT
234
                           a reliable way to trigger an interrupt. */
235
                        outb_p(E8390_NODMA + E8390_STOP, nic_addr);
236
                        outb(0x00, nic_addr+EN0_IMR);   /* Disable all intrs. */
237
                        autoirq_setup(0);
238
                        outb_p(0xff, nic_addr + EN0_IMR);       /* Enable all interrupts. */
239
                        outb_p(0x00, nic_addr + EN0_RCNTLO);
240
                        outb_p(0x00, nic_addr + EN0_RCNTHI);
241
                        outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
242
                        dev->irq = autoirq_report(2);
243
                        outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */
244
 
245
                        if (ei_debug > 2)
246
                                printk(" autoirq is %d", dev->irq);
247
                        if (dev->irq < 2)
248
                                dev->irq = word16 ? 10 : 5;
249
                } else
250
                        dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
251
        } else if (dev->irq == 2)               /* Fixup bogosity: IRQ2 is really IRQ9 */
252
                dev->irq = 9;
253
 
254
        /* Snarf the interrupt now.  There's no point in waiting since we cannot
255
           share and the board will usually be enabled. */
256
        if (request_irq(dev->irq, ei_interrupt, 0, model_name, NULL)) {
257
                printk (" unable to get IRQ %d.\n", dev->irq);
258
                return EAGAIN;
259
        }
260
 
261
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
262
        if (ethdev_init(dev)) {
263
                printk (" unable to get memory for dev->priv.\n");
264
                free_irq(dev->irq, NULL);
265
                return -ENOMEM;
266
        }
267
 
268
        /* OK, were are certain this is going to work.  Setup the device. */
269
        request_region(ioaddr, WD_IO_EXTENT, model_name);
270
 
271
        ei_status.name = model_name;
272
        ei_status.word16 = word16;
273
        ei_status.tx_start_page = WD_START_PG;
274
        ei_status.rx_start_page = WD_START_PG + TX_PAGES;
275
 
276
        /* Don't map in the shared memory until the board is actually opened. */
277
        dev->rmem_start = dev->mem_start + TX_PAGES*256;
278
 
279
        /* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
280
        if (dev->mem_end != 0) {
281
                ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
282
        } else {
283
                ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
284
                dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
285
        }
286
        dev->rmem_end = dev->mem_end;
287
 
288
        printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
289
                   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
290
 
291
        ei_status.reset_8390 = &wd_reset_8390;
292
        ei_status.block_input = &wd_block_input;
293
        ei_status.block_output = &wd_block_output;
294
        ei_status.get_8390_hdr = &wd_get_8390_hdr;
295
        dev->open = &wd_open;
296
        dev->stop = &wd_close_card;
297
        NS8390_init(dev, 0);
298
 
299
#if 1
300
        /* Enable interrupt generation on softconfig cards -- M.U */
301
        /* .. but possibly potentially unsafe - Donald */
302
        if (inb(ioaddr+14) & 0x20)
303
                outb(inb(ioaddr+4)|0x80, ioaddr+4);
304
#endif
305
 
306
        return 0;
307
}
308
 
309
static int
310
wd_open(struct device *dev)
311
{
312
  int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
313
 
314
  /* Map in the shared memory. Always set register 0 last to remain
315
         compatible with very old boards. */
316
  ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
317
  ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
318
 
319
  if (ei_status.word16)
320
          outb(ei_status.reg5, ioaddr+WD_CMDREG5);
321
  outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
322
 
323
  ei_open(dev);
324
  MOD_INC_USE_COUNT;
325
  return 0;
326
}
327
 
328
static void
329
wd_reset_8390(struct device *dev)
330
{
331
        int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
332
 
333
        outb(WD_RESET, wd_cmd_port);
334
        if (ei_debug > 1) printk("resetting the WD80x3 t=%lu...", jiffies);
335
        ei_status.txing = 0;
336
 
337
        /* Set up the ASIC registers, just in case something changed them. */
338
        outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
339
        if (ei_status.word16)
340
                outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
341
 
342
        if (ei_debug > 1) printk("reset done\n");
343
        return;
344
}
345
 
346
/* Grab the 8390 specific header. Similar to the block_input routine, but
347
   we don't need to be concerned with ring wrap as the header will be at
348
   the start of a page, so we optimize accordingly. */
349
 
350
static void
351
wd_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
352
{
353
 
354
        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
355
        unsigned long hdr_start = dev->mem_start + ((ring_page - WD_START_PG)<<8);
356
 
357
        /* We'll always get a 4 byte header read followed by a packet read, so
358
           we enable 16 bit mode before the header, and disable after the body. */
359
        if (ei_status.word16)
360
                outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
361
 
362
#ifdef notdef
363
        /* Officially this is what we are doing, but the readl() is faster */
364
        memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
365
#else
366
        ((unsigned int*)hdr)[0] = readl(hdr_start);
367
#endif
368
}
369
 
370
/* Block input and output are easy on shared memory ethercards, and trivial
371
   on the Western digital card where there is no choice of how to do it.
372
   The only complications are that the ring buffer wraps, and need to map
373
   switch between 8- and 16-bit modes. */
374
 
375
static void
376
wd_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
377
{
378
        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
379
        unsigned long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
380
 
381
        if (xfer_start + count > dev->rmem_end) {
382
                /* We must wrap the input move. */
383
                int semi_count = dev->rmem_end - xfer_start;
384
                memcpy_fromio(skb->data, xfer_start, semi_count);
385
                count -= semi_count;
386
                memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
387
        } else {
388
                /* Packet is in one chunk -- we can copy + cksum. */
389
                eth_io_copy_and_sum(skb, xfer_start, count, 0);
390
        }
391
 
392
        /* Turn off 16 bit access so that reboot works.  ISA brain-damage */
393
        if (ei_status.word16)
394
                outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
395
}
396
 
397
static void
398
wd_block_output(struct device *dev, int count, const unsigned char *buf,
399
                                int start_page)
400
{
401
        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
402
        long shmem = dev->mem_start + ((start_page - WD_START_PG)<<8);
403
 
404
 
405
        if (ei_status.word16) {
406
                /* Turn on and off 16 bit access so that reboot works. */
407
                outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
408
                memcpy_toio(shmem, buf, count);
409
                outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
410
        } else
411
                memcpy_toio(shmem, buf, count);
412
}
413
 
414
 
415
static int
416
wd_close_card(struct device *dev)
417
{
418
        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
419
 
420
        if (ei_debug > 1)
421
                printk("%s: Shutting down ethercard.\n", dev->name);
422
        ei_close(dev);
423
 
424
        /* Change from 16-bit to 8-bit shared memory so reboot works. */
425
        if (ei_status.word16)
426
                outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
427
 
428
        /* And disable the shared memory. */
429
        outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
430
 
431
        MOD_DEC_USE_COUNT;
432
 
433
        return 0;
434
}
435
 
436
 
437
#ifdef MODULE
438
#define MAX_WD_CARDS    4       /* Max number of wd cards per module */
439
#define NAMELEN         8       /* # of chars for storing dev->name */
440
static char namelist[NAMELEN * MAX_WD_CARDS] = { 0, };
441
static struct device dev_wd[MAX_WD_CARDS] = {
442
        {
443
                NULL,           /* assign a chunk of namelist[] below */
444
                0, 0, 0, 0,
445
                0, 0,
446
                0, 0, 0, NULL, NULL
447
        },
448
};
449
 
450
static int io[MAX_WD_CARDS] = { 0, };
451
static int irq[MAX_WD_CARDS]  = { 0, };
452
static int mem[MAX_WD_CARDS] = { 0, };
453
static int mem_end[MAX_WD_CARDS] = { 0, };       /* for non std. mem size */
454
 
455
/* This is set up so that only a single autoprobe takes place per call.
456
ISA device autoprobes on a running machine are not recommended. */
457
int
458
init_module(void)
459
{
460
        int this_dev, found = 0;
461
 
462
        for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
463
                struct device *dev = &dev_wd[this_dev];
464
                dev->name = namelist+(NAMELEN*this_dev);
465
                dev->irq = irq[this_dev];
466
                dev->base_addr = io[this_dev];
467
                dev->mem_start = mem[this_dev];
468
                dev->mem_end = mem_end[this_dev];
469
                dev->init = wd_probe;
470
                if (io[this_dev] == 0)  {
471
                        if (this_dev != 0) break; /* only autoprobe 1st one */
472
                        printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n");
473
                }
474
                if (register_netdev(dev) != 0) {
475
                        printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
476
                        if (found != 0) return 0; /* Got at least one. */
477
                        return -ENXIO;
478
                }
479
                found++;
480
        }
481
 
482
        return 0;
483
}
484
 
485
void
486
cleanup_module(void)
487
{
488
        int this_dev;
489
 
490
        for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
491
                struct device *dev = &dev_wd[this_dev];
492
                if (dev->priv != NULL) {
493
                        int ioaddr = dev->base_addr - WD_NIC_OFFSET;
494
                        kfree(dev->priv);
495
                        dev->priv = NULL;
496
                        free_irq(dev->irq, NULL);
497
                        irq2dev_map[dev->irq] = NULL;
498
                        release_region(ioaddr, WD_IO_EXTENT);
499
                        unregister_netdev(dev);
500
                }
501
        }
502
}
503
#endif /* MODULE */
504
 
505
 
506
/*
507
 * Local variables:
508
 *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c wd.c"
509
 *  version-control: t
510
 *  tab-width: 4
511
 *  kept-new-versions: 5
512
 * End:
513
 */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.