patch-2.4.20 linux-2.4.20/drivers/net/pcmcia/wavelan_cs.c

Next file: linux-2.4.20/drivers/net/pcmcia/wavelan_cs.h
Previous file: linux-2.4.20/drivers/net/pcmcia/wavelan.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/net/pcmcia/wavelan_cs.c linux-2.4.20/drivers/net/pcmcia/wavelan_cs.c
@@ -41,7 +41,8 @@
  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
  * - reorganize kmallocs in wavelan_attach, checking all for failure
  *   and releasing the previous allocations if one fails
- *
+ * <No longer true, we reverted to the version in the Pcmcia package
+ *  which was correct in the first place - Jean II>
  *
  ****************************************************************************
  *   Copyright 1995
@@ -62,6 +63,7 @@
  *
  */
 
+/* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */
 #include "wavelan_cs.h"		/* Private header */
 
 /************************* MISC SUBROUTINES **************************/
@@ -72,6 +74,34 @@
 
 /*------------------------------------------------------------------*/
 /*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local *		lp,
+	 unsigned long *	pflags)
+{
+  spin_lock_irqsave(&lp->spinlock, *pflags);
+  /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local *		lp,
+	unsigned long *		pflags)
+{
+  spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+  /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+   * via : outb(OP1_INT_ENABLE, LCCR(base));
+   */
+}
+
+/*------------------------------------------------------------------*/
+/*
  * Wrapper for reporting error to cardservices
  */
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -103,7 +133,7 @@
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the wavelan
  */
 
 /*------------------------------------------------------------------*/
@@ -138,7 +168,7 @@
 {
   hacr_write(base, hacr);
   /* delay might only be needed sometimes */
-  mdelay(1L);
+  mdelay(1);
 } /* hacr_write_slow */
 
 /*------------------------------------------------------------------*/
@@ -529,7 +559,7 @@
   lp->curr_point=NULL;                        /* No default WavePoint */
   lp->cell_search=0;
   
-  lp->cell_timer.data=(int)lp;                /* Start cell expiry timer */
+  lp->cell_timer.data=(unsigned long)lp;                /* Start cell expiry timer */
   lp->cell_timer.function=wl_cell_expiry;
   lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
   add_timer(&lp->cell_timer);
@@ -569,18 +599,18 @@
 #endif
   
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
   
   m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
   mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
   
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
   if(mode==NWID_PROMISC)
     lp->cell_search=1;
   else
-	lp->cell_search=0;
+    lp->cell_search=0;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
 }
 
 /* Find a record in the WavePoint table matching a given NWID */
@@ -737,7 +767,7 @@
   ioaddr_t              base = lp->dev->base_addr;  
   mm_t                  m;
   unsigned long         flags;
-  
+
   if(wavepoint==lp->curr_point)          /* Sanity check... */
     {
       wv_nwid_filter(!NWID_PROMISC,lp);
@@ -749,16 +779,16 @@
 #endif
  	
   /* Disable interrupts & save flags */
-  spin_lock_irqsave(&lp->lock, flags);
-  
+  wv_splhi(lp, &flags);
+
   m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
   m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
   
   mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
   
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
+  wv_splx(lp, &flags);
+
   wv_nwid_filter(!NWID_PROMISC,lp);
   lp->curr_point=wavepoint;
 }
@@ -775,6 +805,11 @@
   wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
   net_local *lp=(net_local *)dev->priv;              /* Device info */
 
+#ifdef I_NEED_THIS_FEATURE
+  /* Some people don't need this, some other may need it */
+  nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
 #if WAVELAN_ROAMING_DEBUG > 1
   printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
   printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
@@ -832,7 +867,9 @@
 /*------------------------------------------------------------------*/
 /*
  * Routine to synchronously send a command to the i82593 chip. 
- * Should be called with interrupts enabled.
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ *  wv_82593_config() & wv_diag())
  */
 static int
 wv_82593_cmd(device *	dev,
@@ -841,74 +878,98 @@
 	     int	result)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
   int		status;
+  int		wait_completed;
   long		spin;
-  u_long	flags;
 
   /* Spin until the chip finishes executing its current command (if any) */
