linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / net / pcmcia / axnet_cs.c
index 297e9f8..aa55813 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
-#include <linux/crc32.h>
 #include "../8390.h"
 
 #include <pcmcia/cs_types.h>
@@ -86,8 +85,8 @@ static char *version =
 
 /*====================================================================*/
 
-static int axnet_config(struct pcmcia_device *link);
-static void axnet_release(struct pcmcia_device *link);
+static void axnet_config(dev_link_t *link);
+static void axnet_release(dev_link_t *link);
 static int axnet_open(struct net_device *dev);
 static int axnet_close(struct net_device *dev);
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -117,7 +116,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 /*====================================================================*/
 
 typedef struct axnet_dev_t {
-       struct pcmcia_device    *p_dev;
+    dev_link_t         link;
     dev_node_t         node;
     caddr_t            base;
     struct timer_list  watchdog;
@@ -142,9 +141,10 @@ static inline axnet_dev_t *PRIV(struct net_device *dev)
 
 ======================================================================*/
 
-static int axnet_probe(struct pcmcia_device *link)
+static int axnet_attach(struct pcmcia_device *p_dev)
 {
     axnet_dev_t *info;
+    dev_link_t *link;
     struct net_device *dev;
 
     DEBUG(0, "axnet_attach()\n");
@@ -156,7 +156,7 @@ static int axnet_probe(struct pcmcia_device *link)
        return -ENOMEM;
 
     info = PRIV(dev);
-    info->p_dev = link;
+    link = &info->link;
     link->priv = dev;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
@@ -168,7 +168,13 @@ static int axnet_probe(struct pcmcia_device *link)
     dev->do_ioctl = &axnet_ioctl;
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
-    return axnet_config(link);
+    link->handle = p_dev;
+    p_dev->instance = link;
+
+    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+    axnet_config(link);
+
+    return 0;
 } /* axnet_attach */
 
 /*======================================================================
@@ -180,16 +186,18 @@ static int axnet_probe(struct pcmcia_device *link)
 
 ======================================================================*/
 
-static void axnet_detach(struct pcmcia_device *link)
+static void axnet_detach(struct pcmcia_device *p_dev)
 {
+    dev_link_t *link = dev_to_instance(p_dev);
     struct net_device *dev = link->priv;
 
     DEBUG(0, "axnet_detach(0x%p)\n", link);
 
-    if (link->dev_node)
+    if (link->dev)
        unregister_netdev(dev);
 
-    axnet_release(link);
+    if (link->state & DEV_CONFIG)
+       axnet_release(link);
 
     free_netdev(dev);
 } /* axnet_detach */
@@ -200,7 +208,7 @@ static void axnet_detach(struct pcmcia_device *link)
 
 ======================================================================*/
 
-static int get_prom(struct pcmcia_device *link)
+static int get_prom(dev_link_t *link)
 {
     struct net_device *dev = link->priv;
     kio_addr_t ioaddr = dev->base_addr;
@@ -254,7 +262,7 @@ static int get_prom(struct pcmcia_device *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static int try_io_port(struct pcmcia_device *link)
+static int try_io_port(dev_link_t *link)
 {
     int j, ret;
     if (link->io.NumPorts1 == 32) {
@@ -275,23 +283,25 @@ static int try_io_port(struct pcmcia_device *link)
        for (j = 0; j < 0x400; j += 0x20) {
            link->io.BasePort1 = j ^ 0x300;
            link->io.BasePort2 = (j ^ 0x300) + 0x10;
-           ret = pcmcia_request_io(link, &link->io);
+           ret = pcmcia_request_io(link->handle, &link->io);
            if (ret == CS_SUCCESS) return ret;
        }
        return ret;
     } else {
-       return pcmcia_request_io(link, &link->io);
+       return pcmcia_request_io(link->handle, &link->io);
     }
 }
 
-static int axnet_config(struct pcmcia_device *link)
+static void axnet_config(dev_link_t *link)
 {
+    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     axnet_dev_t *info = PRIV(dev);
     tuple_t tuple;
     cisparse_t parse;
     int i, j, last_ret, last_fn;
     u_short buf[64];
+    config_info_t conf;
 
     DEBUG(0, "axnet_config(0x%p)\n", link);
 
@@ -300,22 +310,29 @@ static int axnet_config(struct pcmcia_device *link)
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     /* don't trust the CIS on this; Linksys got it wrong */
     link->conf.Present = 0x63;
 
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Look up current Vcc */
+    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
+    link->conf.Vcc = conf.Vcc;
+
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
     tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
     while (last_ret == CS_SUCCESS) {
        cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
        cistpl_io_t *io = &(parse.cftable_entry.io);
        
-       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-               pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
+       if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
+               pcmcia_parse_tuple(handle, &tuple, &parse) != 0 ||
                cfg->index == 0 || cfg->io.nwin == 0)
            goto next_entry;
        
@@ -337,21 +354,21 @@ static int axnet_config(struct pcmcia_device *link)
            if (last_ret == CS_SUCCESS) break;
        }
     next_entry:
-       last_ret = pcmcia_get_next_tuple(link, &tuple);
+       last_ret = pcmcia_get_next_tuple(handle, &tuple);
     }
     if (last_ret != CS_SUCCESS) {
-       cs_error(link, RequestIO, last_ret);
+       cs_error(handle, RequestIO, last_ret);
        goto failed;
     }
 
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
     
     if (link->io.NumPorts2 == 8) {
        link->conf.Attributes |= CONF_ENABLE_SPKR;
        link->conf.Status = CCSR_AUDIO_ENA;
     }
     
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
 
@@ -388,7 +405,7 @@ static int axnet_config(struct pcmcia_device *link)
        Bit 2 of CCSR is active low. */ 
     if (i == 32) {
        conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 };
-       pcmcia_access_configuration_register(link, &reg);
+       pcmcia_access_configuration_register(link->handle, &reg);
        for (i = 0; i < 32; i++) {
            j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
            if ((j != 0) && (j != 0xffff)) break;
@@ -396,12 +413,13 @@ static int axnet_config(struct pcmcia_device *link)
     }
 
     info->phy_id = (i < 32) ? i : -1;
-    link->dev_node = &info->node;
-    SET_NETDEV_DEV(dev, &handle_to_dev(link));
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
 
     if (register_netdev(dev) != 0) {
        printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n");
-       link->dev_node = NULL;
+       link->dev = NULL;
        goto failed;
     }
 
@@ -417,13 +435,14 @@ static int axnet_config(struct pcmcia_device *link)
     } else {
        printk(KERN_NOTICE "  No MII transceivers found!\n");
     }
-    return 0;
+    return;
 
 cs_failed:
-    cs_error(link, last_fn, last_ret);
+    cs_error(link->handle, last_fn, last_ret);
 failed:
     axnet_release(link);
-    return -ENODEV;
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
 } /* axnet_config */
 
 /*======================================================================
@@ -434,29 +453,45 @@ failed:
 
 ======================================================================*/
 
