patch-1.3.5 linux/drivers/net/de4x5.c

Next file: linux/drivers/net/de4x5.h
Previous file: linux/drivers/net/Space.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.4/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
@@ -1,4 +1,4 @@
-/*  de4x5.c: A DIGITAL DE425/DE434/DE435 ethernet driver for linux.
+/*  de4x5.c: A DIGITAL DE425/DE434/DE435/DE500 ethernet driver for Linux.
 
     Copyright 1994, 1995 Digital Equipment Corporation.
 
@@ -68,7 +68,7 @@
     0) have a copy of the loadable modules code installed on your system.
     1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
-    2) edit the  source code near  line 1945 to reflect  the I/O address and
+    2) edit the  source code near  line 2762 to reflect  the I/O address and
     IRQ you're using, or assign these when loading by:
 
                    insmod de4x5.o irq=x io=y
@@ -93,12 +93,12 @@
     pause whilst the   driver figures out   where its media went).  My tests
     using ping showed that it appears to work....
 
-    A compile time  switch to allow  Zynx  recognition has been  added. This
+    A compile time  switch to allow  Znyx  recognition has been  added. This
     "feature" is in no way supported nor tested  in this driver and the user
     may use it at his/her sole discretion.  I have had 2 conflicting reports
-    that  my driver  will or   won't  work with   Zynx. Try Donald  Becker's
+    that  my driver  will or   won't  work with   Znyx. Try Donald  Becker's
     'tulip.c' if this driver doesn't work for  you. I will not be supporting
-    Zynx cards since I have no information on them  and can't test them in a
+    Znyx cards since I have no information on them  and can't test them in a
     system.
 
     TO DO:
@@ -126,11 +126,22 @@
 			  Change media autodetection to allow manual setting.
 			  Completed DE500 (DC21140) support.
       0.241   18-Apr-95   Interim release without DE500 Autosense Algorithm.
+      0.242   10-May-95   Minor changes
+      0.30    12-Jun-95   Timer fix for DC21140
+                          Portability changes.
+			  Add ALPHA changes from <jestabro@ant.tay1.dec.com>.
+			  Add DE500 semi automatic autosense.
+			  Add Link Fail interrupt TP failure detection.
+			  Add timer based link change detection.
+			  Plugged a memory leak in de4x5_queue_pkt().
+      0.31    13-Jun-95   Fixed PCI stuff for 1.3.1
+      0.32    26-Jun-95   Added verify_area() calls in de4x5_ioctl() from
+                          suggestion by <heiko@colossus.escape.de>
 
     =========================================================================
 */
 
-static char *version = "de4x5.c:v0.241 4/18/95 davies@wanton.lkg.dec.com\n";
+static char *version = "de4x5.c:v0.32 6/26/95 davies@wanton.lkg.dec.com\n";
 
 #include <linux/config.h>
 #ifdef MODULE
@@ -149,6 +160,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/malloc.h>
+#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <asm/bitops.h>
@@ -175,9 +187,17 @@
 #ifdef DE4X5_AUTOSENSE              /* Should be done on a per adapter basis */
 static int de4x5_autosense = DE4X5_AUTOSENSE;
 #else
-static int de4x5_autosense = AUTO;      /* Do auto media/mode sensing */
+static int de4x5_autosense = AUTO;  /* Do auto media/mode sensing */
 #endif
 
+#ifdef DE4X5_FULL_DUPLEX            /* Should be done on a per adapter basis */
+static s32 de4x5_full_duplex = 1;
+#else
+static s32 de4x5_full_duplex = 0;
+#endif
+
+#define DE4X5_NDA 0xffe0            /* No Device (I/O) Address */
+
 /*
 ** Ethernet PROM defines
 */
@@ -187,11 +207,14 @@
 /*
 ** Ethernet Info
 */
-#define PKT_BUF_SZ	1544            /* Buffer size for each Tx/Rx buffer */
+#define PKT_BUF_SZ	1536            /* Buffer size for each Tx/Rx buffer */
 #define MAX_PKT_SZ   	1514            /* Maximum ethernet packet length */
 #define MAX_DAT_SZ   	1500            /* Maximum ethernet data length */
 #define MIN_DAT_SZ   	1               /* Minimum ethernet data length */
 #define PKT_HDR_LEN     14              /* Addresses and data length info */
+#define FAKE_FRAME_LEN  (MAX_PKT_SZ + 1)
+#define QUEUE_PKT_TIMEOUT (300)         /* Jiffies */
+
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL   /* Ethernet CRC, big endian */
 #define CRC_POLYNOMIAL_LE 0xedb88320UL   /* Ethernet CRC, little endian */
@@ -213,6 +236,7 @@
 */
 #define PCI_MAX_BUS_NUM 8
 #define DE4X5_PCI_TOTAL_SIZE 0x80        /* I/O address extent */
+#define DE4X5_CLASS_CODE     0x00020000  /* Network controller, Ethernet */
 
 /*
 ** Memory Alignment. Each descriptor is 4 longwords long. To force a
@@ -230,7 +254,7 @@
 #define ALIGN         ALIGN32          /* Keep the DC21040 happy... */
 #define CACHE_ALIGN   CAL_16LONG
 #define DESC_SKIP_LEN DSL_0            /* Must agree with DESC_ALIGN */
-/*#define DESC_ALIGN    u_long dummy[4]; / * Must agree with DESC_SKIP_LEN */
+/*#define DESC_ALIGN    u32 dummy[4]; / * Must agree with DESC_SKIP_LEN */
 #define DESC_ALIGN
 
 #ifndef IS_NOT_DEC                     /* See README.de4x5 for using this */
@@ -242,29 +266,25 @@
 /*
 ** DE4X5 IRQ ENABLE/DISABLE
 */
-static u_long irq_mask = IMR_SEM | IMR_RIM | IMR_RUM | IMR_TIM | IMR_TUM ;
-
-static u_long irq_en   = IMR_NIM | IMR_AIM;
-
 #define ENABLE_IRQs { \
-    imr |= irq_en;\
+    imr |= lp->irq_en;\
     outl(imr, DE4X5_IMR);                   /* Enable the IRQs */\
 }
 
 #define DISABLE_IRQs {\
     imr = inl(DE4X5_IMR);\
-    imr &= ~irq_en;\
+    imr &= ~lp->irq_en;\
     outl(imr, DE4X5_IMR);                   /* Disable the IRQs */\
 }
 
 #define UNMASK_IRQs {\
-    imr |= irq_mask;\
+    imr |= lp->irq_mask;\
     outl(imr, DE4X5_IMR);                   /* Unmask the IRQs */\
 }
 
 #define MASK_IRQs {\
     imr = inl(DE4X5_IMR);\
-    imr &= ~irq_mask;\
+    imr &= ~lp->irq_mask;\
     outl(imr, DE4X5_IMR);                   /* Mask the IRQs */\
 }
 