+  spin = 1000;
   do
     {
-      spin_lock_irqsave (&lp->lock, flags);
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  /* If the interrupt hasn't be posted */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
 
   /* Issue the command to the controller */
   outb(cmd, LCCR(base));
 
-  /* If we don't have to check the result of the command */
+  /* If we don't have to check the result of the command
+   * Note : this mean that the irq handler will deal with that */
   if(result == SR0_NO_RESULT)
-    {
-      wv_wait_completed = FALSE;
-      return(TRUE);
-    }
+    return(TRUE);
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 1000))
-    udelay(10);
+  /* We are waiting for command completion */
+  wait_completed = TRUE;
 
-  /* If the interrupt handler hasn't be called */
-  if(wv_wait_completed)
+  /* Busy wait while the LAN controller executes the command. */
+  spin = 1000;
+  do
     {
-      outb(OP0_NOP, LCCR(base));
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
       status = inb(LCSR(base));
-      if(status & SR0_INTERRUPT)
+
+      /* Check if there was an interrupt posted */
+      if((status & SR0_INTERRUPT))
 	{
-	  /* There was an interrupt : call the interrupt handler */
-#ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
-#endif
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
 
-	  wavelan_interrupt(dev->irq, (void *) dev,
-			    (struct pt_regs *) NULL);
+	  /* Check if interrupt is a command completion */
+	  if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+	     ((status & SR0_BOTH_RX_TX) != 0x0) &&
+	     !(status & SR0_RECEPTION))
+	    {
+	      /* Signal command completion */
+	      wait_completed = FALSE;
+	    }
+	  else
+	    {
+	      /* Note : Rx interrupts will be handled later, because we can
+	       * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+	      printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+	    }
 	}
-      else
-	{
-	  wv_wait_completed = 0; /* XXX */
+    }
+  while(wait_completed && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(wait_completed)
+    {
 #ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
-		 str, status);
+      printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+	     str, status);
 #endif
-	  /* We probably should reset the controller here */
-	  return(FALSE);
-	}
+      return(FALSE);
     }
 
-  /* Check the return code provided by the interrupt handler against
+  /* Check the return code returned by the card (see above) against
    * the expected return code provided by the caller */
-  if((lp->status & SR0_EVENT_MASK) != result)
+  if((status & SR0_EVENT_MASK) != result)
     {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
-	     str, lp->status);
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+	     str, status);
 #endif
       return(FALSE);
     }
