patch-1.3.5 linux/drivers/net/depca.c
Next file: linux/drivers/net/depca.h
Previous file: linux/drivers/net/de4x5.h
Back to the patch index
Back to the overall index
- Lines: 2558
- Date:
Wed Jun 28 08:48:29 1995
- Orig file:
v1.3.4/linux/drivers/net/depca.c
- Orig date:
Tue Jun 6 11:22:08 1995
diff -u --recursive --new-file v1.3.4/linux/drivers/net/depca.c linux/drivers/net/depca.c
@@ -1,6 +1,6 @@
/* depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux.
- Written 1994 by David C. Davies.
+ Written 1994, 1995 by David C. Davies.
Copyright 1994 David C. Davies
@@ -8,6 +8,8 @@
United States Government
(as represented by the Director, National Security Agency).
+ Copyright 1995 Digital Equipment Corporation.
+
This software may be used and distributed according to the terms of
the GNU Public License, incorporated herein by reference.
@@ -29,16 +31,21 @@
This driver will NOT work for the DE203, DE204 and DE205 series of
cards, since they have a new custom ASIC in place of the AMD LANCE
- chip.
+ chip. See the 'ewrk3.c' driver in the Linux source tree for running
+ those cards.
+
+ I have benchmarked the driver with a DE100 at 595kB/s to (542kB/s from)
+ a DECstation 5000/200.
The author may be reached as davies@wanton.lkg.dec.com or
Digital Equipment Corporation, 550 King Street, Littleton MA 01460.
=========================================================================
- The driver was based on the 'lance.c' driver from Donald Becker which is
- included with the standard driver distribution for linux. Modifications
- were made to most routines and the hardware recognition routines were
- written from scratch. Primary references used were:
+
+ The driver was originally based on the 'lance.c' driver from Donald
+ Becker which is included with the standard driver distribution for
+ linux. V0.4 is a complete re-write with only the kernel interface
+ remaining from the original code.
1) Lance.c code in /linux/drivers/net/
2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
@@ -56,11 +63,9 @@
8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
- Peter Bauer's depca.c (V0.5) was referred to when debugging this driver.
- The hash filter code was derived from Reference 3 and has been tested
- only to the extent that the Table A-1, page A-7, was confirmed to fill
- the filter bit positions correctly. Hash filtering is not yet
- implemented in the current driver set.
+
+ Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
+ driver.
The original DEPCA card requires that the ethernet ROM address counter
be enabled to count and has an 8 bit NICSR. The ROM counter enabling is
@@ -118,35 +123,31 @@
The ability to load this driver as a loadable module has been added. To
utilise this ability, you have to do <8 things:
+ 0) have a copy of the loadable modules code installed on your system.
1) copy depca.c from the /linux/drivers/net directory to your favourite
temporary directory.
- 2) edit the source code near line 1530 to reflect the I/O address and
- IRQ you're using.
+ 2) if you wish, edit the source code near line 1530 to reflect the I/O
+ address and IRQ you're using (see also 5).
3) compile depca.c, but include -DMODULE in the command line to ensure
that the correct bits are compiled (see end of source code).
4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
kernel with the depca configuration turned off and reboot.
- 5) insmod depca.o
+ 5) insmod depca.o [irq=7] [io=0x200]
+ [Alan Cox: Changed the code to allow command line irq/io assignments]
6) run the net startup bits for your eth?? interface manually
(usually /etc/rc.inet[12] at boot time).
7) enjoy!
Note that autoprobing is not allowed in loadable modules - the system is
- already up and running and you're messing with interrupts. Also, there
- is no way to check on the number of depcas installed at the moment.
+ already up and running and you're messing with interrupts.
To unload a module, turn off the associated interface
'ifconfig eth?? down' then 'rmmod depca'.
- [Alan Cox: Changed to split off the module values as ints for insmod
-
- you can now do insmod depca.c irq=7 io=0x200 ]
-
TO DO:
------
- 1. Implement the 2k buffer mode - does anyone need it??
Revision History
----------------
@@ -173,11 +174,19 @@
0.382 9-feb-95 Fix recognition bug reported by <bkm@star.rl.ac.uk>.
0.383 22-feb-95 Fix for conflict with VESA SCSI reported by
<stromain@alf.dec.com>
+ 0.384 17-mar-95 Fix a ring full bug reported by <bkm@star.rl.ac.uk>
+ 0.385 3-apr-95 Fix a recognition bug reported by
+ <ryan.niemi@lastfrontier.com>
+ 0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility
+ 0.40 25-May-95 Rewrite for portability & updated.
+ ALPHA support from <jestabro@amt.tay1.dec.com>
+ 0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from
+ suggestion by <heiko@colossus.escape.de>
=========================================================================
*/
-static char *version = "depca.c:v0.383 2/22/94 davies@wanton.lkg.dec.com\n";
+static char *version = "depca.c:v0.41 5/26/95 davies@wanton.lkg.dec.com\n";
#include <linux/config.h>
#ifdef MODULE
@@ -188,6 +197,7 @@
#define MOD_DEC_USE_COUNT
#endif /* MODULE */
+#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -196,6 +206,7 @@
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
+#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
@@ -212,81 +223,84 @@
static int depca_debug = 1;
#endif
-#ifndef PROBE_LENGTH
-#define PROBE_LENGTH 32
-#endif
+#define DEPCA_NDA 0xffe0 /* No Device Address */
+/*
+** Ethernet PROM defines
+*/
+#define PROBE_LENGTH 32
#define ETH_PROM_SIG 0xAA5500FFUL
-#ifndef DEPCA_SIGNATURE
+/*
+** Set the number of Tx and Rx buffers. Ensure that the memory requested
+** here is <= to the amount of shared memory set up by the board switches.
+** The number of descriptors MUST BE A POWER OF 2.
+**
+** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
+*/
+#define NUM_RX_DESC 8 /* Number of RX descriptors */
+#define NUM_TX_DESC 8 /* Number of TX descriptors */
+#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */
+#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+/*
+** EISA bus defines
+*/
+#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
+#define MAX_EISA_SLOTS 16
+#define EISA_SLOT_INC 0x1000
+
+/*
+** ISA Bus defines
+*/
+#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
+#define DEPCA_IO_PORTS {0x300, 0x200, 0}
+#define DEPCA_TOTAL_SIZE 0x10
+static short mem_chkd = 0;
+
+/*
+** Name <-> Adapter mapping
+*/
#define DEPCA_SIGNATURE {"DEPCA",\
"DE100","DE101",\
"DE200","DE201","DE202",\
"DE210",\
"DE422",\
""}
-#define DEPCA_NAME_LENGTH 8
-#endif
+static enum {DEPCA, de100, de101, de200, de201, de202, de210, de422, unknown} adapter;
-#ifndef DEPCA_RAM_BASE_ADDRESSES
-#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
-#endif
-static short mem_chkd = 0; /* holds which base addrs have been */
- /* checked, for multi-DEPCA case */
-
-#ifndef DEPCA_IO_PORTS
-#define DEPCA_IO_PORTS {0x300, 0x200, 0}
-#endif
-
-#ifndef DEPCA_TOTAL_SIZE
-#define DEPCA_TOTAL_SIZE 0x10
-#endif
-
-#ifndef MAX_NUM_DEPCAS
+/*
+** Miscellaneous info...
+*/
+#define DEPCA_STRLEN 16
#define MAX_NUM_DEPCAS 2
-#endif
-
-#ifndef DEPCA_EISA_IO_PORTS
-#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
-#endif
-
-#ifndef MAX_EISA_SLOTS
-#define MAX_EISA_SLOTS 8
-#endif
/*
-** Set the number of Tx and Rx buffers.
+** Memory Alignment. Each descriptor is 4 longwords long. To force a
+** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
+** DESC_ALIGN. ALIGN aligns the start address of the private memory area
+** and hence the RX descriptor ring's first entry.
*/
-#ifndef DEPCA_BUFFER_LOG_SZ
-#define RING_SIZE 16 /* 16 buffers */
-#else
-#define RING_SIZE (1 << (DEPCA_BUFFERS_LOG_SZ))
-#endif /* DEPCA_BUFFER_LOG_SZ */
-
-#define PKT_BUF_SZ 1544 /* Buffer size for each Tx/Rx buffer */
-#define PKT_SZ 1514 /* Maximum ethernet packet length */
-#define DAT_SZ 1500 /* Maximum ethernet data length */
-#define PKT_HDR_LEN 14 /* Addresses and data length info */
-
-#ifdef HAVE_MULTICAST
-#ifndef CRC_POLYNOMIAL
-#define CRC_POLYNOMIAL 0x04c11db7 /* Ethernet CRC polynomial */
-#endif /* CRC_POLYNOMIAL */
-#endif /* HAVE_MULTICAST */
+#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */
+#define ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */
+#define ALIGN ALIGN8 /* Keep the LANCE happy... */
/*
** The DEPCA Rx and Tx ring descriptors.
*/
-struct depca_rx_head {
- volatile long base;
- short buf_length; /* This length is negative 2's complement! */
- short msg_length; /* This length is "normal". */
+struct depca_rx_desc {
+ volatile s32 base;
+ s16 buf_length; /* This length is negative 2's complement! */
+ s16 msg_length; /* This length is "normal". */
};
-struct depca_tx_head {
- volatile long base;
- short length; /* This length is negative 2's complement! */
- short misc; /* Errors and TDR info */
+struct depca_tx_desc {
+ volatile s32 base;
+ s16 length; /* This length is negative 2's complement! */
+ s16 misc; /* Errors and TDR info */
};
#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM
@@ -296,72 +310,103 @@
** The Lance initialization block, described in databook, in common memory.
*/
struct depca_init {
- unsigned short mode; /* Mode register */
- unsigned char phys_addr[ETH_ALEN]; /* Physical ethernet address */
- unsigned short filter[4]; /* Multicast filter. */
- unsigned long rx_ring; /* Rx ring base pointer & ring length */
- unsigned long tx_ring; /* Tx ring base pointer & ring length */
+ u16 mode; /* Mode register */
+ u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */
+ u8 mcast_table[8]; /* Multicast Hash Table. */
+ u32 rx_ring; /* Rx ring base pointer & ring length */
+ u32 tx_ring; /* Tx ring base pointer & ring length */
};
+#define DEPCA_PKT_STAT_SZ 16
+#define DEPCA_PKT_BIN_SZ 128 /* Should be >=100 unless you
+ increase DEPCA_PKT_STAT_SZ */
struct depca_private {
- char devname[8]; /* Device Product String */
- struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */
- struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */
- struct depca_init init_block;/* Initialization block */
- long bus_offset; /* (E)ISA bus address offset vs LANCE */
- long dma_buffs; /* Start address of Rx and Tx buffers. */
- int cur_rx, cur_tx; /* The next free ring entry */
- int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- int dma;
+ char devname[DEPCA_STRLEN]; /* Device Product String */
+ char adapter_name[DEPCA_STRLEN];/* /proc/ioports string */
+ char adapter; /* Adapter type */
+ struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
+ struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
+ struct depca_init init_block;/* Shadow Initialization block */
+ char *rx_memcpy[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */
+ char *tx_memcpy[NUM_TX_DESC]; /* CPU virt address of sh'd memory buffs */
+ u_long bus_offset; /* (E)ISA bus address offset vs LANCE */
+ u_long sh_mem; /* Physical start addr of shared mem area */
+ u_long dma_buffs; /* LANCE Rx and Tx buffers start address. */
+ int rx_new, tx_new; /* The next free ring entry */
+ int rx_old, tx_old; /* The ring entries to be free()ed. */
struct enet_statistics stats;
- char depca_na; /* NICSR access width: 0=>byte, 1=>word */
- short ringSize; /* ring size based on available memory */
- short rmask; /* modulus mask based on ring size */
- long rlen; /* log2(ringSize) for the descriptors */
+ struct { /* Private stats counters */
+ u32 bins[DEPCA_PKT_STAT_SZ];
+ u32 unicast;
+ u32 multicast;
+ u32 broadcast;
+ u32 excessive_collisions;
+ u32 tx_underruns;
+ u32 excessive_underruns;
+ } pktStats;
+ int txRingMask; /* TX ring mask */
+ int rxRingMask; /* RX ring mask */
+ s32 rx_rlen; /* log2(rxRingMask+1) for the descriptors */
+ s32 tx_rlen; /* log2(txRingMask+1) for the descriptors */
};
/*
+** The transmit ring full condition is described by the tx_old and tx_new
+** pointers by:
+** tx_old = tx_new Empty ring
+** tx_old = tx_new+1 Full ring
+** tx_old+txRingMask = tx_new Full ring (wrapped condition)
+*/
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+ lp->tx_old+lp->txRingMask-lp->tx_new:\
+ lp->tx_old -lp->tx_new-1)
+
+/*
** Public Functions
*/
-static int depca_open(struct device *dev);
-static int depca_start_xmit(struct sk_buff *skb, struct device *dev);
-static void depca_interrupt(int irq, struct pt_regs * regs);
-static int depca_close(struct device *dev);
+static int depca_open(struct device *dev);
+static int depca_start_xmit(struct sk_buff *skb, struct device *dev);
+static void depca_interrupt(int irq, struct pt_regs * regs);
+static int depca_close(struct device *dev);
+static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd);
static struct enet_statistics *depca_get_stats(struct device *dev);
-#ifdef HAVE_MULTICAST
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-#endif
+static void set_multicast_list(struct device *dev,int num_addrs,void *addrs);
/*
** Private functions
*/
-static int depca_probe1(struct device *dev, short ioaddr);
-static void depca_init_ring(struct device *dev);
-static int depca_rx(struct device *dev);
-static int depca_tx(struct device *dev);
-
-static void LoadCSRs(struct device *dev);
-static int InitRestartDepca(struct device *dev);
-static char *DepcaSignature(unsigned long mem_addr);
-static int DevicePresent(short ioaddr);
-static int EISA_signature(short iobase);
-#ifdef HAVE_MULTICAST
-static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table);
-#endif
-
-#ifndef MODULE
-static struct device *isa_probe(struct device *dev);
-static struct device *eisa_probe(struct device *dev);
-static struct device *alloc_device(struct device *dev, int ioaddr);
-
-static int num_depcas = 0, num_eth = 0, autoprobed = 0;
-
-#else
-int init_module(void);
-void cleanup_module(void);
+static int depca_hw_init(struct device *dev, u_long ioaddr);
+static void depca_init_ring(struct device *dev);
+static int depca_rx(struct device *dev);
+static int depca_tx(struct device *dev);
+
+static void LoadCSRs(struct device *dev);
+static int InitRestartDepca(struct device *dev);
+static void DepcaSignature(char *name, u_long paddr);
+static int DevicePresent(u_long ioaddr);
+static int get_hw_addr(struct device *dev);
+static int EISA_signature(char *name, s32 eisa_id);
+static void SetMulticastFilter(struct device *dev,int num_addrs,char *addrs);
+static void isa_probe(struct device *dev, u_long iobase);
+static void eisa_probe(struct device *dev, u_long iobase);
+static struct device *alloc_device(struct device *dev, u_long iobase);
+static int load_packet(struct device *dev, struct sk_buff *skb);
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+static int autoprobed = 1, loading_module = 1;
+# else
+static u_char de1xx_irq[] = {2,3,4,5,7,0};
+static u_char de2xx_irq[] = {5,9,10,11,15,0};
+static u_char de422_irq[] = {5,9,10,11,0};
+static u_char *depca_irq;
+static int autoprobed = 0, loading_module = 0;
#endif /* MODULE */
+static char name[DEPCA_STRLEN];
+static int num_depcas = 0, num_eth = 0;
+
/*
** Miscellaneous defines...
*/
@@ -369,309 +414,238 @@
outw(CSR0, DEPCA_ADDR);\
outw(STOP, DEPCA_DATA)
-
int depca_probe(struct device *dev)
{
- short base_addr = dev->base_addr;
- int status = -ENODEV;
-#ifndef MODULE
- struct device *eth0;
-#endif
-
- if (base_addr > 0x1ff) { /* Check a single specified location. */
- if (DevicePresent(base_addr) == 0) { /* Is DEPCA really here? */
- status = depca_probe1(dev, base_addr);
- }
- } else if (base_addr > 0) { /* Don't probe at all. */
- status = -ENXIO;
+ int tmp = num_depcas, status = -ENODEV;
+ u_long iobase = dev->base_addr;
-#ifdef MODULE
- } else {
- printk("Autoprobing is not supported when loading a module based driver.\n");
- status = -EIO;
-#else
- } else if (!autoprobed) { /* First probe for the DEPCA test */
- /* pattern in ROM */
- eth0=isa_probe(dev);
- eth0=eisa_probe(eth0);
- if (dev->priv) status=0;
- autoprobed = 1;
- } else {
- status = -ENXIO;
-#endif /* MODULE */
+ if ((iobase == 0) && loading_module){
+ printk("Autoprobing is not supported when loading a module based driver.\n");
+ status = -EIO;
+ } else {
+ isa_probe(dev, iobase);
+ eisa_probe(dev, iobase);
+ if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
+ printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name,
+ iobase);
}
- if (status) dev->base_addr = base_addr;
-
- return status; /* ENODEV would be more accurate. */
-}
-
-static int
-depca_probe1(struct device *dev, short ioaddr)
-{
- struct depca_private *lp;
- int i,j, status=0;
- unsigned long mem_start, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
- char *name = NULL;
- unsigned int nicsr, offset, netRAM;
-
-
/*
- ** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot.
+ ** Walk the device list to check that at least one device
+ ** initialised OK
*/
- STOP_DEPCA;
-
- nicsr = inb(DEPCA_NICSR);
- nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
- outb(nicsr, DEPCA_NICSR);
+ for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
- if (inw(DEPCA_DATA) == STOP) {
+ if (dev->priv) status = 0;
+ if (iobase == 0) autoprobed = 1;
+ }
- /* Now find out what kind of DEPCA we have. The DE100 uses a different
- ** addressing scheme for some registers compared to the DE2xx series.
- ** Note that a base address location is marked as checked if no DEPCA is
- ** there or one is found (when the search is immediately terminated). This
- ** shortens the search time a little for multiple DEPCAs.
- */
+ return status;
+}
- for (j = 0, i = 0; mem_base[i] && (j == 0);i++) {
- if (((mem_chkd >> i) & 0x01) == 0) { /* has the memory been checked? */
- name = DepcaSignature(mem_base[i]);/* check for a DEPCA here */
- mem_chkd |= (0x01 << i); /* mark location checked */
- if (*name != '\0') { /* one found? */
- j = 1; /* set exit flag */
- --i;
- }
- }
+static int
+depca_hw_init(struct device *dev, u_long ioaddr)
+{
+ struct depca_private *lp;
+ int i, j, offset, netRAM, mem_len, status=0;
+ s16 nicsr;
+ u_long mem_start=0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+
+ STOP_DEPCA;
+
+ nicsr = inb(DEPCA_NICSR);
+ nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
+ outb(nicsr, DEPCA_NICSR);
+
+ if (inw(DEPCA_DATA) == STOP) {
+ for (; mem_base[mem_chkd]; mem_chkd++) {
+ mem_start = mem_base[mem_chkd];
+ DepcaSignature(name, mem_start);
+ if (*name != '\0') break;
+ }
+
+ if ((*name != '\0') && mem_start) { /* found a DEPCA device */
+ dev->base_addr = ioaddr;
+
+ if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
+ printk("%s: %s at 0x%04lx (EISA slot %d)",
+ dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
+ } else { /* ISA port address */
+ printk("%s: %s at 0x%04lx", dev->name, name, ioaddr);
}
- if (*name != '\0') { /* found a DEPCA device */
- mem_start = mem_base[i];
- dev->base_addr = ioaddr;
-
- if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
- printk("%s: %s at %#3x (EISA slot %d)",
- dev->name, name, ioaddr, ((ioaddr>>12)&0x0f));
- } else { /* ISA port address */
- printk("%s: %s at %#3x", dev->name, name, ioaddr);
- }
-
- /* There is a 32 byte station address PROM at DEPCA_PROM address.
- The first six bytes are the station address. They can be read
- directly since the signature search set up the ROM address
- counter correctly just before this function.
-
- For the DE100 we have to be careful about which port is used to
- read the ROM info.
- */
-
- if (strstr(name,"DE100")!= NULL) {
- j = 1;
- } else {
- j = 0;
- }
-
- printk(", h/w address ");
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
- printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j));
- }
- printk("%2.2x", dev->dev_addr[i] = inb(DEPCA_PROM + j));
-
- for (;i<32;i++) { /* leave ROM counter in known state */
- j=inb(DEPCA_PROM);
- }
-
- request_region(ioaddr, DEPCA_TOTAL_SIZE, dev->name);
-
- /*
- ** Set up the maximum amount of network RAM(kB)
- */
- if (strstr(name,"DEPCA")== NULL) {
- netRAM=64;
- } else {
- netRAM=48;
- }
+ printk(", h/w address ");
+ status = get_hw_addr(dev);
+ for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */
+ printk("%2.2x:", dev->dev_addr[i]);
+ }
+ printk("%2.2x", dev->dev_addr[i]);
- /*
- ** Determine the base address for the DEPCA RAM from the NI-CSR
- ** and make up a DEPCA-specific-data structure.
- */
+ if (status == 0) {
+ /* Set up the maximum amount of network RAM(kB) */
+ netRAM = ((adapter != DEPCA) ? 64 : 48);
+ if ((nicsr & _128KB) && (adapter == de422)) netRAM = 128;
+ offset = 0x0000;
+ /* Shared Memory Base Address */
if (nicsr & BUF) {
offset = 0x8000; /* 32kbyte RAM offset*/
nicsr &= ~BS; /* DEPCA RAM in top 32k */
- printk(",\n has %dkB RAM", netRAM - 32);
- } else if ((nicsr & _128KB) && (netRAM!=48)) {
- offset = 0x0000;
- printk(",\n has 128kB RAM");
- } else {
- offset = 0x0000; /* 64k/48k bytes RAM */
- printk(",\n has %dkB RAM", netRAM);
+ netRAM -= 32;
}
-
mem_start += offset; /* (E)ISA start address */
- printk(" at 0x%.5lx", mem_start);
-
- /*
- ** Enable the shadow RAM.
- */
- if (strstr(name,"DEPCA") == NULL) {
- nicsr |= SHE;
- outb(nicsr, DEPCA_NICSR);
- }
+ if ((mem_len = (NUM_RX_DESC*(sizeof(struct depca_rx_desc)+RX_BUFF_SZ) +
+ NUM_TX_DESC*(sizeof(struct depca_tx_desc)+TX_BUFF_SZ) +
+ sizeof(struct depca_init))) <=
+ (netRAM<<10)) {
+ printk(",\n has %dkB RAM at 0x%.5lx", netRAM, mem_start);
+
+ /* Enable the shadow RAM. */
+ if (adapter != DEPCA) {
+ nicsr |= SHE;
+ outb(nicsr, DEPCA_NICSR);
+ }
- /*
- ** Calculate the ring size based on the available RAM
- ** found above. Allocate an equal number of buffers, each
- ** of size PKT_BUF_SZ (1544 bytes) to the Tx and Rx, allowing one
- ** descriptor entry (8 bytes) for each buffer. Make sure
- ** that this ring size is <= RING_SIZE. The ring size must be
- ** a power of 2.
- */
-
- j = (((netRAM << 10) - offset - sizeof(struct depca_private)) /
- (PKT_BUF_SZ + 8)) >> 1;
- for (i=0;j>1;i++) {
- j >>= 1;
- }
-
- /* Hold the ring size information here before the depca
- ** private structure is allocated. Need this for the memory
- ** space calculations.
- */
- j = 1 << i;
-
- /*
- ** Set up memory information in the device structure.
- ** Align the descriptor rings on an 8 byte (quadword) boundary.
- **
- ** depca_private area
- ** rx ring descriptors
- ** tx ring descriptors
- ** rx buffers
- ** tx buffers
- **
- */
-
- /* private area & initialise */
- dev->priv = (void *)((mem_start + 0x07) & ~0x07);
- lp = (struct depca_private *)dev->priv;
- memset(dev->priv, 0, sizeof(struct depca_private));
- strcpy(lp->devname,name);
-
- /* Tx & Rx descriptors (aligned to a quadword boundary) */
- mem_start = ((((unsigned long)dev->priv +
- sizeof(struct depca_private)) +
- (unsigned long)0x07) & (unsigned long)~0x07);
- lp->rx_ring = (struct depca_rx_head *)mem_start;
-
- mem_start += (sizeof(struct depca_rx_head) * j);
- lp->tx_ring = (struct depca_tx_head *)mem_start;
-
- mem_start += (sizeof(struct depca_tx_head) * j);
- lp->bus_offset = mem_start & 0x00ff0000;
- mem_start &= LA_MASK; /* LANCE re-mapped start address */
-
- lp->dma_buffs = mem_start;
-
- mem_start += (PKT_BUF_SZ * j);
- /* (mem_start now points to the start of the Tx buffers) */
-
- /* Initialise the data structures wrt CPU */
- memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j);
- memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j);
-
- /* This should never happen. */
- if ((long)(lp->rx_ring) & 0x07) {
- printk("\n **ERROR** DEPCA Rx and Tx descriptor rings not on a quadword boundary.\n");
- return -ENXIO;
- }
-
- /*
- ** Finish initialising the ring information.
- */
- lp->ringSize = j;
- if (lp->ringSize > RING_SIZE) lp->ringSize = RING_SIZE;
- lp->rmask = lp->ringSize - 1;
-
- /*
- ** calculate the real RLEN size for the descriptors. It is
- ** log2(ringSize).
- */
- for (i=0, j = lp->ringSize; j>1; i++) {
- j >>= 1;
- }
- lp->rlen = (unsigned long)(i << 29);
-
- /*
- ** load the initialisation block
- */
- depca_init_ring(dev);
+ /* Define the device private memory */
+ dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL);
+ lp = (struct depca_private *)dev->priv;
+ memset((char *)dev->priv, 0, sizeof(struct depca_private));
+ lp->adapter = adapter;
+ sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+ request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name);
+
+ /* Initialisation Block */
+ lp->sh_mem = mem_start;
+ mem_start += sizeof(struct depca_init);
+
+ /* Tx & Rx descriptors (aligned to a quadword boundary) */
+ mem_start = (mem_start + ALIGN) & ~ALIGN;
+ lp->rx_ring = (struct depca_rx_desc *)mem_start;
+
+ mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
+ lp->tx_ring = (struct depca_tx_desc *)mem_start;
+
+ mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
+ lp->bus_offset = mem_start & 0x00ff0000;
+ mem_start &= LA_MASK; /* LANCE re-mapped start address */
+
+ lp->dma_buffs = mem_start;
+
+ /* Finish initialising the ring information. */
+ lp->rxRingMask = NUM_RX_DESC - 1;
+ lp->txRingMask = NUM_TX_DESC - 1;
+
+ /* Calculate Tx/Rx RLEN size for the descriptors. */
+ for (i=0, j = lp->rxRingMask; j>0; i++) {
+ j >>= 1;
+ }
+ lp->rx_rlen = (s32)(i << 29);
+ for (i=0, j = lp->txRingMask; j>0; i++) {
+ j >>= 1;
+ }
+ lp->tx_rlen = (s32)(i << 29);
- /*
- ** Initialise the control and status registers
- */
- LoadCSRs(dev);
+ /* Load the initialisation block */
+ depca_init_ring(dev);
- /*
- ** Enable DEPCA board interrupts for autoprobing
- */
- nicsr = ((nicsr & ~IM)|IEN);
- outb(nicsr, DEPCA_NICSR);
+ /* Initialise the control and status registers */
+ LoadCSRs(dev);
- /* The DMA channel may be passed in on this parameter. */
- dev->dma = 0;
+ /* Enable DEPCA board interrupts for autoprobing */
+ nicsr = ((nicsr & ~IM)|IEN);
+ outb(nicsr, DEPCA_NICSR);
- /* To auto-IRQ we enable the initialization-done and DMA err,
- interrupts. For now we will always get a DMA error. */
- if (dev->irq < 2) {
+ /* To auto-IRQ we enable the initialization-done and DMA err,
+ interrupts. For now we will always get a DMA error. */
+ if (dev->irq < 2) {
#ifndef MODULE
- autoirq_setup(0);
+ unsigned char irqnum;
+ autoirq_setup(0);
+
+ /* Assign the correct irq list */
+ switch (lp->adapter) {
+ case DEPCA:
+ case de100:
+ case de101:
+ depca_irq = de1xx_irq;
+ break;
+ case de200:
+ case de201:
+ case de202:
+ case de210:
+ depca_irq = de2xx_irq;
+ break;
+ case de422:
+ depca_irq = de422_irq;
+ break;
+ }
- /* Trigger an initialization just for the interrupt. */
- outw(INEA | INIT, DEPCA_DATA);
+ /* Trigger an initialization just for the interrupt. */
+ outw(INEA | INIT, DEPCA_DATA);
- dev->irq = autoirq_report(1);
- if (dev->irq) {
- printk(" and uses IRQ%d.\n", dev->irq);
+ irqnum = autoirq_report(1);
+ if (!irqnum) {
+ printk(" and failed to detect IRQ line.\n");
+ status = -ENXIO;
+ } else {
+ for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) {
+ if (irqnum == depca_irq[i]) {
+ dev->irq = irqnum;
+ printk(" and uses IRQ%d.\n", dev->irq);
+ }
+ }
+
+ if (!dev->irq) {
+ printk(" but incorrect IRQ line detected.\n");
+ status = -ENXIO;
+ }
+ }
+#endif /* MODULE */
} else {
- printk(" and failed to detect IRQ line.\n");
- status = -EAGAIN;
+ printk(" and assigned IRQ%d.\n", dev->irq);
}
-#endif /* MODULE */
+ if (status) release_region(ioaddr, DEPCA_TOTAL_SIZE);
} else {
- printk(" and assigned IRQ%d.\n", dev->irq);
+ printk(",\n requests %dkB RAM: only %dkB is available!\n",
+ (mem_len>>10), netRAM);
+ status = -ENXIO;
}
} else {
+ printk(" which has an Ethernet PROM CRC error.\n");
status = -ENXIO;
}
- if (!status) {
- if (depca_debug > 0) {
- printk(version);
- }
+ }
+ if (!status) {
+ if (depca_debug > 0) {
+ printk(version);
+ }
- /* The DEPCA-specific entries in the device structure. */
- dev->open = &depca_open;
- dev->hard_start_xmit = &depca_start_xmit;
- dev->stop = &depca_close;
- dev->get_stats = &depca_get_stats;
-#ifdef HAVE_MULTICAST
- dev->set_multicast_list = &set_multicast_list;
-#endif
+ /* The DEPCA-specific entries in the device structure. */
+ dev->open = &depca_open;
+ dev->hard_start_xmit = &depca_start_xmit;
+ dev->stop = &depca_close;
+ dev->get_stats = &depca_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ dev->do_ioctl = &depca_ioctl;
- dev->mem_start = 0;
+ dev->mem_start = 0;
- /* Fill in the generic field of the device structure. */
- ether_setup(dev);
+ /* Fill in the generic field of the device structure. */
+ ether_setup(dev);
+ } else { /* Incorrectly initialised hardware */
+ if (dev->priv) {
+ kfree_s(dev->priv, sizeof(struct depca_private));
+ dev->priv = NULL;
}
- } else {
- status = -ENXIO;
}
+ } else {
+ status = -ENXIO;
+ }
- return status;
+ return status;
}
@@ -679,66 +653,87 @@
depca_open(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int i,nicsr,ioaddr = dev->base_addr;
+ s16 nicsr;
+ u_long ioaddr = dev->base_addr;
+ int i, status = 0;
+ struct depca_init *p = (struct depca_init *)lp->sh_mem;
- if (request_irq(dev->irq, &depca_interrupt, 0, "depca")) {
+ if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name)) {
printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
- return -EAGAIN;
+ status = -EAGAIN;
}
irq2dev_map[dev->irq] = dev;
-
- /*
- ** Stop the DEPCA & get the board status information.
- */
STOP_DEPCA;
nicsr = inb(DEPCA_NICSR);
- /*
- ** Make sure the shadow RAM is enabled
- */
- if (strstr(lp->devname,"DEPCA") == NULL) {
+ /* Make sure the shadow RAM is enabled */
+ if (adapter != DEPCA) {
nicsr |= SHE;
outb(nicsr, DEPCA_NICSR);
}
- /*
- ** Re-initialize the DEPCA...
- */
- depca_init_ring(dev); /* initialize the descriptor rings */
+ /* Re-initialize the DEPCA... */
+ depca_init_ring(dev);
LoadCSRs(dev);
if (depca_debug > 1){
+ /* Copy the shadow init_block to shared memory */
+ memcpy_toio((char *)lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
+
printk("%s: depca open with irq %d\n",dev->name,dev->irq);
printk("Descriptor head addresses:\n");
- printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
- printk("Descriptor addresses:\n");
- for (i=0;i<lp->ringSize;i++){
- printk("\t0x%8.8lx 0x%8.8lx\n",(long)&lp->rx_ring[i].base,
- (long)&lp->tx_ring[i].base);
- }
- printk("Buffer addresses:\n");
- for (i=0;i<lp->ringSize;i++){
- printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring[i].base,
- (long)lp->tx_ring[i].base);
+ printk("\t0x%lx 0x%lx\n",(u_long)lp->rx_ring, (u_long)lp->tx_ring);
+ printk("Descriptor addresses:\nRX: ");
+ for (i=0;i<lp->rxRingMask;i++){
+ if (i < 3) {
+ printk("0x%8.8lx ", (long) &lp->rx_ring[i].base);
+ }
+ }
+ printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base);
+ printk("TX: ");
+ for (i=0;i<lp->txRingMask;i++){
+ if (i < 3) {
+ printk("0x%8.8lx ", (long) &lp->tx_ring[i].base);
+ }
}
- printk("Initialisation block at 0x%8.8lx\n",(long)&lp->init_block);
- printk("\tmode: 0x%4.4x\n",lp->init_block.mode);
+ printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base);
+ printk("\nDescriptor buffers:\nRX: ");
+ for (i=0;i<lp->rxRingMask;i++){
+ if (i < 3) {
+ printk("0x%8.8x ", readl(&lp->rx_ring[i].base));
+ }
+ }
+ printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
+ printk("TX: ");
+ for (i=0;i<lp->txRingMask;i++){
+ if (i < 3) {
+ printk("0x%8.8x ", readl(&lp->tx_ring[i].base));
+ }
+ }
+ printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
+ printk("Status: %d\n", status);
+ printk("Initialisation block at 0x%8.8lx\n",lp->sh_mem);
+ printk("\tmode: 0x%4.4x\n",readw(&p->mode));
printk("\tphysical address: ");
- for (i=0;i<6;i++){
- printk("%2.2x:",(short)lp->init_block.phys_addr[i]);
+ for (i=0;i<ETH_ALEN-1;i++){
+ printk("%2.2x:",(u_char)readb(&p->phys_addr[i]));
+ }
+ printk("%2.2x\n",(u_char)readb(&p->phys_addr[i]));
+ printk("\tmulticast hash table: ");
+ for (i=0;i<(HASH_TABLE_LEN >> 3)-1;i++){
+ printk("%2.2x:",(u_char)readb(&p->mcast_table[i]));
}
- printk("\n\tlogical address filter: 0x");
- for (i=0;i<4;i++){
- printk("%2.2x",(short)lp->init_block.filter[i]);
- }
- printk("\n\trx_ring at: 0x%8.8lx\n",(long)lp->init_block.rx_ring);
- printk("\ttx_ring at: 0x%8.8lx\n",(long)lp->init_block.tx_ring);
- printk("dma_buffs: 0x%8.8lx\n",(long)lp->dma_buffs);
- printk("Ring size: %d\nMask: 0x%2.2x\nLog2(ringSize): 0x%8.8lx\n",
- (short)lp->ringSize,
- (char)lp->rmask,
- (long)lp->rlen);
+ printk("%2.2x\n",(u_char)readb(&p->mcast_table[i]));
+ printk("\trx_ring at: 0x%8.8x\n",readl(&p->rx_ring));
+ printk("\ttx_ring at: 0x%8.8x\n",readl(&p->tx_ring));
+ printk("dma_buffs: 0x%8.8lx\n",lp->dma_buffs);
+ printk("Ring size:\nRX: %d Log2(rxRingMask): 0x%8.8x\n",
+ (int)lp->rxRingMask + 1,
+ lp->rx_rlen);
+ printk("TX: %d Log2(txRingMask): 0x%8.8x\n",
+ (int)lp->txRingMask + 1,
+ lp->tx_rlen);
outw(CSR2,DEPCA_ADDR);
printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
outw(CSR1,DEPCA_ADDR);
@@ -747,9 +742,7 @@
printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
}
- /*
- ** Enable DEPCA board interrupts and turn off LED
- */
+ /* Enable DEPCA board interrupts and turn off LED */
nicsr = ((nicsr & ~IM & ~LED)|IEN);
outb(nicsr, DEPCA_NICSR);
outw(CSR0,DEPCA_ADDR);
@@ -758,7 +751,7 @@
dev->interrupt = 0;
dev->start = 1;
- InitRestartDepca(dev); /* ignore the return status */
+ status = InitRestartDepca(dev);
if (depca_debug > 1){
printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
@@ -767,39 +760,48 @@
MOD_INC_USE_COUNT;
- return 0; /* Always succeed */
+ return status;
}
/* Initialize the lance Rx and Tx descriptor rings. */
static void
depca_init_ring(struct device *dev)
{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- unsigned long i;
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ u_int i;
+ u_long p;
- lp->init_block.mode = DTX | DRX; /* Disable Rx and Tx. */
- lp->cur_rx = lp->cur_tx = 0;
- lp->dirty_rx = lp->dirty_tx = 0;
+ /* Lock out other processes whilst setting up the hardware */
+ set_bit(0, (void *)&dev->tbusy);
- /* Initialize the base addresses and length of each buffer in the ring */
- for (i = 0; i < lp->ringSize; i++) {
- lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | R_OWN;
- lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
- lp->tx_ring[i].base = (lp->dma_buffs + (i+lp->ringSize) * PKT_BUF_SZ) &
- (unsigned long)(0x00ffffff);
- }
+ lp->rx_new = lp->tx_new = 0;
+ lp->rx_old = lp->tx_old = 0;
- /* Set up the initialization block */
- for (i = 0; i < ETH_ALEN; i++) {
- lp->init_block.phys_addr[i] = dev->dev_addr[i];
- }
- for (i = 0; i < 4; i++) {
- lp->init_block.filter[i] = 0x0000;
- }
- lp->init_block.rx_ring = ((unsigned long)lp->rx_ring & LA_MASK) | lp->rlen;
- lp->init_block.tx_ring = ((unsigned long)lp->tx_ring & LA_MASK) | lp->rlen;
+ /* Initialize the base addresses and length of each buffer in the ring */
+ for (i = 0; i <= lp->rxRingMask; i++) {
+ writel((p=lp->dma_buffs+i*RX_BUFF_SZ) | R_OWN, &lp->rx_ring[i].base);
+ writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
+ lp->rx_memcpy[i]=(char *)(p+lp->bus_offset);
+ }
+ for (i = 0; i <= lp->txRingMask; i++) {
+ writel((p=lp->dma_buffs+(i+lp->txRingMask+1)*TX_BUFF_SZ) & 0x00ffffff,
+ &lp->tx_ring[i].base);
+ lp->tx_memcpy[i]=(char *)(p+lp->bus_offset);
+ }
+
+ /* Set up the initialization block */
+ lp->init_block.rx_ring = ((u32)((u_long)lp->rx_ring)&LA_MASK) | lp->rx_rlen;
+ lp->init_block.tx_ring = ((u32)((u_long)lp->tx_ring)&LA_MASK) | lp->tx_rlen;
+
+ SetMulticastFilter(dev, 0, NULL);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ lp->init_block.phys_addr[i] = dev->dev_addr[i];
+ }
- lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
+ lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
+
+ return;
}
/*
@@ -808,148 +810,58 @@
static int
depca_start_xmit(struct sk_buff *skb, struct device *dev)
{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- int ioaddr = dev->base_addr;
- int status = 0;
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ u_long ioaddr = dev->base_addr;
+ int status = 0;
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10) {
- status = -1;
- } else {
- printk("%s: transmit timed out, status %04x, resetting.\n",
- dev->name, inw(DEPCA_DATA));
+ /* Transmitter timeout, serious problems. */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 100) {
+ status = -1;
+ } else {
+ printk("%s: transmit timed out, status %04x, resetting.\n",
+ dev->name, inw(DEPCA_DATA));
- STOP_DEPCA;
- depca_init_ring(dev);
- LoadCSRs(dev);
- InitRestartDepca(dev);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
- return status;
- }
-
- if (skb == NULL) {
- dev_tint(dev);
- return 0;
- }
-
- if (skb->len <= 0) {
- return 0;
- }
-
- if (depca_debug > 3) {
- outw(CSR0, DEPCA_ADDR);
- printk("%s: depca_start_xmit() called, csr0 %4.4x.\n", dev->name,
- inw(DEPCA_DATA));
- }
-
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
-
- /*
- ** The TX buffer, skb, has to be copied into the local network RAM
- ** for the LANCE to access it. The skb may be at > 16MB for large
- ** (memory) systems.
- */
- { /* Fill in a Tx ring entry */
- unsigned char *buf;
- int entry = lp->cur_tx++;
- int len;
- long skbL = skb->len;
- char *p = (char *) skb->data;
-
- entry &= lp->rmask; /* Ring around buffer number. */
- buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
- 0x00ffffff);
-
- /* Wait for a full ring to free up */
- while (lp->tx_ring[entry].base < 0);
-
- /*
- ** Caution: the write order is important here... don't set up the
- ** ownership rights until all the other information is in place.
- */
- len = ((skbL > PKT_SZ) ? PKT_SZ : skbL); /* skb too long */
- if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */
- skbL -= len;
- lp->tx_ring[entry].length = -len;
-
- /* Clears various error flags */
- lp->tx_ring[entry].misc = 0x0000;
-
- /* copy the data from the socket buffer to the net memory */
- memcpy((unsigned char *)(buf), skb->data, len);
-
- /* Hand over buffer ownership to the LANCE */
- if (skbL <= 0) lp->tx_ring[entry].base |= (T_ENP);
- lp->tx_ring[entry].base |= (T_OWN|T_STP);
-
- /* Trigger an immediate send demand. */
- outw(CSR0, DEPCA_ADDR);
- outw(INEA | TDMD, DEPCA_DATA);
-
+ STOP_DEPCA;
+ depca_init_ring(dev);
+ LoadCSRs(dev);
+ dev->interrupt = UNMASK_INTERRUPTS;
+ dev->start = 1;
+ dev->tbusy=0;
dev->trans_start = jiffies;
+ InitRestartDepca(dev);
+ }
+ return status;
+ } else if (skb == NULL) {
+ dev_tint(dev);
+ } else if (skb->len > 0) {
+ /* Enforce 1 process per h/w access */
+ if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ status = -1;
+ } else {
+ if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
+ status = load_packet(dev, skb);
- for (p += len; skbL > 0; p += len) {
-
- /* Get new buffer pointer */
- entry = lp->cur_tx++;
- entry &= lp->rmask; /* Ring around buffer number. */
- buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
- 0x00ffffff);
-
- /* Wait for a full ring to free up */
- while (lp->tx_ring[entry].base < 0);
- dev->tbusy=0;
-
- /* Copy ethernet header to the new buffer */
- memcpy((unsigned char *)buf, skb->data, PKT_HDR_LEN);
-
- /* Determine length of data buffer */
- len = ((skbL > DAT_SZ) ? DAT_SZ : skbL); /* skbL too long */
- if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */
- skbL -= len;
- lp->tx_ring[entry].length = -len;
-
- /* Clears various error flags */
- lp->tx_ring[entry].misc = 0x0000;
-
- /* copy the data from the socket buffer to the net memory */
- memcpy((unsigned char *)(buf + PKT_HDR_LEN), (unsigned char *)p, len);
-
- /* Hand over buffer ownership to the LANCE */
- if (skbL <= 0) lp->tx_ring[entry].base |= T_ENP;
- lp->tx_ring[entry].base |= T_OWN;
- }
-
- if (depca_debug > 4) {
- unsigned char *pkt =
- (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
- 0x00ffffff);
-
- printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n",
- dev->name, entry, (unsigned long) &lp->tx_ring[entry],
- lp->tx_ring[entry].base, -lp->tx_ring[entry].length);
- printk("%s: Tx %2.2x %2.2x %2.2x ... %2.2x %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x %2.2x %2.2x.\n",
- dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
- pkt[7], pkt[8], pkt[11], pkt[12], pkt[13],
- pkt[14], pkt[15]);
- }
-
- /* Check if the TX ring is full or not - 'tbusy' cleared if not full. */
- if (lp->tx_ring[(entry+1) & lp->rmask].base >= 0) {
- dev->tbusy=0;
+ if (!status) {
+ /* Trigger an immediate send demand. */
+ outw(CSR0, DEPCA_ADDR);
+ outw(INEA | TDMD, DEPCA_DATA);
+
+ dev->trans_start = jiffies;
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+ if (TX_BUFFS_AVAIL) {
+ dev->tbusy=0;
+ }
+ } else {
+ status = -1;
}
-
- dev_kfree_skb (skb, FREE_WRITE);
}
-
- return 0;
+ }
+
+ return status;
}
/*
@@ -958,137 +870,144 @@
static void
depca_interrupt(int irq, struct pt_regs * regs)
{
- struct device *dev = (struct device *)(irq2dev_map[irq]);
- struct depca_private *lp;
- int csr0, ioaddr, nicsr;
-
- if (dev == NULL) {
- printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
- } else {
- lp = (struct depca_private *)dev->priv;
- ioaddr = dev->base_addr;
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+ struct depca_private *lp;
+ s16 csr0, nicsr;
+ u_long ioaddr;
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
- dev->interrupt = MASK_INTERRUPTS;
+ if (dev == NULL) {
+ printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+ } else {
+ lp = (struct depca_private *)dev->priv;
+ ioaddr = dev->base_addr;
+
+ if (dev->interrupt)
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
- /* mask the DEPCA board interrupts and turn on the LED */
- nicsr = inb(DEPCA_NICSR);
- nicsr |= (IM|LED);
- outb(nicsr, DEPCA_NICSR);
+ dev->interrupt = MASK_INTERRUPTS;
- outw(CSR0, DEPCA_ADDR);
- csr0 = inw(DEPCA_DATA);
+ /* mask the DEPCA board interrupts and turn on the LED */
+ nicsr = inb(DEPCA_NICSR);
+ nicsr |= (IM|LED);
+ outb(nicsr, DEPCA_NICSR);
- /* Acknowledge all of the current interrupt sources ASAP. */
- outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA);
+ outw(CSR0, DEPCA_ADDR);
+ csr0 = inw(DEPCA_DATA);
- if (depca_debug > 5)
- printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
- dev->name, csr0, inw(DEPCA_DATA));
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outw(csr0 & INTE, DEPCA_DATA);
- if (csr0 & RINT) /* Rx interrupt (packet arrived) */
- depca_rx(dev);
+ if (csr0 & RINT) /* Rx interrupt (packet arrived) */
+ depca_rx(dev);
- if (csr0 & TINT) /* Tx interrupt (packet sent) */
- depca_tx(dev);
+ if (csr0 & TINT) /* Tx interrupt (packet sent) */
+ depca_tx(dev);
- /* Clear the interrupts we've handled. */
- outw(CSR0, DEPCA_ADDR);
- outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA);
+ if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { /* any resources available? */
+ dev->tbusy = 0; /* clear TX busy flag */
+ mark_bh(NET_BH);
+ }
- if (depca_debug > 4) {
- printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
- dev->name, inw(DEPCA_ADDR),
- inw(DEPCA_DATA));
- }
+ /* Unmask the DEPCA board interrupts and turn off the LED */
+ nicsr = (nicsr & ~IM & ~LED);
+ outb(nicsr, DEPCA_NICSR);
- /* Unmask the DEPCA board interrupts and turn off the LED */
- nicsr = (nicsr & ~IM & ~LED);
- outb(nicsr, DEPCA_NICSR);
- dev->interrupt = UNMASK_INTERRUPTS;
- }
+ dev->interrupt = UNMASK_INTERRUPTS;
+ }
- return;
+ return;
}
static int
depca_rx(struct device *dev)
{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- int entry = lp->cur_rx & lp->rmask;
-
- /* If we own the next entry, it's a new packet. Send it up. */
- for (; lp->rx_ring[entry].base >= 0; entry = (++lp->cur_rx) & lp->rmask) {
- int status = lp->rx_ring[entry].base >> 16 ;
- int chained;
-
- /*
- ** There is a tricky error noted by John Murphy, <murf@perftech.com>
- ** to Russ Nelson: even with full-sized buffers, it's possible for a
- ** jabber packet to use two buffers, with only the last one correctly
- ** noting the error.
- */
-
- /* Check for a chaining buffer */
- chained = 0;
- if (status == R_STP) {
- chained = 1;
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int i, entry;
+ s32 status;
+ char *buf;
+
+ for (entry=lp->rx_new;
+ !(readl(&lp->rx_ring[entry].base) & R_OWN);
+ entry=lp->rx_new){
+ status = readl(&lp->rx_ring[entry].base) >> 16 ;
+ if (status & R_STP) { /* Remember start of frame */
+ lp->rx_old = entry;
+ }
+ if (status & R_ENP) { /* Valid frame status */
+ if (status & R_ERR) { /* There was an error. */
+ lp->stats.rx_errors++; /* Update the error stats. */
+ if (status & R_FRAM) lp->stats.rx_frame_errors++;
+ if (status & R_OFLO) lp->stats.rx_over_errors++;
+ if (status & R_CRC) lp->stats.rx_crc_errors++;
+ if (status & R_BUFF) lp->stats.rx_fifo_errors++;
+ } else {
+ short len, pkt_len = readw(&lp->rx_ring[entry].msg_length);
+ struct sk_buff *skb;
+
+ skb = alloc_skb(pkt_len, GFP_ATOMIC);
+ if (skb != NULL) {
+ skb->len = pkt_len;
+ skb->dev = dev;
+ if (entry < lp->rx_old) { /* Wrapped buffer */
+ len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
+ memcpy_fromio(skb->data, lp->rx_memcpy[lp->rx_old], len);
+ memcpy_fromio(skb->data+len, lp->rx_memcpy[0], pkt_len-len);
+ } else { /* Linear buffer */
+ memcpy_fromio(skb->data, lp->rx_memcpy[lp->rx_old], pkt_len);
+ }
/*
- ** Wait for next buffer to complete to check for errors. This
- ** is slow but infrequent and allows for correct hardware buffer
- ** chaining (whilst defeating the chaining's purpose).
+ ** Notify the upper protocol layers that there is another
+ ** packet to handle
*/
- while ((status=(lp->rx_ring[(entry+1)&lp->rmask].base >> 16)) < 0);
-
- /* NB: 'status' now comes from the buffer following 'entry'. */
- }
-
- if (status & R_ERR) { /* There was an error. */
- lp->stats.rx_errors++; /* Update the error stats. */
- if (status & R_FRAM) lp->stats.rx_frame_errors++;
- if (status & R_OFLO) lp->stats.rx_over_errors++;
- if (status & R_CRC) lp->stats.rx_crc_errors++;
- if (status & R_BUFF) lp->stats.rx_fifo_errors++;
- } else { /* Malloc up new buffer, compatible with net-2e. */
- short pkt_len = lp->rx_ring[entry].msg_length;
- struct sk_buff *skb;
-
- skb = alloc_skb(pkt_len, GFP_ATOMIC);
- if (skb == NULL) {
- printk("%s: Memory squeeze, deferring packet.\n", dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
- break;
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+
+ /*
+ ** Update stats
+ */
+ lp->stats.rx_packets++;
+ for (i=1; i<DEPCA_PKT_STAT_SZ-1; i++) {
+ if (pkt_len < (i*DEPCA_PKT_BIN_SZ)) {
+ lp->pktStats.bins[i]++;
+ i = DEPCA_PKT_STAT_SZ;
}
- skb->len = pkt_len;
- skb->dev = dev;
- memcpy(skb->data,
- (unsigned char *)((lp->rx_ring[entry].base+lp->bus_offset) &
- 0x00ffffff),
- pkt_len);
- /*
- ** Notify the upper protocol layers that there is another
- ** packet to handle
- */
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- lp->stats.rx_packets++;
- }
-
- /* turn over ownership of the current entry back to the LANCE */
- lp->rx_ring[entry].base |= R_OWN;
- if (chained && (status & R_ERR)) { /* next entry also bad */
- entry = (++lp->cur_rx) & lp->rmask;
- lp->rx_ring[entry].base |= R_OWN;
+ }
+ buf = skb->data; /* Look at the dest addr */
+ if (buf[0] & 0x01) { /* Multicast/Broadcast */
+ if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
+ lp->pktStats.broadcast++;
+ } else {
+ lp->pktStats.multicast++;
+ }
+ } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
+ (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
+ lp->pktStats.unicast++;
+ }
+
+ lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
+ if (lp->pktStats.bins[0] == 0) { /* Reset counters */
+ memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
+ }
+ } else {
+ printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+ lp->stats.rx_dropped++; /* Really, deferred. */
+ break;
}
+ }
+ /* Change buffer ownership for this last frame, back to the adapter */
+ for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)&lp->rxRingMask) {
+ writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN,
+ &lp->rx_ring[lp->rx_old].base);
+ }
+ writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
}
- /*
- ** We should check that at least two ring entries are free. If not,
- ** we should free one and mark stats->rx_dropped++.
+ /*
+ ** Update entry information
*/
+ lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
+ }
return 0;
}
@@ -1100,46 +1019,37 @@
depca_tx(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int dirty_tx = lp->dirty_tx & lp->rmask;
+ int entry;
+ s32 status;
+ u_long ioaddr = dev->base_addr;
- if (depca_debug > 5)
- printk("%s: Cleaning tx ring, dirty %d clean %d.\n",
- dev->name, dirty_tx, (lp->cur_tx & lp->rmask));
-
- /*
- ** While the dirty entry is not the current one AND
- ** the LANCE doesn't own it...
- */
- for (; dirty_tx!=(lp->cur_tx & lp->rmask) && lp->tx_ring[dirty_tx].base>0;
- dirty_tx = ++lp->dirty_tx & lp->rmask) {
- unsigned long *tmdp = (unsigned long *)(&lp->tx_ring[dirty_tx]);
- int status = lp->tx_ring[dirty_tx].base >> 16;
+ for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
+ status = readl(&lp->tx_ring[entry].base) >> 16 ;
if (status < 0) { /* Packet not yet sent! */
- printk("interrupt for packet not yet sent!\n");
break;
- }
- if (status & T_ERR) { /* There was an major error, log it. */
- int err_status = lp->tx_ring[dirty_tx].misc;
-
+ } else if (status & T_ERR) { /* An error occured. */
+ status = readl(&lp->tx_ring[entry].misc);
lp->stats.tx_errors++;
- if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
- if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
- if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
- if (err_status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
- /* We should re-init() after the FIFO error. */
+ if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+ if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+ if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
+ if (status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
+ if (status & (TMD3_BUFF | TMD3_UFLO)) {
+ /* Trigger an immediate send demand. */
+ outw(CSR0, DEPCA_ADDR);
+ outw(INEA | TDMD, DEPCA_DATA);
+ }
} else if (status & (T_MORE | T_ONE)) {
lp->stats.collisions++;
} else {
lp->stats.tx_packets++;
}
- if (depca_debug > 5)
- printk("%s: Tx done entry %d, %4.4lx %4.4lx %4.4lx %4.4lx.\n",
- dev->name, dirty_tx,
- tmdp[0], tmdp[1], tmdp[2], tmdp[3]);
+ /* Update all the pointers */
+ lp->tx_old = (++lp->tx_old) & lp->txRingMask;
}
- /*mark_bh(INET_BH);*/
+
return 0;
}
@@ -1147,7 +1057,8 @@
depca_close(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int nicsr, ioaddr = dev->base_addr;
+ s16 nicsr;
+ u_long ioaddr = dev->base_addr;
dev->start = 0;
dev->tbusy = 1;
@@ -1168,15 +1079,17 @@
/*
** Give back the ROM in case the user wants to go to DOS
*/
- if (strstr(lp->devname,"DEPCA") == NULL) {
+ if (lp->adapter != DEPCA) {
nicsr = inb(DEPCA_NICSR);
nicsr &= ~SHE;
outb(nicsr, DEPCA_NICSR);
}
+ /*
+ ** Free the associated irq
+ */
free_irq(dev->irq);
-
- irq2dev_map[dev->irq] = 0;
+ irq2dev_map[dev->irq] = NULL;
MOD_DEC_USE_COUNT;
@@ -1186,25 +1099,29 @@
static void LoadCSRs(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ u_long ioaddr = dev->base_addr;
outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */
- outw((unsigned short)((unsigned long)(&lp->init_block) & LA_MASK),
- DEPCA_DATA);
+ outw((u16)(lp->sh_mem & LA_MASK), DEPCA_DATA);
outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */
- outw((unsigned short)(((unsigned long)(&lp->init_block) & LA_MASK) >> 16),
- DEPCA_DATA);
+ outw((u16)((lp->sh_mem & LA_MASK) >> 16), DEPCA_DATA);
outw(CSR3, DEPCA_ADDR); /* ALE control */
outw(ACON, DEPCA_DATA);
- outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
+
+ outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */
+
+ return;
}
static int InitRestartDepca(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ u_long ioaddr = dev->base_addr;
int i, status=0;
+ /* Copy the shadow init_block to shared memory */
+ memcpy_toio((char *)lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
+
outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
outw(INIT, DEPCA_DATA); /* initialize DEPCA */
@@ -1215,13 +1132,13 @@
/* clear IDON by writing a "1", enable interrupts and start lance */
outw(IDON | INEA | STRT, DEPCA_DATA);
if (depca_debug > 2) {
- printk("%s: DEPCA open after %d ticks, init block %#lx csr0 %4.4x.\n",
- dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+ printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
+ dev->name, i, lp->sh_mem, inw(DEPCA_DATA));
}
} else {
+ printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
+ dev->name, i, lp->sh_mem, inw(DEPCA_DATA));
status = -1;
- printk("%s: DEPCA unopened after %d ticks, init block %#lx csr0 %4.4x.\n",
- dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
}
return status;
@@ -1237,7 +1154,6 @@
return &lp->stats;
}
-#ifdef HAVE_MULTICAST
/*
** Set or clear the multicast filter for this adaptor.
** num_addrs == -1 Promiscuous mode, receive all packets
@@ -1245,20 +1161,22 @@
** num_addrs > 0 Multicast mode, receive normal and MC packets, and do
** best-effort filtering.
*/
-#define hash_filter lp->init_block.filter
-
static void
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
- short ioaddr = dev->base_addr;
struct depca_private *lp = (struct depca_private *)dev->priv;
+ u_long ioaddr = dev->base_addr;
if (irq2dev_map[dev->irq] != NULL) {
+ while(dev->tbusy); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+
STOP_DEPCA; /* Temporarily stop the depca. */
depca_init_ring(dev); /* Initialize the descriptor rings */
if (num_addrs >= 0) {
- SetMulticastFilter(num_addrs, (char *)addrs, (char *)hash_filter);
+ SetMulticastFilter(dev, num_addrs, (char *)addrs);
lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */
} else {
lp->init_block.mode |= PROM; /* Set promiscuous mode */
@@ -1266,171 +1184,269 @@
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
}
}
/*
** Calculate the hash code and update the logical address filter
** from a list of ethernet multicast addresses.
-** Derived from a 'C' program in the AMD data book:
-** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
-** Pub #17781, Rev. A, May 1993
-*/
-static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table)
-{
- char j, ctrl, bit, octet, hashcode;
- short int i;
- long int CRC, poly = (long int) CRC_POLYNOMIAL;
-
- for (i=0;i<num_addrs;i++) { /* for each address in the list */
- if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* is multicast address? */
- CRC = (long int) 0xffffffff; /* init CRC for each address */
- for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
- for(j=0;j<8;j++) { /* process each address bit */
- bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
- ctrl = ((CRC < 0) ? 1 : 0); /* shift the control bit */
- CRC <<= 1; /* shift the CRC */
- if (bit ^ ctrl) { /* (bit) XOR (control bit) */
- CRC ^= poly; /* (CRC) XOR (polynomial) */
+** Big endian crc one liner is mine, all mine, ha ha ha ha!
+** LANCE calculates its hash codes big endian.
+*/
+static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int i, j, bit, byte;
+ u16 hashcode;
+ s32 crc, poly = CRC_POLYNOMIAL_BE;
+
+ if (num_addrs == HASH_TABLE_LEN) { /* Set all multicast bits */
+ for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
+ lp->init_block.mcast_table[i] = (char)0xff;
+ }
+ } else {
+ /* Clear the multicast table first */
+ for (i=0; i<(HASH_TABLE_LEN>>3); i++){
+ lp->init_block.mcast_table[i]=0;
+ }
+
+ /* Add multicast addresses */
+ for (i=0;i<num_addrs;i++) { /* for each address in the list */
+ if ((*addrs & 0x01) == 1) { /* multicast address? */
+ crc = 0xffffffff; /* init CRC for each address */
+ for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
+ /* process each address bit */
+ for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
+ crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0);
}
}
+ hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */
+ for (j=0;j<5;j++) { /* ... in reverse order. */
+ hashcode = (hashcode << 1) | ((crc>>=1) & 1);
+ }
+
+
+ byte = hashcode >> 3; /* bit[3-5] -> byte in filter */
+ bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */
+ lp->init_block.mcast_table[byte] |= bit;
+ } else { /* skip this address */
+ addrs += ETH_ALEN;
}
- hashcode = (CRC & 0x00000001); /* hashcode is 6 LSb of CRC ... */
- for (j=0;j<5;j++) { /* ... in reverse order. */
- hashcode <<= 1;
- CRC >>= 1;
- hashcode |= (CRC & 0x00000001);
- }
- octet = hashcode >> 3; /* bit[3-5] -> octet in filter */
- /* bit[0-2] -> bit in octet */
- multicast_table[octet] |= (1 << (hashcode & 0x07));
}
}
+
return;
}
-#endif /* HAVE_MULTICAST */
-
-#ifndef MODULE
/*
** ISA bus I/O device probe
*/
-static struct device *isa_probe(struct device *dev)
+static void isa_probe(struct device *dev, u_long ioaddr)
{
- int *port, ports[] = DEPCA_IO_PORTS;
- int status;
+ int i = num_depcas, maxSlots;
+ s32 ports[] = DEPCA_IO_PORTS;
- for (status = -ENODEV, port = &ports[0];
- *port && (num_depcas < MAX_NUM_DEPCAS); port++) {
- int ioaddr = *port;
-
- if (DevicePresent(ioaddr) == 0) {
- if (num_depcas > 0) { /* only gets here in autoprobe */
- dev = alloc_device(dev, ioaddr);
- } else {
- if ((status = depca_probe1(dev, ioaddr)) == 0) {
- num_depcas++;
+ if (!ioaddr && autoprobed) return ; /* Been here before ! */
+ if (ioaddr > 0x400) return; /* EISA Address */
+ if (i >= MAX_NUM_DEPCAS) return; /* Too many ISA adapters */
+
+ if (ioaddr == 0) { /* Autoprobing */
+ maxSlots = MAX_NUM_DEPCAS;
+ } else { /* Probe a specific location */
+ ports[i] = ioaddr;
+ maxSlots = i + 1;
+ }
+
+ for (; (i<maxSlots) && (dev!=NULL) && ports[i]; i++) {
+ if (DevicePresent(ports[i]) == 0) {
+ if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+ if ((dev = alloc_device(dev, ports[i])) != NULL) {
+ if (depca_hw_init(dev, ports[i]) == 0) {
+ num_depcas++;
+ }
+ num_eth++;
}
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04x.\n", dev->name,ports[i]);
}
- num_eth++;
}
}
- return dev;
+
+ return;
}
/*
** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
-** the motherboard.
+** the motherboard. Upto 15 EISA devices are supported.
*/
-static struct device *eisa_probe(struct device *dev)
+static void eisa_probe(struct device *dev, u_long ioaddr)
{
- int i, ioaddr = DEPCA_EISA_IO_PORTS;
- int status;
-
- ioaddr+=0x1000; /* get the first slot address */
- for (status = -ENODEV, i=1; i<MAX_EISA_SLOTS; i++, ioaddr+=0x1000) {
+ int i, maxSlots;
+ u_long iobase;
+ char name[DEPCA_STRLEN];
+
+ if (!ioaddr && autoprobed) return ; /* Been here before ! */
+ if ((ioaddr < 0x400) && (ioaddr > 0)) return; /* ISA Address */
+
+ if (ioaddr == 0) { /* Autoprobing */
+ iobase = EISA_SLOT_INC; /* Get the first slot address */
+ i = 1;
+ maxSlots = MAX_EISA_SLOTS;
+ } else { /* Probe a specific location */
+ iobase = ioaddr;
+ i = (ioaddr >> 12);
+ maxSlots = i + 1;
+ }
+ if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
- if (EISA_signature(DEPCA_EISA_ID) == 0) {
- if (num_depcas > 0) { /* only gets here in autoprobe */
- dev = alloc_device(dev, ioaddr);
- } else {
- if ((status = depca_probe1(dev, ioaddr)) == 0) {
- num_depcas++;
+ for (; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
+ if (EISA_signature(name, EISA_ID)) {
+ if (DevicePresent(iobase) == 0) {
+ if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+ if ((dev = alloc_device(dev, iobase)) != NULL) {
+ if (depca_hw_init(dev, iobase) == 0) {
+ num_depcas++;
+ }
+ num_eth++;
+ }
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04lx.\n",dev->name,iobase);
}
}
- num_eth++;
}
}
- return dev;
+
+ return;
}
/*
** Allocate the device by pointing to the next available space in the
** device structure. Should one not be available, it is created.
*/
-static struct device *alloc_device(struct device *dev, int ioaddr)
+static struct device *alloc_device(struct device *dev, u_long iobase)
{
+ int addAutoProbe = 0;
+ struct device *tmp = NULL, *ret;
+ int (*init)(struct device *) = NULL;
+
/*
** Check the device structures for an end of list or unused device
*/
- while (dev->next != NULL) {
- if (dev->next->base_addr == 0xffe0) break;
- dev = dev->next; /* walk through eth device list */
- num_eth++; /* increment eth device number */
- }
+ if (!loading_module) {
+ while (dev->next != NULL) {
+ if ((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0)) break;
+ dev = dev->next; /* walk through eth device list */
+ num_eth++; /* increment eth device number */
+ }
- /*
- ** If no more device structures, malloc one up. If memory could
- ** not be allocated, print an error message.
- */
- if (dev->next == NULL) {
- dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
- GFP_KERNEL);
- if (dev->next == NULL) {
- printk("eth%d: Device not initialised, insufficient memory\n",
- num_eth);
+ /*
+ ** If an autoprobe is requested for another device, we must re-insert
+ ** the request later in the list. Remember the current information.
+ */
+ if ((dev->base_addr == 0) && (num_depcas > 0)) {
+ addAutoProbe++;
+ tmp = dev->next; /* point to the next device */
+ init = dev->init; /* remember the probe function */
}
- }
+
+ /*
+ ** If at end of list and can't use current entry, malloc one up.
+ ** If memory could not be allocated, print an error message.
+ */
+ if ((dev->next == NULL) &&
+ !((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0))){
+ dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+ GFP_KERNEL);
+
+ dev = dev->next; /* point to the new device */
+ if (dev == NULL) {
+ printk("eth%d: Device not initialised, insufficient memory\n",
+ num_eth);
+ } else {
+ /*
+ ** If the memory was allocated, point to the new memory area
+ ** and initialize it (name, I/O address, next device (NULL) and
+ ** initialisation probe routine).
+ */
+ dev->name = (char *)(dev + sizeof(struct device));
+ if (num_eth > 9999) {
+ sprintf(dev->name,"eth????"); /* New device name */
+ } else {
+ sprintf(dev->name,"eth%d", num_eth);/* New device name */
+ }
+ dev->base_addr = iobase; /* assign the io address */
+ dev->next = NULL; /* mark the end of list */
+ dev->init = &depca_probe; /* initialisation routine */
+ num_depcas++;
+ }
+ }
+ ret = dev; /* return current struct, or NULL */
- /*
- ** If the memory was allocated, point to the new memory area
- ** and initialize it (name, I/O address, next device (NULL) and
- ** initialisation probe routine).
- */
- if ((dev->next != NULL) &&
- (num_eth > 0) && (num_eth < 9999)) {
- dev = dev->next; /* point to the new device */
- dev->name = (char *)(dev + 1);
- sprintf(dev->name,"eth%d", num_eth);/* New device name */
- dev->base_addr = ioaddr; /* assign the io address */
- dev->next = NULL; /* mark the end of list */
- dev->init = &depca_probe; /* initialisation routine */
- num_depcas++;
+ /*
+ ** Now figure out what to do with the autoprobe that has to be inserted.
+ ** Firstly, search the (possibly altered) list for an empty space.
+ */
+ if (ret != NULL) {
+ if (addAutoProbe) {
+ for (;(tmp->next!=NULL) && (tmp->base_addr!=DEPCA_NDA); tmp=tmp->next);
+
+ /*
+ ** If no more device structures and can't use the current one, malloc
+ ** one up. If memory could not be allocated, print an error message.
+ */
+ if ((tmp->next == NULL) && !(tmp->base_addr == DEPCA_NDA)) {
+ tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+ GFP_KERNEL);
+ tmp = tmp->next; /* point to the new device */
+ if (tmp == NULL) {
+ printk("%s: Insufficient memory to extend the device list.\n",
+ dev->name);
+ } else {
+ /*
+ ** If the memory was allocated, point to the new memory area
+ ** and initialize it (name, I/O address, next device (NULL) and
+ ** initialisation probe routine).
+ */
+ tmp->name = (char *)(tmp + sizeof(struct device));
+ if (num_eth > 9999) {
+ sprintf(tmp->name,"eth????"); /* New device name */
+ } else {
+ sprintf(tmp->name,"eth%d", num_eth);/* New device name */
+ }
+ tmp->base_addr = 0; /* re-insert the io address */
+ tmp->next = NULL; /* mark the end of list */
+ tmp->init = init; /* initialisation routine */
+ }
+ } else { /* structure already exists */
+ tmp->base_addr = 0; /* re-insert the io address */
+ }
+ }
+ }
+ } else {
+ ret = dev;
}
- return dev;
+ return ret;
}
-#endif /* MODULE */
/*
** Look for a particular board name in the on-board Remote Diagnostics
-** and Boot (RDB) ROM. This will also give us a clue to the network RAM
+** and Boot (readb) ROM. This will also give us a clue to the network RAM
** base address.
*/
-static char *DepcaSignature(unsigned long mem_addr)
+static void DepcaSignature(char *name, u_long paddr)
{
- unsigned long i,j,k;
- static char signatures[][DEPCA_NAME_LENGTH] = DEPCA_SIGNATURE;
- static char thisName[DEPCA_NAME_LENGTH];
- char tmpstr[17];
+ u_int i,j,k;
+ char *signatures[] = DEPCA_SIGNATURE;
+ char tmpstr[16];
for (i=0;i<16;i++) { /* copy the first 16 bytes of ROM to */
- tmpstr[i] = *(unsigned char *)(mem_addr+0xc000+i); /* a temporary string */
+ tmpstr[i] = readb(paddr+0xc000+i); /* a temporary string */
}
- tmpstr[i]='\0';
- strcpy(thisName,"");
- for (i=0;*signatures[i]!='\0' && *thisName=='\0';i++) {
+ strcpy(name,"");
+ for (i=0;*signatures[i]!='\0' && *name=='\0';i++) {
for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
if (signatures[i][k] == tmpstr[j]) { /* track signature */
k++;
@@ -1439,11 +1455,13 @@
}
}
if (k == strlen(signatures[i])) {
- strcpy(thisName,signatures[i]);
+ strcpy(name,signatures[i]);
}
}
- return thisName; /* return the device name string */
+ adapter = i - 1;
+
+ return;
}
/*
@@ -1461,18 +1479,19 @@
** PROM address counter is correctly positioned at the start of the
** ethernet address for later read out.
*/
-static int DevicePresent(short ioaddr)
+static int DevicePresent(u_long ioaddr)
{
union {
struct {
- u_long a;
- u_long b;
+ u32 a;
+ u32 b;
} llsig;
- char Sig[sizeof(long) << 1];
+ char Sig[sizeof(u32) << 1];
} dev;
short sigLength=0;
- char data;
- int i, j, nicsr, status = 0;
+ s8 data;
+ s16 nicsr;
+ int i, j, status = 0;
data = inb(DEPCA_PROM); /* clear counter on DEPCA */
data = inb(DEPCA_PROM); /* read data */
@@ -1485,13 +1504,13 @@
dev.llsig.a = ETH_PROM_SIG;
dev.llsig.b = ETH_PROM_SIG;
- sigLength = sizeof(long) << 1;
+ sigLength = sizeof(u32) << 1;
for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
data = inb(DEPCA_PROM);
if (dev.Sig[j] == data) { /* track signature */
j++;
- } else { /* lost signature; begin search again */
+ } else { /* lost signature; begin search again */
if (data == dev.Sig[0]) { /* rare case.... */
j=1;
} else {
@@ -1508,22 +1527,111 @@
}
/*
+** The DE100 and DE101 PROM accesses were made non-standard for some bizarre
+** reason: access the upper half of the PROM with x=0; access the lower half
+** with x=1.
+*/
+static int get_hw_addr(struct device *dev)
+{
+ u_long ioaddr = dev->base_addr;
+ int i, k, tmp, status = 0;
+ u_short j, x, chksum;
+
+ x = (((adapter == de100) || (adapter == de101)) ? 1 : 0);
+
+ for (i=0,k=0,j=0;j<3;j++) {
+ k <<= 1 ;
+ if (k > 0xffff) k-=0xffff;
+
+ k += (u_char) (tmp = inb(DEPCA_PROM + x));
+ dev->dev_addr[i++] = (u_char) tmp;
+ k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
+ dev->dev_addr[i++] = (u_char) tmp;
+
+ if (k > 0xffff) k-=0xffff;
+ }
+ if (k == 0xffff) k=0;
+
+ chksum = (u_char) inb(DEPCA_PROM + x);
+ chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
+ if (k != chksum) status = -1;
+
+ return status;
+}
+
+/*
+** Load a packet into the shared memory
+*/
+static int load_packet(struct device *dev, struct sk_buff *skb)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int i, entry, end, len, status = 0;
+
+ entry = lp->tx_new; /* Ring around buffer number. */
+ end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
+ if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {/* Enough room? */
+ /*
+ ** Caution: the write order is important here... don't set up the
+ ** ownership rights until all the other information is in place.
+ */
+ if (end < entry) { /* wrapped buffer */
+ len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
+ memcpy_toio(lp->tx_memcpy[entry], skb->data, len);
+ memcpy_toio(lp->tx_memcpy[0], skb->data + len, skb->len - len);
+ } else { /* linear buffer */
+ memcpy_toio(lp->tx_memcpy[entry], skb->data, skb->len);
+ }
+
+ /* set up the buffer descriptors */
+ len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+ for (i = entry; i != end; i = (++i) & lp->txRingMask) {
+ /* clean out flags */
+ writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
+ writew(0x0000, &lp->tx_ring[i].misc); /* clears other error flags */
+ writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);/* packet length in buffer */
+ len -= TX_BUFF_SZ;
+ }
+ /* clean out flags */
+ writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
+ writew(0x0000, &lp->tx_ring[end].misc); /* clears other error flags */
+ writew(-len, &lp->tx_ring[end].length); /* packet length in last buff */
+
+ /* start of packet */
+ writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
+ /* end of packet */
+ writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
+
+ for (i=end; i!=entry; --i) {
+ /* ownership of packet */
+ writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
+ if (i == 0) i=lp->txRingMask+1;
+ }
+ writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
+
+ lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */
+ } else {
+ status = -1;
+ }
+
+ return status;
+}
+
+/*
** Look for a particular board name in the EISA configuration space
*/
-static int EISA_signature(short iobase)
+static int EISA_signature(char *name, s32 eisa_id)
{
- unsigned long i;
- int status;
+ u_int i;
char *signatures[] = DEPCA_SIGNATURE;
- char ManCode[8];
+ char ManCode[DEPCA_STRLEN];
union {
- u_long ID;
- u_char Id[4];
+ s32 ID;
+ char Id[4];
} Eisa;
+ int status = 0;
- for (i=0; i<4; i++) {
- Eisa.Id[i] = inb(iobase + i);
- }
+ *name = '\0';
+ Eisa.ID = inl(eisa_id);
ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
@@ -1532,13 +1640,179 @@
ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
ManCode[5]='\0';
- for (status = -ENXIO, i=0;*signatures[i] != '\0' && status;i++) {
+ for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
if (strstr(ManCode, signatures[i]) != NULL) {
- status = 0;
+ strcpy(name,ManCode);
+ status = 1;
}
}
-
- return status; /* return the device name string */
+
+ return status;
+}
+
+/*
+** Perform IOCTL call functions here. Some are privileged operations and the
+** effective uid is checked in those cases.
+*/
+static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data;
+ int i, status = 0;
+ u_long ioaddr = dev->base_addr;
+ union {
+ u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
+ u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+ u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
+ } tmp;
+
+ switch(ioc->cmd) {
+ case DEPCA_GET_HWADDR: /* Get the hardware address */
+ for (i=0; i<ETH_ALEN; i++) {
+ tmp.addr[i] = dev->dev_addr[i];
+ }
+ ioc->len = ETH_ALEN;
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ }
+
+ break;
+ case DEPCA_SET_HWADDR: /* Set the hardware address */
+ if (suser()) {
+ if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) {
+ memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
+ for (i=0; i<ETH_ALEN; i++) {
+ dev->dev_addr[i] = tmp.addr[i];
+ }
+ while(dev->tbusy); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new);/* Wait for the ring to empty */
+
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
+ }
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_SET_PROM: /* Set Promiscuous Mode */
+ if (suser()) {
+ while(dev->tbusy); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ lp->init_block.mode |= PROM; /* Set promiscuous mode */
+
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */
+ if (suser()) {
+ while(dev->tbusy); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */
+
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */
+ printk("%s: Boo!\n", dev->name);
+
+ break;
+ case DEPCA_GET_MCA: /* Get the multicast address table */
+ ioc->len = (HASH_TABLE_LEN >> 3);
+ if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, lp->init_block.mcast_table, ioc->len);
+ }
+
+ break;
+ case DEPCA_SET_MCA: /* Set a multicast address */
+ if (suser()) {
+ if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */
+ if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) {
+ memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+ set_multicast_list(dev, ioc->len, tmp.addr);
+ }
+ } else {
+ set_multicast_list(dev, ioc->len, NULL);
+ }
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_CLR_MCA: /* Clear all multicast addresses */
+ if (suser()) {
+ set_multicast_list(dev, 0, NULL);
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_MCA_EN: /* Enable pass all multicast addressing */
+ if (suser()) {
+ set_multicast_list(dev, HASH_TABLE_LEN, NULL);
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_GET_STATS: /* Get the driver statistics */
+ cli();
+ ioc->len = sizeof(lp->pktStats);
+ if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, &lp->pktStats, ioc->len);
+ }
+ sti();
+
+ break;
+ case DEPCA_CLR_STATS: /* Zero out the driver statistics */
+ if (suser()) {
+ cli();
+ memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+ sti();
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_GET_REG: /* Get the DEPCA Registers */
+ i=0;
+ tmp.sval[i++] = inw(DEPCA_NICSR);
+ outw(CSR0, DEPCA_ADDR); /* status register */
+ tmp.sval[i++] = inw(DEPCA_DATA);
+ memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
+ ioc->len = i+sizeof(struct depca_init);
+ if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ }
+
+ break;
+ default:
+ status = -EOPNOTSUPP;
+ }
+
+ return status;
}
#ifdef MODULE
@@ -1549,13 +1823,8 @@
0x200, 7, /* I/O address, IRQ */
0, 0, 0, NULL, depca_probe };
-/*
- * This is a tweak to keep the insmod program happy. It can only
- * set int values with var=value so we split these out.
- */
-
-int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */
-int io=0x200; /* Or use the irq= io= options to insmod */
+static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */
+static int io=0x200; /* Or use the irq= io= options to insmod */
int
init_module(void)
@@ -1564,6 +1833,7 @@
thisDepca.base_addr=io;
if (register_netdev(&thisDepca) != 0)
return -EIO;
+
return 0;
}
@@ -1574,6 +1844,11 @@
printk("%s: device busy, remove delayed\n",thisDepca.name);
} else {
release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE);
+ if (thisDepca.priv) {
+ kfree_s(thisDepca.priv, sizeof(struct depca_private));
+ thisDepca.priv = NULL;
+ }
+
unregister_netdev(&thisDepca);
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this