]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/atmel_cs.c
[netdrvr] fix array overflows in Chelsio driver
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / atmel_cs.c
index 195cb36619e859ea2475ee3032adc78d9826e9ec..d6f4a5a3e55a614cb1131d66e91c95e7b2eec840 100644 (file)
@@ -63,6 +63,7 @@
    be present but disabled -- but it can then be enabled for specific
    modules at load time with a 'pc_debug=#' option to insmod.
 */
+
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
 module_param(pc_debug, int, 0);
@@ -92,8 +93,6 @@ MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards");
 
 static void atmel_config(dev_link_t *link);
 static void atmel_release(dev_link_t *link);
-static int atmel_event(event_t event, int priority,
-                      event_callback_args_t *args);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -101,8 +100,7 @@ static int atmel_event(event_t event, int priority,
    needed to manage one actual PCMCIA card.
 */
 
-static dev_link_t *atmel_attach(void);
-static void atmel_detach(dev_link_t *);
+static void atmel_detach(struct pcmcia_device *p_dev);
 
 /*
    You'll also need to prototype all the functions that will actually
@@ -111,14 +109,6 @@ static void atmel_detach(dev_link_t *);
    less on other parts of the kernel.
 */
 
-/*
-   The dev_info variable is the "key" that is used to match up this
-   device driver with appropriate cards, through the card configuration
-   database.
-*/
-
-static dev_info_t dev_info = "atmel_cs";
-
 /*
    A linked list of "instances" of the  atmelnet device.  Each actual
    PCMCIA card corresponds to one device instance, and is described
@@ -129,15 +119,7 @@ static dev_info_t dev_info = "atmel_cs";
    device numbers are used to derive the corresponding array index.
 */
 
-static dev_link_t *dev_list = NULL;
-
 /*
-   A dev_link_t structure has fields for most things that are needed
-   to keep track of a socket, but there will usually be some device
-   specific information that also needs to be kept track of.  The
-   'priv' pointer in a dev_link_t structure can be used to point to
-   a device-specific private data structure, like this.
-
    A driver needs to provide a dev_node_t structure for each device
    on a card.  In some cases, there is only one device per card (for
    example, ethernet cards, modems).  In other cases, there may be
@@ -170,28 +152,25 @@ typedef struct local_info_t {
   
   ======================================================================*/
 
-static dev_link_t *atmel_attach(void)
+static int atmel_attach(struct pcmcia_device *p_dev)
 {
-       client_reg_t client_reg;
        dev_link_t *link;
        local_info_t *local;
-       int ret;
-       
+
        DEBUG(0, "atmel_attach()\n");
 
        /* Initialize the dev_link_t structure */
-       link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+       link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
        if (!link) {
                printk(KERN_ERR "atmel_cs: no memory for new device\n");
-               return NULL;
+               return -ENOMEM;
        }
-       memset(link, 0, sizeof(struct dev_link_t));
-       
+
        /* Interrupt setup */
        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
        link->irq.IRQInfo1 = IRQ_LEVEL_ID;
        link->irq.Handler = NULL;
-       
+
        /*
          General socket configuration defaults can go here.  In this
          client, we assume very little, and rely on the CIS for almost
@@ -202,31 +181,23 @@ static dev_link_t *atmel_attach(void)
        link->conf.Attributes = 0;
        link->conf.Vcc = 50;
        link->conf.IntType = INT_MEMORY_AND_IO;
-       
+
        /* Allocate space for private device-specific data */
-       local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+       local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
        if (!local) {
                printk(KERN_ERR "atmel_cs: no memory for new device\n");
                kfree (link);
-               return NULL;
+               return -ENOMEM;
        }
-       memset(local, 0, sizeof(local_info_t));
        link->priv = local;
-       
-       /* Register with Card Services */
-       link->next = dev_list;
-       dev_list = link;
-       client_reg.dev_info = &dev_info;
-       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);
-               atmel_detach(link);
-               return NULL;
-       }
-       
-       return link;
+
+       link->handle = p_dev;
+       p_dev->instance = link;
+
+       link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+       atmel_config(link);
+
+       return 0;
 } /* atmel_attach */
 
 /*======================================================================
@@ -238,27 +209,15 @@ static dev_link_t *atmel_attach(void)
   
   ======================================================================*/
 
