]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/pcmcia/ds.c
[PATCH] pcmcia: embed dev_link_t into struct pcmcia_device
[mirror_ubuntu-artful-kernel.git] / drivers / pcmcia / ds.c
index 8eff55b6c9e931c5983ded56fe520597d58a9257..4ab956843d86b2d25791e43878d20fca551630e9 100644 (file)
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * (C) 1999            David A. Hinds
- * (C) 2003 - 2005     Dominik Brodowski
+ * (C) 2003 - 2006     Dominik Brodowski
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -23,6 +22,7 @@
 #include <linux/workqueue.h>
 #include <linux/crc32.h>
 #include <linux/firmware.h>
+#include <linux/kref.h>
 
 #define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
@@ -203,7 +203,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
        unsigned int i;
        u32 hash;
 
-       if (!p_drv->attach || !p_drv->event || !p_drv->remove)
+       if (!p_drv->probe || !p_drv->remove)
                printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback "
                       "function\n", p_drv->drv.name);
 
@@ -264,12 +264,10 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
                if (fw->size >= CISTPL_MAX_CIS_SIZE)
                        goto release;
 
-               cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+               cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
                if (!cis)
                        goto release;
 
-               memset(cis, 0, sizeof(cisdump_t));
-
                cis->Length = fw->size + 1;
                memcpy(cis->Data, fw->data, fw->size);
 
@@ -313,8 +311,6 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
        /* initialize common fields */
        driver->drv.bus = &pcmcia_bus_type;
        driver->drv.owner = driver->owner;
-       driver->drv.probe = pcmcia_device_probe;
-       driver->drv.remove = pcmcia_device_remove;
 
        return driver_register(&driver->drv);
 }
@@ -347,20 +343,37 @@ void pcmcia_put_dev(struct pcmcia_device *p_dev)
                put_device(&p_dev->dev);
 }
 
+static void pcmcia_release_function(struct kref *ref)
+{
+       struct config_t *c = container_of(ref, struct config_t, ref);
+       kfree(c);
+}
+
 static void pcmcia_release_dev(struct device *dev)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        ds_dbg(1, "releasing dev %p\n", p_dev);
        pcmcia_put_socket(p_dev->socket);
        kfree(p_dev->devname);
+       kref_put(&p_dev->function_config->ref, pcmcia_release_function);
        kfree(p_dev);
 }
 
