Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
[safe/jmp/linux-2.6] / drivers / net / pcmcia / smc91c92_cs.c
index 85a1521..7da544c 100644 (file)
 #include <linux/ioport.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/jiffies.h>
+#include <linux/firmware.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
+#include <pcmcia/ss.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-/* Ositech Seven of Diamonds firmware */
-#include "ositech.h"
-
 /*====================================================================*/
 
-static char *if_names[] = { "auto", "10baseT", "10base2"};
+static const char *if_names[] = { "auto", "10baseT", "10base2"};
+
+/* Firmware name */
+#define FIRMWARE_NAME          "ositech/Xilinx7OD.bin"
 
 /* Module parameters */
 
 MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE_NAME);
 
 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
 
@@ -76,17 +79,9 @@ MODULE_LICENSE("GPL");
 */
 INT_MODULE_PARM(if_port, 0);
 
-#ifdef PCMCIA_DEBUG
-INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
-static const char *version =
-"smc91c92_cs.c 0.09 1996/8/4 Donald Becker, becker@scyld.com.\n";
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-#else
-#define DEBUG(n, args...)
-#endif
 
 #define DRV_NAME       "smc91c92_cs"
-#define DRV_VERSION    "1.122"
+#define DRV_VERSION    "1.123"
 
 /*====================================================================*/
 
@@ -102,16 +97,12 @@ static const char *version =
    currently have room for another Tx packet. */
 #define MEMORY_WAIT_TIME               8
 
-static dev_info_t dev_info = "smc91c92_cs";
-
-static dev_link_t *dev_list;
-
 struct smc_private {
-    dev_link_t                 link;
+       struct pcmcia_device    *p_dev;
     spinlock_t                 lock;
     u_short                    manfid;
     u_short                    cardid;
-    struct net_device_stats    stats;
+
     dev_node_t                 node;
     struct sk_buff             *saved_skb;
     int                                packets_waiting;
@@ -275,31 +266,41 @@ enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
 
 /*====================================================================*/
 
-static dev_link_t *smc91c92_attach(void);
-static void smc91c92_detach(dev_link_t *);
-static void smc91c92_config(dev_link_t *link);
-static void smc91c92_release(dev_link_t *link);
-static int smc91c92_event(event_t event, int priority,
-                         event_callback_args_t *args);
+static void smc91c92_detach(struct pcmcia_device *p_dev);
+static int smc91c92_config(struct pcmcia_device *link);
+static void smc91c92_release(struct pcmcia_device *link);
 
 static int smc_open(struct net_device *dev);
 static int smc_close(struct net_device *dev);
 static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void smc_tx_timeout(struct net_device *dev);
-static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
+                                       struct net_device *dev);
+static irqreturn_t smc_interrupt(int irq, void *dev_id);
 static void smc_rx(struct net_device *dev);
-static struct net_device_stats *smc_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static int s9k_config(struct net_device *dev, struct ifmap *map);
 static void smc_set_xcvr(struct net_device *dev, int if_port);
 static void smc_reset(struct net_device *dev);
 static void media_check(u_long arg);
-static void mdio_sync(kio_addr_t addr);
+static void mdio_sync(unsigned int addr);
 static int mdio_read(struct net_device *dev, int phy_id, int loc);
 static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
 static int smc_link_ok(struct net_device *dev);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
+
+static const struct net_device_ops smc_netdev_ops = {
+       .ndo_open               = smc_open,
+       .ndo_stop               = smc_close,
+       .ndo_start_xmit         = smc_start_xmit,
+       .ndo_tx_timeout         = smc_tx_timeout,
+       .ndo_set_config         = s9k_config,
+       .ndo_set_multicast_list = set_rx_mode,
+       .ndo_do_ioctl           = &smc_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
 /*======================================================================
 
@@ -309,50 +310,34 @@ static struct ethtool_ops ethtool_ops;
 
 ======================================================================*/
 
-static dev_link_t *smc91c92_attach(void)
+static int smc91c92_probe(struct pcmcia_device *link)
 {
-    client_reg_t client_reg;
     struct smc_private *smc;
-    dev_link_t *link;
     struct net_device *dev;
-    int ret;
 
-    DEBUG(0, "smc91c92_attach()\n");
+    dev_dbg(&link->dev, "smc91c92_attach()\n");
 
     /* Create new ethernet device */
     dev = alloc_etherdev(sizeof(struct smc_private));
     if (!dev)
-       return NULL;
+       return -ENOMEM;
     smc = netdev_priv(dev);
-    link = &smc->link;
+    smc->p_dev = link;
     link->priv = dev;
 
     spin_lock_init(&smc->lock);
     link->io.NumPorts1 = 16;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
     link->io.IOAddrLines = 4;
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
     link->irq.Handler = &smc_interrupt;
-    link->irq.Instance = dev;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
     /* The SMC91c92-specific entries in the device structure. */
-    SET_MODULE_OWNER(dev);
-    dev->hard_start_xmit = &smc_start_xmit;
-    dev->get_stats = &smc_get_stats;
-    dev->set_config = &s9k_config;
-    dev->set_multicast_list = &set_rx_mode;
-    dev->open = &smc_open;
-    dev->stop = &smc_close;
-    dev->do_ioctl = &smc_ioctl;
+    dev->netdev_ops = &smc_netdev_ops;
     SET_ETHTOOL_OPS(dev, &ethtool_ops);
-#ifdef HAVE_TX_TIMEOUT
-    dev->tx_timeout = smc_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
-#endif
 
     smc->mii_if.dev = dev;
     smc->mii_if.mdio_read = mdio_read;
@@ -360,24 +345,7 @@ static dev_link_t *smc91c92_attach(void)
     smc->mii_if.phy_id_mask = 0x1f;
     smc->mii_if.reg_num_mask = 0x1f;
 
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-    client_reg.dev_info = &dev_info;
-    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 = &smc91c92_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);
-       smc91c92_detach(link);
-       return NULL;
-    }
-
-    return link;
+    return smc91c92_config(link);
 } /* smc91c92_attach */
 
 /*======================================================================
@@ -389,30 +357,17 @@ static dev_link_t *smc91c92_attach(void)
 
 ======================================================================*/
 
-static void smc91c92_detach(dev_link_t *link)
+static void smc91c92_detach(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    dev_link_t **linkp;
-
-    DEBUG(0, "smc91c92_detach(0x%p)\n", link);
 
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-       if (*linkp == link) break;
-    if (*linkp == NULL)
-       return;
+    dev_dbg(&link->dev, "smc91c92_detach\n");
 
-    if (link->dev)
+    if (link->dev_node)
        unregister_netdev(dev);
 
-    if (link->state & DEV_CONFIG)
-       smc91c92_release(link);
-
-    if (link->handle)
-       pcmcia_deregister_client(link->handle);
+    smc91c92_release(link);
 
-    /* Unlink device structure, free bits */
-    *linkp = link->next;
     free_netdev(dev);
 } /* smc91c92_detach */
 
