linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / net / wireless / wavelan_cs.c
index 561250f..98122f3 100644 (file)
@@ -1005,7 +1005,7 @@ static inline void
 wv_82593_reconfig(struct net_device *  dev)
 {
   net_local *          lp = netdev_priv(dev);
-  struct pcmcia_device *               link = lp->link;
+  dev_link_t *         link = lp->link;
   unsigned long                flags;
 
   /* Arm the flag, will be cleard in wv_82593_config() */
@@ -3194,8 +3194,11 @@ wavelan_packet_xmit(struct sk_buff *     skb,
         * and we don't have the Ethernet specific requirement of beeing
         * able to detect collisions, therefore in theory we don't really
         * need to pad. Jean II */
-       if (skb_padto(skb, ETH_ZLEN))
-               return 0;
+       if (skb->len < ETH_ZLEN) {
+               skb = skb_padto(skb, ETH_ZLEN);
+               if (skb == NULL)
+                       return 0;
+       }
 
   wv_packet_write(dev, skb->data, skb->len);
 
@@ -3741,16 +3744,16 @@ wv_pcmcia_reset(struct net_device *     dev)
 {
   int          i;
   conf_reg_t   reg = { 0, CS_READ, CISREG_COR, 0 };
-  struct pcmcia_device *       link = ((net_local *)netdev_priv(dev))->link;
+  dev_link_t * link = ((net_local *)netdev_priv(dev))->link;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
 #endif
 
-  i = pcmcia_access_configuration_register(link, &reg);
+  i = pcmcia_access_configuration_register(link->handle, &reg);
   if(i != CS_SUCCESS)
     {
-      cs_error(link, AccessConfigurationRegister, i);
+      cs_error(link->handle, AccessConfigurationRegister, i);
       return FALSE;
     }
       
@@ -3761,19 +3764,19 @@ wv_pcmcia_reset(struct net_device *     dev)
 
   reg.Action = CS_WRITE;
   reg.Value = reg.Value | COR_SW_RESET;
-  i = pcmcia_access_configuration_register(link, &reg);
+  i = pcmcia_access_configuration_register(link->handle, &reg);
   if(i != CS_SUCCESS)
     {
-      cs_error(link, AccessConfigurationRegister, i);
+      cs_error(link->handle, AccessConfigurationRegister, i);
       return FALSE;
     }
       
   reg.Action = CS_WRITE;
   reg.Value = COR_LEVEL_IRQ | COR_CONFIG;
-  i = pcmcia_access_configuration_register(link, &reg);
+  i = pcmcia_access_configuration_register(link->handle, &reg);
   if(i != CS_SUCCESS)
     {
-      cs_error(link, AccessConfigurationRegister, i);
+      cs_error(link->handle, AccessConfigurationRegister, i);
       return FALSE;
     }
 
@@ -3937,8 +3940,9 @@ wv_hw_reset(struct net_device *   dev)
  * (called by wavelan_event())
  */
 static inline int
-wv_pcmcia_config(struct pcmcia_device *        link)
+wv_pcmcia_config(dev_link_t *  link)
 {
+  client_handle_t      handle = link->handle;
   tuple_t              tuple;
   cisparse_t           parse;
   struct net_device *  dev = (struct net_device *) link->priv;
@@ -3961,16 +3965,16 @@ wv_pcmcia_config(struct pcmcia_device * link)
     {
       tuple.Attributes = 0;
       tuple.DesiredTuple = CISTPL_CONFIG;
-      i = pcmcia_get_first_tuple(link, &tuple);
+      i = pcmcia_get_first_tuple(handle, &tuple);
       if(i != CS_SUCCESS)
        break;
       tuple.TupleData = (cisdata_t *)buf;
       tuple.TupleDataMax = 64;
       tuple.TupleOffset = 0;
-      i = pcmcia_get_tuple_data(link, &tuple);
+      i = pcmcia_get_tuple_data(handle, &tuple);
       if(i != CS_SUCCESS)
        break;
-      i = pcmcia_parse_tuple(link, &tuple, &parse);
+      i = pcmcia_parse_tuple(handle, &tuple, &parse);
       if(i != CS_SUCCESS)
        break;
       link->conf.ConfigBase = parse.config.base;
@@ -3979,16 +3983,19 @@ wv_pcmcia_config(struct pcmcia_device * link)
   while(0);
   if(i != CS_SUCCESS)
     {
-      cs_error(link, ParseTuple, i);
+      cs_error(link->handle, ParseTuple, i);
+      link->state &= ~DEV_CONFIG_PENDING;
       return FALSE;
     }
-
+    
+  /* Configure card */
+  link->state |= DEV_CONFIG;
   do
     {
-      i = pcmcia_request_io(link, &link->io);
+      i = pcmcia_request_io(link->handle, &link->io);
       if(i != CS_SUCCESS)
        {
-         cs_error(link, RequestIO, i);
+         cs_error(link->handle, RequestIO, i);
          break;
        }
 
@@ -3996,10 +4003,10 @@ wv_pcmcia_config(struct pcmcia_device * link)
        * Now allocate an interrupt line.  Note that this does not
        * actually assign a handler to the interrupt.
        */
-      i = pcmcia_request_irq(link, &link->irq);
+      i = pcmcia_request_irq(link->handle, &link->irq);
       if(i != CS_SUCCESS)
        {
-         cs_error(link, RequestIRQ, i);
+         cs_error(link->handle, RequestIRQ, i);
          break;
        }
 
@@ -4008,15 +4015,15 @@ wv_pcmcia_config(struct pcmcia_device * link)
        * the I/O windows and the interrupt mapping.
        */
       link->conf.ConfigIndex = 1;
-      i = pcmcia_request_configuration(link, &link->conf);
+      i = pcmcia_request_configuration(link->handle, &link->conf);
       if(i != CS_SUCCESS)
        {
-         cs_error(link, RequestConfiguration, i);
+         cs_error(link->handle, RequestConfiguration, i);
          break;
        }
 
       /*
-       * Allocate a small memory window.  Note that the struct pcmcia_device
+       * 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.
@@ -4024,10 +4031,10 @@ wv_pcmcia_config(struct pcmcia_device * link)
       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
       req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
-      i = pcmcia_request_window(&link, &req, &link->win);
+      i = pcmcia_request_window(&link->handle, &req, &link->win);
       if(i != CS_SUCCESS)
        {
-         cs_error(link, RequestWindow, i);
+         cs_error(link->handle, RequestWindow, i);
          break;
        }
 
@@ -4039,7 +4046,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
       i = pcmcia_map_mem_page(link->win, &mem);
       if(i != CS_SUCCESS)
        {
-         cs_error(link, MapMemPage, i);
+         cs_error(link->handle, MapMemPage, i);
          break;
        }
 
@@ -4053,7 +4060,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
             lp->mem, dev->irq, (u_int) dev->base_addr);
 #endif
 
-      SET_NETDEV_DEV(dev, &handle_to_dev(link));
+      SET_NETDEV_DEV(dev, &handle_to_dev(handle));
       i = register_netdev(dev);
       if(i != 0)
        {
@@ -4065,6 +4072,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
     }
   while(0);            /* Humm... Disguised goto !!! */
 
+  link->state &= ~DEV_CONFIG_PENDING;
   /* If any step failed, release any partially configured state */
   if(i != 0)
     {
@@ -4073,7 +4081,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
     }
 
   strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name);
-  link->dev_node = &((net_local *) netdev_priv(dev))->node;
+  link->dev = &((net_local *) netdev_priv(dev))->node;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
@@ -4088,20 +4096,26 @@ wv_pcmcia_config(struct pcmcia_device * link)
  * still open, this will be postponed until it is closed.
  */
 static void
-wv_pcmcia_release(struct pcmcia_device *link)
+wv_pcmcia_release(dev_link_t *link)
 {
-       struct net_device *     dev = (struct net_device *) link->priv;
-       net_local *             lp = netdev_priv(dev);
+  struct net_device *  dev = (struct net_device *) link->priv;
+  net_local *          lp = netdev_priv(dev);
 
 #ifdef DEBUG_CONFIG_TRACE
-       printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
+  printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
 #endif
 
-       iounmap(lp->mem);
-       pcmcia_disable_device(link);
+  /* Don't bother checking to see if these succeed or not */
+  iounmap(lp->mem);
+  pcmcia_release_window(link->win);
+  pcmcia_release_configuration(link->handle);
+  pcmcia_release_io(link->handle, &link->io);
+  pcmcia_release_irq(link->handle, &link->irq);
+
+  link->state &= ~DEV_CONFIG;
 
 #ifdef DEBUG_CONFIG_TRACE
-       printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
+  printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
 #endif
 }
 
@@ -4465,7 +4479,7 @@ static int
 wavelan_open(struct net_device *       dev)
 {
   net_local *  lp = netdev_priv(dev);
-  struct pcmcia_device *       link = lp->link;
+  dev_link_t * link = lp->link;
   kio_addr_t   base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4519,7 +4533,7 @@ wavelan_open(struct net_device *  dev)
 static int
 wavelan_close(struct net_device *      dev)
 {
-  struct pcmcia_device *       link = ((net_local *)netdev_priv(dev))->link;
+  dev_link_t * link = ((net_local *)netdev_priv(dev))->link;
   kio_addr_t   base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4573,36 +4587,45 @@ wavelan_close(struct net_device *       dev)
  * card insertion event.
  */
 static int
-wavelan_probe(struct pcmcia_device *p_dev)
+wavelan_attach(struct pcmcia_device *p_dev)
 {
+  dev_link_t * link;           /* Info for cardmgr */
   struct net_device *  dev;            /* Interface generic data */
   net_local *  lp;             /* Interface specific data */
-  int ret;
 
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "-> wavelan_attach()\n");
 #endif
 
+  /* Initialize the dev_link_t structure */
+  link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+  if (!link) return -ENOMEM;
+
   /* The io structure describes IO port mapping */
-  p_dev->io.NumPorts1 = 8;
-  p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-  p_dev->io.IOAddrLines = 3;
+  link->io.NumPorts1 = 8;
+  link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+  link->io.IOAddrLines = 3;
 
   /* Interrupt setup */
-  p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-  p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
-  p_dev->irq.Handler = wavelan_interrupt;
+  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+  link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+  link->irq.Handler = wavelan_interrupt;
 
   /* General socket configuration */
-  p_dev->conf.Attributes = CONF_ENABLE_IRQ;
-  p_dev->conf.IntType = INT_MEMORY_AND_IO;
+  link->conf.Attributes = CONF_ENABLE_IRQ;
+  link->conf.Vcc = 50;
+  link->conf.IntType = INT_MEMORY_AND_IO;
+
+  /* Chain drivers */
+  link->next = NULL;
 
   /* Allocate the generic data structure */
   dev = alloc_etherdev(sizeof(net_local));
-  if (!dev)
+  if (!dev) {
+      kfree(link);
       return -ENOMEM;
-
-  p_dev->priv = p_dev->irq.Instance = dev;
+  }
+  link->priv = link->irq.Instance = dev;
 
   lp = netdev_priv(dev);
 
@@ -4619,6 +4642,7 @@ wavelan_probe(struct pcmcia_device *p_dev)
   spin_lock_init(&lp->spinlock);
 
   /* back links */
+  lp->link = link;
   lp->dev = dev;
 
   /* wavelan NET3 callbacks */
@@ -4644,18 +4668,15 @@ wavelan_probe(struct pcmcia_device *p_dev)
   /* Other specific data */
   dev->mtu = WAVELAN_MTU;
 
-  ret = wv_pcmcia_config(p_dev);
-  if (ret)
-         return ret;
+  link->handle = p_dev;
+  p_dev->instance = link;
 
-  ret = wv_hw_config(dev);
-  if (ret) {
+  link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+  if(wv_pcmcia_config(link) &&
+     wv_hw_config(dev))
+         wv_init_info(dev);
+  else
          dev->irq = 0;
-         pcmcia_disable_device(p_dev);
-         return ret;
-  }
-
-  wv_init_info(dev);
 
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "<- wavelan_attach()\n");
@@ -4672,14 +4693,25 @@ wavelan_probe(struct pcmcia_device *p_dev)
  * is released.
  */
 static void
-wavelan_detach(struct pcmcia_device *link)
+wavelan_detach(struct pcmcia_device *p_dev)
 {
+   dev_link_t *link = dev_to_instance(p_dev);
+
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link);
 #endif
 
-  /* Some others haven't done their job : give them another chance */
-  wv_pcmcia_release(link);
+  /*
+   * If the device is currently configured and active, we won't
+   * actually delete it yet.  Instead, it is marked so that when the
+   * release() function is called, that will trigger a proper
+   * detach().
+   */
+  if(link->state & DEV_CONFIG)
+    {
+      /* Some others haven't done their job : give them another chance */
+      wv_pcmcia_release(link);
+    }
 
   /* Free pieces */
   if(link->priv)
@@ -4688,21 +4720,23 @@ wavelan_detach(struct pcmcia_device *link)
 
       /* Remove ourselves from the kernel list of ethernet devices */
       /* Warning : can't be called from interrupt, timer or wavelan_close() */
-      if (link->dev_node)
+      if (link->dev)
        unregister_netdev(dev);
-      link->dev_node = NULL;
+      link->dev = NULL;
       ((net_local *)netdev_priv(dev))->link = NULL;
       ((net_local *)netdev_priv(dev))->dev = NULL;
       free_netdev(dev);
     }
+  kfree(link);
 
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "<- wavelan_detach()\n");
 #endif
 }
 
-static int wavelan_suspend(struct pcmcia_device *link)
+static int wavelan_suspend(struct pcmcia_device *p_dev)
 {
+       dev_link_t *link = dev_to_instance(p_dev);
        struct net_device *     dev = (struct net_device *) link->priv;
 
        /* NB: wavelan_close will be called, but too late, so we are
@@ -4714,22 +4748,36 @@ static int wavelan_suspend(struct pcmcia_device *link)
        /* Stop receiving new messages and wait end of transmission */
        wv_ru_stop(dev);
 
-       if (link->open)
-               netif_device_detach(dev);
-
        /* Power down the module */
        hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT));
 
+       /* The card is now suspended */
+       link->state |= DEV_SUSPEND;
+
+       if(link->state & DEV_CONFIG)
+       {
+               if(link->open)
+                       netif_device_detach(dev);
+               pcmcia_release_configuration(link->handle);
+       }
+
        return 0;
 }
 
-static int wavelan_resume(struct pcmcia_device *link)
+static int wavelan_resume(struct pcmcia_device *p_dev)
 {
+       dev_link_t *link = dev_to_instance(p_dev);
        struct net_device *     dev = (struct net_device *) link->priv;
 
-       if (link->open) {
-               wv_hw_reset(dev);
-               netif_device_attach(dev);
+       link->state &= ~DEV_SUSPEND;
+       if(link->state & DEV_CONFIG)
+       {
+               pcmcia_request_configuration(link->handle, &link->conf);
+               if(link->open)  /* If RESET -> True, If RESUME -> False ? */
+               {
+                       wv_hw_reset(dev);
+                       netif_device_attach(dev);
+               }
        }
 
        return 0;
@@ -4750,7 +4798,7 @@ static struct pcmcia_driver wavelan_driver = {
        .drv            = {
                .name   = "wavelan_cs",
        },
-       .probe          = wavelan_probe,
+       .probe          = wavelan_attach,
        .remove         = wavelan_detach,
        .id_table       = wavelan_ids,
        .suspend        = wavelan_suspend,