+static void pcmcia_add_pseudo_device(struct pcmcia_socket *s)
+{
+       if (!s->pcmcia_state.device_add_pending) {
+               s->pcmcia_state.device_add_pending = 1;
+               schedule_work(&s->device_add);
+       }
+       return;
+}
 
 static int pcmcia_device_probe(struct device * dev)
 {
        struct pcmcia_device *p_dev;
        struct pcmcia_driver *p_drv;
+       struct pcmcia_device_id *did;
+       struct pcmcia_socket *s;
        int ret = 0;
 
        dev = get_device(dev);
@@ -369,25 +382,37 @@ static int pcmcia_device_probe(struct device * dev)
 
        p_dev = to_pcmcia_dev(dev);
        p_drv = to_pcmcia_drv(dev->driver);
+       s = p_dev->socket;
 
-       if (!try_module_get(p_drv->owner)) {
+       if ((!p_drv->probe) || (!p_dev->function_config) ||
+           (!try_module_get(p_drv->owner))) {
                ret = -EINVAL;
                goto put_dev;
        }
 
-       if (p_drv->attach) {
-               p_dev->instance = p_drv->attach();
-               if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) {
-                       printk(KERN_NOTICE "ds: unable to create instance "
-                              "of '%s'!\n", p_drv->drv.name);
-                       ret = -EINVAL;
-               }
-       }
+       p_dev->p_state &= ~CLIENT_UNBOUND;
+       p_dev->handle = p_dev;
 
+       ret = p_drv->probe(p_dev);
+       if (ret)
+               goto put_module;
+
+       /* handle pseudo multifunction devices:
+        * there are at most two pseudo multifunction devices.
+        * if we're matching against the first, schedule a
+        * call which will then check whether there are two
+        * pseudo devices, and if not, add the second one.
+        */
+       did = (struct pcmcia_device_id *) p_dev->dev.driver_data;
+       if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
+           (p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
+               pcmcia_add_pseudo_device(p_dev->socket);
+
+ put_module:
        if (ret)
                module_put(p_drv->owner);
  put_dev:
-       if ((ret) || !(p_drv->attach))
+       if (ret)
                put_device(dev);
        return (ret);
 }
@@ -409,20 +434,17 @@ static int pcmcia_device_remove(struct device * dev)
                p_drv->remove(p_dev);
 
        /* check for proper unloading */
-       if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+       if (p_dev->p_state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
                printk(KERN_INFO "pcmcia: driver %s did not release config properly\n",
                       p_drv->drv.name);
 
        for (i = 0; i < MAX_WIN; i++)
-               if (p_dev->state & CLIENT_WIN_REQ(i))
+               if (p_dev->p_state & CLIENT_WIN_REQ(i))
                        printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n",
                               p_drv->drv.name);
 
-       /* undo pcmcia_register_client */
-       p_dev->state = CLIENT_UNBOUND;
-       pcmcia_put_dev(p_dev);
-
        /* references from pcmcia_probe_device */
+       p_dev->p_state = CLIENT_UNBOUND;
        pcmcia_put_dev(p_dev);
        module_put(p_drv->owner);
 
@@ -451,7 +473,7 @@ static void pcmcia_card_remove(struct pcmcia_socket *s)
                }
                p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
                list_del(&p_dev->socket_device_list);
-               p_dev->state |= CLIENT_STALE;
+               p_dev->p_state |= CLIENT_STALE;
                spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
                device_unregister(&p_dev->dev);
@@ -517,7 +539,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
                        tmp = vers1->str + vers1->ofs[i];
 
                        length = strlen(tmp) + 1;
-                       if ((length < 3) || (length > 255))
+                       if ((length < 2) || (length > 255))
                                continue;
 
                        p_dev->prod_id[i] = kmalloc(sizeof(char) * length,
@@ -542,11 +564,11 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
  * won't work, this doesn't matter much at the moment: the driver core doesn't
  * support it either.
  */
-static DECLARE_MUTEX(device_add_lock);
+static DEFINE_MUTEX(device_add_lock);
 
 struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
 {
-       struct pcmcia_device *p_dev;
+       struct pcmcia_device *p_dev, *tmp_dev;
        unsigned long flags;
        int bus_id_len;
 
@@ -554,20 +576,21 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
        if (!s)
                return NULL;
 
-       down(&device_add_lock);
+       mutex_lock(&device_add_lock);
 
        /* max of 2 devices per card */
        if (s->device_count == 2)
                goto err_put;
 
-       p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
+       p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
        if (!p_dev)
                goto err_put;
-       memset(p_dev, 0, sizeof(struct pcmcia_device));
 
        p_dev->socket = s;
        p_dev->device_no = (s->device_count++);
        p_dev->func   = function;
+       if (s->functions <= function)
+               s->functions = function + 1;
 
        p_dev->dev.bus = &pcmcia_bus_type;
        p_dev->dev.parent = s->dev.dev;
@@ -580,36 +603,58 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
        sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id);
 
        /* compat */
-       p_dev->state = CLIENT_UNBOUND;
+       p_dev->p_state = CLIENT_UNBOUND;
+
 
-       /* Add to the list in pcmcia_bus_socket */
        spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+
+       /*
+        * p_dev->function_config must be the same for all card functions.
+        * Note that this is serialized by the device_add_lock, so that
+        * only one such struct will be created.
+        */
+        list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
+                if (p_dev->func == tmp_dev->func) {
+                       p_dev->function_config = tmp_dev->function_config;
+                       kref_get(&p_dev->function_config->ref);
+               }
+
+       /* Add to the list in pcmcia_bus_socket */
        list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+
        spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
+       if (!p_dev->function_config) {
+               p_dev->function_config = kzalloc(sizeof(struct config_t),
+                                                GFP_KERNEL);
+               if (!p_dev->function_config)
+                       goto err_unreg;
+               kref_init(&p_dev->function_config->ref);
+       }
+
        printk(KERN_NOTICE "pcmcia: registering new device %s\n",
               p_dev->devname);
 
        pcmcia_device_query(p_dev);
 
-       if (device_register(&p_dev->dev)) {
-               spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-               list_del(&p_dev->socket_device_list);
-               spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
-               goto err_free;
-       }
+       if (device_register(&p_dev->dev))
+               goto err_unreg;
 
-       up(&device_add_lock);
+       mutex_unlock(&device_add_lock);
 
        return p_dev;
 
+ err_unreg:
+       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+       list_del(&p_dev->socket_device_list);
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
  err_free:
        kfree(p_dev->devname);
        kfree(p_dev);
        s->device_count--;
  err_put:
-       up(&device_add_lock);
+       mutex_unlock(&device_add_lock);
        pcmcia_put_socket(s);
 
        return NULL;
@@ -654,15 +699,6 @@ static void pcmcia_delayed_add_pseudo_device(void *data)
        s->pcmcia_state.device_add_pending = 0;
 }
 