@@ -437,31 +392,7 @@ static int cvt_ascii_address(struct net_device *dev, char *s)
     return 0;
 }
 
-/*====================================================================*/
-
-static int first_tuple(client_handle_t handle, tuple_t *tuple,
-               cisparse_t *parse)
-{
-       int i;
-
-       if ((i = pcmcia_get_first_tuple(handle, tuple)) != CS_SUCCESS ||
-                       (i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS)
-               return i;
-       return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int next_tuple(client_handle_t handle, tuple_t *tuple,
-               cisparse_t *parse)
-{
-       int i;
-
-       if ((i = pcmcia_get_next_tuple(handle, tuple)) != CS_SUCCESS ||
-                       (i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS)
-               return i;
-       return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-/*======================================================================
+/*====================================================================
 
     Configuration stuff for Megahertz cards
 
@@ -472,7 +403,7 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple,
 
 ======================================================================*/
 
-static int mhz_3288_power(dev_link_t *link)
+static int mhz_3288_power(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
@@ -494,109 +425,117 @@ static int mhz_3288_power(dev_link_t *link)
     return 0;
 }
 
-static int mhz_mfc_config(dev_link_t *link)
+static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
+                               cistpl_cftable_entry_t *cf,
+                               cistpl_cftable_entry_t *dflt,
+                               unsigned int vcc,
+                               void *priv_data)
+{
+       int k;
+       p_dev->io.BasePort2 = cf->io.win[0].base;
+       for (k = 0; k < 0x400; k += 0x10) {
+               if (k & 0x80)
+                       continue;
+               p_dev->io.BasePort1 = k ^ 0x300;
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -ENODEV;
+}
+
+static int mhz_mfc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
-    tuple_t tuple;
-    cisparse_t parse;
-    u_char buf[255];
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     win_req_t req;
     memreq_t mem;
-    int i, k;
+    int i;
 
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
-    link->irq.Attributes =
-       IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
     link->io.IOAddrLines = 16;
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
 
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
-    i = first_tuple(link->handle, &tuple, &parse);
     /* The Megahertz combo cards have modem-like CIS entries, so
        we have to explicitly try a bunch of port combinations. */
-    while (i == CS_SUCCESS) {
-       link->conf.ConfigIndex = cf->index;
-       link->io.BasePort2 = cf->io.win[0].base;
-       for (k = 0; k < 0x400; k += 0x10) {
-           if (k & 0x80) continue;
-           link->io.BasePort1 = k ^ 0x300;
-           i = pcmcia_request_io(link->handle, &link->io);
-           if (i == CS_SUCCESS) break;
-       }
-       if (i == CS_SUCCESS) break;
-       i = next_tuple(link->handle, &tuple, &parse);
-    }
-    if (i != CS_SUCCESS)
-       return i;
+    if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
+           return -ENODEV;
+
     dev->base_addr = link->io.BasePort1;
 
     /* Allocate a memory window, for accessing the ISR */
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
     req.Base = req.Size = 0;
     req.AccessSpeed = 0;
-    i = pcmcia_request_window(&link->handle, &req, &link->win);
-    if (i != CS_SUCCESS)
-       return i;
+    i = pcmcia_request_window(link, &req, &link->win);
+    if (i != 0)
+           return -ENODEV;
+
     smc->base = ioremap(req.Base, req.Size);
     mem.CardOffset = mem.Page = 0;
     if (smc->manfid == MANFID_MOTOROLA)
        mem.CardOffset = link->conf.ConfigBase;
-    i = pcmcia_map_mem_page(link->win, &mem);
+    i = pcmcia_map_mem_page(link, link->win, &mem);
 
-    if ((i == CS_SUCCESS)
-       && (smc->manfid == MANFID_MEGAHERTZ)
-       && (smc->cardid == PRODID_MEGAHERTZ_EM3288))
-       mhz_3288_power(link);
+    if ((i == 0) &&
+       (smc->manfid == MANFID_MEGAHERTZ) &&
+       (smc->cardid == PRODID_MEGAHERTZ_EM3288))
+           mhz_3288_power(link);
 
-    return i;
+    return 0;
 }
 
-static int mhz_setup(dev_link_t *link)
+static int pcmcia_get_versmac(struct pcmcia_device *p_dev,
+                             tuple_t *tuple,
+                             void *priv)
 {
-    client_handle_t handle = link->handle;
-    struct net_device *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    u_char buf[255], *station_addr;
+       struct net_device *dev = priv;
+       cisparse_t parse;
+       u8 *buf;
+
+       if (pcmcia_parse_tuple(tuple, &parse))
+               return -EINVAL;
 
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
+       buf = parse.version_1.str + parse.version_1.ofs[3];
+
+       if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0))
+               return 0;
+
+       return -EINVAL;
+};
+
+static int mhz_setup(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    size_t len;
+    u8 *buf;
+    int rc;
 
     /* Read the station address from the CIS.  It is stored as the last
        (fourth) string in the Version 1 Version/ID tuple. */
-    tuple.DesiredTuple = CISTPL_VERS_1;
-    if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
-       return -1;
+    if ((link->prod_id[3]) &&
+       (cvt_ascii_address(dev, link->prod_id[3]) == 0))
+           return 0;
+
+    /* Workarounds for broken cards start here. */
     /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
-    if (next_tuple(handle, &tuple, &parse) != CS_SUCCESS)
-       first_tuple(handle, &tuple, &parse);
-    if (parse.version_1.ns > 3) {
-       station_addr = parse.version_1.str + parse.version_1.ofs[3];
-       if (cvt_ascii_address(dev, station_addr) == 0)
+    if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev))
            return 0;
-    }
 
     /* Another possibility: for the EM3288, in a special tuple */
-    tuple.DesiredTuple = 0x81;
-    if (pcmcia_get_first_tuple(handle, &tuple) != CS_SUCCESS)
-       return -1;
-    if (pcmcia_get_tuple_data(handle, &tuple) != CS_SUCCESS)
-       return -1;
-    buf[12] = '\0';
-    if (cvt_ascii_address(dev, buf) == 0)
-       return 0;
+    rc = -1;
+    len = pcmcia_get_tuple(link, 0x81, &buf);
+    if (buf && len >= 13) {
+           buf[12] = '\0';
+           if (cvt_ascii_address(dev, buf) == 0)
+                   rc = 0;
+    }
+    kfree(buf);
 
-    return -1;
-}
+    return rc;
+};
 
 /*======================================================================
 
@@ -607,12 +546,12 @@ static int mhz_setup(dev_link_t *link)
 
 ======================================================================*/
 
