fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / arm / kernel / ecard.c
index d3dafbf..71257e3 100644 (file)
  */
 #define ECARD_C
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 
 #include <asm/dma.h>
 #include <asm/ecard.h>
 #define HAVE_EXPMASK
 #endif
 
-enum req {
-       req_readbytes,
-       req_reset
-};
-
 struct ecard_request {
-       enum req        req;
+       void            (*fn)(struct ecard_request *);
        ecard_t         *ec;
        unsigned int    address;
        unsigned int    length;
        unsigned int    use_loader;
        void            *buffer;
+       struct completion *complete;
 };
 
 struct expcard_blacklist {
@@ -88,27 +85,21 @@ static struct expcard_blacklist __initdata blacklist[] = {
 };
 
 asmlinkage extern int
-ecard_loader_reset(volatile unsigned char *pa, loader_t loader);
+ecard_loader_reset(unsigned long base, loader_t loader);
 asmlinkage extern int
-ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader);
+ecard_loader_read(int off, unsigned long base, loader_t loader);
 
-static const struct ecard_id *
-ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec);
-
-static inline unsigned short
-ecard_getu16(unsigned char *v)
+static inline unsigned short ecard_getu16(unsigned char *v)
 {
        return v[0] | v[1] << 8;
 }
 
-static inline signed long
-ecard_gets24(unsigned char *v)
+static inline signed long ecard_gets24(unsigned char *v)
 {
        return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
 }
 
-static inline ecard_t *
-slot_to_ecard(unsigned int slot)
+static inline ecard_t *slot_to_ecard(unsigned int slot)
 {
        return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
 }
@@ -125,27 +116,31 @@ slot_to_ecard(unsigned int slot)
  * From a security standpoint, we trust the card vendors.  This
  * may be a misplaced trust.
  */
-#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
-#define POD_INT_ADDR(x)        ((volatile unsigned char *)\
-                        ((BUS_ADDR((x)) - IO_BASE) + IO_START))
-
-static inline void ecard_task_reset(struct ecard_request *req)
+static void ecard_task_reset(struct ecard_request *req)
 {
        struct expansion_card *ec = req->ec;
-       if (ec->loader)
-               ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader);
+       struct resource *res;
+
+       res = ec->slot_no == 8
+               ? &ec->resource[ECARD_RES_MEMC]
+               : ec->type == ECARD_EASI
+                 ? &ec->resource[ECARD_RES_EASI]
+                 : &ec->resource[ECARD_RES_IOCSYNC];
+
+       ecard_loader_reset(res->start, ec->loader);
 }
 