@@ -924,14 +985,16 @@
 static inline int
 wv_diag(device *	dev)
 {
+  int		ret = FALSE;
+
   if(wv_82593_cmd(dev, "wv_diag(): diagnose",
 		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
-    return(TRUE);
+    ret = TRUE;
 
 #ifdef DEBUG_CONFIG_ERROR
   printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
 #endif
-  return(FALSE);
+  return(ret);
 } /* wv_diag */
 
 /*------------------------------------------------------------------*/
@@ -951,15 +1014,6 @@
   int		chunk_len;
   char *	buf_ptr = buf;
 
-#ifdef OLDIES
-  /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
-   * quite safe to remove this... */
-
-  /* If buf is NULL, just increment the ring buffer pointer */
-  if(buf == NULL)
-    return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
-#endif
-
   /* Get all the buffer */
   while(len > 0)
     {
@@ -990,70 +1044,32 @@
  * wavelan_interrupt is not an option...), so you may experience
  * some delay sometime...
  */
-static inline void wv_82593_reconfig (device * dev)
+static inline void
+wv_82593_reconfig(device *	dev)
 {
-	net_local *lp = (net_local *) dev->priv;
-	dev_link_t *link = ((net_local *) dev->priv)->link;
+  net_local *		lp = (net_local *)dev->priv;
+  dev_link_t *		link = ((net_local *) dev->priv)->link;
+  unsigned long		flags;
 
-	/* Check if we can do it now ! */
-	if (!(link->open)) {
-		lp->reconfig_82593 = TRUE;
+  /* Arm the flag, will be cleard in wv_82593_config() */
+  lp->reconfig_82593 = TRUE;
+
+  /* Check if we can do it now ! */
+  if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+    }
+  else
+    {
 #ifdef DEBUG_IOCTL_INFO
-		printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
-			dev->name, link->open);
+      printk(KERN_DEBUG
+	     "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+	     dev->name, dev->state, link->open);
 #endif
-	} else {
-		netif_stop_queue (dev);
-
-		lp->reconfig_82593 = FALSE;
-		wv_82593_config (dev);
-		netif_wake_queue (dev);
-	}
-}
-
-#ifdef OLDIES
-/*------------------------------------------------------------------*/
-/*
- * Dumps the current i82593 receive buffer to the console.
- */
-static void wavelan_dump(device *dev)
-{
-  ioaddr_t base = dev->base_addr;
-  int i, c;
-
-  /* disable receiver so we can use channel 1 */
-  outb(OP0_RCV_DISABLE, LCCR(base));
-
-  /* reset receive DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-
-  /* dump into receive buffer */
-  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
-
-  /* set read pointer to start of receive buffer */
-  outb(0, PIORL(base));
-  outb(0, PIORH(base));
-
-  printk(KERN_DEBUG "wavelan_cs: dump:\n");
-  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
-  for(i = 0; i < 73; i++){
-    if((i % 16) == 0) {
-      printk("\n0x%02x:", i);
-      if (!i) {
-	printk("   ");
-	continue;
-      }
     }
-    c = inb(PIOP(base));
-    printk("%02x ", c);
-  }
-  printk("\n");
-
-  /* enable the receiver again */
-  wv_ru_start(dev);
 }
-#endif
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
 /*
@@ -1171,6 +1187,8 @@
       return;
     }
 
+  wv_splhi(lp, &flags);
+
   /* Read the mmc */
   mmc_out(base, mmwoff(0, mmw_freeze), 1);
   mmc_read(base, 0, (u_char *)&m, sizeof(m));
@@ -1181,6 +1199,8 @@
   lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
 #endif	/* WIRELESS_EXT */
 
+  wv_splx(lp, &flags);
+
   printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -1265,6 +1285,7 @@
 wv_dev_show(device *	dev)
 {
   printk(KERN_DEBUG "dev:");
+  printk(" state=%lX,", dev->state);
   printk(" trans_start=%ld,", dev->trans_start);
   printk(" flags=0x%x,", dev->flags);
   printk("\n");
@@ -1869,6 +1890,26 @@
 }
 #endif	/* HISTOGRAM */
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /*------------------------------------------------------------------*/
 /*
  * Perform ioctl : config & info stuff
@@ -1891,8 +1932,11 @@
   printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
 #endif
 
+  if (cmd == SIOCETHTOOL)
+    return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Look what is the request */
   switch(cmd)
@@ -1968,7 +2012,7 @@
 
     case SIOCGIWFREQ:
       /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody XXX - especially old cards...) */
+       * (does it work for everybody ? - especially old cards...) */
       if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
 	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	{
@@ -2239,15 +2283,17 @@
 	{
 	  struct iw_range	range;
 
-	  /* Set the length (very important for backward compatibility) */
-	  wrq->u.data.length = sizeof(struct iw_range);
+	   /* Set the length (very important for backward compatibility) */
+	   wrq->u.data.length = sizeof(struct iw_range);
 
-	  /* Set all the info we don't care or don't know about to zero */
-	  memset(&range, 0, sizeof(range));
+	   /* Set all the info we don't care or don't know about to zero */
+	   memset(&range, 0, sizeof(range));
 
-	  /* Set the Wireless Extension versions */
-	  range.we_version_compiled = WIRELESS_EXT;
-	  range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#if WIRELESS_EXT > 10
+	   /* Set the Wireless Extension versions */
+	   range.we_version_compiled = WIRELESS_EXT;
+	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
 
 	  /* Set information in the range struct */
 	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
@@ -2517,7 +2563,7 @@
     }
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2543,11 +2589,8 @@
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
-  if (lp == NULL) /* XXX will this ever occur? */
-    return NULL;
-
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   wstats = &lp->wstats;
 
@@ -2573,7 +2616,7 @@
   wstats->discard.misc = 0L;
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2692,12 +2735,6 @@
   skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-  /* Another glitch : Due to the way the GET_PACKET macro is written,
-   * we are not sure to have the same thing in skb->data. On the other
-   * hand, skb->mac.raw is not defined everywhere...
-   * For versions between 1.2.13 and those where skb->mac.raw appear,
-   * I don't have a clue...
-   */
   wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
 #endif	/* DEBUG_RX_INFO */
      
@@ -2731,9 +2768,7 @@
 	  wl_roam_gather(dev, skb->data, stats);
 #endif	/* WAVELAN_ROAMING */
 	  
-      /* Spying stuff */
 #ifdef WIRELESS_SPY
-      /* Same as above */
       wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
 #endif	/* WIRELESS_SPY */
 #ifdef HISTOGRAM
@@ -2766,6 +2801,7 @@
  * called to do the actual transfer of the card's data including the
  * ethernet header into a packet consisting of an sk_buff chain.
  * (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
  */
 static inline void
 wv_packet_rcv(device *	dev)
@@ -2916,7 +2952,7 @@
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Check if we need some padding */
   if(clen < ETH_ZLEN)
@@ -2943,18 +2979,13 @@
   wv_82593_cmd(dev, "wv_packet_write(): transmit",
 	       OP0_TRANSMIT, SR0_NO_RESULT);
 
+  /* Make sure the watchdog will keep quiet for a while */
+  dev->trans_start = jiffies;
+
   /* Keep stats up to date */
   lp->stats.tx_bytes += length;
 
-  /* If watchdog not already active, activate it... */
-  if (!timer_pending(&lp->watchdog))
-    {
-      /* set timer to expire in WATCHDOG_JIFFIES */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
-
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_TX_INFO
   wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2963,56 +2994,57 @@
 #ifdef DEBUG_TX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
 #endif
-
-  netif_start_queue (dev);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
+ * In this routine, we check if the harware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
  * to send the packet...
  */
-static int wavelan_packet_xmit (struct sk_buff *skb,
-				device * dev)
+static int
+wavelan_packet_xmit(struct sk_buff *	skb,
+		    device *		dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *)dev->priv;
+  unsigned long		flags;
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-		(unsigned) skb);
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	 (unsigned) skb);
 #endif
 
-	/*
-	 * For ethernet, fill in the header.
-	 */
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  netif_stop_queue(dev);
 
-	netif_stop_queue (dev);
+  /* If somebody has asked to reconfigure the controller,
+   * we can do it now */
+  if(lp->reconfig_82593)
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+      /* Note : the configure procedure was totally synchronous,
+       * so the Tx buffer is now free */
+    }
 
-	/*
-	 * Block a timer-based transmit from overlapping a previous transmit.
-	 * In other words, prevent reentering this routine.
-	 */
-	if (1) {
-		/* If somebody has asked to reconfigure the controller, we can do it now */
-		if (lp->reconfig_82593) {
-			lp->reconfig_82593 = FALSE;
-			wv_82593_config (dev);
-		}
 #ifdef DEBUG_TX_ERROR
-		if (skb->next)
-			printk (KERN_INFO "skb has next\n");
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
 #endif
 
-		wv_packet_write (dev, skb->data, skb->len);
-	}
-	dev_kfree_skb (skb);
+  wv_packet_write(dev, skb->data, skb->len);
+
+  dev_kfree_skb(skb);
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-	return (0);
+  return(0);
 }
 
 /********************** HARDWARE CONFIGURATION **********************/
