Add support for the Arcom/Eurotech Viper SBC CompactFlash card slot
[safe/jmp/linux-2.6] / drivers / pcmcia / cs.c
index 613f2f1..d120739 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/pci.h>
 #include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 
-#define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -89,7 +87,7 @@ DECLARE_RWSEM(pcmcia_socket_list_rwsem);
 EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
 
 
-/**
+/*
  * Low-level PCMCIA socket drivers need to register with the PCCard
  * core using pcmcia_register_socket.
  *
@@ -109,11 +107,11 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state)
 
        down_read(&pcmcia_socket_list_rwsem);
        list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
-               if (socket->dev.dev != dev)
+               if (socket->dev.parent != dev)
                        continue;
-               down(&socket->skt_sem);
+               mutex_lock(&socket->skt_mutex);
                socket_suspend(socket);
-               up(&socket->skt_sem);
+               mutex_unlock(&socket->skt_mutex);
        }
        up_read(&pcmcia_socket_list_rwsem);
 
@@ -127,11 +125,11 @@ int pcmcia_socket_dev_resume(struct device *dev)
 
        down_read(&pcmcia_socket_list_rwsem);
        list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
-               if (socket->dev.dev != dev)
+               if (socket->dev.parent != dev)
                        continue;
-               down(&socket->skt_sem);
+               mutex_lock(&socket->skt_mutex);
                socket_resume(socket);
-               up(&socket->skt_sem);
+               mutex_unlock(&socket->skt_mutex);
        }
        up_read(&pcmcia_socket_list_rwsem);
 
@@ -142,12 +140,12 @@ EXPORT_SYMBOL(pcmcia_socket_dev_resume);
 
 struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt)
 {
-       struct class_device *cl_dev = class_device_get(&skt->dev);
-       if (!cl_dev)
+       struct device *dev = get_device(&skt->dev);
+       if (!dev)
                return NULL;
-       skt = class_get_devdata(cl_dev);
+       skt = dev_get_drvdata(dev);
        if (!try_module_get(skt->owner)) {
-               class_device_put(&skt->dev);
+               put_device(&skt->dev);
                return NULL;
        }
        return (skt);
@@ -158,14 +156,14 @@ EXPORT_SYMBOL(pcmcia_get_socket);
 void pcmcia_put_socket(struct pcmcia_socket *skt)
 {
        module_put(skt->owner);
-       class_device_put(&skt->dev);
+       put_device(&skt->dev);
 }
 EXPORT_SYMBOL(pcmcia_put_socket);
 
 
-static void pcmcia_release_socket(struct class_device *class_dev)
+static void pcmcia_release_socket(struct device *dev)
 {
-       struct pcmcia_socket *socket = class_get_devdata(class_dev);
+       struct pcmcia_socket *socket = dev_get_drvdata(dev);
 
        complete(&socket->socket_released);
 }
@@ -174,12 +172,14 @@ static int pccardd(void *__skt);
 
 /**
  * pcmcia_register_socket - add a new pcmcia socket device
+ * @socket: the &socket to register
  */
 int pcmcia_register_socket(struct pcmcia_socket *socket)
 {
+       struct task_struct *tsk;
        int ret;
 
-       if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops)
+       if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops)
                return -EINVAL;
 
        cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
@@ -224,9 +224,9 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
 #endif
 
        /* set proper values in socket->dev */
-       socket->dev.class_data = socket;
+       dev_set_drvdata(&socket->dev, socket);
        socket->dev.class = &pcmcia_socket_class;
-       snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
+       snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
 
        /* base address = 0, map = 0 */
        socket->cis_mem.flags = 0;
@@ -236,19 +236,21 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
 
        init_completion(&socket->socket_released);
        init_completion(&socket->thread_done);
-       init_waitqueue_head(&socket->thread_wait);
-       init_MUTEX(&socket->skt_sem);
+       mutex_init(&socket->skt_mutex);
        spin_lock_init(&socket->thread_lock);
 
-       ret = kernel_thread(pccardd, socket, CLONE_KERNEL);
-       if (ret < 0)
+       tsk = kthread_run(pccardd, socket, "pccardd");
+       if (IS_ERR(tsk)) {
+               ret = PTR_ERR(tsk);
                goto err;
+       }
 
        wait_for_completion(&socket->thread_done);
-       if(!socket->thread) {
+       if (!socket->thread) {
                printk(KERN_WARNING "PCMCIA: warning: socket thread for socket %p did not start\n", socket);
                return -EIO;
        }
+
        pcmcia_parse_events(socket, SS_DETECT);
 
        return 0;
@@ -264,6 +266,7 @@ EXPORT_SYMBOL(pcmcia_register_socket);
 
 /**
  * pcmcia_unregister_socket - remove a pcmcia socket device
+ * @socket: the &socket to unregister
  */
 void pcmcia_unregister_socket(struct pcmcia_socket *socket)
 {
@@ -272,12 +275,9 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
 
        cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops);
 
-       if (socket->thread) {
-               init_completion(&socket->thread_done);
-               socket->thread = NULL;
-               wake_up(&socket->thread_wait);
-               wait_for_completion(&socket->thread_done);
-       }
+       if (socket->thread)
+               kthread_stop(socket->thread);
+
        release_cis_mem(socket);
 
        /* remove from our own list */
@@ -309,7 +309,7 @@ struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr)
 }
 EXPORT_SYMBOL(pcmcia_get_socket_by_nr);
 