-static void mot_config(dev_link_t *link)
+static void mot_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
-    kio_addr_t iouart = link->io.BasePort2;
+    unsigned int ioaddr = dev->base_addr;
+    unsigned int iouart = link->io.BasePort2;
 
     /* Set UART base address and force map with COR bit 1 */
     writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
@@ -628,10 +567,10 @@ static void mot_config(dev_link_t *link)
     mdelay(100);
 }
 
-static int mot_setup(dev_link_t *link)
+static int mot_setup(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int i, wait, loop;
     u_int addr;
 
@@ -662,90 +601,58 @@ static int mot_setup(dev_link_t *link)
 
 /*====================================================================*/
 
-static int smc_config(dev_link_t *link)
+static int smc_configcheck(struct pcmcia_device *p_dev,
+                          cistpl_cftable_entry_t *cf,
+                          cistpl_cftable_entry_t *dflt,
+                          unsigned int vcc,
+                          void *priv_data)
+{
+       p_dev->io.BasePort1 = cf->io.win[0].base;
+       p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+       return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
+static int smc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    u_char buf[255];
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     int i;
 
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
     link->io.NumPorts1 = 16;
-    i = first_tuple(link->handle, &tuple, &parse);
-    while (i != CS_NO_MORE_ITEMS) {
-       if (i == CS_SUCCESS) {
-           link->conf.ConfigIndex = cf->index;
-           link->io.BasePort1 = cf->io.win[0].base;
-           link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-           i = pcmcia_request_io(link->handle, &link->io);
-           if (i == CS_SUCCESS) break;
-       }
-       i = next_tuple(link->handle, &tuple, &parse);
-    }
-    if (i == CS_SUCCESS)
-       dev->base_addr = link->io.BasePort1;
+    i = pcmcia_loop_config(link, smc_configcheck, NULL);
+    if (!i)
+           dev->base_addr = link->io.BasePort1;
+
     return i;
 }
 
-static int smc_setup(dev_link_t *link)
+
+static int smc_setup(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    cistpl_lan_node_id_t *node_id;
-    u_char buf[255], *station_addr;
-    int i;
-
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
 
     /* Check for a LAN function extension tuple */
-    tuple.DesiredTuple = CISTPL_FUNCE;
-    i = first_tuple(handle, &tuple, &parse);
-    while (i == CS_SUCCESS) {
-       if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID)
-           break;
-       i = next_tuple(handle, &tuple, &parse);
-    }
-    if (i == CS_SUCCESS) {
-       node_id = (cistpl_lan_node_id_t *)parse.funce.data;
-       if (node_id->nb == 6) {
-           for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = node_id->id[i];
+    if (!pcmcia_get_mac_from_cis(link, dev))
            return 0;
-       }
-    }
-    /* Try the third string in the Version 1 Version/ID tuple. */
-    tuple.DesiredTuple = CISTPL_VERS_1;
-    if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
-       return -1;
-    station_addr = parse.version_1.str + parse.version_1.ofs[2];
-    if (cvt_ascii_address(dev, station_addr) == 0)
-       return 0;
 
+    /* Try the third string in the Version 1 Version/ID tuple. */
+    if (link->prod_id[2]) {
+           if (cvt_ascii_address(dev, link->prod_id[2]) == 0)
+                   return 0;
+    }
     return -1;
 }
 
 /*====================================================================*/
 
-static int osi_config(dev_link_t *link)
+static int osi_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    static kio_addr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+    static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
     int i, j;
 
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
-    link->irq.Attributes =
-       IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
     link->io.NumPorts1 = 64;
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
@@ -756,68 +663,131 @@ static int osi_config(dev_link_t *link)
 
     for (i = j = 0; j < 4; j++) {
        link->io.BasePort2 = com[j];
-       i = pcmcia_request_io(link->handle, &link->io);
-       if (i == CS_SUCCESS) break;
+       i = pcmcia_request_io(link, &link->io);
+       if (i == 0)
+               break;
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        /* Fallback: turn off hard decode */
        link->conf.ConfigIndex = 0x03;
        link->io.NumPorts2 = 0;
-       i = pcmcia_request_io(link->handle, &link->io);
+       i = pcmcia_request_io(link, &link->io);
     }
     dev->base_addr = link->io.BasePort1 + 0x10;
     return i;
 }
 
-static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
+static int osi_load_firmware(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
-    struct net_device *dev = link->priv;
-    tuple_t tuple;
-    u_char buf[255];
-    int i;
+       const struct firmware *fw;
+       int i, err;
+
+       err = request_firmware(&fw, FIRMWARE_NAME, &link->dev);
+       if (err) {
+               pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME);
+               return err;
+       }
 
-    tuple.Attributes = TUPLE_RETURN_COMMON;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
+       /* Download the Seven of Diamonds firmware */
+       for (i = 0; i < fw->size; i++) {
+           outb(fw->data[i], link->io.BasePort1 + 2);
+           udelay(50);
+       }
+       release_firmware(fw);
+       return err;
+}
+
+static int pcmcia_osi_mac(struct pcmcia_device *p_dev,
+                         tuple_t *tuple,
+                         void *priv)
+{
+       struct net_device *dev = priv;
+       int i;
+
+       if (tuple->TupleDataLen < 8)
+               return -EINVAL;
+       if (tuple->TupleData[0] != 0x04)
+               return -EINVAL;
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = tuple->TupleData[i+2];
+       return 0;
+};
+
+
+static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
+{
+    struct net_device *dev = link->priv;
+    int rc;
 
     /* Read the station address from tuple 0x90, subtuple 0x04 */
-    tuple.DesiredTuple = 0x90;
-    i = pcmcia_get_first_tuple(handle, &tuple);
-    while (i == CS_SUCCESS) {
-       i = pcmcia_get_tuple_data(handle, &tuple);
-       if ((i != CS_SUCCESS) || (buf[0] == 0x04))
-           break;
-       i = pcmcia_get_next_tuple(handle, &tuple);
-    }
-    if (i != CS_SUCCESS)
-       return -1;
-    for (i = 0; i < 6; i++)
-       dev->dev_addr[i] = buf[i+2];
+    if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev))
+           return -1;
 
     if (((manfid == MANFID_OSITECH) &&
         (cardid == PRODID_OSITECH_SEVEN)) ||
        ((manfid == MANFID_PSION) &&
         (cardid == PRODID_PSION_NET100))) {
-       /* Download the Seven of Diamonds firmware */
-       for (i = 0; i < sizeof(__Xilinx7OD); i++) {
-           outb(__Xilinx7OD[i], link->io.BasePort1+2);
-           udelay(50);
-       }
+       rc = osi_load_firmware(link);
+       if (rc)
+               return rc;
     } else if (manfid == MANFID_OSITECH) {
        /* Make sure both functions are powered up */
        set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR);
        /* Now, turn on the interrupt for both card functions */
        set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR);