@@ -289,6 +309,11 @@
 #define RESET_SIA outl(0, DE4X5_SICR);      /* Reset SIA connectivity regs */
 
 /*
+** DE500 AUTOSENSE TIMER INTERVAL (MILLISECS)
+*/
+#define DE4X5_AUTOSENSE_MS  250
+
+/*
 ** SROM Structure
 */
 struct de4x5_srom {
@@ -303,21 +328,21 @@
 /*
 ** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
 ** and have sizes of both a power of 2 and a multiple of 4.
-** A size of 256 bytes for each buffer was chosen because over 90% of
+** A size of 256 bytes for each buffer could be chosen because over 90% of
 ** all packets in our network are <256 bytes long and 64 longword alignment
-** is possible.
+** is possible. 1536 showed better 'ttcp' performance. Take your pick. 32 TX
+** descriptors are needed for machines with an ALPHA CPU.
 */
 #define NUM_RX_DESC 8                        /* Number of RX descriptors */
-#define NUM_TX_DESC 8                        /* Number of TX descriptors */
+#define NUM_TX_DESC 32                       /* Number of TX descriptors */
 #define BUFF_ALLOC_RETRIES 10                /* In case of memory shortage */
 #define RX_BUFF_SZ 1536                      /* Power of 2 for kmalloc and */
                                              /* Multiple of 4 for DC21040 */
-
 struct de4x5_desc {
-    volatile long status;
-    u_long des1;
-    char *buf;
-    char *next;
+    volatile s32 status;
+    u32 des1;
+    u32 buf;
+    u32 next;
     DESC_ALIGN
 };
 
@@ -338,22 +363,26 @@
     char setup_frame[SETUP_FRAME_LEN];       /* Holds MCA and PA info. */
     struct enet_statistics stats;            /* Public stats */
     struct {
-	unsigned long bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
-	unsigned long unicast;
-	unsigned long multicast;
-	unsigned long broadcast;
-	unsigned long excessive_collisions;
-	unsigned long tx_underruns;
-	unsigned long excessive_underruns;
+	u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
+	u_int unicast;
+	u_int multicast;
+	u_int broadcast;
+	u_int excessive_collisions;
+	u_int tx_underruns;
+	u_int excessive_underruns;
     } pktStats;
     char rxRingSize;
     char txRingSize;
-    char bus;                                /* EISA or PCI */
-    u_short chipset;                         /* DC21040, DC21041 or DC21140 */
-    long media;                              /* Media (eg TP), mode (eg 100B)*/
+    int  bus;                                /* EISA or PCI */
+    int  bus_num;                            /* PCI Bus number */
+    int  chipset;                            /* DC21040, DC21041 or DC21140 */
+    s32  irq_mask;                           /* Interrupt Mask (Enable) bits */
+    s32  irq_en;                             /* Summary interrupt bits */
+    int  media;                              /* Media (eg TP), mode (eg 100B)*/
+    int  linkProb;                           /* Possible Link Problem */
     int  autosense;                          /* Allow/disallow autosensing */
     int  tx_enable;                          /* Enable descriptor polling */
-    char lostMedia;                          /* Possibly lost media */
+    int  lostMedia;                          /* Possibly lost media */
     int  setup_f;                            /* Setup frame filtering type */
 };
 
@@ -368,7 +397,6 @@
 #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
 			 lp->tx_old+lp->txRingSize-lp->tx_new-1:\
                          lp->tx_old               -lp->tx_new-1)
-/*#define TX_BUFFS_AVAIL ((lp->tx_ring[lp->tx_new].status)>=0 ? 1 : 0)*/
 
 /*
 ** Public Functions
@@ -384,41 +412,46 @@
 /*
 ** Private functions
 */
-static int     de4x5_hw_init(struct device *dev, short iobase);
+static int     de4x5_hw_init(struct device *dev, u_long iobase);
 static int     de4x5_init(struct device *dev);
 static int     de4x5_rx(struct device *dev);
 static int     de4x5_tx(struct device *dev);
+static int     de4x5_ast(struct device *dev);
 
 static int     autoconf_media(struct device *dev);
 static void    create_packet(struct device *dev, char *frame, int len);
-static void    dce_us_delay(u_long usec);
-static void    dce_ms_delay(u_long msec);
-static void    load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb);
+static void    dce_us_delay(u32 usec);
+static void    dce_ms_delay(u32 msec);
+static void    load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb);
 static void    dc21040_autoconf(struct device *dev);
 static void    dc21041_autoconf(struct device *dev);
 static void    dc21140_autoconf(struct device *dev);
-static long    test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec);
-static long    ping_media(struct device *dev);
-static void    reset_init_sia(struct device *dev, long sicr, long strr, long sigr);
-static int     test_ans(struct device *dev, long irqs, long irq_mask, long msec);
-static void    load_ms_timer(struct device *dev, u_long msec);
-static int     EISA_signature(char *name, long eisa_id);
-static int     DevicePresent(short iobase);
-static short   srom_rd(u_short address, u_char offset);
-static void    srom_latch(u_long command, u_short address);
-static void    srom_command(u_long command, u_short address);
-static void    srom_address(u_long command, u_short address, u_char offset);
-static short   srom_data(u_long command, u_short address);
-/*static void    srom_busy(u_long command, u_short address);*/
-static void    sendto_srom(u_long command, u_short addr);
-static long    getfrom_srom(u_short addr);
+static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
+/*static int     test_sym_link(struct device *dev, u32 msec);*/
+static int     ping_media(struct device *dev);
+static void    reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr);
+static int     test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec);
+static void    load_ms_timer(struct device *dev, u32 msec);
+static int     EISA_signature(char *name, s32 eisa_id);
+static int     DevicePresent(u_long iobase);
+static short   srom_rd(u_long address, u_char offset);
+static void    srom_latch(u_int command, u_long address);
+static void    srom_command(u_int command, u_long address);
+static void    srom_address(u_int command, u_long address, u_char offset);
+static short   srom_data(u_int command, u_long address);
+/*static void    srom_busy(u_int command, u_long address);*/
+static void    sendto_srom(u_int command, u_long addr);
+static int     getfrom_srom(u_long addr);
 static void    SetMulticastFilter(struct device *dev, int num_addrs, char *addrs);
-static int     aprom_crc (struct device *dev);
+static int     get_hw_addr(struct device *dev);
 
-static void    eisa_probe(struct device *dev, short iobase);
-static void    pci_probe(struct device *dev, short iobase);
-static struct  device *alloc_device(struct device *dev, int iobase);
+static void    eisa_probe(struct device *dev, u_long iobase);
+static void    pci_probe(struct device *dev, u_long iobase);
+static struct  device *alloc_device(struct device *dev, u_long iobase);
 static char    *build_setup_frame(struct device *dev, int mode);
+static void    disable_ast(struct device *dev);
+static void    enable_ast(struct device *dev, u32 time_out);
+static void    kick_tx(struct device *dev);
 
 #ifdef MODULE
 int  init_module(void);