-static void atmel_detach(dev_link_t *link)
+static void atmel_detach(struct pcmcia_device *p_dev)
 {
-       dev_link_t **linkp;
-       
+       dev_link_t *link = dev_to_instance(p_dev);
+
        DEBUG(0, "atmel_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)
                atmel_release(link);
-               
-       /* Break the link with Card Services */
-       if (link->handle)
-               pcmcia_deregister_client(link->handle);
 
-       /* Unlink device structure, free pieces */
-       *linkp = link->next;
        kfree(link->priv);
        kfree(link);
 }
@@ -287,41 +246,6 @@ static int card_present(void *arg)
        return 0;
 }
 
-/* list of cards we know about and their firmware requirements.
-   Go either by Manfid or version strings.
-   Cards not in this list will need a firmware parameter to the module
-   in all probability. Note that the SMC 2632 V2 and V3 have the same
-   manfids, so we ignore those and use the version1 strings. */
-
-static struct { 
-       int manf, card;
-       char *ver1;
-       AtmelFWType firmware;
-       char *name;
-} card_table[] = {
-       { 0, 0, "WLAN/802.11b PC CARD", ATMEL_FW_TYPE_502D, "Actiontec 802CAT1" },  
-       { 0, 0, "ATMEL/AT76C502AR", ATMEL_FW_TYPE_502, "NoName-RFMD" }, 
-       { 0, 0, "ATMEL/AT76C502AR_D", ATMEL_FW_TYPE_502D, "NoName-revD" }, 
-       { 0, 0, "ATMEL/AT76C502AR_E", ATMEL_FW_TYPE_502E, "NoName-revE" },
-       { 0, 0, "ATMEL/AT76C504", ATMEL_FW_TYPE_504, "NoName-504" },
-       { 0, 0, "ATMEL/AT76C504A", ATMEL_FW_TYPE_504A_2958, "NoName-504a-2958" },
-       { 0, 0, "ATMEL/AT76C504_R", ATMEL_FW_TYPE_504_2958, "NoName-504-2958" },
-       { MANFID_3COM, 0x0620, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRWE62092B" }, 
-       { MANFID_3COM, 0x0696, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRSHPW196" }, 
-       { 0, 0, "SMC/2632W-V2", ATMEL_FW_TYPE_502, "SMC 2632W-V2" },
-       { 0, 0, "SMC/2632W", ATMEL_FW_TYPE_502D, "SMC 2632W-V3" },
-       { 0xd601, 0x0007, NULL, ATMEL_FW_TYPE_502, "Sitecom WLAN-011" }, 
-       { 0x01bf, 0x3302, NULL, ATMEL_FW_TYPE_502E, "Belkin F5D6020-V2" }, 
-       { 0, 0, "BT/Voyager 1020 Laptop Adapter", ATMEL_FW_TYPE_502, "BT Voyager 1020" },
-       { 0, 0, "IEEE 802.11b/Wireless LAN PC Card", ATMEL_FW_TYPE_502, "Siemens Gigaset PC Card II" },
-       { 0, 0, "IEEE 802.11b/Wireless LAN Card S", ATMEL_FW_TYPE_504_2958, "Siemens Gigaset PC Card II" },
-       { 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", ATMEL_FW_TYPE_502E, "CNet CNWLC-811ARL" },
-       { 0, 0, "Wireless/PC_CARD", ATMEL_FW_TYPE_502D, "Planet WL-3552" },
-       { 0, 0, "OEM/11Mbps Wireless LAN PC Card V-3", ATMEL_FW_TYPE_502, "OEM 11Mbps WLAN PCMCIA Card" },
-       { 0, 0, "11WAVE/11WP611AL-E", ATMEL_FW_TYPE_502E, "11WAVE WaveBuddy" },
-       { 0, 0, "LG/LW2100N", ATMEL_FW_TYPE_502E, "LG LW2100N 11Mbps WLAN PCMCIA Card" },
-};
-
 static void atmel_config(dev_link_t *link)
 {
        client_handle_t handle;
@@ -330,10 +254,11 @@ static void atmel_config(dev_link_t *link)
        local_info_t *dev;
        int last_fn, last_ret;
        u_char buf[64];
-       int card_index = -1, done = 0;
-       
+       struct pcmcia_device_id *did;
+
        handle = link->handle;
        dev = link->priv;
+       did = handle_to_dev(handle).driver_data;
 
        DEBUG(0, "atmel_config(0x%p)\n", link);
        
@@ -342,59 +267,6 @@ static void atmel_config(dev_link_t *link)
        tuple.TupleDataMax = sizeof(buf);
        tuple.TupleOffset = 0;
        
-       tuple.DesiredTuple = CISTPL_MANFID;
-       if (pcmcia_get_first_tuple(handle, &tuple) == 0) {
-               int i;
-               cistpl_manfid_t *manfid;
-               CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-               CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-               manfid = &(parse.manfid);
-               for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
-                       if (!card_table[i].ver1 &&
-                           manfid->manf == card_table[i].manf &&
-                           manfid->card == card_table[i].card) {
-                               card_index = i;
-                               done = 1;
-                       }
-               }
-       }
-
-       tuple.DesiredTuple = CISTPL_VERS_1;
-       if (!done && (pcmcia_get_first_tuple(handle, &tuple) == 0)) {
-               int i, j, k;
-               cistpl_vers_1_t *ver1;
-               CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-               CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-               ver1 = &(parse.version_1);
-               
-               for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
-                       for (j = 0; j < ver1->ns; j++) {
-                               char *p = card_table[i].ver1;
-                               char *q = &ver1->str[ver1->ofs[j]];
-                               if (!p)
-                                       goto mismatch;
-                               for (k = 0; k < j; k++) {
-                                       while ((*p != '\0') && (*p != '/')) p++;
-                                       if (*p == '\0') {
-                                               if (*q != '\0')
-                                                       goto mismatch;
-                                       } else {
-                                               p++;
-                                       }
-                               }
-                               while((*q != '\0') && (*p != '\0') && 
-                                     (*p != '/') && (*p == *q)) p++, q++;
-                               if (((*p != '\0') && *p != '/') || *q != '\0')
-                                       goto mismatch;
-                       }
-                       card_index = i;
-                       break;  /* done */
-                       
-               mismatch:
-                       j = 0; /* dummy stmt to shut up compiler */
-               }
-       }               
-
        /*
          This reads the card's CONFIG tuple to find its configuration
          registers.
@@ -511,12 +383,13 @@ static void atmel_config(dev_link_t *link)
        ((local_info_t*)link->priv)->eth_dev = 
                init_atmel_card(link->irq.AssignedIRQ,
                                link->io.BasePort1,
-                               card_index == -1 ? ATMEL_FW_TYPE_NONE :  card_table[card_index].firmware,
+                               did ? did->driver_info : ATMEL_FW_TYPE_NONE,
                                &handle_to_dev(handle),
                                card_present, 
                                link);
        if (!((local_info_t*)link->priv)->eth_dev) 
-               goto cs_failed;
+                       goto cs_failed;
+       
        
        /*
          At this point, the dev_node_t structure(s) need to be
@@ -525,26 +398,7 @@ static void atmel_config(dev_link_t *link)
        strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
        dev->node.major = dev->node.minor = 0;
        link->dev = &dev->node;
-       
-       /* Finally, report what we've done */
-       printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d",
-              dev->node.dev_name,
-              card_index == -1 ? "" :  card_table[card_index].name,
-              card_index == -1 ? "" : " ",
-              link->conf.ConfigIndex,
-              link->conf.Vcc/10, link->conf.Vcc%10);
-       if (link->conf.Vpp1)
-               printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %d", link->irq.AssignedIRQ);
-       if (link->io.NumPorts1)
-               printk(", io 0x%04x-0x%04x", link->io.BasePort1,
-                      link->io.BasePort1+link->io.NumPorts1-1);
-       if (link->io.NumPorts2)
-               printk(" & 0x%04x-0x%04x", link->io.BasePort2,
-                      link->io.BasePort2+link->io.NumPorts2-1);
-       printk("\n");
-       
+                       
        link->state &= ~DEV_CONFIG_PENDING;
        return;
        
@@ -571,7 +425,7 @@ static void atmel_release(dev_link_t *link)
        link->dev = NULL;
        
        if (dev) 
-               stop_atmel_card(dev, 0);
+               stop_atmel_card(dev);
        ((local_info_t*)link->priv)->eth_dev = NULL; 
        
        /* Don't bother checking to see if these succeed or not */
@@ -583,81 +437,77 @@ static void atmel_release(dev_link_t *link)
        link->state &= ~DEV_CONFIG;
 }
 
