Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / net / pcmcia / axnet_cs.c
index 67e1526..297e9f8 100644 (file)
@@ -35,9 +35,9 @@
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
+#include <linux/crc32.h>
 #include "../8390.h"
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -73,14 +73,9 @@ MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver");
 MODULE_LICENSE("GPL");
 
-#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
-
-/* Bit map of interrupts to choose from */
-INT_MODULE_PARM(irq_mask,      0xdeb8);
-static int irq_list[4] = { -1 };
-MODULE_PARM(irq_list, "1-4i");
-
 #ifdef PCMCIA_DEBUG
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
+
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
@@ -91,10 +86,8 @@ static char *version =
 
 /*====================================================================*/
 
-static void axnet_config(dev_link_t *link);
-static void axnet_release(dev_link_t *link);
-static int axnet_event(event_t event, int priority,
-                      event_callback_args_t *args);
+static int axnet_config(struct pcmcia_device *link);
+static void axnet_release(struct pcmcia_device *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);
@@ -103,8 +96,8 @@ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
 static void ei_watchdog(u_long arg);
 static void axnet_reset_8390(struct net_device *dev);
 
-static int mdio_read(ioaddr_t addr, int phy_id, int loc);
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value);
+static int mdio_read(kio_addr_t addr, int phy_id, int loc);
+static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value);
 
 static void get_8390_hdr(struct net_device *,
                         struct e8390_pkt_hdr *, int);
@@ -113,11 +106,7 @@ static void block_input(struct net_device *dev, int count,
 static void block_output(struct net_device *dev, int count,
                         const u_char *buf, const int start_page);
 
-static dev_link_t *axnet_attach(void);
-static void axnet_detach(dev_link_t *);
-
-static dev_info_t dev_info = "axnet_cs";
-static dev_link_t *dev_list;
+static void axnet_detach(struct pcmcia_device *p_dev);
 
 static void axdev_setup(struct net_device *dev);
 static void AX88190_init(struct net_device *dev, int startp);
@@ -128,7 +117,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 /*====================================================================*/
 
 typedef struct axnet_dev_t {
-    dev_link_t         link;
+       struct pcmcia_device    *p_dev;
     dev_node_t         node;
     caddr_t            base;
     struct timer_list  watchdog;
@@ -153,13 +142,10 @@ static inline axnet_dev_t *PRIV(struct net_device *dev)
 
 ======================================================================*/
 
-static dev_link_t *axnet_attach(void)
+static int axnet_probe(struct pcmcia_device *link)
 {
     axnet_dev_t *info;
-    dev_link_t *link;
     struct net_device *dev;
-    client_reg_t client_reg;
-    int i, ret;
 
     DEBUG(0, "axnet_attach()\n");
 
@@ -167,18 +153,13 @@ static dev_link_t *axnet_attach(void)
                        "eth%d", axdev_setup);
 
     if (!dev)
-       return NULL;
+       return -ENOMEM;
 
     info = PRIV(dev);
-    link = &info->link;
+    info->p_dev = link;
     link->priv = dev;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-    if (irq_list[0] == -1)
-       link->irq.IRQInfo2 = irq_mask;
-    else
-       for (i = 0; i < 4; i++)
-           link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
     link->conf.Attributes = CONF_ENABLE_IRQ;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
@@ -187,26 +168,7 @@ static dev_link_t *axnet_attach(void)
     dev->do_ioctl = &axnet_ioctl;
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-    client_reg.dev_info = &dev_info;
-    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-    client_reg.EventMask =
-       CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-       CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-       CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &axnet_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = pcmcia_register_client(&link->handle, &client_reg);
-    if (ret != CS_SUCCESS) {
-       cs_error(link->handle, RegisterClient, ret);
-       axnet_detach(link);
-       return NULL;
-    }
-
-    return link;
+    return axnet_config(link);
 } /* axnet_attach */
 
 /*======================================================================
@@ -218,29 +180,17 @@ static dev_link_t *axnet_attach(void)
 
 ======================================================================*/
 
-static void axnet_detach(dev_link_t *link)
+static void axnet_detach(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    dev_link_t **linkp;
 
     DEBUG(0, "axnet_detach(0x%p)\n", link);
 
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-       if (*linkp == link) break;
-    if (*linkp == NULL)
-       return;
-
-    if (link->state & DEV_CONFIG)
-       axnet_release(link);
+    if (link->dev_node)
+       unregister_netdev(dev);
 
-    if (link->handle)
-       pcmcia_deregister_client(link->handle);
+    axnet_release(link);
 
-    /* Unlink device structure, free bits */
-    *linkp = link->next;
-    if (link->dev)
-       unregister_netdev(dev);
     free_netdev(dev);
 } /* axnet_detach */
 
@@ -250,10 +200,10 @@ static void axnet_detach(dev_link_t *link)
 
 ======================================================================*/
 
-static int get_prom(dev_link_t *link)
+static int get_prom(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     int i, j;
 
     /* This is based on drivers/net/ne.c */
@@ -304,7 +254,7 @@ static int get_prom(dev_link_t *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(dev_link_t *link)
+static int try_io_port(struct pcmcia_device *link)
 {
     int j, ret;
     if (link->io.NumPorts1 == 32) {
@@ -325,25 +275,23 @@ static int try_io_port(dev_link_t *link)
        for (j = 0; j < 0x400; j += 0x20) {
            link->io.BasePort1 = j ^ 0x300;
            link->io.BasePort2 = (j ^ 0x300) + 0x10;
-           ret = pcmcia_request_io(link->handle, &link->io);
+           ret = pcmcia_request_io(link, &link->io);
            if (ret == CS_SUCCESS) return ret;
        }
        return ret;
     } else {
-       return pcmcia_request_io(link->handle, &link->io);
+       return pcmcia_request_io(link, &link->io);
     }
 }
 
-static void axnet_config(dev_link_t *link)
+static int axnet_config(struct pcmcia_device *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);
 
@@ -352,29 +300,22 @@ static void axnet_config(dev_link_t *link)
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    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));
+    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));
     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(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &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(handle, &tuple) != 0 ||
-               pcmcia_parse_tuple(handle, &tuple, &parse) != 0 ||
+       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+               pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
                cfg->index == 0 || cfg->io.nwin == 0)
            goto next_entry;
        