-static void
-ecard_task_readbytes(struct ecard_request *req)
+static void ecard_task_readbytes(struct ecard_request *req)
 {
-       unsigned char *buf = (unsigned char *)req->buffer;
-       volatile unsigned char *base_addr =
-               (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr);
+       struct expansion_card *ec = req->ec;
+       unsigned char *buf = req->buffer;
        unsigned int len = req->length;
        unsigned int off = req->address;
 
-       if (req->ec->slot_no == 8) {
+       if (ec->slot_no == 8) {
+               void __iomem *base = (void __iomem *)
+                               ec->resource[ECARD_RES_MEMC].start;
+
                /*
                 * The card maintains an index which increments the address
                 * into a 4096-byte page on each access.  We need to keep
@@ -165,7 +160,7 @@ ecard_task_readbytes(struct ecard_request *req)
                 * greater than the offset, reset the hardware index counter.
                 */
                if (off == 0 || index > off) {
-                       *base_addr = 0;
+                       writeb(0, base);
                        index = 0;
                }
 
@@ -174,21 +169,24 @@ ecard_task_readbytes(struct ecard_request *req)
                 * required offset.  The read bytes are discarded.
                 */
                while (index < off) {
-                       unsigned char byte;
-                       byte = base_addr[page];
+                       readb(base + page);
                        index += 1;
                }
 
                while (len--) {
-                       *buf++ = base_addr[page];
+                       *buf++ = readb(base + page);
                        index += 1;
                }
        } else {
+               unsigned long base = (ec->type == ECARD_EASI
+                        ? &ec->resource[ECARD_RES_EASI]
+                        : &ec->resource[ECARD_RES_IOCSYNC])->start;
+               void __iomem *pbase = (void __iomem *)base;
 
-               if (!req->use_loader || !req->ec->loader) {
+               if (!req->use_loader || !ec->loader) {
                        off *= 4;
                        while (len--) {
-                               *buf++ = base_addr[off];
+                               *buf++ = readb(pbase + off);
                                off += 4;
                        }
                } else {
@@ -198,34 +196,17 @@ ecard_task_readbytes(struct ecard_request *req)
                                 * expansion card loader programs.
                                 */
                                *(unsigned long *)0x108 = 0;
-                               *buf++ = ecard_loader_read(off++, base_addr,
-                                                          req->ec->loader);
+                               *buf++ = ecard_loader_read(off++, base,
+                                                          ec->loader);
                        }
                }
        }
 
 }
 
-static void ecard_do_request(struct ecard_request *req)
-{
-       switch (req->req) {
-       case req_readbytes:
-               ecard_task_readbytes(req);
-               break;
-
-       case req_reset:
-               ecard_task_reset(req);
-               break;
-       }
-}
-
-#include <linux/completion.h>
-
-static pid_t ecard_pid;
-static wait_queue_head_t ecard_wait;
+static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
 static struct ecard_request *ecard_req;
-
-static DECLARE_COMPLETION(ecard_completion);
+static DEFINE_MUTEX(ecard_mutex);
 
 /*
  * Set up the expansion card daemon's page tables.
@@ -247,7 +228,7 @@ static void ecard_init_pgtables(struct mm_struct *mm)
         */
        pgd_t *src_pgd, *dst_pgd;
 
-       src_pgd = pgd_offset(mm, IO_BASE);
+       src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
        dst_pgd = pgd_offset(mm, IO_START);
 
        memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
@@ -282,8 +263,6 @@ static int ecard_init_mm(void)
 static int
 ecard_task(void * unused)
 {
-       struct task_struct *tsk = current;
-
        daemonize("kecardd");
 
        /*
@@ -298,17 +277,13 @@ ecard_task(void * unused)
        while (1) {
                struct ecard_request *req;
 
-               do {
-                       req = xchg(&ecard_req, NULL);
+               wait_event_interruptible(ecard_wait, ecard_req != NULL);
 
-                       if (req == NULL) {
-                               sigemptyset(&tsk->pending.signal);
-                               interruptible_sleep_on(&ecard_wait);
-                       }
-               } while (req == NULL);
-
-               ecard_do_request(req);
-               complete(&ecard_completion);
+               req = xchg(&ecard_req, NULL);
+               if (req != NULL) {
+                       req->fn(req);
+                       complete(req->complete);
+               }
        }
 }
 
@@ -318,25 +293,21 @@ ecard_task(void * unused)
  * FIXME: The test here is not sufficient to detect if the
  * kcardd is running.
  */
-static void
-ecard_call(struct ecard_request *req)
+static void ecard_call(struct ecard_request *req)
 {
-       /*
-        * Make sure we have a context that is able to sleep.
-        */
-       if (current == &init_task || in_interrupt())
-               BUG();
+       DECLARE_COMPLETION_ONSTACK(completion);
 
-       if (ecard_pid <= 0)
-               ecard_pid = kernel_thread(ecard_task, NULL, CLONE_KERNEL);
+       req->complete = &completion;
 
+       mutex_lock(&ecard_mutex);
        ecard_req = req;
        wake_up(&ecard_wait);
 
        /*
         * Now wait for kecardd to run.
         */
-       wait_for_completion(&ecard_completion);
+       wait_for_completion(&completion);
+       mutex_unlock(&ecard_mutex);
 }
 
 /* ======================= Mid-level card control ===================== */
@@ -346,7 +317,7 @@ ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
 {
        struct ecard_request req;
 
-       req.req         = req_readbytes;
+       req.fn          = ecard_task_readbytes;
        req.ec          = ec;
        req.address     = off;
        req.length      = len;
@@ -382,7 +353,7 @@ int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
                }
                if (c_id(&excd) == 0x80) { /* loader */
                        if (!ec->loader) {
-                               ec->loader = (loader_t)kmalloc(c_len(&excd),
+                               ec->loader = kmalloc(c_len(&excd),
                                                               GFP_KERNEL);
                                if (ec->loader)
                                        ecard_readbytes(ec->loader, ec,
@@ -437,7 +408,7 @@ static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
 
 static int ecard_def_irq_pending(ecard_t *ec)
 {
-       return !ec->irqmask || ec->irqaddr[0] & ec->irqmask;
+       return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
 }
 
 static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
@@ -452,7 +423,7 @@ static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
 
 static int ecard_def_fiq_pending(ecard_t *ec)
 {
-       return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask;
+       return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
 }
 
 static expansioncard_ops_t ecard_default_ops = {
@@ -499,7 +470,8 @@ static void ecard_irq_mask(unsigned int irqnr)
        }
 }
 
-static struct irqchip ecard_chip = {
+static struct irq_chip ecard_chip = {
+       .name   = "ECARD",
        .ack    = ecard_irq_mask,
        .mask   = ecard_irq_mask,
        .unmask = ecard_irq_unmask,
@@ -534,27 +506,33 @@ void ecard_disablefiq(unsigned int fiqnr)
        }
 }
 
-static void
-ecard_dump_irq_state(ecard_t *ec)
+static void ecard_dump_irq_state(void)
 {
-       printk("  %d: %sclaimed, ",
-              ec->slot_no,
-              ec->claimed ? "" : "not ");
-
-       if (ec->ops && ec->ops->irqpending &&
-           ec->ops != &ecard_default_ops)
-               printk("irq %spending\n",
-                      ec->ops->irqpending(ec) ? "" : "not ");
-       else
-               printk("irqaddr %p, mask = %02X, status = %02X\n",
-                      ec->irqaddr, ec->irqmask, *ec->irqaddr);
+       ecard_t *ec;
+
+       printk("Expansion card IRQ state:\n");
+
+       for (ec = cards; ec; ec = ec->next) {
+               if (ec->slot_no == 8)
+                       continue;
+
+               printk("  %d: %sclaimed, ",
+                      ec->slot_no, ec->claimed ? "" : "not ");
+
+               if (ec->ops && ec->ops->irqpending &&
+                   ec->ops != &ecard_default_ops)
+                       printk("irq %spending\n",
+                              ec->ops->irqpending(ec) ? "" : "not ");
+               else
+                       printk("irqaddr %p, mask = %02X, status = %02X\n",
+                              ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
+       }
 }
 
-static void ecard_check_lockup(struct irqdesc *desc)
+static void ecard_check_lockup(struct irq_desc *desc)
 {
        static unsigned long last;
        static int lockup;
-       ecard_t *ec;
 
        /*
         * If the timer interrupt has not run since the last million
@@ -572,11 +550,7 @@ static void ecard_check_lockup(struct irqdesc *desc)
                               "disabling all expansion card interrupts\n");
 
                        desc->chip->mask(IRQ_EXPANSIONCARD);
-
-                       printk("Expansion card IRQ state:\n");
-
-                       for (ec = cards; ec; ec = ec->next)
-                               ecard_dump_irq_state(ec);
+                       ecard_dump_irq_state();
                }
        } else
                lockup = 0;
@@ -588,11 +562,12 @@ static void ecard_check_lockup(struct irqdesc *desc)
        if (!last || time_after(jiffies, last + 5*HZ)) {
                last = jiffies;
                printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
+               ecard_dump_irq_state();
        }
 }
 
 static void
-ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
        ecard_t *ec;
        int called = 0;
@@ -610,8 +585,8 @@ ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
                        pending = ecard_default_ops.irqpending(ec);
 
                if (pending) {
-                       struct irqdesc *d = irq_desc + ec->irq;
-                       d->handle(ec->irq, d, regs);
+                       struct irq_desc *d = irq_desc + ec->irq;
+                       desc_handle_irq(ec->irq, d);
                        called ++;
                }
        }
@@ -634,7 +609,7 @@ static unsigned char first_set[] =
 };
 
 static void
-ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+ecard_irqexp_handler(unsigned int irq, struct irq_desc *desc)
 {
        const unsigned int statusmask = 15;
        unsigned int status;
@@ -645,7 +620,7 @@ ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg
                ecard_t *ec = slot_to_ecard(slot);
 
                if (ec->claimed) {
-                       struct irqdesc *d = irqdesc + ec->irq;
+                       struct irq_desc *d = irq_desc + ec->irq;
                        /*
                         * this ugly code is so that we can operate a
                         * prioritorising system:
@@ -658,7 +633,7 @@ ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg
                         * Serial cards should go in 0/1, ethernet/scsi in 2/3
                         * otherwise you will lose serial data at high speeds!
                         */
-                       d->handle(ec->irq, d, regs);
+                       desc_handle_irq(ec->irq, d);
                } else {
                        printk(KERN_WARNING "card%d: interrupt from unclaimed "
                               "card???\n", slot);
@@ -703,7 +678,7 @@ static int __init ecard_probeirqhw(void)
 #define IO_EC_MEMC8_BASE 0
 #endif
 
-unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
+unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
 {
        unsigned long address = 0;
        int slot = ec->slot_no;
@@ -807,81 +782,109 @@ static void ecard_proc_init(void)
                get_ecard_dev_info);
 }
 
-#define ec_set_resource(ec,nr,st,sz,flg)                       \
+#define ec_set_resource(ec,nr,st,sz)                           \
        do {                                                    \
                (ec)->resource[nr].name = ec->dev.bus_id;       \
                (ec)->resource[nr].start = st;                  \
                (ec)->resource[nr].end = (st) + (sz) - 1;       \
-               (ec)->resource[nr].flags = flg;                 \
+               (ec)->resource[nr].flags = IORESOURCE_MEM;      \
        } while (0)
 
-static void __init ecard_init_resources(struct expansion_card *ec)
+static void __init ecard_free_card(struct expansion_card *ec)
+{
+       int i;
+
+       for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+               if (ec->resource[i].flags)
+                       release_resource(&ec->resource[i]);
+
+       kfree(ec);
+}
+
+static struct expansion_card *__init ecard_alloc_card(int type, int slot)
 {
-       unsigned long base = PODSLOT_IOC4_BASE;
-       unsigned int slot = ec->slot_no;
+       struct expansion_card *ec;
+       unsigned long base;
        int i;
 
+       ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
+       if (!ec) {
+               ec = ERR_PTR(-ENOMEM);
+               goto nomem;
+       }
+
+       ec->slot_no = slot;
+       ec->type = type;
+       ec->irq = NO_IRQ;
+       ec->fiq = NO_IRQ;
+       ec->dma = NO_DMA;
+       ec->ops = &ecard_default_ops;
+
+       snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot);
+       ec->dev.parent = NULL;
+       ec->dev.bus = &ecard_bus_type;
+       ec->dev.dma_mask = &ec->dma_mask;
+       ec->dma_mask = (u64)0xffffffff;
+
        if (slot < 4) {
                ec_set_resource(ec, ECARD_RES_MEMC,
                                PODSLOT_MEMC_BASE + (slot << 14),
-                               PODSLOT_MEMC_SIZE, IORESOURCE_MEM);
-               base = PODSLOT_IOC0_BASE;
-       }
+                               PODSLOT_MEMC_SIZE);
+               base = PODSLOT_IOC0_BASE + (slot << 14);
+       } else
+               base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
 
 #ifdef CONFIG_ARCH_RPC
        if (slot < 8) {
                ec_set_resource(ec, ECARD_RES_EASI,
                                PODSLOT_EASI_BASE + (slot << 24),
-                               PODSLOT_EASI_SIZE, IORESOURCE_MEM);
+                               PODSLOT_EASI_SIZE);
        }
 
        if (slot == 8) {
-               ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE,
-                               NETSLOT_SIZE, IORESOURCE_MEM);
+               ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
        } else
 #endif
 
-       for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) {
+       for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
                ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
-                               base + (slot << 14) + (i << 19),
-                               PODSLOT_IOC_SIZE, IORESOURCE_MEM);
-       }
+                               base + (i << 19), PODSLOT_IOC_SIZE);
 
        for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