@@ -3165,7 +3197,7 @@
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody XXX - especially old cards...) */
+   * (does it work for everybody ? - especially old cards...) */
   /* Note : WFREQSEL verify that it is able to read from EEprom
    * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
    * is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -3223,7 +3255,7 @@
 wv_ru_stop(device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *lp = (net_local *) dev->priv;
+  net_local *	lp = (net_local *) dev->priv;
   unsigned long	flags;
   int		status;
   int		spin;
@@ -3232,35 +3264,35 @@
   printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
 #endif
 
+  wv_splhi(lp, &flags);
+
   /* First, send the LAN controller a stop receive command */
   wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
 	       OP0_STOP_RCV, SR0_NO_RESULT);
 
   /* Then, spin until the receive unit goes idle */
-  spin = 0;
+  spin = 300;
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
 
   /* Now, spin until the chip finishes executing its current command */
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  wv_splx(lp, &flags);
 
   /* If there was a problem */
-  if(spin > 300)
+  if(spin <= 0)
     {
 #ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
@@ -3287,6 +3319,7 @@
 {
   ioaddr_t	base = dev->base_addr;
   net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
@@ -3300,6 +3333,8 @@
   if(!wv_ru_stop(dev))
     return FALSE;
 
+  wv_splhi(lp, &flags);
+
   /* Now we know that no command is being executed. */
 
   /* Set the receive frame pointer and stop pointer */
@@ -3309,8 +3344,17 @@
   /* Reset ring management.  This sets the receive frame pointer to 1 */
   outb(OP1_RESET_RING_MNGMT, LCCR(base));
 
+#if 0
+  /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+     should be set as below */
+  /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+  /* but I set it 0 instead */
+  lp->stop = 0;
+#else
   /* but I set it to 3 bytes per packet less than 8K */
   lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
   outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
   outb(OP1_INT_ENABLE, LCCR(base));
   outb(OP1_SWIT_TO_PORT_0, LCCR(base));
@@ -3326,17 +3370,15 @@
 #ifdef DEBUG_I82593_SHOW
   {
     int	status;
-    unsigned long flags;
-    int	i = 0;
+    int	opri;
+    int	spin = 10000;
 
     /* spin until the chip starts receiving */
     do
       {
-	spin_lock_irqsave (&lp->lock, flags);
 	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
 	status = inb(LCSR(base));
-	spin_unlock_irqrestore (&lp->lock, flags);
-	if(i++ > 10000)
+	if(spin-- <= 0)
 	  break;
       }
     while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
@@ -3345,6 +3387,9 @@
 	   (status & SR3_RCV_STATE_MASK), i);
   }
 #endif
+
+  wv_splx(lp, &flags);
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
 #endif
@@ -3363,6 +3408,7 @@
   ioaddr_t			base = dev->base_addr;
   net_local *			lp = (net_local *) dev->priv;
   struct i82593_conf_block	cfblk;
+  int				ret = TRUE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
@@ -3457,7 +3503,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
 		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
-    return(FALSE);
+    ret = FALSE;
 
   /* Initialize adapter's ethernet MAC address */
   outb(TX_BASE & 0xff, PIORL(base));
@@ -3471,7 +3517,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
 		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
-    return(FALSE);
+    ret = FALSE;
 
 #ifdef WAVELAN_ROAMING
     /* If roaming is enabled, join the "Beacon Request" multicast group... */
@@ -3508,14 +3554,17 @@
       hacr_write(base, HACR_DEFAULT);
       if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
 		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
-	return(FALSE);
+	ret = FALSE;
       lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
     }
 