@@ -396,21 +337,21 @@ static void axnet_config(dev_link_t *link)
            if (last_ret == CS_SUCCESS) break;
        }
     next_entry:
-       last_ret = pcmcia_get_next_tuple(handle, &tuple);
+       last_ret = pcmcia_get_next_tuple(link, &tuple);
     }
     if (last_ret != CS_SUCCESS) {
-       cs_error(handle, RequestIO, last_ret);
+       cs_error(link, RequestIO, last_ret);
        goto failed;
     }
 
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &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(handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
 
@@ -447,7 +388,7 @@ static void axnet_config(dev_link_t *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->handle, &reg);
+       pcmcia_access_configuration_register(link, &reg);
        for (i = 0; i < 32; i++) {
            j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
            if ((j != 0) && (j != 0xffff)) break;
@@ -455,12 +396,12 @@ static void axnet_config(dev_link_t *link)
     }
 
     info->phy_id = (i < 32) ? i : -1;
-    link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
+    link->dev_node = &info->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     if (register_netdev(dev) != 0) {
        printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n");
-       link->dev = NULL;
+       link->dev_node = NULL;
        goto failed;
     }
 
@@ -476,14 +417,13 @@ static void axnet_config(dev_link_t *link)
     } else {
        printk(KERN_NOTICE "  No MII transceivers found!\n");
     }
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     axnet_release(link);
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
+    return -ENODEV;
 } /* axnet_config */
 
 /*======================================================================
@@ -494,72 +434,34 @@ failed:
 
 ======================================================================*/
 
-static void axnet_release(dev_link_t *link)
+static void axnet_release(struct pcmcia_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;
+       pcmcia_disable_device(link);
 }
 
-/*======================================================================
+static int axnet_suspend(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
 
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the net drivers from trying
-    to talk to the card any more.
+       if (link->open)
+               netif_device_detach(dev);
 
-======================================================================*/
+       return 0;
+}
 