-/*======================================================================
-  
-  The card status event handler.  Mostly, this schedules other
-  stuff to run after an event is received.
+static int atmel_suspend(struct pcmcia_device *dev)
+{
+       dev_link_t *link = dev_to_instance(dev);
+       local_info_t *local = link->priv;
 
-  When a CARD_REMOVAL event is received, we immediately set a
-  private flag to block future accesses to this device.  All the
-  functions that actually access the device should check this flag
-  to make sure the card is still present.
-  
-  ======================================================================*/
+       link->state |= DEV_SUSPEND;
+       if (link->state & DEV_CONFIG) {
+               netif_device_detach(local->eth_dev);
+               pcmcia_release_configuration(link->handle);
+       }
 
-static int atmel_event(event_t event, int priority,
-                     event_callback_args_t *args)
+       return 0;
+}
+
+static int atmel_resume(struct pcmcia_device *dev)
 {
-       dev_link_t *link = args->client_data;
+       dev_link_t *link = dev_to_instance(dev);
        local_info_t *local = link->priv;
-       
-       DEBUG(1, "atmel_event(0x%06x)\n", event);
-       
-       switch (event) {
-       case CS_EVENT_CARD_REMOVAL:
-               link->state &= ~DEV_PRESENT;
-               if (link->state & DEV_CONFIG) {
-                       netif_device_detach(local->eth_dev);
-                       atmel_release(link);
-               }
-               break;
-       case CS_EVENT_CARD_INSERTION:
-               link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-               atmel_config(link);
-               break;
-       case CS_EVENT_PM_SUSPEND:
-               link->state |= DEV_SUSPEND;
-               /* Fall through... */
-       case CS_EVENT_RESET_PHYSICAL:
-               if (link->state & DEV_CONFIG) {
-                       netif_device_detach(local->eth_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);
-                       atmel_open(local->eth_dev);
-                       netif_device_attach(local->eth_dev);
-               }
-               break;
+
+       link->state &= ~DEV_SUSPEND;
+       if (link->state & DEV_CONFIG) {
+               pcmcia_request_configuration(link->handle, &link->conf);
+               atmel_open(local->eth_dev);
+               netif_device_attach(local->eth_dev);
        }
+
        return 0;
-} /* atmel_event */
+}
 
 /*====================================================================*/