-static inline void pcmcia_add_pseudo_device(struct pcmcia_socket *s)
-{
-       if (!s->pcmcia_state.device_add_pending) {
-               s->pcmcia_state.device_add_pending = 1;
-               schedule_work(&s->device_add);
-       }
-       return;
-}
-
 static int pcmcia_requery(struct device *dev, void * _data)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
@@ -677,7 +713,7 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt)
        int no_devices=0;
        unsigned long flags;
 
-       /* must be called with skt_sem held */
+       /* must be called with skt_mutex held */
        spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
        if (list_empty(&skt->devices_list))
                no_devices=1;
@@ -749,15 +785,6 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
        }
 
        if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
-               /* handle pseudo multifunction devices:
-                * there are at most two pseudo multifunction devices.
-                * if we're matching against the first, schedule a
-                * call which will then check whether there are two
-                * pseudo devices, and if not, add the second one.
-                */
-               if (dev->device_no == 0)
-                       pcmcia_add_pseudo_device(dev->socket);
-
                if (dev->device_no != did->device_no)
                        return 0;
        }
@@ -809,9 +836,11 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
        struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
        struct pcmcia_device_id *did = p_drv->id_table;
 
+#ifdef CONFIG_PCMCIA_IOCTL
        /* matching by cardmgr */
        if (p_dev->cardmgr == p_drv)
                return 1;
+#endif
 
        while (did && did->match_flags) {
                if (pcmcia_devmatch(p_dev, did))
@@ -912,6 +941,37 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]);
 pcmcia_device_stringattr(prod_id3, prod_id[2]);
 pcmcia_device_stringattr(prod_id4, prod_id[3]);
 
+
+static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+
+       if (p_dev->dev.power.power_state.event != PM_EVENT_ON)
+               return sprintf(buf, "off\n");
+       else
+               return sprintf(buf, "on\n");
+}
+
+static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+       int ret = 0;
+
+        if (!count)
+                return -EINVAL;
+
+       if ((p_dev->dev.power.power_state.event == PM_EVENT_ON) &&
+           (!strncmp(buf, "off", 3)))
+               ret = dpm_runtime_suspend(dev, PMSG_SUSPEND);
+       else if ((p_dev->dev.power.power_state.event != PM_EVENT_ON) &&
+                (!strncmp(buf, "on", 2)))
+               dpm_runtime_resume(dev);
+
+       return ret ? ret : count;
+}
+
+
 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
@@ -937,12 +997,13 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
-        if (!count)
-                return -EINVAL;
 