-       DEBUG(2, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
+       dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
              inw(link->io.BasePort1 + OSITECH_AUI_PWR),
              inw(link->io.BasePort1 + OSITECH_RESET_ISR));
     }
-
     return 0;
 }
 
+static int smc91c92_suspend(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+
+       if (link->open)
+               netif_device_detach(dev);
+
+       return 0;
+}
+
+static int smc91c92_resume(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       struct smc_private *smc = netdev_priv(dev);
+       int i;
+
+       if ((smc->manfid == MANFID_MEGAHERTZ) &&
+           (smc->cardid == PRODID_MEGAHERTZ_EM3288))
+               mhz_3288_power(link);
+       if (smc->manfid == MANFID_MOTOROLA)
+               mot_config(link);
+       if ((smc->manfid == MANFID_OSITECH) &&
+           (smc->cardid != PRODID_OSITECH_SEVEN)) {
+               /* Power up the card and enable interrupts */
+               set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
+               set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
+       }
+       if (((smc->manfid == MANFID_OSITECH) &&
+            (smc->cardid == PRODID_OSITECH_SEVEN)) ||
+           ((smc->manfid == MANFID_PSION) &&
+            (smc->cardid == PRODID_PSION_NET100))) {
+               i = osi_load_firmware(link);
+               if (i) {
+                       pr_err("smc91c92_cs: Failed to load firmware\n");
+                       return i;
+               }
+       }
+       if (link->open) {
+               smc_reset(dev);
+               netif_device_attach(dev);
+       }
+
+       return 0;
+}
+
+
 /*======================================================================
 
     This verifies that the chip is some SMC91cXX variant, and returns
@@ -825,10 +795,10 @@ static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
 
 ======================================================================*/
 
-static int check_sig(dev_link_t *link)
+static int check_sig(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int width;
     u_short s;
 
@@ -858,15 +828,15 @@ static int check_sig(dev_link_t *link)
     }
 
     if (width) {
-       event_callback_args_t args;
-       printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
-       args.client_data = link;
-       smc91c92_event(CS_EVENT_RESET_PHYSICAL, 0, &args);
-       pcmcia_release_io(link->handle, &link->io);
-       link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-       pcmcia_request_io(link->handle, &link->io);
-       smc91c92_event(CS_EVENT_CARD_RESET, 0, &args);
-       return check_sig(link);
+           modconf_t mod = {
+                   .Attributes = CONF_IO_CHANGE_WIDTH,
+           };
+           printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
+
+           smc91c92_suspend(link);
+           pcmcia_modify_configuration(link, &mod);
+           smc91c92_resume(link);
+           return check_sig(link);
     }
     return -ENODEV;
 }
@@ -879,43 +849,19 @@ static int check_sig(dev_link_t *link)
 
 ======================================================================*/
 
-#define CS_EXIT_TEST(ret, svc, label) \
-if (ret != CS_SUCCESS) { cs_error(link->handle, svc, ret); goto label; }
-
-static void smc91c92_config(dev_link_t *link)
+static int smc91c92_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
-    tuple_t tuple;
-    cisparse_t parse;
-    u_short buf[32];
     char *name;
     int i, j, rev;
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     u_long mir;
 
-    DEBUG(0, "smc91c92_config(0x%p)\n", link);
-
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
+    dev_dbg(&link->dev, "smc91c92_config\n");
 
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    i = first_tuple(handle, &tuple, &parse);
-    CS_EXIT_TEST(i, ParseTuple, config_failed);
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
-
-    tuple.DesiredTuple = CISTPL_MANFID;
-    tuple.Attributes = TUPLE_RETURN_COMMON;
-    if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
-       smc->manfid = parse.manfid.manf;
-       smc->cardid = parse.manfid.card;
-    }
-
-    /* Configure card */
-    link->state |= DEV_CONFIG;
+    smc->manfid = link->manf_id;
+    smc->cardid = link->card_id;
 
     if ((smc->manfid == MANFID_OSITECH) &&
        (smc->cardid != PRODID_OSITECH_SEVEN)) {
@@ -928,12 +874,15 @@ static void smc91c92_config(dev_link_t *link)
     } else {
        i = smc_config(link);
     }
-    CS_EXIT_TEST(i, RequestIO, config_failed);
+    if (i)
+           goto config_failed;
 
-    i = pcmcia_request_irq(link->handle, &link->irq);
-    CS_EXIT_TEST(i, RequestIRQ, config_failed);
-    i = pcmcia_request_configuration(link->handle, &link->conf);
-    CS_EXIT_TEST(i, RequestConfiguration, config_failed);
+    i = pcmcia_request_irq(link, &link->irq);
+    if (i)
+           goto config_failed;
+    i = pcmcia_request_configuration(link, &link->conf);
+    if (i)
+           goto config_failed;
 
     if (smc->manfid == MANFID_MOTOROLA)
        mot_config(link);
@@ -962,7 +911,7 @@ static void smc91c92_config(dev_link_t *link)
 
     if (i != 0) {
        printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
-       goto config_undo;
+       goto config_failed;
     }
 
     smc->duplex = 0;
@@ -1011,23 +960,21 @@ static void smc91c92_config(dev_link_t *link)
        SMC_SELECT_BANK(0);
     }
 
-    link->dev = &smc->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &smc->node;
+    SET_NETDEV_DEV(dev, &link->dev);
 
     if (register_netdev(dev) != 0) {
        printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
-       link->dev = NULL;
+       link->dev_node = NULL;
        goto config_undo;
     }
 
     strcpy(smc->node.dev_name, dev->name);
 
     printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
