X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fkernel%2Fecard.c;h=71257e3d513f4604ed1d01c3db5eb8fb565bcf47;hb=refs%2Fheads%2Fvserver;hp=d3dafbf4f3815bc1411bb30e7c55ac8d130a2968;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index d3dafbf4f..71257e3d5 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -27,18 +27,19 @@ */ #define ECARD_C -#include #include #include #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -53,18 +54,14 @@ #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 - -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);