-static int axnet_event(event_t event, int priority,
-                      event_callback_args_t *args)
+static int axnet_resume(struct pcmcia_device *link)
 {
-    dev_link_t *link = args->client_data;
-    struct net_device *dev = link->priv;
+       struct net_device *dev = link->priv;
 
-    DEBUG(2, "axnet_event(0x%06x)\n", event);
-
-    switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-       link->state &= ~DEV_PRESENT;
-       if (link->state & DEV_CONFIG) {
-           netif_device_detach(dev);
-           axnet_release(link);
-       }
-       break;
-    case CS_EVENT_CARD_INSERTION:
-       link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-       axnet_config(link);
-       break;
-    case CS_EVENT_PM_SUSPEND:
-       link->state |= DEV_SUSPEND;
-       /* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-       if (link->state & DEV_CONFIG) {
-           if (link->open)
-               netif_device_detach(dev);
-           pcmcia_release_configuration(link->handle);
-       }
-       break;
-    case CS_EVENT_PM_RESUME:
-       link->state &= ~DEV_SUSPEND;
-       /* Fall through... */
-    case CS_EVENT_CARD_RESET:
-       if (link->state & DEV_CONFIG) {
-           pcmcia_request_configuration(link->handle, &link->conf);
-           if (link->open) {
+       if (link->open) {
                axnet_reset_8390(dev);
                AX88190_init(dev, 1);
                netif_device_attach(dev);
-           }
        }
-       break;
-    }
-    return 0;
-} /* axnet_event */
+
+       return 0;
+}
+
 
 /*======================================================================
 
@@ -574,7 +476,7 @@ static int axnet_event(event_t event, int priority,
 #define MDIO_MASK              0x0f
 #define MDIO_ENB_IN            0x02
 
-static void mdio_sync(ioaddr_t addr)
+static void mdio_sync(kio_addr_t addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -583,7 +485,7 @@ static void mdio_sync(ioaddr_t addr)
     }
 }
 
-static int mdio_read(ioaddr_t addr, int phy_id, int loc)
+static int mdio_read(kio_addr_t addr, int phy_id, int loc)
 {
     u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
@@ -602,7 +504,7 @@ static int mdio_read(ioaddr_t addr, int phy_id, int loc)
     return (retval>>1) & 0xffff;
 }
 
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
+static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
 {
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
@@ -624,16 +526,16 @@ static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
 static int axnet_open(struct net_device *dev)
 {
     axnet_dev_t *info = PRIV(dev);
-    dev_link_t *link = &info->link;
+    struct pcmcia_device *link = info->p_dev;
     
     DEBUG(2, "axnet_open('%s')\n", dev->name);
 
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
        return -ENODEV;
 
     link->open++;
 
-    request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
+    request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
 
     info->link_status = 0x00;
     init_timer(&info->watchdog);
@@ -650,7 +552,7 @@ static int axnet_open(struct net_device *dev)
 static int axnet_close(struct net_device *dev)
 {
     axnet_dev_t *info = PRIV(dev);
-    dev_link_t *link = &info->link;
+    struct pcmcia_device *link = info->p_dev;
 
     DEBUG(2, "axnet_close('%s')\n", dev->name);
 
@@ -673,7 +575,7 @@ static int axnet_close(struct net_device *dev)
 
 static void axnet_reset_8390(struct net_device *dev)
 {
-    ioaddr_t nic_base = dev->base_addr;
+    kio_addr_t nic_base = dev->base_addr;
     int i;
 
     ei_status.txing = ei_status.dmaing = 0;
@@ -708,8 +610,8 @@ static void ei_watchdog(u_long arg)
 {
     struct net_device *dev = (struct net_device *)(arg);
     axnet_dev_t *info = PRIV(dev);
-    ioaddr_t nic_base = dev->base_addr;
-    ioaddr_t mii_addr = nic_base + AXNET_MII_EEP;
+    kio_addr_t nic_base = dev->base_addr;
+    kio_addr_t mii_addr = nic_base + AXNET_MII_EEP;
     u_short link;
 
     if (!netif_device_present(dev)) goto reschedule;
@@ -778,8 +680,8 @@ static struct ethtool_ops netdev_ethtool_ops = {
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
     axnet_dev_t *info = PRIV(dev);
-    u16 *data = (u16 *)&rq->ifr_data;
-    ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
+    u16 *data = (u16 *)&rq->ifr_ifru;
+    kio_addr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
     switch (cmd) {
     case SIOCGMIIPHY:
        data[0] = info->phy_id;
@@ -801,7 +703,7 @@ static void get_8390_hdr(struct net_device *dev,
                         struct e8390_pkt_hdr *hdr,
                         int ring_page)
 {
-    ioaddr_t nic_base = dev->base_addr;
+    kio_addr_t nic_base = dev->base_addr;
 
     outb_p(0, nic_base + EN0_RSARLO);          /* On page boundary */
     outb_p(ring_page, nic_base + EN0_RSARHI);