-          "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
-          dev->irq);
-    for (i = 0; i < 6; i++)
-       printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+          "hw_addr %pM\n",
+          dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
+          dev->dev_addr);
 
     if (rev > 0) {
        if (mir & 0x3ff)
@@ -1040,21 +987,20 @@ static void smc91c92_config(dev_link_t *link)
 
     if (smc->cfg & CFG_MII_SELECT) {
        if (smc->mii_if.phy_id != -1) {
-           DEBUG(0, "  MII transceiver at index %d, status %x.\n",
+           dev_dbg(&link->dev, "  MII transceiver at index %d, status %x.\n",
                  smc->mii_if.phy_id, j);
        } else {
            printk(KERN_NOTICE "  No MII transceivers found!\n");
        }
     }
-
-    return;
+    return 0;
 
 config_undo:
     unregister_netdev(dev);
-config_failed:                 /* CS_EXIT_TEST() calls jump to here... */
+config_failed:
     smc91c92_release(link);
-    link->state &= ~DEV_CONFIG_PENDING;
-
+    free_netdev(dev);
+    return -ENODEV;
 } /* smc91c92_config */
 
 /*======================================================================
@@ -1065,99 +1011,16 @@ config_failed:                  /* CS_EXIT_TEST() calls jump to here... */
 
 ======================================================================*/
 
-static void smc91c92_release(dev_link_t *link)
+static void smc91c92_release(struct pcmcia_device *link)
 {
-
-    DEBUG(0, "smc91c92_release(0x%p)\n", link);
-
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    if (link->win) {
-       struct net_device *dev = link->priv;
-       struct smc_private *smc = netdev_priv(dev);
-       iounmap(smc->base);
-       pcmcia_release_window(link->win);
-    }
-
-    link->state &= ~DEV_CONFIG;
-}
-
-/*======================================================================
-
-    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.
-
-======================================================================*/
-
-static int smc91c92_event(event_t event, int priority,
-                         event_callback_args_t *args)
-{
-    dev_link_t *link = args->client_data;
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    int i;
-
-    DEBUG(1, "smc91c92_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;
-       smc91c92_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);
+       dev_dbg(&link->dev, "smc91c92_release\n");
+       if (link->win) {
+               struct net_device *dev = link->priv;
+               struct smc_private *smc = netdev_priv(dev);
+               iounmap(smc->base);
        }
-       break;
-    case CS_EVENT_PM_RESUME:
-       link->state &= ~DEV_SUSPEND;
-       /* Fall through... */
-    case CS_EVENT_CARD_RESET:
-       if (link->state & DEV_CONFIG) {
-           if ((smc->manfid == MANFID_MEGAHERTZ) &&
-               (smc->cardid == PRODID_MEGAHERTZ_EM3288))
-               mhz_3288_power(link);
-           pcmcia_request_configuration(link->handle, &link->conf);
-           if (smc->manfid == MANFID_MOTOROLA)
-               mot_config(link);
-           if ((smc->manfid == MANFID_OSITECH) &&
-               (smc->cardid != PRODID_OSITECH_SEVEN)) {
-               /* Power up the card and enable interrupts */
-               set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
-               set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
-           }
-           if (((smc->manfid == MANFID_OSITECH) &&
-               (smc->cardid == PRODID_OSITECH_SEVEN)) ||
-               ((smc->manfid == MANFID_PSION) &&
-               (smc->cardid == PRODID_PSION_NET100))) {
-               /* Download the Seven of Diamonds firmware */
-               for (i = 0; i < sizeof(__Xilinx7OD); i++) {
-                   outb(__Xilinx7OD[i], link->io.BasePort1+2);
-                   udelay(50);
-               }
-           }
-           if (link->open) {
-               smc_reset(dev);
-               netif_device_attach(dev);
-           }
-       }
-       break;
-    }
-    return 0;
-} /* smc91c92_event */
+       pcmcia_disable_device(link);
+}
 
 /*======================================================================
 
@@ -1171,7 +1034,7 @@ static int smc91c92_event(event_t event, int priority,
 #define MDIO_DATA_WRITE1       (MDIO_DIR_WRITE | MDIO_DATA_OUT)
 #define MDIO_DATA_READ         0x02
 
-static void mdio_sync(kio_addr_t addr)
+static void mdio_sync(unsigned int addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -1182,7 +1045,7 @@ static void mdio_sync(kio_addr_t addr)
 
 static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
-    kio_addr_t addr = dev->base_addr + MGMT;
+    unsigned int addr = dev->base_addr + MGMT;
     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
 
@@ -1202,7 +1065,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc)
 
 static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 {
-    kio_addr_t addr = dev->base_addr + MGMT;
+    unsigned int addr = dev->base_addr + MGMT;
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
 
@@ -1228,7 +1091,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 #ifdef PCMCIA_DEBUG
 static void smc_dump(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short i, w, save;
     save = inw(ioaddr + BANK_SELECT);
     for (w = 0; w < 4; w++) {
@@ -1245,16 +1108,16 @@ static void smc_dump(struct net_device *dev)
 static int smc_open(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    dev_link_t *link = &smc->link;
+    struct pcmcia_device *link = smc->p_dev;
 
-#ifdef PCMCIA_DEBUG
-    DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n",
+    dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n",
          dev->name, dev, inw(dev->base_addr + BANK_SELECT));
-    if (pc_debug > 1) smc_dump(dev);
+#ifdef PCMCIA_DEBUG
+    smc_dump(dev);
 #endif
 
     /* Check that the PCMCIA card is still here. */
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
        return -ENODEV;
     /* Physical device present signature. */
     if (check_sig(link) < 0) {
@@ -1282,10 +1145,10 @@ static int smc_open(struct net_device *dev)
 static int smc_close(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    dev_link_t *link = &smc->link;
-    kio_addr_t ioaddr = dev->base_addr;
+    struct pcmcia_device *link = smc->p_dev;
+    unsigned int ioaddr = dev->base_addr;
 
-    DEBUG(0, "%s: smc_close(), status %4.4x.\n",
+    dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n",
          dev->name, inw(ioaddr + BANK_SELECT));
 
     netif_stop_queue(dev);
@@ -1320,7 +1183,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
 {
     struct smc_private *smc = netdev_priv(dev);
     struct sk_buff *skb = smc->saved_skb;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_char packet_no;
 
     if (!skb) {
@@ -1340,7 +1203,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
        return;
     }
 
-    smc->stats.tx_bytes += skb->len;
+    dev->stats.tx_bytes += skb->len;
     /* The card should use the just-allocated buffer. */
     outw(packet_no, ioaddr + PNR_ARR);
     /* point to the beginning of the packet */
@@ -1352,7 +1215,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
        u_char *buf = skb->data;
        u_int length = skb->len; /* The chip will pad to ethernet min. */
 
-       DEBUG(2, "%s: Trying to xmit packet of length %d.\n",
+       pr_debug("%s: Trying to xmit packet of length %d.\n",
              dev->name, length);
        
        /* send the packet length: +6 for status word, length, and ctl */
@@ -1376,7 +1239,6 @@ static void smc_hardware_send_packet(struct net_device * dev)
     dev_kfree_skb_irq(skb);
     dev->trans_start = jiffies;
     netif_start_queue(dev);
-    return;
 }
 
 /*====================================================================*/
@@ -1384,36 +1246,38 @@ static void smc_hardware_send_packet(struct net_device * dev)
 static void smc_tx_timeout(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
           "Tx_status %2.2x status %4.4x.\n",
           dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
-    smc->stats.tx_errors++;
+    dev->stats.tx_errors++;
     smc_reset(dev);
-    dev->trans_start = jiffies;
+    dev->trans_start = jiffies; /* prevent tx timeout */
     smc->saved_skb = NULL;
     netif_wake_queue(dev);
 }
 
-static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
+                                       struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short num_pages;
     short time_out, ir;
+    unsigned long flags;
 
     netif_stop_queue(dev);
 
-    DEBUG(2, "%s: smc_start_xmit(length = %d) called,"
+    pr_debug("%s: smc_start_xmit(length = %d) called,"
          " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
 
     if (smc->saved_skb) {
        /* THIS SHOULD NEVER HAPPEN. */
-       smc->stats.tx_aborted_errors++;
+       dev->stats.tx_aborted_errors++;
        printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
               dev->name);
-       return 1;
+       return NETDEV_TX_BUSY;
     }
     smc->saved_skb = skb;
 
@@ -1423,12 +1287,13 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
        printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
        dev_kfree_skb (skb);
        smc->saved_skb = NULL;
-       smc->stats.tx_dropped++;
-       return 0;               /* Do not re-queue this packet. */
+       dev->stats.tx_dropped++;
+       return NETDEV_TX_OK;            /* Do not re-queue this packet. */
     }
     /* A packet is now waiting. */
     smc->packets_waiting++;
 
+    spin_lock_irqsave(&smc->lock, flags);
     SMC_SELECT_BANK(2);        /* Paranoia, we should always be in window 2 */
 
     /* need MC_RESET to keep the memory consistent. errata? */
@@ -1445,15 +1310,17 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
            /* Acknowledge the interrupt, send the packet. */
            outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
            smc_hardware_send_packet(dev);      /* Send the packet now.. */
-           return 0;
+           spin_unlock_irqrestore(&smc->lock, flags);
+           return NETDEV_TX_OK;
        }
     }
 
     /* Otherwise defer until the Tx-space-allocated interrupt. */
-    DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
+    pr_debug("%s: memory allocation deferred.\n", dev->name);
     outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
+    spin_unlock_irqrestore(&smc->lock, flags);
 
-    return 0;
+    return NETDEV_TX_OK;
 }
 
 /*======================================================================
@@ -1465,7 +1332,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static void smc_tx_err(struct net_device * dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
     int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
     int tx_status;
@@ -1478,11 +1345,11 @@ static void smc_tx_err(struct net_device * dev)
 
     tx_status = inw(ioaddr + DATA_1);
 
-    smc->stats.tx_errors++;
-    if (tx_status & TS_LOSTCAR) smc->stats.tx_carrier_errors++;
-    if (tx_status & TS_LATCOL)  smc->stats.tx_window_errors++;
+    dev->stats.tx_errors++;
+    if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++;
+    if (tx_status & TS_LATCOL)  dev->stats.tx_window_errors++;
     if (tx_status & TS_16COL) {
-       smc->stats.tx_aborted_errors++;
+       dev->stats.tx_aborted_errors++;
        smc->tx_err++;
     }
 
@@ -1501,7 +1368,6 @@ static void smc_tx_err(struct net_device * dev)
     smc->packets_waiting--;
 
     outw(saved_packet, ioaddr + PNR_ARR);
-    return;
 }
 
 /*====================================================================*/