-               if (ec->resource[i].start &&
+               if (ec->resource[i].flags &&
                    request_resource(&iomem_resource, &ec->resource[i])) {
                        printk(KERN_ERR "%s: resource(s) not available\n",
                                ec->dev.bus_id);
                        ec->resource[i].end -= ec->resource[i].start;
                        ec->resource[i].start = 0;
+                       ec->resource[i].flags = 0;
                }
        }
+
+ nomem:
+       return ec;
 }
 
-static ssize_t ecard_show_irq(struct device *dev, char *buf)
+static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct expansion_card *ec = ECARD_DEV(dev);
        return sprintf(buf, "%u\n", ec->irq);
 }
 
-static DEVICE_ATTR(irq, S_IRUGO, ecard_show_irq, NULL);
-
-static ssize_t ecard_show_dma(struct device *dev, char *buf)
+static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct expansion_card *ec = ECARD_DEV(dev);
        return sprintf(buf, "%u\n", ec->dma);
 }
 
-static DEVICE_ATTR(dma, S_IRUGO, ecard_show_dma, NULL);
-
-static ssize_t ecard_show_resources(struct device *dev, char *buf)
+static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct expansion_card *ec = ECARD_DEV(dev);
        char *str = buf;
        int i;
 
        for (i = 0; i < ECARD_NUM_RESOURCES; i++)