+/* We use the driver_info field to store the correct firmware type for a card. */
+
+#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+        .driver_info = (kernel_ulong_t)(info), }
+
+#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+        .driver_info = (kernel_ulong_t)(info), }
+
 static struct pcmcia_device_id atmel_ids[] = {
-       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0620),
-       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0696),
-       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3302),
-       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0007),
-       PCMCIA_DEVICE_PROD_ID12("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9),
-       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f),
-       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504", 0xabda4164, 0x5040670a),
-       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f),
-       PCMCIA_DEVICE_PROD_ID12("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5),
-       PCMCIA_DEVICE_PROD_ID12("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b),
-       PCMCIA_DEVICE_PROD_ID12("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6),
-       PCMCIA_DEVICE_PROD_ID12("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68),
-       PCMCIA_DEVICE_PROD_ID12("SMC", "2632W", 0xc4f8b18b, 0x30f38774),
-       PCMCIA_DEVICE_PROD_ID12("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377),
-       PCMCIA_DEVICE_PROD_ID12("Wireless", "PC", 0xa407ecdd, 0x556e4d7e),
-       PCMCIA_DEVICE_PROD_ID12("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4),
+       PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
+       PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
+       PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
+       PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958),
+       PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E),
+       PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958),
+       PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D),
+       PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D),
+       PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D),
+       PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E),
        PCMCIA_DEVICE_NULL
 };
+
 MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
 
 static struct pcmcia_driver atmel_driver = {
@@ -665,10 +515,11 @@ static struct pcmcia_driver atmel_driver = {
        .drv            = {
                .name   = "atmel_cs",
         },
-       .attach         = atmel_attach,
-       .event          = atmel_event,
-       .detach         = atmel_detach,
+       .probe          = atmel_attach,
+       .remove         = atmel_detach,
        .id_table       = atmel_ids,
+       .suspend        = atmel_suspend,
+       .resume         = atmel_resume,
 };
 
 static int atmel_cs_init(void)
@@ -679,7 +530,6 @@ static int atmel_cs_init(void)
 static void atmel_cs_cleanup(void)
 {
         pcmcia_unregister_driver(&atmel_driver);
-       BUG_ON(dev_list != NULL);
 }
 
 /*