@@ -439,6 +472,7 @@
 */
 static struct bus_type {
     int bus;
+    int bus_num;
     int device;
     int chipset;
     struct de4x5_srom srom;
@@ -449,30 +483,33 @@
 ** Miscellaneous defines...
 */
 #define RESET_DE4X5 {\
-    long i;\
+    int i;\
     i=inl(DE4X5_BMR);\
+    dce_ms_delay(1);\
     outl(i | BMR_SWR, DE4X5_BMR);\
+    dce_ms_delay(1);\
     outl(i, DE4X5_BMR);\
-    for (i=0;i<5;i++) inl(DE4X5_BMR);\
+    dce_ms_delay(1);\
+    for (i=0;i<5;i++) {inl(DE4X5_BMR); dce_ms_delay(1);}\
+    dce_ms_delay(1);\
 }
 
 
 
 int de4x5_probe(struct device *dev)
 {
-  int tmp = num_de4x5s, iobase = dev->base_addr;
-  int status = -ENODEV;
+  int tmp = num_de4x5s, status = -ENODEV;
+  u_long iobase = dev->base_addr;
 
   if ((iobase == 0) && loading_module){
     printk("Autoprobing is not supported when loading a module based driver.\n");
     status = -EIO;
-  } else {                              /* First probe for the Ethernet */
-	                                /* Address PROM pattern */
+  } else {
     eisa_probe(dev, iobase);
     pci_probe(dev, iobase);
 
-    if ((tmp == num_de4x5s) && (iobase != 0)) {
-      printk("%s: de4x5_probe() cannot find device at 0x%04x.\n", dev->name, 
+    if ((tmp == num_de4x5s) && (iobase != 0) && loading_module) {
+      printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name, 
 	                                                               iobase);
     }
 
@@ -490,12 +527,11 @@
 }
 
 static int
-de4x5_hw_init(struct device *dev, short iobase)
+de4x5_hw_init(struct device *dev, u_long iobase)
 {
   struct bus_type *lp = &bus;
   int tmpbus, tmpchs, i, j, status=0;
   char *tmp;
-  u_long nicsr;
 
   /* Ensure we're not sleeping */
   if (lp->chipset == DC21041) {
@@ -505,7 +541,7 @@
 
   RESET_DE4X5;
 
-  if (((nicsr=inl(DE4X5_STS)) & (STS_TS | STS_RS)) == 0) {
+  if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) == 0) {
     /* 
     ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
     */
@@ -525,16 +561,16 @@
 
     if (*name != '\0') {                         /* found a board signature */
       dev->base_addr = iobase;
-      
       if (lp->bus == EISA) {
-	printk("%s: %s at %#3x (EISA slot %d)", 
-	       dev->name, name, (u_short)iobase, (((u_short)iobase>>12)&0x0f));
+	printk("%s: %s at %04lx (EISA slot %ld)", 
+	                        dev->name, name, iobase, ((iobase>>12)&0x0f));
       } else {                                   /* PCI port address */
-	printk("%s: %s at %#3x (PCI device %d)", dev->name, name, (u_short)iobase,lp->device);
+	printk("%s: %s at %04lx (PCI bus %d, device %d)", dev->name, name,
+	                                      iobase, lp->bus_num, lp->device);
       }
 	
       printk(", h/w address ");
-      status = aprom_crc(dev);
+      status = get_hw_addr(dev);
       for (i = 0; i < ETH_ALEN - 1; i++) {       /* get the ethernet addr. */
 	printk("%2.2x:", dev->dev_addr[i]);
       }
@@ -597,9 +633,10 @@
 	    for (i=0; i<NUM_RX_DESC; i++) {
 	      lp->rx_ring[i].status = 0;
 	      lp->rx_ring[i].des1 = RX_BUFF_SZ;
-	      lp->rx_ring[i].buf = tmp + i * RX_BUFF_SZ;
-	      lp->rx_ring[i].next = NULL;
+	      lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
+	      lp->rx_ring[i].next = (u32)NULL;
 	    }
+	    barrier();
 	  }
 	}
 
@@ -612,15 +649,19 @@
 	  lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
 
 	  /* Tell the adapter where the TX/RX rings are located. */
-	  outl((long)lp->rx_ring, DE4X5_RRBA);
-	  outl((long)lp->tx_ring, DE4X5_TRBA);
+	  outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+	  outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+
+	  /* Initialise the IRQ mask and Enable/Disable */
+	  lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
+	  lp->irq_en   = IMR_NIM | IMR_AIM;
 
 	  lp->tx_enable = TRUE;
 
 	  if (dev->irq < 2) {
 #ifndef MODULE
 	    unsigned char irqnum;
-	    u_long omr;
+	    s32 omr;
 	    autoirq_setup(0);
 	    
 	    omr = inl(DE4X5_OMR);
@@ -698,7 +739,8 @@
   } else {                            /* Incorrectly initialised hardware */
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     if (lp) {
-      kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
+      kfree_s(bus_to_virt(lp->rx_ring[0].buf),
+	                                    RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
     }
     if (dev->priv) {
       kfree_s(dev->priv, sizeof(struct de4x5_private) + ALIGN);
@@ -714,9 +756,9 @@
 de4x5_open(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  short iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
   int i, status = 0;
-  long imr, omr, sts;
+  s32 imr, omr, sts;
 
   /*
   ** Wake up the adapter
@@ -745,35 +787,35 @@
       }
       printk("\n");
       printk("Descriptor head addresses:\n");
-      printk("\t0x%8.8lx  0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
+      printk("\t0x%8.8lx  0x%8.8lx\n",(u_long)lp->rx_ring,(u_long)lp->tx_ring);
       printk("Descriptor addresses:\nRX: ");
       for (i=0;i<lp->rxRingSize-1;i++){
 	if (i < 3) {
-	  printk("0x%8.8lx  ",(long)&lp->rx_ring[i].status);
+	  printk("0x%8.8lx  ",(u_long)&lp->rx_ring[i].status);
 	}
       }
-      printk("...0x%8.8lx\n",(long)&lp->rx_ring[i].status);
+      printk("...0x%8.8lx\n",(u_long)&lp->rx_ring[i].status);
       printk("TX: ");
       for (i=0;i<lp->txRingSize-1;i++){
 	if (i < 3) {
-	  printk("0x%8.8lx  ", (long)&lp->tx_ring[i].status);
+	  printk("0x%8.8lx  ", (u_long)&lp->tx_ring[i].status);
 	}
       }
-      printk("...0x%8.8lx\n", (long)&lp->tx_ring[i].status);
+      printk("...0x%8.8lx\n", (u_long)&lp->tx_ring[i].status);
       printk("Descriptor buffers:\nRX: ");
       for (i=0;i<lp->rxRingSize-1;i++){
 	if (i < 3) {
-	  printk("0x%8.8lx  ",(long)lp->rx_ring[i].buf);
+	  printk("0x%8.8x  ",lp->rx_ring[i].buf);
 	}
       }
-      printk("...0x%8.8lx\n",(long)lp->rx_ring[i].buf);
+      printk("...0x%8.8x\n",lp->rx_ring[i].buf);
       printk("TX: ");
       for (i=0;i<lp->txRingSize-1;i++){
 	if (i < 3) {
-	  printk("0x%8.8lx  ", (long)lp->tx_ring[i].buf);
+	  printk("0x%8.8x  ", lp->tx_ring[i].buf);
 	}
       }
-      printk("...0x%8.8lx\n", (long)lp->tx_ring[i].buf);
+      printk("...0x%8.8x\n", lp->tx_ring[i].buf);
       printk("Ring size: \nRX: %d\nTX: %d\n", 
 	     (short)lp->rxRingSize, 
 	     (short)lp->txRingSize); 
@@ -827,9 +869,9 @@
 de4x5_init(struct device *dev)
 {  
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  short iobase = dev->base_addr;
-  int status = 0;
-  long i, j, bmr, omr;
+  u_long iobase = dev->base_addr;
+  int i, j, status = 0;
+  s32 bmr, omr;
 
   /* Lock out other processes whilst setting up the hardware */
   set_bit(0, (void *)&dev->tbusy);
@@ -847,8 +889,8 @@
     omr = OMR_SDP | OMR_SF;
     lp->setup_f = PERFECT;
   }
-  outl((long)lp->rx_ring, DE4X5_RRBA);
-  outl((long)lp->tx_ring, DE4X5_TRBA);
+  outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+  outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
 
   lp->rx_new = lp->rx_old = 0;
   lp->tx_new = lp->tx_old = 0;
@@ -861,6 +903,8 @@
     lp->tx_ring[i].status = 0;
   }
 
+  barrier();
+
   /* Build the setup frame depending on filtering mode */
   SetMulticastFilter(dev, 0, NULL);
 
@@ -872,12 +916,12 @@
   outl(omr|OMR_ST, DE4X5_OMR);
 
   /* Poll for completion of setup frame (interrupts are disabled for now) */
-  for (j=0, i=0;(i<100) && (j==0);i++) {
+  for (j=0, i=jiffies;(i==jiffies) && (j==0);) {
     if (lp->tx_ring[lp->tx_new].status >= 0) j=1;
   }
   outl(omr, DE4X5_OMR);                        /* Stop everything! */
 
-  if (i == 100) {
+  if (j == 0) {
     printk("%s: Setup frame timed out, status %08x\n", dev->name, 
 	                                                       inl(DE4X5_STS));
     status = -EIO;
@@ -900,27 +944,63 @@
 static int
 de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
 {
-  volatile struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  int status = 0;
-  u_long imr, omr, sts;
-
-  sts = inl(DE4X5_STS);
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+  int i, status = 0;
+  s32 imr, omr, sts;
 
+  /*
+  ** Clean out the TX ring asynchronously to interrupts - sometimes the
+  ** interrupts are lost by delayed descriptor status updates relative to
+  ** the irq assertion, especially with a busy PCI bus.
+  */
+  if (set_bit(0, (void*)&dev->tbusy) == 0) {
+    cli();
+    de4x5_tx(dev);
+    dev->tbusy = 0;
+    sti();
+  }
+  
   /* 
   ** Transmitter timeout, possibly serious problems.
   ** The 'lostMedia' threshold accounts for transient errors that
   ** were noticed when switching media.
   */
   if (dev->tbusy || (lp->lostMedia > LOST_MEDIA_THRESHOLD)) {
-    int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 10 && (lp->lostMedia <= LOST_MEDIA_THRESHOLD)) {
+    u_long tickssofar = jiffies - dev->trans_start;
+    if ((tickssofar < QUEUE_PKT_TIMEOUT) &&
+	(lp->lostMedia <= LOST_MEDIA_THRESHOLD)) {
       status = -1;
     } else {
-      printk("%s: transmit timed out, status %08x, tbusy:%d, lostMedia:%d tickssofar:%d, resetting.\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, tickssofar);
-	
+      if (de4x5_debug >= 1) {
+	printk("%s: transmit timed out, status %08x, tbusy:%d, lostMedia:%d tickssofar:%ld, resetting.\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, tickssofar);
+      }
+
       /* Stop and reset the TX and RX... */
       STOP_DE4X5;
+
+      /* Re-queue any skb's. */
+      for (i=lp->tx_old; i!=lp->tx_new; i=(++i)%lp->txRingSize) {
+	if (lp->skb[i] != NULL) {
+	  if (lp->skb[i]->len != FAKE_FRAME_LEN) {
+	    if (lp->tx_ring[i].status == T_OWN) {
+	      dev_queue_xmit(lp->skb[i], dev, SOPRI_NORMAL);
+	    } else {                               /* already sent */
+	      dev_kfree_skb(lp->skb[i], FREE_WRITE);
+	    }
+	  } else {
+	    dev_kfree_skb(lp->skb[i], FREE_WRITE);
+	  }
+	  lp->skb[i] = NULL;
+	}
+      }
+      if (skb->len != FAKE_FRAME_LEN) {
+	dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+      } else {
+	dev_kfree_skb(skb, FREE_WRITE);
+      }
+
+      /* Initialise the hardware */
       status = de4x5_init(dev);
 
       /* Unmask DE4X5 board interrupts */
@@ -949,28 +1029,31 @@
     }
   } else if (skb == NULL) {
     dev_tint(dev);
+  } else if (skb->len == FAKE_FRAME_LEN) {     /* Don't TX a fake frame! */
+    dev_kfree_skb(skb, FREE_WRITE);
   } else if (skb->len > 0) {
-
-    /* 
-    ** 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)
+    /* 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;                             /* Re-queue packet */
+    } else {
+      cli();
+      if (TX_BUFFS_AVAIL) {                    /* Fill in a Tx ring entry */
+	load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
+	if (lp->tx_enable) {
+	  outl(POLL_DEMAND, DE4X5_TPD);        /* Start the TX */
+	}
 
-    if (TX_BUFFS_AVAIL) {                       /* Fill in a Tx ring entry */
-      load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
-      if (lp->tx_enable) {
-	outl(POLL_DEMAND, DE4X5_TPD);           /* Start the TX */
-      }
-
-      lp->tx_new = (++lp->tx_new) % lp->txRingSize; /* Ensure a wrap */
-	
-      dev->trans_start = jiffies;
-    }
+	lp->tx_new = (++lp->tx_new) % lp->txRingSize; /* Ensure a wrap */
+	dev->trans_start = jiffies;
 
-    if (TX_BUFFS_AVAIL) {
-      dev->tbusy = 0;                           /* Another pkt may be queued */
+	if (TX_BUFFS_AVAIL) {
+	  dev->tbusy = 0;                      /* Another pkt may be queued */
+	}
+      } else {                                 /* Ring full - re-queue */
+	status = -1;
+      }
+      sti();
     }
   }
 
@@ -979,14 +1062,22 @@
 
 /*
 ** The DE4X5 interrupt handler. 
+** 
+** I/O Read/Writes through intermediate PCI bridges are never 'posted',
+** so that the asserted interrupt always has some real data to work with -
+** if these I/O accesses are ever changed to memory accesses, ensure the
+** STS write is read immediately to complete the transaction if the adapter
+** is not on bus 0. Lost interrupts can still occur when the PCI bus load
+** is high and descriptor status bits cannot be set before the associated
+** interrupt is asserted and this routine entered.
 */
 static void
 de4x5_interrupt(int irq, struct pt_regs *regs)
 {
     struct device *dev = (struct device *)(irq2dev_map[irq]);
     struct de4x5_private *lp;
-    int iobase;
-    u_long imr, omr, sts;
+    s32 imr, omr, sts;
+    u_long iobase;
 
     if (dev == NULL) {
 	printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
@@ -997,29 +1088,32 @@
       if (dev->interrupt)
 	printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
+      DISABLE_IRQs;                      /* Ensure non re-entrancy */
       dev->interrupt = MASK_INTERRUPTS;
 
-      /* 
-      ** Get the interrupt information and disable them. 
-      ** The device read will ensure pending buffers are flushed
-      ** in intermediate PCI bridges, so that the posted interrupt
-      ** has some real data to work with.
-      */
-      sts = inl(DE4X5_STS);
-      MASK_IRQs;
+      while ((sts = inl(DE4X5_STS)) & lp->irq_mask) { /* Read IRQ status */
+	outl(sts, DE4X5_STS);            /* Reset the board interrupts */
 
-      outl(sts, DE4X5_STS);              /* Reset the board interrupts */
+	if (sts & (STS_RI | STS_RU))	 /* Rx interrupt (packet[s] arrived) */
+	  de4x5_rx(dev);
 
-      if (sts & (STS_RI | STS_RU))	 /* Rx interrupt (packet[s] arrived) */
-	de4x5_rx(dev);
+	if (sts & (STS_TI | STS_TU))     /* Tx interrupt (packet sent) */
+	  de4x5_tx(dev); 
 
-      if (sts & (STS_TI | STS_TU))       /* Tx interrupt (packet sent) */
-	de4x5_tx(dev); 
+	if (sts & STS_TM)                /* Autosense tick */
+	  de4x5_ast(dev);
+
+	if (sts & STS_LNF) {             /* TP Link has failed */
+	  lp->lostMedia = LOST_MEDIA_THRESHOLD + 1;
+	  lp->irq_mask &= ~IMR_LFM;
+	  kick_tx(dev);
+	}
 
-      if (sts & STS_SE) {                /* Bus Error */
-	STOP_DE4X5;
-	printk("%s: Fatal bus error occurred, sts=0x%08lx, device stopped.\n", 
-	                                                       dev->name, sts);
+	if (sts & STS_SE) {              /* Bus Error */
+	  STOP_DE4X5;
+	  printk("%s: Fatal bus error occured, sts=%#8x, device stopped.\n",
+	                                                      dev->name, sts);
+	}
       }
 
       if (TX_BUFFS_AVAIL && dev->tbusy) {/* Any resources available? */
@@ -1028,8 +1122,7 @@
       }
 
       dev->interrupt = UNMASK_INTERRUPTS;
-
-      UNMASK_IRQs;
+      ENABLE_IRQs;
     }
 
     return;
@@ -1040,7 +1133,7 @@
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   int i, entry;
-  volatile long status;
+  s32 status;
   char *buf;
 
   for (entry = lp->rx_new; lp->rx_ring[entry].status >= 0;entry = lp->rx_new) {
@@ -1066,22 +1159,17 @@
 	
 	  if (entry < lp->rx_old) {         /* Wrapped buffer */
 	    short len = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
-	    memcpy(skb->data, lp->rx_ring[lp->rx_old].buf, len);
-	    memcpy(skb->data + len, lp->rx_ring[0].buf, pkt_len - len);
+	    memcpy(skb->data, bus_to_virt(lp->rx_ring[lp->rx_old].buf), len);
+	    memcpy(skb->data + len, bus_to_virt(lp->rx_ring[0].buf), pkt_len - len);
 	  } else {                          /* Linear buffer */
-	    memcpy(skb->data, lp->rx_ring[lp->rx_old].buf, pkt_len);
+	    memcpy(skb->data, bus_to_virt(lp->rx_ring[lp->rx_old].buf), pkt_len);
 	  }
 
-	  /* 
-	  ** Notify the upper protocol layers that there is another 
-	  ** packet to handle
-	  */
+	  /* Push up the protocol stack */
 	  skb->protocol=eth_type_trans(skb,dev);
 	  netif_rx(skb);
 
-	  /*
-	  ** Update stats
-	  */
+	  /* Update stats */
 	  lp->stats.rx_packets++;
 	  for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
 	    if (pkt_len < (i*DE4X5_PKT_BIN_SZ)) {
@@ -1091,13 +1179,13 @@
 	  }
 	  buf = skb->data;                  /* Look at the dest addr */
 	  if (buf[0] & 0x01) {              /* Multicast/Broadcast */
-	    if ((*(long *)&buf[0] == -1) && (*(short *)&buf[4] == -1)) {
+	    if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
 	      lp->pktStats.broadcast++;
 	    } else {
 	      lp->pktStats.multicast++;
 	    }
-	  } else if ((*(long *)&buf[0] == *(long *)&dev->dev_addr[0]) &&
-		     (*(short *)&buf[4] == *(short *)&dev->dev_addr[4])) {
+	  } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
+		     (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
 	    lp->pktStats.unicast++;
 	  }
 	  
@@ -1115,8 +1203,10 @@
       /* Change buffer ownership for this last frame, back to the adapter */
       for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
 	lp->rx_ring[lp->rx_old].status = R_OWN;
+	barrier();
       }
       lp->rx_ring[entry].status = R_OWN;
+      barrier();
     }
 
     /*
@@ -1135,8 +1225,9 @@
 de4x5_tx(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int entry, iobase = dev->base_addr;
-  long status;
+  u_long iobase = dev->base_addr;
+  int entry;
+  s32 status;
 
   for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
     status = lp->tx_ring[entry].status;
@@ -1151,8 +1242,12 @@
       if (status & TD_EC)  lp->pktStats.excessive_collisions++;
       if (status & TD_DE)  lp->stats.tx_aborted_errors++;
 
-      if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) {
+      if ((status != 0x7fffffff) &&              /* Not setup frame */
+	  (status & (TD_LO | TD_NC | TD_EC | TD_LF))) {
 	lp->lostMedia++;
+	if (lp->lostMedia > LOST_MEDIA_THRESHOLD) { /* Trip autosense */
+	  kick_tx(dev);
+	}
       } else {
 	outl(POLL_DEMAND, DE4X5_TPD);            /* Restart a stalled TX */
       }
@@ -1163,6 +1258,7 @@
     /* Free the buffer if it's not a setup frame. */
     if (lp->skb[entry] != NULL) {
       dev_kfree_skb(lp->skb[entry], FREE_WRITE);
+      lp->skb[entry] = NULL;
     }
 
     /* Update all the pointers */
@@ -1173,11 +1269,57 @@
 }
 
 static int
+de4x5_ast(struct device *dev)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+  s32 gep;
+
+  disable_ast(dev);
+
+  if (lp->chipset == DC21140) {
+    gep = inl(DE4X5_GEP);
+    if (((lp->media == _100Mb) &&  (gep & GEP_SLNK)) ||
+	((lp->media == _10Mb)  &&  (gep & GEP_LNP))  ||
+	((lp->media == _10Mb)  && !(gep & GEP_SLNK)) ||
+	 (lp->media == NC)) {
+      if (lp->linkProb || ((lp->media == NC) && (!(gep & GEP_LNP)))) {
+	lp->lostMedia = LOST_MEDIA_THRESHOLD + 1;
+	lp->linkProb = 0;
+	kick_tx(dev);
+      } else {
+	switch(lp->media) {
+	case NC:
+	  lp->linkProb = 0;
+	  enable_ast(dev, DE4X5_AUTOSENSE_MS);
+	  break;
+
+	case _10Mb:
+	  lp->linkProb = 1;                    /* Flag a potential problem */
+	  enable_ast(dev, 1500);
+	  break;
+
+	case _100Mb:
+	  lp->linkProb = 1;                    /* Flag a potential problem */
+	  enable_ast(dev, 4000);
+	  break;
+	}
+      }
+    } else {
+      lp->linkProb = 0;                        /* Link OK */
+      enable_ast(dev, DE4X5_AUTOSENSE_MS);
+    }
+  }
+
+  return 0;
+}
+
+static int
 de4x5_close(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  u_long imr, omr;
+  u_long iobase = dev->base_addr;
+  s32 imr, omr;
 
   dev->start = 0;
   dev->tbusy = 1;
@@ -1215,22 +1357,24 @@
 de4x5_get_stats(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
 
   lp->stats.rx_missed_errors = (int) (inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
     
   return &lp->stats;
 }
 
-static void load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb)
+static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
 
-  lp->tx_ring[lp->tx_new].buf = buf;
+  lp->tx_ring[lp->tx_new].buf = virt_to_bus(buf);
   lp->tx_ring[lp->tx_new].des1 &= TD_TER;
   lp->tx_ring[lp->tx_new].des1 |= flags;
   lp->skb[lp->tx_new] = skb;
+  barrier();
   lp->tx_ring[lp->tx_new].status = T_OWN;
+  barrier();
 
   return;
 }
@@ -1248,7 +1392,7 @@
 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
 
   /* First, double check that the adapter is open */
   if (irq2dev_map[dev->irq] != NULL) {
@@ -1279,9 +1423,10 @@
 static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int i, j, bit, byte, iobase = dev->base_addr;
-  u_short hashcode;
-  u_long crc, omr, poly = CRC_POLYNOMIAL_LE;
+  u_long iobase = dev->base_addr;
+  int i, j, bit, byte;
+  u16 hashcode;
+  u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
   char *pa;
 
   omr = inl(DE4X5_OMR);
@@ -1336,14 +1481,14 @@
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-static void eisa_probe(struct device *dev, short ioaddr)
+static void eisa_probe(struct device *dev, u_long ioaddr)
 {
-  int i, maxSlots;
-  int status;
-  u_short vendor, device, iobase;
+  int i, maxSlots, status;
+  u_short vendor, device;
+  s32 cfid;
+  u_long iobase;
   struct bus_type *lp = &bus;
   char name[DE4X5_STRLEN];
-  long cfid;
 
   if (!ioaddr && autoprobed) return ;            /* Been here before ! */
   if ((ioaddr < 0x1000) && (ioaddr > 0)) return; /* PCI MODULE special */
@@ -1372,17 +1517,17 @@
 	/* Write the PCI Configuration Registers */
 	outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
 	outl(0x00004000, PCI_CFLT);
-	outl((u_long)iobase, PCI_CBIO);
+	outl(iobase, PCI_CBIO);
 
 	if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
 	  if ((dev = alloc_device(dev, iobase)) != NULL) {
 	    if ((status = de4x5_hw_init(dev, iobase)) == 0) {
 	      num_de4x5s++;
 	    }
-	  num_eth++;
+	    num_eth++;
 	  }
 	} else if (autoprobed) {
-	  printk("%s: region already allocated at 0x%04x.\n", dev->name, iobase);
+	  printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
 	}
       }
     }
@@ -1393,17 +1538,26 @@
 
 /*
 ** PCI bus I/O device probe
+** NB: PCI I/O accesses and Bus Mastering are enabled by the PCI BIOS, not
+** the driver. Some PCI BIOS's, pre V2.1, need the slot + features to be
+** enabled by the user first in the set up utility. Hence we just check for
+** enabled features and silently ignore the card if they're not.
+**
+** STOP PRESS: Some BIOS's __require__ the driver to enable the bus mastering
+** bit. Here, check for I/O accesses and then set BM. If you put the card in
+** a non BM slot, you're on your own (and complain to the PC vendor that your
+** PC doesn't conform to the PCI standard)!
 */
 #define PCI_DEVICE    (dev_num << 3)
 #define PCI_LAST_DEV  32
 
-static void pci_probe(struct device *dev, short ioaddr)
-
+static void pci_probe(struct device *dev, u_long ioaddr)
 {
   u_char irq;
-  u_short pb, dev_num, dev_last;
-  u_short vendor, device, status;
-  u_long class, iobase;
+  u_char pb, pbus, dev_num, dnum, dev_fn;
+  u_short vendor, device, index, status;
+  u_int class = DE4X5_CLASS_CODE;
+  u_int iobase;
   struct bus_type *lp = &bus;
 
   if (!ioaddr && autoprobed) return ;        /* Been here before ! */
@@ -1412,26 +1566,25 @@
     lp->bus = PCI;
 
     if (ioaddr < 0x1000) {
-      pb = (u_short)(ioaddr >> 8);
-      dev_num = (u_short)(ioaddr & 0xff);
-    } else {
-      pb = 0;
-      dev_num = 0;
-    }
-    if (ioaddr > 0) {
-      dev_last = (dev_num < PCI_LAST_DEV) ? dev_num + 1 : PCI_LAST_DEV;
+      pbus = (u_short)(ioaddr >> 8);
+      dnum = (u_short)(ioaddr & 0xff);
     } else {
-      dev_last = PCI_LAST_DEV;
+      pbus = 0;
+      dnum = 0;
     }
+    
+    for (index=0; 
+	 (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+	 index++) {
+      dev_num = PCI_SLOT(dev_fn);
 
-    for (; (dev_num < dev_last) && (dev != NULL); dev_num++) {
-      pcibios_read_config_dword(pb, PCI_DEVICE, PCI_CLASS_REVISION, &class);
-      if (class != 0xffffffff) {
+      if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
 	pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
 	pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
 	if (is_DC21040 || is_DC21041 || is_DC21140) {
 	  /* Set the device number information */
 	  lp->device = dev_num;
+	  lp->bus_num = pb;
 
 	  /* Set the chipset information */
 	  lp->chipset = device;
@@ -1439,27 +1592,32 @@
 	  /* Get the board I/O address */
 	  pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
 	  iobase &= CBIO_MASK;
-	  
+
 	  /* Fetch the IRQ to be used */
 	  pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
 
-	  /* Enable I/O Accesses and Bus Mastering */
+	  /* Check if I/O accesses and Bus Mastering are enabled */
 	  pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
-	  status |= PCI_COMMAND_IO | PCI_COMMAND_MASTER;
-	  pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
-
-	  /* If there is a device and I/O region is open, initialise dev. */
-	  if ((DevicePresent(DE4X5_APROM) == 0) || is_not_dec) {
-	    if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
-	      if ((dev = alloc_device(dev, iobase)) != NULL) {
-		dev->irq = irq;
-		if ((status = de4x5_hw_init(dev, iobase)) == 0) {
-		  num_de4x5s++;
+	  if (status & PCI_COMMAND_IO) {
+	    if (!(status & PCI_COMMAND_MASTER)) {
+	      status |= PCI_COMMAND_MASTER;
+	      pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
+	      pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+	    }
+	    if (status & PCI_COMMAND_MASTER) {
+	      if ((DevicePresent(DE4X5_APROM) == 0) || is_not_dec) {
+		if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
+		  if ((dev = alloc_device(dev, iobase)) != NULL) {
+		    dev->irq = irq;
+		    if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+		      num_de4x5s++;
+		    }
+		    num_eth++;
+		  }
+		} else if (autoprobed) {
+		  printk("%s: region already allocated at 0x%04x.\n", dev->name, (u_short)iobase);
 		}
-		num_eth++;
 	      }
-	    } else if (autoprobed) {
-	      printk("%s: region already allocated at 0x%04x.\n", dev->name, (u_short)iobase);
 	    }
 	  }
 	}
@@ -1474,7 +1632,7 @@
 ** 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 iobase)
+static struct device *alloc_device(struct device *dev, u_long iobase)
 {
   int addAutoProbe = 0;
   struct device *tmp = NULL, *ret;
@@ -1485,7 +1643,7 @@
   */
   if (!loading_module) {
     while (dev->next != NULL) {
-      if ((dev->base_addr == 0xffe0) || (dev->base_addr == 0)) break;
+      if ((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0)) break;
       dev = dev->next;                     /* walk through eth device list */
       num_eth++;                           /* increment eth device number */
     }
@@ -1505,7 +1663,7 @@
     ** If memory could not be allocated, print an error message.
     */
     if ((dev->next == NULL) &&  
-	!((dev->base_addr == 0xffe0) || (dev->base_addr == 0))){
+	!((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0))){
       dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
 					   GFP_KERNEL);
 
@@ -1539,13 +1697,13 @@
     */
     if (ret != NULL) {
       if (addAutoProbe) {
-	for (; (tmp->next!=NULL) && (tmp->base_addr!=0xffe0); tmp=tmp->next);
+	for (; (tmp->next!=NULL) && (tmp->base_addr!=DE4X5_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 == 0xffe0)) {
+	if ((tmp->next == NULL) && !(tmp->base_addr == DE4X5_NDA)) {
 	  tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8,
 					       GFP_KERNEL);
 	  tmp = tmp->next;                     /* point to the new device */
@@ -1589,7 +1747,16 @@
 static int autoconf_media(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
+
+  lp->tx_enable = YES;
+  if (de4x5_debug > 0 ) {
+    if (lp->chipset != DC21140) {
+      printk("%s: Searching for media... ",dev->name);
+    } else {
+      printk("%s: Searching for mode... ",dev->name);
+    }
+  }
 
   if (lp->chipset == DC21040) {
     lp->media = (lp->autosense == AUTO ? TP : lp->autosense);
@@ -1598,34 +1765,35 @@
     lp->media = (lp->autosense == AUTO ? TP_NW : lp->autosense);
     dc21041_autoconf(dev);
   } else if (lp->chipset == DC21140) {
-    /* Force 10Mb/s (_100Mb for 100Mb/s) */
+    disable_ast(dev);
     lp->media = (lp->autosense == AUTO ? _10Mb : lp->autosense);
     dc21140_autoconf(dev);
   }
 
-  if (de4x5_debug >= 1 ) {
+  if (de4x5_debug > 0 ) {
     if (lp->chipset != DC21140) {
-      printk("%s: Media is %s\n",dev->name,
-	                                (lp->media == NC  ? "unconnected!" :
-					(lp->media == TP  ? "TP." :
-					(lp->media == ANS ? "TP/Nway." :
-					(lp->media == BNC ? "BNC." : 
-					(lp->media == AUI ? "AUI." : 
-                                                            "BNC/AUI."
-					))))));
+      printk("media is %s\n", (lp->media == NC  ? "unconnected!" :
+			      (lp->media == TP  ? "TP." :
+			      (lp->media == ANS ? "TP/Nway." :
+			      (lp->media == BNC ? "BNC." : 
+			      (lp->media == AUI ? "AUI." : 
+				                  "BNC/AUI."
+			      ))))));
     } else {
-      printk("%s: Mode is forced to %s\n",dev->name,
-	                                (lp->media == NC      ? "link down.":
-					(lp->media == _100Mb  ? "100Mb/s." :
-					(lp->media == _10Mb   ? "10Mb/s." :
-					                        "\?\?\?"
-					))));
+      printk("mode is %s\n",(lp->media == NC      ? "link down.":
+			    (lp->media == _100Mb  ? "100Mb/s." :
+			    (lp->media == _10Mb   ? "10Mb/s." :
+				                    "\?\?\?"
+			    ))));
     }
   }
 
   if (lp->media) {
     lp->lostMedia = 0;
     inl(DE4X5_MFC);                         /* Zero the lost frames counter */
+    if ((lp->media == TP) || (lp->media == ANS)) {
+      lp->irq_mask |= IMR_LFM;
+    }
   }
   dce_ms_delay(10);
 
@@ -1635,9 +1803,9 @@
 static void dc21040_autoconf(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  u_long i, sisr = 0, linkBad;
-  u_long t_3s    = 3000;
+  u_long iobase = dev->base_addr;
+  int i, linkBad;
+  s32 sisr = 0, t_3s    = 3000;
 
   switch (lp->media) {
   case TP:
@@ -1656,7 +1824,7 @@
   case AUI:
   case BNC_AUI:
     reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
-    dce_ms_delay(330);
+    dce_ms_delay(500);
     linkBad = ping_media(dev);
     if (linkBad && (lp->autosense == AUTO)) {
       lp->media = NC;
@@ -1665,8 +1833,13 @@
     break;
 
   case NC:
+#ifdef i386
     reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
     break;
+#else
+    /* JAE: for Alpha, default to BNC/AUI, *not* TP */
+    reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
+#endif  /* i386 */
   }
 
   return;
@@ -1681,8 +1854,8 @@
 static void dc21041_autoconf(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  u_long sts, irqs, irq_mask, omr;
+  u_long iobase = dev->base_addr;
+  s32 sts, irqs, irq_mask, omr;
 
   switch (lp->media) {
   case TP_NW:
@@ -1766,18 +1939,20 @@
 static void dc21140_autoconf(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  u_long omr;
+  u_long iobase = dev->base_addr;
+  s32 omr;
 
   switch(lp->media) {
   case _100Mb:      /* Set 100Mb/s, MII Port with PCS Function and Scrambler */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+    omr |= (de4x5_full_duplex ? OMR_FD : 0);   /* Set up Full Duplex */
     outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);
     outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);
     break;
 
   case _10Mb:       /* Set conventional 10Mb/s ENDEC interface */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+    omr |= (de4x5_full_duplex ? OMR_FD : 0);   /* Set up Full Duplex */
     outl(omr | OMR_TTM, DE4X5_OMR);
     outl(GEP_FDXD, DE4X5_GEP);
     break;
@@ -1786,11 +1961,12 @@
   return;
 }
 
-static long test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec)
+static int
+test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  long sts, time, csr12;
+  u_long iobase = dev->base_addr;
+  s32 sts, time, csr12;
 
   reset_init_sia(dev, csr13, csr14, csr15);
 
@@ -1815,18 +1991,36 @@
 
   return sts;
 }
+/*
+static int test_sym_link(struct device *dev, u32 msec)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+  u32 gep, time;
+
+  / * Set link_fail_inhibit_timer * /
+  load_ms_timer(dev, msec);
+
+  / * Poll for timeout or SYM_LINK=0 * /
+  do {
+    time = inl(DE4X5_GPT) & GPT_VAL;
+    gep = inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP);
+  } while ((time > 0) && (gep & GEP_SLNK));
 
+  return gep;
+}
+*/
 /*
 ** Send a packet onto the media and watch for send errors that indicate the
 ** media is bad or unconnected.
 */
-static long ping_media(struct device *dev)
+static int ping_media(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int entry, iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
+  int i, entry, linkBad;
+  s32 omr, t_3s = 4000;
   char frame[64];
-  long i, linkBad, omr;
-  u_long t_3s    = 3000;
 
   create_packet(dev, frame, sizeof(frame));
 
@@ -1854,11 +2048,11 @@
 ** Check the Auto Negotiation State. Return OK when a link pass interrupt
 ** is received and the auto-negotiation status is NWAY OK.
 */
-static int test_ans(struct device *dev, long irqs, long irq_mask, long msec)
+static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  long sts, ans;
+  u_long iobase = dev->base_addr;
+  s32 sts, ans;
 
   outl(irq_mask, DE4X5_IMR);
 
@@ -1881,10 +2075,10 @@
 /*
 **
 */
-static void reset_init_sia(struct device *dev, long sicr, long strr, long sigr)
+static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
 
   RESET_SIA;
   outl(sigr, DE4X5_SIGR);
@@ -1897,12 +2091,22 @@
 /*
 ** Load the timer on the DC21041 and 21140. Max time is 13.42 secs.
 */
-static void load_ms_timer(struct device *dev, u_long msec)
+static void load_ms_timer(struct device *dev, u32 msec)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
+  s32 i = 2048, j;
+
+  if (lp->chipset == DC21140) {
+    j = inl(DE4X5_OMR);
+    if ((j & OMR_TTM) && (j & OMR_PS)) {          /* 10Mb/s MII */
+      i = 8192;
+    } else if ((~j & OMR_TTM) && (j & OMR_PS)) {  /* 100Mb/s MII */
+      i = 819;
+    }
+  }
 
-  outl((long)(msec * 10000)/2048, DE4X5_GPT);
+  outl((s32)(msec * 10000)/i, DE4X5_GPT);
 
   return;
 }
@@ -1931,7 +2135,7 @@
 /*
 ** Known delay in microseconds
 */
-static void dce_us_delay(u_long usec)
+static void dce_us_delay(u32 usec)
 {
   udelay(usec);
 
@@ -1941,9 +2145,9 @@
 /*
 ** Known delay in milliseconds, in millisecond steps.
 */
-static void dce_ms_delay(u_long msec)
+static void dce_ms_delay(u32 msec)
 {
-  u_long i;
+  u_int i;
   
   for (i=0; i<msec; i++) {
     dce_us_delay(1000);
@@ -1956,13 +2160,13 @@
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-int EISA_signature(char *name, long eisa_id)
+static int EISA_signature(char *name, s32 eisa_id)
 {
-  unsigned long i;
+  u_int i;
   char *signatures[] = DE4X5_SIGNATURE;
   char ManCode[DE4X5_STRLEN];
   union {
-    long ID;
+    s32 ID;
     char Id[4];
   } Eisa;
   int status = 0;
@@ -1999,24 +2203,23 @@
 ** ethernet address for later read out.
 */
 
-static int DevicePresent(short aprom_addr)
+static int DevicePresent(u_long aprom_addr)
 {
   union {
     struct {
-      u_long a;
-      u_long b;
+      u32 a;
+      u32 b;
     } llsig;
-    char Sig[sizeof(long) << 1];
+    char Sig[sizeof(u32) << 1];
   } dev;
   char data;
-  long i, j, tmp;
+  int i, j, tmp, status = 0;
   short sigLength;
-  int status = 0;
   struct bus_type *lp = &bus;
 
   dev.llsig.a = ETH_PROM_SIG;
   dev.llsig.b = ETH_PROM_SIG;
-  sigLength = sizeof(long) << 1;
+  sigLength = sizeof(u32) << 1;
 
   if (lp->chipset == DC21040) {
     for (i=0,j=0;(j<sigLength) && (i<PROBE_LENGTH+sigLength-1);i++) {
@@ -2051,12 +2254,11 @@
   return status;
 }
 
-static int aprom_crc(struct device *dev)
+static int get_hw_addr(struct device *dev)
 {
-  int iobase = dev->base_addr;
-  long i, k, tmp;
-  unsigned short j,chksum;
-  unsigned char status = 0;
+  u_long iobase = dev->base_addr;
+  int i, k, tmp, status = 0;
+  u_short j,chksum;
   struct bus_type *lp = &bus;
 
   for (i=0,k=0,j=0;j<3;j++) {
@@ -2107,7 +2309,7 @@
 /*
 ** SROM Read
 */
-static short srom_rd(u_short addr, u_char offset)
+static short srom_rd(u_long addr, u_char offset)
 {
   sendto_srom(SROM_RD | SROM_SR, addr);
 
@@ -2118,7 +2320,7 @@
   return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
 }
 
-static void srom_latch(u_long command, u_short addr)
+static void srom_latch(u_int command, u_long addr)
 {
   sendto_srom(command, addr);
   sendto_srom(command | DT_CLK, addr);
@@ -2127,7 +2329,7 @@
   return;
 }
 
-static void srom_command(u_long command, u_short addr)
+static void srom_command(u_int command, u_long addr)
 {
   srom_latch(command, addr);
   srom_latch(command, addr);
@@ -2136,9 +2338,9 @@
   return;
 }
 
-static void srom_address(u_long command, u_short addr, u_char offset)
+static void srom_address(u_int command, u_long addr, u_char offset)
 {
-  long i;
+  int i;
   char a;
 
   a = (char)(offset << 2);
@@ -2150,16 +2352,17 @@
   i = (getfrom_srom(addr) >> 3) & 0x01;
   if (i != 0) {
     printk("Bad SROM address phase.....\n");
+/*    printk(".");*/
   }
 
   return;
 }
 
-static short srom_data(u_long command, u_short addr)
+static short srom_data(u_int command, u_long addr)
 {
   int i;
   short word = 0;
-  long tmp;
+  s32 tmp;
 
   for (i=0; i<16; i++) {
     sendto_srom(command  | DT_CLK, addr);
@@ -2175,7 +2378,7 @@
 }
 
 /*
-static void srom_busy(u_long command, u_short addr)
+static void srom_busy(u_int command, u_long addr)
 {
   sendto_srom((command & 0x0000ff00) | DT_CS, addr);
 
@@ -2189,7 +2392,7 @@
 }
 */
 
-static void sendto_srom(u_long command, u_short addr)
+static void sendto_srom(u_int command, u_long addr)
 {
   outl(command, addr);
   dce_us_delay(1);
@@ -2197,9 +2400,9 @@
   return;
 }
 
-static long getfrom_srom(u_short addr)
+static int getfrom_srom(u_long addr)
 {
-  long tmp;
+  s32 tmp;
 
   tmp = inl(addr);
   dce_us_delay(1);
@@ -2238,6 +2441,44 @@
   return pa;                     /* Points to the next entry */
 }
 
+static void enable_ast(struct device *dev, u32 time_out)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+
+  lp->irq_mask |= IMR_TMM;
+  outl(lp->irq_mask, DE4X5_IMR);
+  load_ms_timer(dev, time_out);
+
+  return;
+}
+
+static void disable_ast(struct device *dev)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+
+  lp->irq_mask &= ~IMR_TMM;
+  outl(lp->irq_mask, DE4X5_IMR);
+  load_ms_timer(dev, 0);
+
+  return;
+}
+
+static void kick_tx(struct device *dev)
+{
+  struct sk_buff *skb;
+
+  if ((skb = alloc_skb(0, GFP_ATOMIC)) != NULL) {
+    skb->len= FAKE_FRAME_LEN;
+    skb->arp=1;
+    skb->dev=dev;
+    dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+  }
+
+  return;
+}
+
 /*
 ** Perform IOCTL call functions here. Some are privileged operations and the
 ** effective uid is checked in those cases.
@@ -2246,12 +2487,13 @@
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
-  int i, j, iobase = dev->base_addr, status = 0;
-  u_long omr;
+  u_long iobase = dev->base_addr;
+  int i, j, status = 0;
+  s32 omr;
   union {
-    unsigned char  addr[(HASH_TABLE_LEN * ETH_ALEN)];
-    unsigned short sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-    unsigned long  lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
+    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) {
@@ -2260,29 +2502,32 @@
       tmp.addr[i] = dev->dev_addr[i];
     }
     ioc->len = ETH_ALEN;
-    memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    }
 
     break;
   case DE4X5_SET_HWADDR:             /* Set the hardware address */
     if (suser()) {
-      memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
-      for (i=0; i<ETH_ALEN; i++) {
-	dev->dev_addr[i] = tmp.addr[i];
-      }
-      build_setup_frame(dev, PHYS_ADDR_ONLY);
-      /* Set up the descriptor and give ownership to the card */
-      while (set_bit(0, (void *)&dev->tbusy) != 0); /* Wait for lock to free */
-      if (lp->setup_f == HASH_PERF) {
-	load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
+      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];
+	}
+	build_setup_frame(dev, PHYS_ADDR_ONLY);
+	/* Set up the descriptor and give ownership to the card */
+	while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
+	if (lp->setup_f == HASH_PERF) {
+	  load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
 		                                        SETUP_FRAME_LEN, NULL);
-      } else {
-	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+	} else {
+	  load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
 		                                        SETUP_FRAME_LEN, NULL);
+	}
+	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+	outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
+	dev->tbusy = 0;                              /* Unlock the TX ring */
       }
-      lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-      outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
-      dev->tbusy = 0;                              /* Unlock the TX ring */
-
     } else {
       status = -EPERM;
     }
@@ -2314,15 +2559,21 @@
     break;
   case DE4X5_GET_MCA:                /* Get the multicast address table */
     ioc->len = (HASH_TABLE_LEN >> 3);
-    memcpy_tofs(ioc->data, lp->setup_frame, 192); 
+    if (!(status = verify_area(VERIFY_WRITE, ioc->data, 192))) {
+      memcpy_tofs(ioc->data, lp->setup_frame, 192); 
+    }
 
     break;
   case DE4X5_SET_MCA:                /* Set a multicast address */
     if (suser()) {
       if (ioc->len != HASH_TABLE_LEN) {         /* MCA changes */
-	memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+	if (!(status = verify_area(VERIFY_READ, (void *)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);
       }
-      set_multicast_list(dev, ioc->len, tmp.addr);
     } else {
       status = -EPERM;
     }
@@ -2348,8 +2599,10 @@
     break;
   case DE4X5_GET_STATS:              /* Get the driver statistics */
     cli();
-    memcpy_tofs(ioc->data, &lp->pktStats, sizeof(lp->pktStats)); 
-    ioc->len = DE4X5_PKT_STAT_SZ;
+    ioc->len = sizeof(lp->pktStats);
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, sizeof(lp->pktStats)))) {
+      memcpy_tofs(ioc->data, &lp->pktStats, ioc->len); 
+    }
     sti();
 
     break;
@@ -2365,29 +2618,36 @@
     break;
   case DE4X5_GET_OMR:                /* Get the OMR Register contents */
     tmp.addr[0] = inl(DE4X5_OMR);
-    memcpy_tofs(ioc->data, tmp.addr, 1);
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
+      memcpy_tofs(ioc->data, tmp.addr, 1);
+    }
 
     break;
   case DE4X5_SET_OMR:                /* Set the OMR Register contents */
     if (suser()) {
-      memcpy_fromfs(tmp.addr, ioc->data, 1);
-      outl(tmp.addr[0], DE4X5_OMR);
+      if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) {
+	memcpy_fromfs(tmp.addr, ioc->data, 1);
+	outl(tmp.addr[0], DE4X5_OMR);
+      }
     } else {
       status = -EPERM;
     }
 
     break;
   case DE4X5_GET_REG:                /* Get the DE4X5 Registers */
-    tmp.lval[0] = inl(DE4X5_STS);
-    tmp.lval[1] = inl(DE4X5_BMR);
-    tmp.lval[2] = inl(DE4X5_IMR);
-    tmp.lval[3] = inl(DE4X5_OMR);
-    tmp.lval[4] = inl(DE4X5_SISR);
-    tmp.lval[5] = inl(DE4X5_SICR);
-    tmp.lval[6] = inl(DE4X5_STRR);
-    tmp.lval[7] = inl(DE4X5_SIGR);
-    memcpy_tofs(ioc->data, tmp.addr, 32);
-
+    j = 0;
+    tmp.lval[0] = inl(DE4X5_STS); j+=4;
+    tmp.lval[1] = inl(DE4X5_BMR); j+=4;
+    tmp.lval[2] = inl(DE4X5_IMR); j+=4;
+    tmp.lval[3] = inl(DE4X5_OMR); j+=4;
+    tmp.lval[4] = inl(DE4X5_SISR); j+=4;
+    tmp.lval[5] = inl(DE4X5_SICR); j+=4;
+    tmp.lval[6] = inl(DE4X5_STRR); j+=4;
+    tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
+    ioc->len = j;
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    }
     break;
 
 #define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
@@ -2399,35 +2659,35 @@
       tmp.addr[j++] = dev->dev_addr[i];
     }
     tmp.addr[j++] = lp->rxRingSize;
-    tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
-    tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
+    tmp.lval[j>>2] = (s32)lp->rx_ring; j+=4;
+    tmp.lval[j>>2] = (s32)lp->tx_ring; j+=4;
 
     for (i=0;i<lp->rxRingSize-1;i++){
       if (i < 3) {
-	tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+	tmp.lval[j>>2] = (s32)&lp->rx_ring[i].status; j+=4;
       }
     }
-    tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+    tmp.lval[j>>2] = (s32)&lp->rx_ring[i].status; j+=4;
     for (i=0;i<lp->txRingSize-1;i++){
       if (i < 3) {
-	tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
+	tmp.lval[j>>2] = (s32)&lp->tx_ring[i].status; j+=4;
       }
     }
-    tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-
+    tmp.lval[j>>2] = (s32)&lp->tx_ring[i].status; j+=4;
+      
     for (i=0;i<lp->rxRingSize-1;i++){
       if (i < 3) {
-	tmp.lval[j>>2] = (long)lp->rx_ring[i].buf; j+=4;
+	tmp.lval[j>>2] = (s32)lp->rx_ring[i].buf; j+=4;
       }
     }
-    tmp.lval[j>>2] = (long)lp->rx_ring[i].buf; j+=4;
+    tmp.lval[j>>2] = (s32)lp->rx_ring[i].buf; j+=4;
     for (i=0;i<lp->txRingSize-1;i++){
       if (i < 3) {
-	tmp.lval[j>>2] = (long)lp->tx_ring[i].buf; j+=4;
+	tmp.lval[j>>2] = (s32)lp->tx_ring[i].buf; j+=4;
       }
     }
-    tmp.lval[j>>2] = (long)lp->tx_ring[i].buf; j+=4;
-
+    tmp.lval[j>>2] = (s32)lp->tx_ring[i].buf; j+=4;
+      
     for (i=0;i<lp->rxRingSize;i++){
       tmp.lval[j>>2] = lp->rx_ring[i].status; j+=4;
     }
@@ -2443,12 +2703,14 @@
     tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
     tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
     tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; 
-
+    
     tmp.addr[j++] = lp->txRingSize;
     tmp.addr[j++] = dev->tbusy;
-
+      
     ioc->len = j;
-    memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    }
 
     break;
   default:
@@ -2466,8 +2728,8 @@
   0x2000, 10, /* I/O address, IRQ */
   0, 0, 0, NULL, de4x5_probe };
 	
-int io=0x000b;	/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-int irq=10;	/* or use the insmod io= irq= options 		*/
+static int io=0x000b;	/* EDIT THESE LINES FOR YOUR CONFIGURATION */
+static int irq=10;	/* or use the insmod io= irq= options 		*/
 
 int
 init_module(void)
@@ -2487,15 +2749,15 @@
   if (MOD_IN_USE) {
     printk("%s: device busy, remove delayed\n",thisDE4X5.name);
   } else {
-    release_region(thisDE4X5.base_addr, (lp->bus == PCI ? 
-					             DE4X5_PCI_TOTAL_SIZE :
-			                             DE4X5_EISA_TOTAL_SIZE));
     if (lp) {
-      kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
+      kfree_s(bus_to_virt(lp->rx_ring[0].buf), RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
     }
     kfree_s(thisDE4X5.priv, sizeof(struct de4x5_private) + ALIGN);
     thisDE4X5.priv = NULL;
 
+    release_region(thisDE4X5.base_addr, (lp->bus == PCI ? 
+					             DE4X5_PCI_TOTAL_SIZE :
+			                             DE4X5_EISA_TOTAL_SIZE));
     unregister_netdev(&thisDE4X5);
   }
 }

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