-/**
+/*
  * The central event handler.  Send_event() sends an event to the
  * 16-bit subsystem, which then calls the relevant device drivers.
  * Parse_events() interprets the event bits from
@@ -378,7 +378,7 @@ static int socket_reset(struct pcmcia_socket *skt)
        return CS_GENERAL_FAILURE;
 }
 
-/**
+/*
  * socket_setup() and socket_shutdown() are called by the main event handler
  * when card insertion and removal events are received.
  * socket_setup() turns on socket power and resets the socket, in two stages.
@@ -406,8 +406,9 @@ static void socket_shutdown(struct pcmcia_socket *s)
        cb_free(s);
 #endif
        s->functions = 0;
-       kfree(s->config);
-       s->config = NULL;
+
+       /* give socket some time to power down */
+       msleep(100);
 
        s->ops->get_status(s, &status);
        if (status & SS_POWERON) {
@@ -630,28 +631,29 @@ static void socket_detect_change(struct pcmcia_socket *skt)
 static int pccardd(void *__skt)
 {
        struct pcmcia_socket *skt = __skt;
-       DECLARE_WAITQUEUE(wait, current);
        int ret;
 
-       daemonize("pccardd");
-
        skt->thread = current;
        skt->socket = dead_socket;
        skt->ops->init(skt);
        skt->ops->set_socket(skt, &skt->socket);
 
        /* register with the device core */
-       ret = class_device_register(&skt->dev);
+       ret = device_register(&skt->dev);
        if (ret) {
                printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
                        skt);
                skt->thread = NULL;
-               complete_and_exit(&skt->thread_done, 0);
+               complete(&skt->thread_done);
+               return 0;
        }
+       ret = pccard_sysfs_add_socket(&skt->dev);
+       if (ret)
+               dev_warn(&skt->dev, "err %d adding socket attributes\n", ret);
 
-       add_wait_queue(&skt->thread_wait, &wait);
        complete(&skt->thread_done);
 
+       set_freezable();
        for (;;) {
                unsigned long flags;
                unsigned int events;
@@ -664,7 +666,7 @@ static int pccardd(void *__skt)
                spin_unlock_irqrestore(&skt->thread_lock, flags);
 
                if (events) {
-                       down(&skt->skt_sem);
+                       mutex_lock(&skt->skt_mutex);
                        if (events & SS_DETECT)
                                socket_detect_change(skt);
                        if (events & SS_BATDEAD)
@@ -673,11 +675,11 @@ static int pccardd(void *__skt)
                                send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
                        if (events & SS_READY)
                                send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
-                       up(&skt->skt_sem);
+                       mutex_unlock(&skt->skt_mutex);
                        continue;
                }
 
-               if (!skt->thread)
+               if (kthread_should_stop())
                        break;
 
                schedule();
@@ -686,12 +688,11 @@ static int pccardd(void *__skt)
        /* make sure we are running before we exit */
        set_current_state(TASK_RUNNING);
 
-       remove_wait_queue(&skt->thread_wait, &wait);
-
        /* remove from the device core */
-       class_device_unregister(&skt->dev);
+       pccard_sysfs_remove_socket(&skt->dev);
+       device_unregister(&skt->dev);
 
-       complete_and_exit(&skt->thread_done, 0);
+       return 0;
 }
 
 /*
@@ -700,13 +701,14 @@ static int pccardd(void *__skt)
  */
 void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
 {
+       unsigned long flags;
        cs_dbg(s, 4, "parse_events: events %08x\n", events);
        if (s->thread) {
-               spin_lock(&s->thread_lock);
+               spin_lock_irqsave(&s->thread_lock, flags);
                s->thread_events |= events;
-               spin_unlock(&s->thread_lock);
+               spin_unlock_irqrestore(&s->thread_lock, flags);
 
-               wake_up(&s->thread_wait);
+               wake_up_process(s->thread);
        }
 } /* pcmcia_parse_events */
 EXPORT_SYMBOL(pcmcia_parse_events);
@@ -717,8 +719,8 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
 {
         int ret = 0;
 
-       /* s->skt_sem also protects s->callback */
-       down(&s->skt_sem);
+       /* s->skt_mutex also protects s->callback */
+       mutex_lock(&s->skt_mutex);
 
        if (c) {
                /* registration */
@@ -734,7 +736,7 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
        } else
                s->callback = NULL;
  err:
-       up(&s->skt_sem);
+       mutex_unlock(&s->skt_mutex);
 
        return ret;
 }
@@ -752,7 +754,7 @@ int pccard_reset_card(struct pcmcia_socket *skt)
 
        cs_dbg(skt, 1, "resetting socket\n");
 
-       down(&skt->skt_sem);
+       mutex_lock(&skt->skt_mutex);
        do {
                if (!(skt->state & SOCKET_PRESENT)) {
                        ret = CS_NO_CARD;
@@ -781,7 +783,7 @@ int pccard_reset_card(struct pcmcia_socket *skt)
 
                ret = CS_SUCCESS;
        } while (0);
-       up(&skt->skt_sem);
+       mutex_unlock(&skt->skt_mutex);
 
        return ret;
 } /* reset_card */
@@ -797,7 +799,7 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
 
        cs_dbg(skt, 1, "suspending socket\n");
 
-       down(&skt->skt_sem);
+       mutex_lock(&skt->skt_mutex);
        do {
                if (!(skt->state & SOCKET_PRESENT)) {
                        ret = CS_NO_CARD;
@@ -814,7 +816,7 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
                }
                ret = socket_suspend(skt);
        } while (0);
-       up(&skt->skt_sem);
+       mutex_unlock(&skt->skt_mutex);
 
        return ret;
 } /* suspend_card */
