fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / pcmcia / 3c589_cs.c
index 2e0135d..461e827 100644 (file)
@@ -38,8 +38,9 @@
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -50,7 +51,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 
 /* To minimize the size of the driver source I only define operating
    constants if they are used several times.  You'll need the manual
@@ -105,7 +105,7 @@ enum RxFilter {
 #define TX_TIMEOUT     ((400*HZ)/1000)
 
 struct el3_private {
-    dev_link_t         link;
+       struct pcmcia_device    *p_dev;
     dev_node_t                 node;
     struct net_device_stats stats;
     /* For transceiver monitoring */
@@ -116,7 +116,7 @@ struct el3_private {
     spinlock_t         lock;
 };
 
-static char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
+static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
 
 /*====================================================================*/
 
@@ -126,16 +126,11 @@ MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver");
 MODULE_LICENSE("GPL");
 
-#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
 
 /* Special hook for setting if_port when module is loaded */
 INT_MODULE_PARM(if_port, 0);
 
-/* 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
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
@@ -147,32 +142,25 @@ DRV_NAME ".c " DRV_VERSION " 2001/10/13 00:08:50 (David Hinds)";
 
 /*====================================================================*/
 
-static void tc589_config(dev_link_t *link);
-static void tc589_release(dev_link_t *link);
-static int tc589_event(event_t event, int priority,
-                      event_callback_args_t *args);
+static int tc589_config(struct pcmcia_device *link);
+static void tc589_release(struct pcmcia_device *link);
 