-       down(&p_dev->socket->skt_sem);
+       if (!count)
+               return -EINVAL;
+
+       mutex_lock(&p_dev->socket->skt_mutex);
        p_dev->allow_func_id_match = 1;
-       up(&p_dev->socket->skt_sem);
+       mutex_unlock(&p_dev->socket->skt_mutex);
 
        bus_rescan_devices(&pcmcia_bus_type);
 
@@ -951,6 +1012,7 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
 
 static struct device_attribute pcmcia_dev_attrs[] = {
        __ATTR(function, 0444, func_show, NULL),
+       __ATTR(pm_state, 0644, pcmcia_show_pm_state, pcmcia_store_pm_state),
        __ATTR_RO(func_id),
        __ATTR_RO(manf_id),
        __ATTR_RO(card_id),
@@ -969,12 +1031,20 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        struct pcmcia_driver *p_drv = NULL;
+       int ret;
 
        if (dev->driver)
                p_drv = to_pcmcia_drv(dev->driver);
 
-       if (p_drv && p_drv->suspend)
-               return p_drv->suspend(p_dev);
+       if (p_drv && p_drv->suspend) {
+               ret = p_drv->suspend(p_dev);
+               if (ret)
+                       return ret;
+               p_dev->state |= DEV_SUSPEND;
+                       if ((p_dev->state & DEV_CONFIG) &&
+                           !(p_dev->state & DEV_SUSPEND_NORELEASE))
+                               pcmcia_release_configuration(p_dev);
+       }
 
        return 0;
 }
@@ -984,12 +1054,22 @@ static int pcmcia_dev_resume(struct device * dev)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
         struct pcmcia_driver *p_drv = NULL;
+       int ret;
 
        if (dev->driver)
                p_drv = to_pcmcia_drv(dev->driver);
 
-       if (p_drv && p_drv->resume)
+       if (p_drv && p_drv->resume) {
+               p_dev->state &= ~DEV_SUSPEND;
+                       if ((p_dev->state & DEV_CONFIG) &&
+                           !(p_dev->state & DEV_SUSPEND_NORELEASE)){
+                               ret = pcmcia_request_configuration(p_dev,
+                                                &p_dev->conf);
+                               if (ret)
+                                       return ret;
+                       }
                return p_drv->resume(p_dev);
+       }
 
        return 0;
 }
@@ -1042,49 +1122,6 @@ static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
     
 ======================================================================*/
 
-struct send_event_data {
-       struct pcmcia_socket *skt;
-       event_t event;
-       int priority;
-};
-
-static int send_event_callback(struct device *dev, void * _data)
-{
-       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
-       struct pcmcia_driver *p_drv;
-       struct send_event_data *data = _data;
-
-       /* we get called for all sockets, but may only pass the event
-        * for drivers _on the affected socket_ */
-       if (p_dev->socket != data->skt)
-               return 0;
-
-       p_drv = to_pcmcia_drv(p_dev->dev.driver);
-       if (!p_drv)
-               return 0;
-
-       if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE))
-               return 0;
-
-       if (p_drv->event)
-               return p_drv->event(data->event, data->priority,
-                                   &p_dev->event_callback_args);
-
-       return 0;
-}
-
-static int send_event(struct pcmcia_socket *s, event_t event, int priority)
-{
-       struct send_event_data private;
-
-       private.skt = s;
-       private.event = event;
-       private.priority = priority;
-
-       return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
-} /* send_event */
-
-
 /* Normally, the event is passed to individual drivers after
  * informing userspace. Only for CS_EVENT_CARD_REMOVAL this
  * is inversed to maintain historic compatibility.
@@ -1093,20 +1130,17 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
 static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
 {
        struct pcmcia_socket *s = pcmcia_get_socket(skt);
-       int ret = 0;
 
        ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
               event, priority, skt);
-    
-       switch (event) {
 
+       switch (event) {
        case CS_EVENT_CARD_REMOVAL:
                s->pcmcia_state.present = 0;
-               send_event(skt, event, priority);
                pcmcia_card_remove(skt);
                handle_event(skt, event);
                break;
-       
+
        case CS_EVENT_CARD_INSERTION:
                s->pcmcia_state.present = 1;
                pcmcia_card_add(skt);
@@ -1114,19 +1148,14 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
                break;
 
        case CS_EVENT_EJECTION_REQUEST:
-               ret = send_event(skt, event, priority);
                break;
 
        case CS_EVENT_PM_SUSPEND:
        case CS_EVENT_PM_RESUME:
        case CS_EVENT_RESET_PHYSICAL:
        case CS_EVENT_CARD_RESET:
-               handle_event(skt, event);
-               break;
-
        default:
                handle_event(skt, event);
-               send_event(skt, event, priority);
                break;
     }
 
@@ -1136,90 +1165,6 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
 } /* ds_event */
 
 