@@ -827,7 +829,7 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
     
        cs_dbg(skt, 1, "waking up socket\n");
 
-       down(&skt->skt_sem);
+       mutex_lock(&skt->skt_mutex);
        do {
                if (!(skt->state & SOCKET_PRESENT)) {
                        ret = CS_NO_CARD;
@@ -841,7 +843,7 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
                if (!ret && skt->callback)
                        skt->callback->resume(skt);
        } while (0);
-       up(&skt->skt_sem);
+       mutex_unlock(&skt->skt_mutex);
 
        return ret;
 } /* resume_card */
@@ -855,7 +857,7 @@ int pcmcia_eject_card(struct pcmcia_socket *skt)
     
        cs_dbg(skt, 1, "user eject request\n");
 
-       down(&skt->skt_sem);
+       mutex_lock(&skt->skt_mutex);
        do {
                if (!(skt->state & SOCKET_PRESENT)) {
                        ret = -ENODEV;
@@ -871,7 +873,7 @@ int pcmcia_eject_card(struct pcmcia_socket *skt)
                socket_remove(skt);
                ret = 0;
        } while (0);
-       up(&skt->skt_sem);
+       mutex_unlock(&skt->skt_mutex);
 
        return ret;
 } /* eject_card */
@@ -884,7 +886,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
 
        cs_dbg(skt, 1, "user insert request\n");
 
-       down(&skt->skt_sem);
+       mutex_lock(&skt->skt_mutex);
        do {
                if (skt->state & SOCKET_PRESENT) {
                        ret = -EBUSY;
@@ -896,25 +898,21 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
                }
                ret = 0;
        } while (0);
-       up(&skt->skt_sem);
+       mutex_unlock(&skt->skt_mutex);
 
        return ret;
 } /* insert_card */
 EXPORT_SYMBOL(pcmcia_insert_card);
 
 
-static int pcmcia_socket_uevent(struct class_device *dev, char **envp,
-                               int num_envp, char *buffer, int buffer_size)
+static int pcmcia_socket_uevent(struct device *dev,
+                               struct kobj_uevent_env *env)
 {
        struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
-       int i = 0, length = 0;
 
-       if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-                          &length, "SOCKET_NO=%u", s->sock))
+       if (add_uevent_var(env, "SOCKET_NO=%u", s->sock))
                return -ENOMEM;
 
-       envp[i] = NULL;
-
        return 0;
 }
 
@@ -929,8 +927,8 @@ static void pcmcia_release_socket_class(struct class *data)
 
 struct class pcmcia_socket_class = {
        .name = "pcmcia_socket",
-       .uevent = pcmcia_socket_uevent,
-       .release = pcmcia_release_socket,
+       .dev_uevent = pcmcia_socket_uevent,
+       .dev_release = pcmcia_release_socket,
        .class_release = pcmcia_release_socket_class,
 };
 EXPORT_SYMBOL(pcmcia_socket_class);
@@ -938,20 +936,13 @@ EXPORT_SYMBOL(pcmcia_socket_class);
 
 static int __init init_pcmcia_cs(void)
 {
-       int ret;
-
        init_completion(&pcmcia_unload);
-       ret = class_register(&pcmcia_socket_class);
-       if (ret)
-               return (ret);
-       return class_interface_register(&pccard_sysfs_interface);
+       return class_register(&pcmcia_socket_class);
 }
 
 static void __exit exit_pcmcia_cs(void)
 {
-       class_interface_unregister(&pccard_sysfs_interface);
        class_unregister(&pcmcia_socket_class);
-
        wait_for_completion(&pcmcia_unload);
 }