+  /* Job done, clear the flag */
+  lp->reconfig_82593 = FALSE;
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
 #endif
-  return(TRUE);
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3594,6 +3643,8 @@
 {
   net_local *		lp = (net_local *) dev->priv;
   ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			ret = FALSE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
@@ -3612,50 +3663,78 @@
   if(wv_pcmcia_reset(dev) == FALSE)
     return FALSE;
 
-  /* Power UP the module + reset the modem + reset host adapter
-   * (in fact, reset DMA channels) */
-  hacr_write_slow(base, HACR_RESET);
-  hacr_write(base, HACR_DEFAULT);
+  /* Disable interrupts */
+  wv_splhi(lp, &flags);
 
-  /* Check if the module has been powered up... */
-  if(hasr_read(base) & HASR_NO_CLK)
+  /* Disguised goto ;-) */
+  do
     {
+      /* Power UP the module + reset the modem + reset host adapter
+       * (in fact, reset DMA channels) */
+      hacr_write_slow(base, HACR_RESET);
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
-	     dev->name);
+	  printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* initialize the modem */
-  if(wv_mmc_init(dev) == FALSE)
-    return FALSE;
+      /* initialize the modem */
+      if(wv_mmc_init(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* reset the LAN controller (i82593) */
-  outb(OP0_RESET, LCCR(base));
-  mdelay(1);	/* A bit crude ! */
-
-  /* Initialize the LAN controller */
-  if((wv_82593_config(dev) == FALSE) ||
-     (wv_diag(dev) == FALSE))
-    {
+      /* reset the LAN controller (i82593) */
+      outb(OP0_RESET, LCCR(base));
+      mdelay(1);	/* A bit crude ! */
+
+      /* Initialize the LAN controller */
+      if(wv_82593_config(dev) == FALSE)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* 
-   * insert code for loopback test here
-   */
+      /* Diagnostic */
+      if(wv_diag(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* The device is now configured */
-  lp->configured = 1;
+      /* 
+       * insert code for loopback test here
+       */
+
+      /* The device is now configured */
+      lp->configured = 1;
+      ret = TRUE;
+    }
+  while(0);
+
+  /* Re-enable interrupts */
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
 #endif
-  return TRUE;
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3675,10 +3754,6 @@
   printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
 #endif
 
-  /* If watchdog was activated, kill it ! */
-  if (timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   lp->nresets++;
   lp->configured = 0;
   
@@ -3786,13 +3861,13 @@
 	}
 
       /*
-       * Allocate a 4K memory window.  Note that the dev_link_t
+       * Allocate a small memory window.  Note that the dev_link_t
        * structure provides space for one window handle -- if your
        * device needs several windows, you'll need to keep track of
        * the handles in your private data structure, link->priv.
        */
       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-      req.Base = 0; req.Size = 0x1000;
+      req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
       link->win = (window_handle_t)link->handle;
       i = CardServices(RequestWindow, &link->win, &req);
@@ -3803,7 +3878,7 @@
 	}
 
       dev->rmem_start = dev->mem_start =
-	  (u_long)ioremap(req.Base, 0x1000);
+	  (u_long)ioremap(req.Base, req.Size);
       dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
 
       mem.CardOffset = 0; mem.Page = 0;
@@ -3817,7 +3892,7 @@
       /* Feed device with this info... */
       dev->irq = link->irq.AssignedIRQ;
       dev->base_addr = link->io.BasePort1;
-      netif_start_queue (dev);
+      netif_start_queue(dev);
 
 #ifdef DEBUG_CONFIG_INFO
       printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3843,7 +3918,7 @@
       return FALSE;
     }
 
-  /* XXX Could you explain me this, Dave ? */
+  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
   link->dev = &((net_local *) dev->priv)->node;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3887,7 +3962,7 @@
   CardServices(ReleaseIO, link->handle, &link->io);
   CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+  link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
@@ -3896,7 +3971,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Sometimes, netwave_detach can't be performed following a call from
+ * Sometimes, wavelan_detach can't be performed following a call from
  * cardmgr (device still open, pcmcia_release not done) and the device
  * is put in a STALE_LINK state and remains in memory.
  *
@@ -3970,7 +4045,19 @@
   lp = (net_local *) dev->priv;
   base = dev->base_addr;
 
-  spin_lock (&lp->lock);
+#ifdef DEBUG_INTERRUPT_INFO
+  /* Check state of our spinlock (it should be cleared) */
+  if(spin_is_locked(&lp->spinlock))
+    printk(KERN_DEBUG
+	   "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+	   dev->name);
+#endif
+
+  /* Prevent reentrancy. We need to do that because we may have
+   * multiple interrupt handler running concurently.
+   * It is safe because wv_splhi() disable interrupts before aquiring
+   * the spinlock. */
+  spin_lock(&lp->spinlock);
 
   /* Treat all pending interrupts */
   while(1)
@@ -4015,8 +4102,6 @@
 	  break;
 	}
 
-      lp->status = status0;	/* Save current status (for commands) */
-
       /* ----------------- RECEIVING PACKET ----------------- */
       /*
        * When the wavelan signal the reception of a new packet,
@@ -4054,22 +4139,6 @@
        * Most likely : transmission done
        */
 
-      /* If we are already waiting elsewhere for the command to complete */
-      if(wv_wait_completed)
-	{
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
-		 dev->name);
-#endif
-
-	  /* Signal command completion */
-	  wv_wait_completed = 0;
-
-	  /* Acknowledge the interrupt */
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-	  continue;
-    	}
-
       /* If a transmission has been done */
       if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
 	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
@@ -4081,10 +4150,6 @@
 		   dev->name);
 #endif
 
-	  /* If watchdog was activated, kill it ! */
-	  if(timer_pending(&lp->watchdog))
-	    del_timer(&lp->watchdog);
-
 	  /* Get transmission status */
 	  tx_status = inb(LCSR(base));
 	  tx_status |= (inb(LCSR(base)) << 8);
@@ -4174,7 +4239,7 @@
 	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
 	  lp->stats.tx_packets++;
 
-	  netif_wake_queue (dev);
+	  netif_wake_queue(dev);
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	} 
       else	/* if interrupt = transmit done or retransmit done */