-
-int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req)
-{
-       struct pcmcia_socket *s = NULL;
-       struct pcmcia_device *p_dev = NULL;
-       struct pcmcia_driver *p_drv = NULL;
-
-       /* Look for unbound client with matching dev_info */
-       down_read(&pcmcia_socket_list_rwsem);
-       list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
-               unsigned long flags;
-
-               if (s->state & SOCKET_CARDBUS)
-                       continue;
-
-               s = pcmcia_get_socket(s);
-               if (!s)
-                       continue;
-               spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-               list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
-                       p_dev = pcmcia_get_dev(p_dev);
-                       if (!p_dev)
-                               continue;
-                       if (!(p_dev->state & CLIENT_UNBOUND) ||
-                           (!p_dev->dev.driver)) {
-                               pcmcia_put_dev(p_dev);
-                               continue;
-                       }
-                       p_drv = to_pcmcia_drv(p_dev->dev.driver);
-                       if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) {
-                               spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-                               goto found;
-                       }
-                       pcmcia_put_dev(p_dev);
-               }
-               spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-               pcmcia_put_socket(s);
-       }
- found:
-       up_read(&pcmcia_socket_list_rwsem);
-       if (!p_dev)
-               return -ENODEV;
-
-       pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */
-
-       *handle = p_dev;
-       p_dev->state &= ~CLIENT_UNBOUND;
-       p_dev->event_callback_args = req->event_callback_args;
-       p_dev->event_callback_args.client_handle = p_dev;
-
-
-       if (!s->functions) {
-               cistpl_longlink_mfc_t mfc;
-               if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc)
-                   == CS_SUCCESS)
-                       s->functions = mfc.nfn;
-               else
-                       s->functions = 1;
-               s->config = kmalloc(sizeof(config_t) * s->functions,
-                                   GFP_KERNEL);
-               if (!s->config)
-                       goto out_no_resource;
-               memset(s->config, 0, sizeof(config_t) * s->functions);
-       }
-
-       ds_dbg(1, "register_client(): client 0x%p, dev %s\n",
-              p_dev, p_dev->dev.bus_id);
-
-       if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) {
-               if (p_drv->event)
-                       p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW,
-                                    &p_dev->event_callback_args);
-
-       }
-
-       return CS_SUCCESS;
-
- out_no_resource:
-       pcmcia_put_dev(p_dev);
-       return CS_OUT_OF_RESOURCE;
-} /* register_client */
-EXPORT_SYMBOL(pcmcia_register_client);
-
-
 static struct pcmcia_callback pcmcia_bus_callback = {
        .owner = THIS_MODULE,
        .event = ds_event,
@@ -1294,6 +1239,8 @@ struct bus_type pcmcia_bus_type = {
        .uevent = pcmcia_bus_uevent,
        .match = pcmcia_bus_match,
        .dev_attrs = pcmcia_dev_attrs,
+       .probe = pcmcia_device_probe,
+       .remove = pcmcia_device_remove,
        .suspend = pcmcia_dev_suspend,
        .resume = pcmcia_dev_resume,
 };