-               str += sprintf(str, "%08lx %08lx %08lx\n",
+               str += sprintf(str, "%08x %08x %08lx\n",
                                ec->resource[i].start,
                                ec->resource[i].end,
                                ec->resource[i].flags);
@@ -889,23 +892,33 @@ static ssize_t ecard_show_resources(struct device *dev, char *buf)
        return str - buf;
 }
 
-static DEVICE_ATTR(resource, S_IRUGO, ecard_show_resources, NULL);
-
-static ssize_t ecard_show_vendor(struct device *dev, char *buf)
+static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct expansion_card *ec = ECARD_DEV(dev);
        return sprintf(buf, "%u\n", ec->cid.manufacturer);
 }
 
-static DEVICE_ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL);
-
-static ssize_t ecard_show_device(struct device *dev, char *buf)
+static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct expansion_card *ec = ECARD_DEV(dev);
        return sprintf(buf, "%u\n", ec->cid.product);
 }
 
-static DEVICE_ATTR(device, S_IRUGO, ecard_show_device, NULL);
+static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC");
+}
+
+static struct device_attribute ecard_dev_attrs[] = {
+       __ATTR(device,   S_IRUGO, ecard_show_device,    NULL),
+       __ATTR(dma,      S_IRUGO, ecard_show_dma,       NULL),
+       __ATTR(irq,      S_IRUGO, ecard_show_irq,       NULL),
+       __ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
+       __ATTR(type,     S_IRUGO, ecard_show_type,      NULL),
+       __ATTR(vendor,   S_IRUGO, ecard_show_vendor,    NULL),
+       __ATTR_NULL,
+};
 
 
 int ecard_request_resources(struct expansion_card *ec)