@@ -819,7 +721,7 @@ static void get_8390_hdr(struct net_device *dev,
 static void block_input(struct net_device *dev, int count,
                        struct sk_buff *skb, int ring_offset)
 {
-    ioaddr_t nic_base = dev->base_addr;
+    kio_addr_t nic_base = dev->base_addr;
     int xfer_count = count;
     char *buf = skb->data;
 
@@ -842,7 +744,7 @@ static void block_input(struct net_device *dev, int count,
 static void block_output(struct net_device *dev, int count,
                         const u_char *buf, const int start_page)
 {
-    ioaddr_t nic_base = dev->base_addr;
+    kio_addr_t nic_base = dev->base_addr;
 
 #ifdef PCMCIA_DEBUG
     if (ei_debug > 4)
@@ -861,13 +763,45 @@ static void block_output(struct net_device *dev, int count,
     outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
 }
 
+static struct pcmcia_device_id axnet_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
+       PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
+       PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
+       PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
+       PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
+       PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1),
+       PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc),
+       PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
+       PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
+       PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6,  0xab9be5ef),
+       /* this is not specific enough */
+       /* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
+
 static struct pcmcia_driver axnet_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = "axnet_cs",
        },
-       .attach         = axnet_attach,
-       .detach         = axnet_detach,
+       .probe          = axnet_probe,
+       .remove         = axnet_detach,
+       .id_table       = axnet_ids,
+       .suspend        = axnet_suspend,
+       .resume         = axnet_resume,
 };
 
 static int __init init_axnet_cs(void)
@@ -878,8 +812,6 @@ static int __init init_axnet_cs(void)
 static void __exit exit_axnet_cs(void)
 {
        pcmcia_unregister_driver(&axnet_cs_driver);
-       while (dev_list != NULL)
-               axnet_detach(dev_list);
 }
 
 module_init(init_axnet_cs);
@@ -937,8 +869,7 @@ module_exit(exit_axnet_cs);
 static const char *version_8390 =
     "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n";
 
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/irq.h>
 #include <linux/fcntl.h>
 #include <linux/in.h>
@@ -1180,7 +1111,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        else if (ei_local->tx2 == 0) 
        {
-               output_page = ei_local->tx_start_page + TX_1X_PAGES;
+               output_page = ei_local->tx_start_page + TX_PAGES/2;
                ei_local->tx2 = send_length;
                if (ei_debug  &&  ei_local->tx1 > 0)
                        printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
@@ -1629,7 +1560,7 @@ static void ei_receive(struct net_device *dev)
 
 static void ei_rx_overrun(struct net_device *dev)
 {
-       axnet_dev_t *info = (axnet_dev_t *)dev;
+       axnet_dev_t *info = PRIV(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);
@@ -1716,17 +1647,56 @@ 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. May be called
- *     from a BH in 2.1.x. Must be called with lock held. 
+ *     Set or clear the multicast filter for this adaptor.
+ *     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);
@@ -1734,6 +1704,8 @@ 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);
 }
 
 /*
@@ -1828,12 +1800,6 @@ 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);