-static u16 read_eeprom(ioaddr_t ioaddr, int index);
+static u16 read_eeprom(kio_addr_t ioaddr, int index);
 static void tc589_reset(struct net_device *dev);
 static void media_check(unsigned long arg);
 static int el3_config(struct net_device *dev, struct ifmap *map);
 static int el3_open(struct net_device *dev);
 static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t el3_interrupt(int irq, void *dev_id);
 static void update_stats(struct net_device *dev);
 static struct net_device_stats *el3_get_stats(struct net_device *dev);
 static int el3_rx(struct net_device *dev);
 static int el3_close(struct net_device *dev);
 static void el3_tx_timeout(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
-
-static dev_info_t dev_info = "3c589_cs";
+static const struct ethtool_ops netdev_ethtool_ops;
 
-static dev_link_t *tc589_attach(void);
-static void tc589_detach(dev_link_t *);
-
-static dev_link_t *dev_list;
+static void tc589_detach(struct pcmcia_device *p_dev);
 
 /*======================================================================
 
@@ -182,42 +170,32 @@ static dev_link_t *dev_list;
 
 ======================================================================*/
 
-static dev_link_t *tc589_attach(void)
+static int tc589_probe(struct pcmcia_device *link)
 {
     struct el3_private *lp;
-    client_reg_t client_reg;
-    dev_link_t *link;
     struct net_device *dev;
-    int i, ret;
 
     DEBUG(0, "3c589_attach()\n");
-    
+
     /* Create new ethernet device */
     dev = alloc_etherdev(sizeof(struct el3_private));
     if (!dev)
-        return NULL;
+        return -ENOMEM;
     lp = netdev_priv(dev);
-    link = &lp->link;
     link->priv = dev;
+    lp->p_dev = link;
 
     spin_lock_init(&lp->lock);
     link->io.NumPorts1 = 16;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-    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->irq.Handler = &el3_interrupt;
     link->irq.Instance = dev;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.ConfigIndex = 1;
-    link->conf.Present = PRESENT_OPTION;
-    
+
     /* The EL3-specific entries in the device structure. */
     SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &el3_start_xmit;
@@ -232,26 +210,7 @@ static dev_link_t *tc589_attach(void)
 #endif
     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 = &tc589_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = pcmcia_register_client(&link->handle, &client_reg);
-    if (ret != 0) {
-       cs_error(link->handle, RegisterClient, ret);
-       tc589_detach(link);
-       return NULL;
-    }
-    
-    return link;
+    return tc589_config(link);
 } /* tc589_attach */
 
 /*======================================================================
@@ -263,30 +222,17 @@ static dev_link_t *tc589_attach(void)
 
 ======================================================================*/
 
-static void tc589_detach(dev_link_t *link)
+static void tc589_detach(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    dev_link_t **linkp;
-    
+
     DEBUG(0, "3c589_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->dev)
+    if (link->dev_node)
        unregister_netdev(dev);
 
-    if (link->state & DEV_CONFIG)
-       tc589_release(link);
-    
-    if (link->handle)
-       pcmcia_deregister_client(link->handle);
-    
-    /* Unlink device structure, free bits */
-    *linkp = link->next;
+    tc589_release(link);
+
     free_netdev(dev);
 } /* tc589_detach */
 
@@ -301,60 +247,45 @@ static void tc589_detach(dev_link_t *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void tc589_config(dev_link_t *link)
+static int tc589_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     struct el3_private *lp = netdev_priv(dev);
     tuple_t tuple;
-    cisparse_t parse;
     u16 buf[32], *phys_addr;
     int last_fn, last_ret, i, j, multi = 0, fifo;
-    ioaddr_t ioaddr;
+    kio_addr_t ioaddr;
     char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
     
     DEBUG(0, "3c589_config(0x%p)\n", link);
 
     phys_addr = (u16 *)dev->dev_addr;
     tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
-    
-    /* Is this a 3c562? */
-    tuple.DesiredTuple = CISTPL_MANFID;
     tuple.Attributes = TUPLE_RETURN_COMMON;
-    if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) &&
-       (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) {
-       if (le16_to_cpu(buf[0]) != MANFID_3COM)
+
+    /* Is this a 3c562? */
+    if (link->manf_id != MANFID_3COM)
            printk(KERN_INFO "3c589_cs: hmmm, is this really a "
                   "3Com card??\n");
-       multi = (le16_to_cpu(buf[1]) == PRODID_3COM_3C562);
-    }
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
+    multi = (link->card_id == PRODID_3COM_3C562);
 
     /* For the 3c562, the base address must be xx00-xx7f */
     link->io.IOAddrLines = 16;
     for (i = j = 0; j < 0x400; j += 0x10) {
        if (multi && (j & 0x80)) continue;
        link->io.BasePort1 = j ^ 0x300;
-       i = pcmcia_request_io(link->handle, &link->io);
+       i = pcmcia_request_io(link, &link->io);
        if (i == CS_SUCCESS) break;
     }
     if (i != CS_SUCCESS) {
-       cs_error(link->handle, RequestIO, i);
+       cs_error(link, RequestIO, i);
        goto failed;
     }
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
        
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
@@ -364,8 +295,8 @@ static void tc589_config(dev_link_t *link)
     /* The 3c589 has an extra EEPROM for configuration info, including
        the hardware address.  The 3c562 puts the address in the CIS. */
     tuple.DesiredTuple = 0x88;
-    if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) {
-       pcmcia_get_tuple_data(handle, &tuple);
+    if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+       pcmcia_get_tuple_data(link, &tuple);
        for (i = 0; i < 3; i++)
            phys_addr[i] = htons(buf[i]);
     } else {
@@ -389,12 +320,12 @@ static void tc589_config(dev_link_t *link)
     else
        printk(KERN_ERR "3c589_cs: invalid if_port requested\n");
     
-    link->dev = &lp->node;
-    link->state &= ~DEV_CONFIG_PENDING;
+    link->dev_node = &lp->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     if (register_netdev(dev) != 0) {
        printk(KERN_ERR "3c589_cs: register_netdev() failed\n");
-       link->dev = NULL;
+       link->dev_node = NULL;
        goto failed;
     }
 
@@ -408,14 +339,13 @@ static void tc589_config(dev_link_t *link)
     printk(KERN_INFO "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
           (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
           if_names[dev->if_port]);
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     tc589_release(link);
-    return;
-    
+    return -ENODEV;
 } /* tc589_config */
 
 /*======================================================================
@@ -426,69 +356,32 @@ failed:
     
 ======================================================================*/
 
-static void tc589_release(dev_link_t *link)
+static void tc589_release(struct pcmcia_device *link)
 {
-    DEBUG(0, "3c589_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 tc589_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);
 
-static int tc589_event(event_t event, int priority,
-                      event_callback_args_t *args)
+       return 0;
+}
+
+static int tc589_resume(struct pcmcia_device *link)
 {
-    dev_link_t *link = args->client_data;
-    struct net_device *dev = link->priv;
-    
-    DEBUG(1, "3c589_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);
-       break;
-    case CS_EVENT_CARD_INSERTION:
-       link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-       tc589_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) {
+       struct net_device *dev = link->priv;
+
+       if (link->open) {
                tc589_reset(dev);
                netif_device_attach(dev);
-           }
        }
-       break;
-    }
-    return 0;
-} /* tc589_event */
+
+       return 0;
+}
 
 /*====================================================================*/
 
@@ -510,7 +403,7 @@ static void tc589_wait_for_completion(struct net_device *dev, int cmd)
   Read a word from the EEPROM using the regular EEPROM access register.
   Assume that we are in register window zero.
 */
-static u16 read_eeprom(ioaddr_t ioaddr, int index)
+static u16 read_eeprom(kio_addr_t ioaddr, int index)
 {
     int i;
     outw(EEPROM_READ + index, ioaddr + 10);
@@ -528,7 +421,7 @@ static u16 read_eeprom(ioaddr_t ioaddr, int index)
 static void tc589_set_xcvr(struct net_device *dev, int if_port)
 {
     struct el3_private *lp = netdev_priv(dev);
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     
     EL3WINDOW(0);
     switch (if_port) {
@@ -550,7 +443,7 @@ static void tc589_set_xcvr(struct net_device *dev, int if_port)
 
 static void dump_status(struct net_device *dev)
 {
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     EL3WINDOW(1);
     printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
           "%02x  tx free %04x\n", inw(ioaddr+EL3_STATUS),
@@ -566,7 +459,7 @@ static void dump_status(struct net_device *dev)
 /* Reset and restore all of the 3c589 registers. */
 static void tc589_reset(struct net_device *dev)
 {
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     int i;
     
     EL3WINDOW(0);
@@ -625,7 +518,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
 }
 #endif /* PCMCIA_DEBUG */
 
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
        .get_drvinfo            = netdev_get_drvinfo,
 #ifdef PCMCIA_DEBUG
        .get_msglevel           = netdev_get_msglevel,
@@ -650,9 +543,9 @@ static int el3_config(struct net_device *dev, struct ifmap *map)
 static int el3_open(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
     
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
        return -ENODEV;
 
     link->open++;
@@ -674,7 +567,7 @@ static int el3_open(struct net_device *dev)
 static void el3_tx_timeout(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     
     printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name);
     dump_status(dev);
@@ -689,7 +582,7 @@ static void el3_tx_timeout(struct net_device *dev)
 static void pop_tx_status(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     int i;
     
     /* Clear the Tx status stack. */
@@ -711,13 +604,16 @@ static void pop_tx_status(struct net_device *dev)
 
 static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     struct el3_private *priv = netdev_priv(dev);
+    unsigned long flags;
 
     DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
          "status %4.4x.\n", dev->name, (long)skb->len,
          inw(ioaddr + EL3_STATUS));
 
+    spin_lock_irqsave(&priv->lock, flags);    
+
     priv->stats.tx_bytes += skb->len;
 
     /* Put out the doubleword header... */
@@ -735,16 +631,18 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
     dev_kfree_skb(skb);
     pop_tx_status(dev);
+    spin_unlock_irqrestore(&priv->lock, flags);    
     
     return 0;
 }
 
 /* The EL3 interrupt handler. */
-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t el3_interrupt(int irq, void *dev_id)
 {
     struct net_device *dev = (struct net_device *) dev_id;
     struct el3_private *lp = netdev_priv(dev);
-    ioaddr_t ioaddr, status;
+    kio_addr_t ioaddr;
+    __u16 status;
     int i = 0, handled = 1;
     
     if (!netif_device_present(dev))
@@ -829,20 +727,19 @@ static void media_check(unsigned long arg)
 {
     struct net_device *dev = (struct net_device *)(arg);
     struct el3_private *lp = netdev_priv(dev);
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     u16 media, errs;
     unsigned long flags;
 
     if (!netif_device_present(dev)) goto reschedule;
 
-    EL3WINDOW(1);
     /* Check for pending interrupt with expired latency timer: with
        this, we can limp along even if the interrupt is blocked */
     if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
        (inb(ioaddr + EL3_TIMER) == 0xff)) {
        if (!lp->fast_poll)
            printk(KERN_WARNING "%s: interrupt(s) dropped!\n", dev->name);
-       el3_interrupt(dev->irq, lp, NULL);
+       el3_interrupt(dev->irq, dev);
        lp->fast_poll = HZ;
     }
     if (lp->fast_poll) {
@@ -859,7 +756,7 @@ static void media_check(unsigned long arg)
     media = inw(ioaddr+WN4_MEDIA) & 0xc810;
 
     /* Ignore collisions unless we've had no irq's recently */
-    if (jiffies - lp->last_irq < HZ) {
+    if (time_before(jiffies, lp->last_irq + HZ)) {
        media &= ~0x0010;
     } else {
        /* Try harder to detect carrier errors */
@@ -910,9 +807,9 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
     unsigned long flags;
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
 
-    if (DEV_OK(link)) {
+    if (pcmcia_dev_present(link)) {
        spin_lock_irqsave(&lp->lock, flags);
        update_stats(dev);
        spin_unlock_irqrestore(&lp->lock, flags);
@@ -931,7 +828,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
 static void update_stats(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
 
     DEBUG(2, "%s: updating the statistics.\n", dev->name);
     /* Turn off statistics updates while reading. */
@@ -958,7 +855,7 @@ static void update_stats(struct net_device *dev)
 static int el3_rx(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    ioaddr_t ioaddr = dev->base_addr;
+    kio_addr_t ioaddr = dev->base_addr;
     int worklimit = 32;
     short rx_status;
     
@@ -1012,11 +909,11 @@ static int el3_rx(struct net_device *dev)
 static void set_multicast_list(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
-    ioaddr_t ioaddr = dev->base_addr;
+    struct pcmcia_device *link = lp->p_dev;
+    kio_addr_t ioaddr = dev->base_addr;
     u16 opts = SetRxFilter | RxStation | RxBroadcast;
 
-    if (!(DEV_OK(link))) return;
+    if (!pcmcia_dev_present(link)) return;
     if (dev->flags & IFF_PROMISC)
        opts |= RxMulticast | RxProm;
     else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
@@ -1027,12 +924,12 @@ static void set_multicast_list(struct net_device *dev)
 static int el3_close(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
-    ioaddr_t ioaddr = dev->base_addr;
+    struct pcmcia_device *link = lp->p_dev;
+    kio_addr_t ioaddr = dev->base_addr;
     
     DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
 
-    if (DEV_OK(link)) {
+    if (pcmcia_dev_present(link)) {
        /* Turn off statistics ASAP.  We update lp->stats below. */
        outw(StatsDisable, ioaddr + EL3_CMD);
        
@@ -1066,13 +963,27 @@ static int el3_close(struct net_device *dev)
     return 0;
 }
 
+static struct pcmcia_device_id tc589_ids[] = {
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
+       PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
+       PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "3CXEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "3CXEM556.cis"),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
+
 static struct pcmcia_driver tc589_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = "3c589_cs",
        },
-       .attach         = tc589_attach,
-       .detach         = tc589_detach,
+       .probe          = tc589_probe,
+       .remove         = tc589_detach,
+        .id_table       = tc589_ids,
+       .suspend        = tc589_suspend,
+       .resume         = tc589_resume,
 };
 
 static int __init init_tc589(void)
@@ -1083,8 +994,6 @@ static int __init init_tc589(void)
 static void __exit exit_tc589(void)
 {
        pcmcia_unregister_driver(&tc589_driver);
-       while (dev_list != NULL)
-               tc589_detach(dev_list);
 }
 
 module_init(init_tc589);