-static void axnet_release(struct pcmcia_device *link)
+static void axnet_release(dev_link_t *link)
 {
-       pcmcia_disable_device(link);
+    DEBUG(0, "axnet_release(0x%p)\n", link);
+
+    pcmcia_release_configuration(link->handle);
+    pcmcia_release_io(link->handle, &link->io);
+    pcmcia_release_irq(link->handle, &link->irq);
+
+    link->state &= ~DEV_CONFIG;
 }
 
-static int axnet_suspend(struct pcmcia_device *link)
+static int axnet_suspend(struct pcmcia_device *p_dev)
 {
+       dev_link_t *link = dev_to_instance(p_dev);
        struct net_device *dev = link->priv;
 
-       if (link->open)
-               netif_device_detach(dev);
+       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 axnet_resume(struct pcmcia_device *link)
+static int axnet_resume(struct pcmcia_device *p_dev)
 {
+       dev_link_t *link = dev_to_instance(p_dev);
        struct net_device *dev = link->priv;
 
-       if (link->open) {
-               axnet_reset_8390(dev);
-               AX88190_init(dev, 1);
-               netif_device_attach(dev);
+       link->state &= ~DEV_SUSPEND;
+       if (link->state & DEV_CONFIG) {
+               pcmcia_request_configuration(link->handle, &link->conf);
+               if (link->open) {
+                       axnet_reset_8390(dev);
+                       AX88190_init(dev, 1);
+                       netif_device_attach(dev);
+               }
        }
 
        return 0;
@@ -526,16 +561,16 @@ static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
 static int axnet_open(struct net_device *dev)
 {
     axnet_dev_t *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
+    dev_link_t *link = &info->link;
     
     DEBUG(2, "axnet_open('%s')\n", dev->name);
 
-    if (!pcmcia_dev_present(link))
+    if (!DEV_OK(link))
        return -ENODEV;
 
     link->open++;
 
-    request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
+    request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, "axnet_cs", dev);
 
     info->link_status = 0x00;
     init_timer(&info->watchdog);
@@ -552,7 +587,7 @@ static int axnet_open(struct net_device *dev)
 static int axnet_close(struct net_device *dev)
 {
     axnet_dev_t *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
+    dev_link_t *link = &info->link;
 
     DEBUG(2, "axnet_close('%s')\n", dev->name);
 
@@ -797,7 +832,7 @@ static struct pcmcia_driver axnet_cs_driver = {
        .drv            = {
                .name   = "axnet_cs",
        },
-       .probe          = axnet_probe,
+       .probe          = axnet_attach,
        .remove         = axnet_detach,
        .id_table       = axnet_ids,
        .suspend        = axnet_suspend,
@@ -1560,7 +1595,7 @@ static void ei_receive(struct net_device *dev)
 
 static void ei_rx_overrun(struct net_device *dev)
 {
-       axnet_dev_t *info = PRIV(dev);
+       axnet_dev_t *info = (axnet_dev_t *)dev;
        long e8390_base = dev->base_addr;
        unsigned char was_txing, must_resend = 0;
        struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
@@ -1647,56 +1682,17 @@ static struct net_device_stats *get_stats(struct net_device *dev)
        return &ei_local->stat;
 }
 
-/*
- * Form the 64 bit 8390 multicast table from the linked list of addresses
- * associated with this dev structure.
- */
-static inline void make_mc_bits(u8 *bits, struct net_device *dev)
-{
-       struct dev_mc_list *dmi;
-       u32 crc;
-
-       for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
-               
-               crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
-               /* 
-                * The 8390 uses the 6 most significant bits of the
-                * CRC to index the multicast table.
-                */
-               bits[crc>>29] |= (1<<((crc>>26)&7));
-       }
-}
-
 /**
  * do_set_multicast_list - set/clear multicast filter
  * @dev: net device for which multicast filter is adjusted
  *
- *     Set or clear the multicast filter for this adaptor.
- *     Must be called with lock held. 
+ *     Set or clear the multicast filter for this adaptor. May be called
+ *     from a BH in 2.1.x. Must be called with lock held. 
  */
  
 static void do_set_multicast_list(struct net_device *dev)
 {
        long e8390_base = dev->base_addr;
-       int i;
-       struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
-
-       if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
-               memset(ei_local->mcfilter, 0, 8);
-               if (dev->mc_list)
-                       make_mc_bits(ei_local->mcfilter, dev);
-       } else {
-               /* set to accept-all */
-               memset(ei_local->mcfilter, 0xFF, 8);
-       }
-
-       outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
-       for(i = 0; i < 8; i++) 
-       {
-               outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
-       }
-       outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
 
        if(dev->flags&IFF_PROMISC)
                outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
@@ -1704,8 +1700,6 @@ static void do_set_multicast_list(struct net_device *dev)
                outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
        else
                outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
-
-       outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
 }
 
 /*
@@ -1800,6 +1794,12 @@ static void AX88190_init(struct net_device *dev, int startp)
                if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
                        printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
        }
+       /*
+        * Initialize the multicast list to accept-all.  If we enable multicast
+        * the higher levels can do the filtering.
+        */
+       for (i = 0; i < 8; i++)
+               outb_p(0xff, e8390_base + EN1_MULT + i);
 
        outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
        outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);