@@ -4185,9 +4250,9 @@
 #endif
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	}
-    }
+    }	/* while(1) */
 
-  spin_unlock_irq (&lp->lock);
+  spin_unlock(&lp->spinlock);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4196,30 +4261,23 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
  *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the ISA driver. I make it this way because the overhead
- * of add_timer() and del_timer() is nothing and that it avoid calling
- * the watchdog, saving some CPU... If you want to apply the same
- * watchdog to the ISA driver, you should be a bit carefull, because
- * of the many transmit buffers...
- * This watchdog is also move clever, it try to abort the current
- * command before reseting everything...
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
  */
 static void
-wavelan_watchdog(u_long		a)
+wavelan_watchdog(device *	dev)
 {
-  device *		dev;
-  net_local *		lp;
-  ioaddr_t		base;
-  int			spin;
-
-  dev = (device *) a;
-  base = dev->base_addr;
-  lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			aborted = FALSE;
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
@@ -4230,21 +4288,21 @@
 	 dev->name);
 #endif
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  wv_splhi(lp, &flags);
 
   /* Ask to abort the current command */
   outb(OP0_ABORT, LCCR(base));
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 250))
-    udelay(10);
-
-  /* If the interrupt handler hasn't be called or invalid status */
-  if((wv_wait_completed) ||
-     ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
+  /* Wait for the end of the command (a bit hackish) */
+  if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+		  OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+    aborted = TRUE;
+
+  /* Release spinlock here so that wv_hw_reset() can grab it */
+  wv_splx(lp, &flags);
+
+  /* Check if we were successful in aborting it */
+  if(!aborted)
     {
       /* It seem that it wasn't enough */
 #ifdef DEBUG_INTERRUPT_ERROR
@@ -4269,7 +4327,7 @@
 #endif
 
   /* We are no more waiting for something... */
-  netif_start_queue (dev);
+  netif_wake_queue(dev);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4322,7 +4380,7 @@
     return FALSE;
   if(!wv_ru_start(dev))
     wv_hw_reset(dev);		/* If problem : reset */
-  netif_start_queue (dev);
+  netif_start_queue(dev);
 
   /* Mark the device as used */
   link->open++;
@@ -4348,7 +4406,6 @@
 wavelan_close(device *	dev)
 {
   dev_link_t *	link = ((net_local *) dev->priv)->link;
-  net_local *	lp = (net_local *)dev->priv;
   ioaddr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4356,8 +4413,6 @@
 	 (unsigned int) dev);
 #endif
 
-  netif_stop_queue (dev);
-
   /* If the device isn't open, then nothing to do */
   if(!link->open)
     {
@@ -4373,17 +4428,13 @@
     wv_roam_cleanup(dev);
 #endif	/* WAVELAN_ROAMING */
 
-  /* If watchdog was activated, kill it ! */
-  if(timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   link->open--;
   MOD_DEC_USE_COUNT;
 
   /* If the card is still present */
-  if (netif_device_present(dev))
+  if(netif_running(dev))
     {
-      netif_stop_queue (dev);
+      netif_stop_queue(dev);
 
       /* Stop receiving new messages and wait end of transmission */
       wv_ru_stop(dev);
@@ -4404,21 +4455,6 @@
 
 /*------------------------------------------------------------------*/
 /*
- * We never need to do anything when a wavelan device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-wavelan_init(device *	dev)
-{
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<>wavelan_init()\n");
-#endif
-
-  return(0);
-}
-
-/*------------------------------------------------------------------*/
-/*
  * wavelan_attach() creates an "instance" of the driver, allocating
  * local data structures for one device (one interface).  The device
  * is registered with Card Services.
@@ -4445,24 +4481,8 @@
 
   /* Initialize the dev_link_t structure */
   link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-  if (!link)
-	  return NULL;
-  
-  /* Allocate the generic data structure */
-  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-  if (!dev)
-	  goto fail_alloc_dev;
-  
-  /* Allocate the wavelan-specific data structure. */
-  lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
-  if (!lp)
-	  goto fail_alloc_dev_priv;
-  
-  memset(lp, 0, sizeof(net_local));
+  if (!link) return NULL;
   memset(link, 0, sizeof(struct dev_link_t));
-  memset(dev, 0, sizeof(struct net_device));
-
-  dev->priv = lp;
 
   /* Unused for the Wavelan */
   link->release.function = &wv_pcmcia_release;
@@ -4492,18 +4512,35 @@
   link->next = dev_list;
   dev_list = link;
 
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  if (!dev) {
+      kfree(link);
+      return NULL;
+  }
+  memset(dev, 0x00, sizeof(struct net_device));
   link->priv = link->irq.Instance = dev;
 
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  if (!lp) {
+      kfree(link);
+      kfree(dev);
+      return NULL;
+  }
+  memset(lp, 0x00, sizeof(net_local));
+
   /* Init specific data */
-  wv_wait_completed = 0;
-  lp->status = FALSE;
   lp->configured = 0;
   lp->reconfig_82593 = FALSE;
   lp->nresets = 0;
+  /* Multicast stuff */
+  lp->promiscuous = 0;
+  lp->allmulticast = 0;
+  lp->mc_count = 0;
 
-  /* Set the watchdog timer */
-  lp->watchdog.function = wavelan_watchdog;
-  lp->watchdog.data = (unsigned long) dev;
+  /* Init spinlock */
+  spin_lock_init(&lp->spinlock);
 
   /* back links */
   lp->link = link;
@@ -4513,7 +4550,6 @@
   ether_setup(dev);
 
   /* wavelan NET3 callbacks */
-  dev->init = &wavelan_init;
   dev->open = &wavelan_open;
   dev->stop = &wavelan_close;
   dev->hard_start_xmit = &wavelan_packet_xmit;
@@ -4523,14 +4559,16 @@
   dev->set_mac_address = &wavelan_set_mac_address;
 #endif	/* SET_MAC_ADDRESS */
 
+  /* Set the watchdog timer */
+  dev->tx_timeout	= &wavelan_watchdog;
+  dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+
 #ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
   dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
   /* Other specific data */
-  strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
-  netif_start_queue (dev);
   dev->mtu = WAVELAN_MTU;
 
   /* Register with Card Services */
@@ -4562,12 +4600,6 @@
 #endif
 
   return link;
-
-fail_alloc_dev_priv:
-  kfree(dev);
-fail_alloc_dev:
-  kfree(link);
-  return NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -4698,7 +4730,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
 	    /* Accept no more transmissions */
-      	    netif_device_detach(dev);
+	    netif_device_detach(dev);
 
 	    /* Release the card */
 	    wv_pcmcia_release((u_long) link);
@@ -4720,7 +4752,7 @@
 	 * obliged to close nicely the wavelan here. David, could you
 	 * close the device before suspending them ? And, by the way,
 	 * could you, on resume, add a "route add -net ..." after the
-	 * ifconfig up XXX Thanks... */
+	 * ifconfig up ? Thanks... */
 
 	/* Stop receiving new messages and wait end of transmission */
 	wv_ru_stop(dev);
@@ -4735,8 +4767,7 @@
     	if(link->state & DEV_CONFIG)
 	  {
       	    if(link->open)
-	      	netif_device_detach(dev);
-
+	      netif_device_detach(dev);
       	    CardServices(ReleaseConfiguration, link->handle);
 	  }
 	break;
@@ -4748,7 +4779,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
       	    CardServices(RequestConfiguration, link->handle, &link->conf);
-      	    if(link->open)	/* If RESET -> True, If RESUME -> False XXX */
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False ? */
 	      {
 		wv_hw_reset(dev);
 		netif_device_attach(dev);
@@ -4838,4 +4869,5 @@
 
 module_init(init_wavelan_cs);
 module_exit(exit_wavelan_cs);
-MODULE_LICENSE("Dual BSD/GPL");
+
+/* Note : Modules parameters are in wavelan_cs.h - Jean II */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)