@@ -955,21 +968,13 @@ ecard_probe(int slot, card_type_t type)
        ecard_t **ecp;
        ecard_t *ec;
        struct ex_ecid cid;
-       int i, rc = -ENOMEM;
+       int i, rc;
 
-       ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
-       if (!ec)
+       ec = ecard_alloc_card(type, slot);
+       if (IS_ERR(ec)) {
+               rc = PTR_ERR(ec);
                goto nomem;
-
-       memset(ec, 0, sizeof(ecard_t));
-
-       ec->slot_no     = slot;
-       ec->type        = type;
-       ec->irq         = NO_IRQ;
-       ec->fiq         = NO_IRQ;
-       ec->dma         = NO_DMA;
-       ec->card_desc   = NULL;
-       ec->ops         = &ecard_default_ops;
+       }
 
        rc = -ENODEV;
        if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0)
@@ -992,7 +997,7 @@ ecard_probe(int slot, card_type_t type)
        ec->cid.fiqmask = cid.r_fiqmask;
        ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
        ec->fiqaddr     =
-       ec->irqaddr     = (unsigned char *)ioaddr(ec->podaddr);
+       ec->irqaddr     = (void __iomem *)ioaddr(ec->podaddr);
 
        if (ec->cid.is) {
                ec->irqmask = ec->cid.irqmask;
@@ -1011,21 +1016,13 @@ ecard_probe(int slot, card_type_t type)
                        break;
                }
 