@@ -1509,20 +1375,20 @@ static void smc_tx_err(struct net_device * dev)
 static void smc_eph_irq(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short card_stats, ephs;
 
     SMC_SELECT_BANK(0);
     ephs = inw(ioaddr + EPH);
-    DEBUG(2, "%s: Ethernet protocol handler interrupt, status"
+    pr_debug("%s: Ethernet protocol handler interrupt, status"
          " %4.4x.\n", dev->name, ephs);
     /* Could be a counter roll-over warning: update stats. */
     card_stats = inw(ioaddr + COUNTER);
     /* single collisions */
-    smc->stats.collisions += card_stats & 0xF;
+    dev->stats.collisions += card_stats & 0xF;
     card_stats >>= 4;
     /* multiple collisions */
-    smc->stats.collisions += card_stats & 0xF;
+    dev->stats.collisions += card_stats & 0xF;
 #if 0          /* These are for when linux supports these statistics */
     card_stats >>= 4;                  /* deferred */
     card_stats >>= 4;                  /* excess deferred */
@@ -1540,11 +1406,11 @@ static void smc_eph_irq(struct net_device *dev)
 
 /*====================================================================*/
 
-static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t smc_interrupt(int irq, void *dev_id)
 {
     struct net_device *dev = dev_id;
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     u_short saved_bank, saved_pointer, mask, status;
     unsigned int handled = 1;
     char bogus_cnt = INTR_WORK;                /* Work we are willing to do. */
@@ -1554,15 +1420,16 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
     ioaddr = dev->base_addr;
 
-    DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
+    pr_debug("%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
          irq, ioaddr);
 
+    spin_lock(&smc->lock);
     smc->watchdog = 0;
     saved_bank = inw(ioaddr + BANK_SELECT);
     if ((saved_bank & 0xff00) != 0x3300) {
        /* The device does not exist -- the card could be off-line, or
           maybe it has been ejected. */
-       DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"
+       pr_debug("%s: SMC91c92 interrupt %d for non-existent"
              "/ejected device.\n", dev->name, irq);
        handled = 0;
        goto irq_done;
@@ -1576,7 +1443,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
     do { /* read the status flag, and mask it */
        status = inw(ioaddr + INTERRUPT) & 0xff;
-       DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
+       pr_debug("%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
              status, mask);
        if ((status & mask) == 0) {
            if (bogus_cnt == INTR_WORK)
@@ -1595,7 +1462,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        if (status & IM_TX_EMPTY_INT) {
            outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
            mask &= ~IM_TX_EMPTY_INT;
-           smc->stats.tx_packets += smc->packets_waiting;
+           dev->stats.tx_packets += smc->packets_waiting;
            smc->packets_waiting = 0;
        }
        if (status & IM_ALLOC_INT) {
@@ -1611,8 +1478,8 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            netif_wake_queue(dev);
        }
        if (status & IM_RX_OVRN_INT) {
-           smc->stats.rx_errors++;
-           smc->stats.rx_fifo_errors++;
+           dev->stats.rx_errors++;
+           dev->stats.rx_fifo_errors++;
            if (smc->duplex)
                smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
            outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
@@ -1621,7 +1488,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            smc_eph_irq(dev);
     } while (--bogus_cnt);
 
-    DEBUG(3, "  Restoring saved registers mask %2.2x bank %4.4x"
+    pr_debug("  Restoring saved registers mask %2.2x bank %4.4x"
          " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
 
     /* restore state register */
@@ -1629,7 +1496,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     outw(saved_pointer, ioaddr + POINTER);
     SMC_SELECT_BANK(saved_bank);
 
-    DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
+    pr_debug("%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
 
 irq_done:
 
@@ -1654,6 +1521,7 @@ irq_done:
        readb(smc->base+MEGAHERTZ_ISR);
     }
 #endif
+    spin_unlock(&smc->lock);
     return IRQ_RETVAL(handled);
 }
 
@@ -1661,8 +1529,7 @@ irq_done:
 
 static void smc_rx(struct net_device *dev)
 {
-    struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int rx_status;
     int packet_length; /* Caution: not frame length, rather words
                           to transfer from the chip. */
@@ -1680,7 +1547,7 @@ static void smc_rx(struct net_device *dev)
     rx_status = inw(ioaddr + DATA_1);
     packet_length = inw(ioaddr + DATA_1) & 0x07ff;
 
-    DEBUG(2, "%s: Receive status %4.4x length %d.\n",
+    pr_debug("%s: Receive status %4.4x length %d.\n",
          dev->name, rx_status, packet_length);
 
     if (!(rx_status & RS_ERRORS)) {            
@@ -1691,8 +1558,8 @@ static void smc_rx(struct net_device *dev)
        skb = dev_alloc_skb(packet_length+2);
        
        if (skb == NULL) {
-           DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name);
-           smc->stats.rx_dropped++;
+           pr_debug("%s: Low memory, packet dropped.\n", dev->name);
+           dev->stats.rx_dropped++;
            outw(MC_RELEASE, ioaddr + MMU_CMD);
            return;
        }
@@ -1703,56 +1570,23 @@ static void smc_rx(struct net_device *dev)
             (packet_length+1)>>1);
        skb->protocol = eth_type_trans(skb, dev);
        
-       skb->dev = dev;
        netif_rx(skb);
        dev->last_rx = jiffies;
-       smc->stats.rx_packets++;
-       smc->stats.rx_bytes += packet_length;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += packet_length;
        if (rx_status & RS_MULTICAST)
-           smc->stats.multicast++;
+           dev->stats.multicast++;
     } else {
        /* error ... */
-       smc->stats.rx_errors++;
+       dev->stats.rx_errors++;
        
-       if (rx_status & RS_ALGNERR)  smc->stats.rx_frame_errors++;
+       if (rx_status & RS_ALGNERR)  dev->stats.rx_frame_errors++;
        if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
-           smc->stats.rx_length_errors++;
-       if (rx_status & RS_BADCRC)      smc->stats.rx_crc_errors++;
+           dev->stats.rx_length_errors++;
+       if (rx_status & RS_BADCRC)      dev->stats.rx_crc_errors++;
     }
     /* Let the MMU free the memory of this packet. */
     outw(MC_RELEASE, ioaddr + MMU_CMD);
-
-    return;
-}
-
-/*====================================================================*/
-
-static struct net_device_stats *smc_get_stats(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    /* Nothing to update - the 91c92 is a pretty primative chip. */
-    return &smc->stats;
-}
-
-/*======================================================================
-
-    Calculate values for the hardware multicast filter hash table.
-
-======================================================================*/
-
-static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
-                              u_char *multicast_table)
-{
-    struct dev_mc_list *mc_addr;
-
-    for (mc_addr = addrs;  mc_addr && --count > 0;  mc_addr = mc_addr->next) {
-       u_int position = ether_crc(6, mc_addr->dmi_addr);
-#ifndef final_version          /* Verify multicast address. */
-       if ((mc_addr->dmi_addr[0] & 1) == 0)
-           continue;
-#endif
-       multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
-    }
 }
 
 /*======================================================================
@@ -1768,21 +1602,27 @@ static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
 
 static void set_rx_mode(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     struct smc_private *smc = netdev_priv(dev);
-    u_int multicast_table[ 2 ] = { 0, };
+    unsigned char multicast_table[8];
     unsigned long flags;
     u_short rx_cfg_setting;
+    int i;
+
+    memset(multicast_table, 0, sizeof(multicast_table));
 
     if (dev->flags & IFF_PROMISC) {
-       printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
        rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
     } else if (dev->flags & IFF_ALLMULTI)
        rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
     else {
-       if (dev->mc_count)  {
-           fill_multicast_tbl(dev->mc_count, dev->mc_list,
-                              (u_char *)multicast_table);
+       if (!netdev_mc_empty(dev)) {
+           struct netdev_hw_addr *ha;
+
+           netdev_for_each_mc_addr(ha, dev) {
+               u_int position = ether_crc(6, ha->addr);
+               multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
+           }
        }
        rx_cfg_setting = RxStripCRC | RxEnable;
     }
@@ -1790,14 +1630,12 @@ static void set_rx_mode(struct net_device *dev)
     /* Load MC table and Rx setting into the chip without interrupts. */
     spin_lock_irqsave(&smc->lock, flags);
     SMC_SELECT_BANK(3);
-    outl(multicast_table[0], ioaddr + MULTICAST0);
-    outl(multicast_table[1], ioaddr + MULTICAST4);
+    for (i = 0; i < 8; i++)
+       outb(multicast_table[i], ioaddr + MULTICAST0 + i);
     SMC_SELECT_BANK(0);
     outw(rx_cfg_setting, ioaddr + RCR);
     SMC_SELECT_BANK(2);
     spin_unlock_irqrestore(&smc->lock, flags);
-
-    return;
 }
 
 /*======================================================================
@@ -1835,7 +1673,7 @@ static int s9k_config(struct net_device *dev, struct ifmap *map)
 static void smc_set_xcvr(struct net_device *dev, int if_port)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short saved_bank;
 
     saved_bank = inw(ioaddr + BANK_SELECT);
@@ -1858,11 +1696,11 @@ static void smc_set_xcvr(struct net_device *dev, int if_port)
 
 static void smc_reset(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     struct smc_private *smc = netdev_priv(dev);
     int i;
 
-    DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
+    pr_debug("%s: smc91c92 reset called.\n", dev->name);
 
     /* The first interaction must be a write to bring the chip out
        of sleep mode. */
@@ -1878,7 +1716,7 @@ static void smc_reset(struct net_device *dev)
     /* Set the Window 1 control, configuration and station addr registers.
        No point in writing the I/O base register ;-> */
     SMC_SELECT_BANK(1);
-    /* Automatically release succesfully transmitted packets,
+    /* Automatically release successfully transmitted packets,
        Accept link errors, counter and Tx error interrupts. */
     outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
         ioaddr + CONTROL);
@@ -1935,9 +1773,12 @@ static void media_check(u_long arg)
 {
     struct net_device *dev = (struct net_device *) arg;
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short i, media, saved_bank;
     u_short link;
+    unsigned long flags;
+
+    spin_lock_irqsave(&smc->lock, flags);
 
     saved_bank = inw(ioaddr + BANK_SELECT);
 
@@ -1957,22 +1798,30 @@ static void media_check(u_long arg)
     SMC_SELECT_BANK(1);
     media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
 
+    SMC_SELECT_BANK(saved_bank);
+    spin_unlock_irqrestore(&smc->lock, flags);
+
     /* Check for pending interrupt with watchdog flag set: with
        this, we can limp along even if the interrupt is blocked */
     if (smc->watchdog++ && ((i>>8) & i)) {
        if (!smc->fast_poll)
            printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
-       smc_interrupt(dev->irq, smc, NULL);
+       local_irq_save(flags);
+       smc_interrupt(dev->irq, dev);
+       local_irq_restore(flags);
        smc->fast_poll = HZ;
     }
     if (smc->fast_poll) {
        smc->fast_poll--;
        smc->media.expires = jiffies + HZ/100;
        add_timer(&smc->media);
-       SMC_SELECT_BANK(saved_bank);
        return;
     }
 
+    spin_lock_irqsave(&smc->lock, flags);
+
+    saved_bank = inw(ioaddr + BANK_SELECT);
+
     if (smc->cfg & CFG_MII_SELECT) {
        if (smc->mii_if.phy_id < 0)
            goto reschedule;
@@ -2006,7 +1855,7 @@ static void media_check(u_long arg)
     }
 
     /* Ignore collisions unless we've had no rx's recently */
-    if (jiffies - dev->last_rx > HZ) {
+    if (time_after(jiffies, dev->last_rx + HZ)) {
        if (smc->tx_err || (smc->media_status & EPH_16COL))
            media |= EPH_16COL;
     }
@@ -2043,11 +1892,12 @@ reschedule:
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
     SMC_SELECT_BANK(saved_bank);
+    spin_unlock_irqrestore(&smc->lock, flags);
 }
 
 static int smc_link_ok(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     struct smc_private *smc = netdev_priv(dev);
 
     if (smc->cfg & CFG_MII_SELECT) {
@@ -2061,7 +1911,7 @@ static int smc_link_ok(struct net_device *dev)
 static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
     u16 tmp;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
        SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
@@ -2083,7 +1933,7 @@ static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
 static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
     u16 tmp;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     if (ecmd->speed != SPEED_10)
        return -EINVAL;
@@ -2126,71 +1976,62 @@ static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct smc_private *smc = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        u16 saved_bank = inw(ioaddr + BANK_SELECT);
        int ret;
+       unsigned long flags;
 
+       spin_lock_irqsave(&smc->lock, flags);
        SMC_SELECT_BANK(3);
-       spin_lock_irq(&smc->lock);
        if (smc->cfg & CFG_MII_SELECT)
                ret = mii_ethtool_gset(&smc->mii_if, ecmd);
        else
                ret = smc_netdev_get_ecmd(dev, ecmd);
-       spin_unlock_irq(&smc->lock);
        SMC_SELECT_BANK(saved_bank);
+       spin_unlock_irqrestore(&smc->lock, flags);
        return ret;
 }
 
 static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct smc_private *smc = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        u16 saved_bank = inw(ioaddr + BANK_SELECT);
        int ret;
+       unsigned long flags;
 
+       spin_lock_irqsave(&smc->lock, flags);
        SMC_SELECT_BANK(3);
-       spin_lock_irq(&smc->lock);
        if (smc->cfg & CFG_MII_SELECT)
                ret = mii_ethtool_sset(&smc->mii_if, ecmd);
        else
                ret = smc_netdev_set_ecmd(dev, ecmd);
-       spin_unlock_irq(&smc->lock);
        SMC_SELECT_BANK(saved_bank);
+       spin_unlock_irqrestore(&smc->lock, flags);
        return ret;
 }
 
 static u32 smc_get_link(struct net_device *dev)
 {
        struct smc_private *smc = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        u16 saved_bank = inw(ioaddr + BANK_SELECT);
        u32 ret;
+       unsigned long flags;
 
+       spin_lock_irqsave(&smc->lock, flags);
        SMC_SELECT_BANK(3);
-       spin_lock_irq(&smc->lock);
        ret = smc_link_ok(dev);
-       spin_unlock_irq(&smc->lock);
        SMC_SELECT_BANK(saved_bank);
+       spin_unlock_irqrestore(&smc->lock, flags);
        return ret;
 }
 
-#ifdef PCMCIA_DEBUG
-static u32 smc_get_msglevel(struct net_device *dev)
-{
-       return pc_debug;
-}
-
-static void smc_set_msglevel(struct net_device *dev, u32 val)
-{
-       pc_debug = val;
-}
-#endif
-
 static int smc_nway_reset(struct net_device *dev)
 {
        struct smc_private *smc = netdev_priv(dev);
        if (smc->cfg & CFG_MII_SELECT) {
-               kio_addr_t ioaddr = dev->base_addr;
+               unsigned int ioaddr = dev->base_addr;
                u16 saved_bank = inw(ioaddr + BANK_SELECT);
                int res;
 
@@ -2203,16 +2044,12 @@ static int smc_nway_reset(struct net_device *dev)
                return -EOPNOTSUPP;
 }
 
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
        .begin = check_if_running,
        .get_drvinfo = smc_get_drvinfo,
        .get_settings = smc_get_settings,
        .set_settings = smc_set_settings,
        .get_link = smc_get_link,
-#ifdef PCMCIA_DEBUG
-       .get_msglevel = smc_get_msglevel,
-       .set_msglevel = smc_set_msglevel,
-#endif
        .nway_reset = smc_nway_reset,
 };
 
@@ -2222,27 +2059,63 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
        struct mii_ioctl_data *mii = if_mii(rq);
        int rc = 0;
        u16 saved_bank;
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
+       unsigned long flags;
 
        if (!netif_running(dev))
                return -EINVAL;
 
-       spin_lock_irq(&smc->lock);
+       spin_lock_irqsave(&smc->lock, flags);
        saved_bank = inw(ioaddr + BANK_SELECT);
        SMC_SELECT_BANK(3);
        rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
        SMC_SELECT_BANK(saved_bank);
-       spin_unlock_irq(&smc->lock);
+       spin_unlock_irqrestore(&smc->lock, flags);
        return rc;
 }
 
+static struct pcmcia_device_id smc91c92_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
+       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
+       PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
+       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
+       PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
+       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
+       PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
+       PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
+       PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
+       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),
+       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
+       PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
+       /* These conflict with other cards! */
+       /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
+       /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
+
 static struct pcmcia_driver smc91c92_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = "smc91c92_cs",
        },
-       .attach         = smc91c92_attach,
-       .detach         = smc91c92_detach,
+       .probe          = smc91c92_probe,
+       .remove         = smc91c92_detach,
+       .id_table       = smc91c92_ids,
+       .suspend        = smc91c92_suspend,
+       .resume         = smc91c92_resume,
 };
 
 static int __init init_smc91c92_cs(void)
@@ -2253,7 +2126,6 @@ static int __init init_smc91c92_cs(void)
 static void __exit exit_smc91c92_cs(void)
 {
        pcmcia_unregister_driver(&smc91c92_cs_driver);
-       BUG_ON(dev_list != NULL);
 }
 
 module_init(init_smc91c92_cs);