-       snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot);
-       ec->dev.parent = NULL;
-       ec->dev.bus    = &ecard_bus_type;
-       ec->dev.dma_mask = &ec->dma_mask;
-       ec->dma_mask = (u64)0xffffffff;
-
-       ecard_init_resources(ec);
-
        /*
         * hook the interrupt handlers
         */
        if (slot < 8) {
                ec->irq = 32 + slot;
                set_irq_chip(ec->irq, &ecard_chip);
-               set_irq_handler(ec->irq, do_level_IRQ);
+               set_irq_handler(ec->irq, handle_level_irq);
                set_irq_flags(ec->irq, IRQF_VALID);
        }
 
@@ -1045,17 +1042,12 @@ ecard_probe(int slot, card_type_t type)
        slot_to_expcard[slot] = ec;
 
        device_register(&ec->dev);
-       device_create_file(&ec->dev, &dev_attr_dma);
-       device_create_file(&ec->dev, &dev_attr_irq);
-       device_create_file(&ec->dev, &dev_attr_resource);
-       device_create_file(&ec->dev, &dev_attr_vendor);
-       device_create_file(&ec->dev, &dev_attr_device);
 
        return 0;
 
-nodev:
-       kfree(ec);
-nomem:
+ nodev:
+       ecard_free_card(ec);
+ nomem:
        return rc;
 }
 
@@ -1066,9 +1058,14 @@ nomem:
  */
 static int __init ecard_init(void)
 {
-       int slot, irqhw;
+       int slot, irqhw, ret;
 
-       init_waitqueue_head(&ecard_wait);
+       ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL);
+       if (ret < 0) {
+               printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n",
+                      ret);
+               return ret;
+       }
 
        printk("Probing expansion cards\n");
 
@@ -1148,20 +1145,25 @@ static void ecard_drv_shutdown(struct device *dev)
        struct ecard_driver *drv = ECARD_DRV(dev->driver);
        struct ecard_request req;
 
-       if (drv->shutdown)
-               drv->shutdown(ec);
-       ecard_release(ec);
-       req.req = req_reset;
-       req.ec = ec;
-       ecard_call(&req);
+       if (dev->driver) {
+               if (drv->shutdown)
+                       drv->shutdown(ec);
+               ecard_release(ec);
+       }
+
+       /*
+        * If this card has a loader, call the reset handler.
+        */
+       if (ec->loader) {
+               req.fn = ecard_task_reset;
+               req.ec = ec;
+               ecard_call(&req);
+       }
 }
 
 int ecard_register_driver(struct ecard_driver *drv)
 {
        drv->drv.bus = &ecard_bus_type;
-       drv->drv.probe = ecard_drv_probe;
-       drv->drv.remove = ecard_drv_remove;
-       drv->drv.shutdown = ecard_drv_shutdown;
 
        return driver_register(&drv->drv);
 }
@@ -1187,8 +1189,12 @@ static int ecard_match(struct device *_dev, struct device_driver *_drv)
 }
 
 struct bus_type ecard_bus_type = {
-       .name   = "ecard",
-       .match  = ecard_match,
+       .name           = "ecard",
+       .dev_attrs      = ecard_dev_attrs,
+       .match          = ecard_match,
+       .probe          = ecard_drv_probe,
+       .remove         = ecard_drv_remove,
+       .shutdown       = ecard_drv_shutdown,
 };
 
 static int ecard_bus_init(void)
@@ -1199,7 +1205,7 @@ static int ecard_bus_init(void)
 postcore_initcall(ecard_bus_init);
 
 EXPORT_SYMBOL(ecard_readchunk);
-EXPORT_SYMBOL(ecard_address);
+EXPORT_SYMBOL(__ecard_address);
 EXPORT_SYMBOL(ecard_register_driver);
 EXPORT_SYMBOL(ecard_remove_driver);
 EXPORT_SYMBOL(ecard_bus_type);