blob: 1a6cfc8ca2770f91f675a18add1485bb0d787d2f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/arm/kernel/ecard.c
3 *
4 * Copyright 1995-2001 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Find all installed expansion cards, and handle interrupts from them.
11 *
12 * Created from information from Acorns RiscOS3 PRMs
13 *
14 * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether
15 * podule slot.
16 * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work.
17 * 12-Sep-1997 RMK Created new handling of interrupt enables/disables
18 * - cards can now register their own routine to control
19 * interrupts (recommended).
20 * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled
21 * on reset from Linux. (Caused cards not to respond
22 * under RiscOS without hard reset).
23 * 15-Feb-1998 RMK Added DMA support
24 * 12-Sep-1998 RMK Added EASI support
25 * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment.
26 * 17-Apr-1999 RMK Support for EASI Type C cycles.
27 */
28#define ECARD_C
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/types.h>
33#include <linux/sched.h>
34#include <linux/interrupt.h>
35#include <linux/completion.h>
36#include <linux/reboot.h>
37#include <linux/mm.h>
38#include <linux/slab.h>
39#include <linux/proc_fs.h>
Alexey Dobriyan9b001212008-04-29 01:01:49 -070040#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/device.h>
42#include <linux/init.h>
Arjan van de Ven00431702006-01-12 18:42:23 +000043#include <linux/mutex.h>
Eric W. Biederman134c99e2007-04-26 00:04:40 -070044#include <linux/kthread.h>
Russell Kingb4ac0842012-03-01 17:50:33 +000045#include <linux/irq.h>
Russell King10bdaaa2007-05-10 18:40:51 +010046#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#include <asm/dma.h>
49#include <asm/ecard.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010050#include <mach/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <asm/irq.h>
52#include <asm/mmu_context.h>
53#include <asm/mach/irq.h>
54#include <asm/tlbflush.h>
55
Russell Kingc0b04d12007-05-03 10:20:47 +010056#include "ecard.h"
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#ifndef CONFIG_ARCH_RPC
59#define HAVE_EXPMASK
60#endif
61
62struct ecard_request {
63 void (*fn)(struct ecard_request *);
64 ecard_t *ec;
65 unsigned int address;
66 unsigned int length;
67 unsigned int use_loader;
68 void *buffer;
69 struct completion *complete;
70};
71
72struct expcard_blacklist {
73 unsigned short manufacturer;
74 unsigned short product;
75 const char *type;
76};
77
78static ecard_t *cards;
79static ecard_t *slot_to_expcard[MAX_ECARDS];
80static unsigned int ectcr;
81#ifdef HAS_EXPMASK
82static unsigned int have_expmask;
83#endif
84
85/* List of descriptions of cards which don't have an extended
86 * identification, or chunk directories containing a description.
87 */
88static struct expcard_blacklist __initdata blacklist[] = {
89 { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
90};
91
92asmlinkage extern int
93ecard_loader_reset(unsigned long base, loader_t loader);
94asmlinkage extern int
95ecard_loader_read(int off, unsigned long base, loader_t loader);
96
97static inline unsigned short ecard_getu16(unsigned char *v)
98{
99 return v[0] | v[1] << 8;
100}
101
102static inline signed long ecard_gets24(unsigned char *v)
103{
104 return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
105}
106
107static inline ecard_t *slot_to_ecard(unsigned int slot)
108{
109 return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
110}
111
112/* ===================== Expansion card daemon ======================== */
113/*
114 * Since the loader programs on the expansion cards need to be run
115 * in a specific environment, create a separate task with this
116 * environment up, and pass requests to this task as and when we
117 * need to.
118 *
119 * This should allow 99% of loaders to be called from Linux.
120 *
121 * From a security standpoint, we trust the card vendors. This
122 * may be a misplaced trust.
123 */
124static void ecard_task_reset(struct ecard_request *req)
125{
126 struct expansion_card *ec = req->ec;
127 struct resource *res;
128
129 res = ec->slot_no == 8
130 ? &ec->resource[ECARD_RES_MEMC]
Russell King5559bca2007-05-03 10:47:37 +0100131 : ec->easi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 ? &ec->resource[ECARD_RES_EASI]
133 : &ec->resource[ECARD_RES_IOCSYNC];
134
135 ecard_loader_reset(res->start, ec->loader);
136}
137
138static void ecard_task_readbytes(struct ecard_request *req)
139{
140 struct expansion_card *ec = req->ec;
141 unsigned char *buf = req->buffer;
142 unsigned int len = req->length;
143 unsigned int off = req->address;
144
145 if (ec->slot_no == 8) {
146 void __iomem *base = (void __iomem *)
147 ec->resource[ECARD_RES_MEMC].start;
148
149 /*
150 * The card maintains an index which increments the address
151 * into a 4096-byte page on each access. We need to keep
152 * track of the counter.
153 */
154 static unsigned int index;
155 unsigned int page;
156
157 page = (off >> 12) * 4;
158 if (page > 256 * 4)
159 return;
160
161 off &= 4095;
162
163 /*
164 * If we are reading offset 0, or our current index is
165 * greater than the offset, reset the hardware index counter.
166 */
167 if (off == 0 || index > off) {
168 writeb(0, base);
169 index = 0;
170 }
171
172 /*
173 * Increment the hardware index counter until we get to the
174 * required offset. The read bytes are discarded.
175 */
176 while (index < off) {
177 readb(base + page);
178 index += 1;
179 }
180
181 while (len--) {
182 *buf++ = readb(base + page);
183 index += 1;
184 }
185 } else {
Russell King5559bca2007-05-03 10:47:37 +0100186 unsigned long base = (ec->easi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 ? &ec->resource[ECARD_RES_EASI]
188 : &ec->resource[ECARD_RES_IOCSYNC])->start;
189 void __iomem *pbase = (void __iomem *)base;
190
191 if (!req->use_loader || !ec->loader) {
192 off *= 4;
193 while (len--) {
194 *buf++ = readb(pbase + off);
195 off += 4;
196 }
197 } else {
198 while(len--) {
199 /*
200 * The following is required by some
201 * expansion card loader programs.
202 */
203 *(unsigned long *)0x108 = 0;
204 *buf++ = ecard_loader_read(off++, base,
205 ec->loader);
206 }
207 }
208 }
209
210}
211
212static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
213static struct ecard_request *ecard_req;
Arjan van de Ven00431702006-01-12 18:42:23 +0000214static DEFINE_MUTEX(ecard_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216/*
217 * Set up the expansion card daemon's page tables.
218 */
219static void ecard_init_pgtables(struct mm_struct *mm)
220{
221 struct vm_area_struct vma;
222
223 /* We want to set up the page tables for the following mapping:
224 * Virtual Physical
225 * 0x03000000 0x03000000
226 * 0x03010000 unmapped
227 * 0x03210000 0x03210000
228 * 0x03400000 unmapped
229 * 0x08000000 0x08000000
230 * 0x10000000 unmapped
231 *
232 * FIXME: we don't follow this 100% yet.
233 */
234 pgd_t *src_pgd, *dst_pgd;
235
236 src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
237 dst_pgd = pgd_offset(mm, IO_START);
238
239 memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
240
Russell King5e4cdb82011-07-07 11:40:52 +0100241 src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 dst_pgd = pgd_offset(mm, EASI_START);
243
244 memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
245
246 vma.vm_mm = mm;
247
248 flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
249 flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
250}
251
252static int ecard_init_mm(void)
253{
254 struct mm_struct * mm = mm_alloc();
255 struct mm_struct *active_mm = current->active_mm;
256
257 if (!mm)
258 return -ENOMEM;
259
260 current->mm = mm;
261 current->active_mm = mm;
262 activate_mm(active_mm, mm);
263 mmdrop(active_mm);
264 ecard_init_pgtables(mm);
265 return 0;
266}
267
268static int
269ecard_task(void * unused)
270{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 /*
272 * Allocate a mm. We're not a lazy-TLB kernel task since we need
273 * to set page table entries where the user space would be. Note
274 * that this also creates the page tables. Failure is not an
275 * option here.
276 */
277 if (ecard_init_mm())
278 panic("kecardd: unable to alloc mm\n");
279
280 while (1) {
281 struct ecard_request *req;
282
283 wait_event_interruptible(ecard_wait, ecard_req != NULL);
284
285 req = xchg(&ecard_req, NULL);
286 if (req != NULL) {
287 req->fn(req);
288 complete(req->complete);
289 }
290 }
291}
292
293/*
294 * Wake the expansion card daemon to action our request.
295 *
296 * FIXME: The test here is not sufficient to detect if the
297 * kcardd is running.
298 */
299static void ecard_call(struct ecard_request *req)
300{
Peter Zijlstra6e9a4732006-09-30 23:28:10 -0700301 DECLARE_COMPLETION_ONSTACK(completion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 req->complete = &completion;
304
Arjan van de Ven00431702006-01-12 18:42:23 +0000305 mutex_lock(&ecard_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 ecard_req = req;
307 wake_up(&ecard_wait);
308
309 /*
310 * Now wait for kecardd to run.
311 */
312 wait_for_completion(&completion);
Arjan van de Ven00431702006-01-12 18:42:23 +0000313 mutex_unlock(&ecard_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
315
316/* ======================= Mid-level card control ===================== */
317
318static void
319ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
320{
321 struct ecard_request req;
322
323 req.fn = ecard_task_readbytes;
324 req.ec = ec;
325 req.address = off;
326 req.length = len;
327 req.use_loader = useld;
328 req.buffer = addr;
329
330 ecard_call(&req);
331}
332
333int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
334{
335 struct ex_chunk_dir excd;
336 int index = 16;
337 int useld = 0;
338
339 if (!ec->cid.cd)
340 return 0;
341
342 while(1) {
343 ecard_readbytes(&excd, ec, index, 8, useld);
344 index += 8;
345 if (c_id(&excd) == 0) {
346 if (!useld && ec->loader) {
347 useld = 1;
348 index = 0;
349 continue;
350 }
351 return 0;
352 }
353 if (c_id(&excd) == 0xf0) { /* link */
354 index = c_start(&excd);
355 continue;
356 }
357 if (c_id(&excd) == 0x80) { /* loader */
358 if (!ec->loader) {
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800359 ec->loader = kmalloc(c_len(&excd),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 GFP_KERNEL);
361 if (ec->loader)
362 ecard_readbytes(ec->loader, ec,
363 (int)c_start(&excd),
364 c_len(&excd), useld);
365 else
366 return 0;
367 }
368 continue;
369 }
370 if (c_id(&excd) == id && num-- == 0)
371 break;
372 }
373
374 if (c_id(&excd) & 0x80) {
375 switch (c_id(&excd) & 0x70) {
376 case 0x70:
377 ecard_readbytes((unsigned char *)excd.d.string, ec,
378 (int)c_start(&excd), c_len(&excd),
379 useld);
380 break;
381 case 0x00:
382 break;
383 }
384 }
385 cd->start_offset = c_start(&excd);
386 memcpy(cd->d.string, excd.d.string, 256);
387 return 1;
388}
389
390/* ======================= Interrupt control ============================ */
391
392static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
393{
394#ifdef HAS_EXPMASK
395 if (irqnr < 4 && have_expmask) {
396 have_expmask |= 1 << irqnr;
397 __raw_writeb(have_expmask, EXPMASK_ENABLE);
398 }
399#endif
400}
401
402static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
403{
404#ifdef HAS_EXPMASK
405 if (irqnr < 4 && have_expmask) {
406 have_expmask &= ~(1 << irqnr);
407 __raw_writeb(have_expmask, EXPMASK_ENABLE);
408 }
409#endif
410}
411
412static int ecard_def_irq_pending(ecard_t *ec)
413{
414 return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
415}
416
417static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
418{
419 panic("ecard_def_fiq_enable called - impossible");
420}
421
422static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
423{
424 panic("ecard_def_fiq_disable called - impossible");
425}
426
427static int ecard_def_fiq_pending(ecard_t *ec)
428{
429 return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
430}
431
432static expansioncard_ops_t ecard_default_ops = {
433 ecard_def_irq_enable,
434 ecard_def_irq_disable,
435 ecard_def_irq_pending,
436 ecard_def_fiq_enable,
437 ecard_def_fiq_disable,
438 ecard_def_fiq_pending
439};
440
441/*
442 * Enable and disable interrupts from expansion cards.
443 * (interrupts are disabled for these functions).
444 *
445 * They are not meant to be called directly, but via enable/disable_irq.
446 */
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100447static void ecard_irq_unmask(struct irq_data *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
Russell Kingc402c112012-03-01 17:54:11 +0000449 ecard_t *ec = irq_data_get_irq_chip_data(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 if (ec) {
452 if (!ec->ops)
453 ec->ops = &ecard_default_ops;
454
455 if (ec->claimed && ec->ops->irqenable)
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100456 ec->ops->irqenable(ec, d->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 else
458 printk(KERN_ERR "ecard: rejecting request to "
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100459 "enable IRQs for %d\n", d->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 }
461}
462
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100463static void ecard_irq_mask(struct irq_data *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{
Russell Kingc402c112012-03-01 17:54:11 +0000465 ecard_t *ec = irq_data_get_irq_chip_data(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 if (ec) {
468 if (!ec->ops)
469 ec->ops = &ecard_default_ops;
470
471 if (ec->ops && ec->ops->irqdisable)
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100472 ec->ops->irqdisable(ec, d->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 }
474}
475
David Brownell38c677c2006-08-01 22:26:25 +0100476static struct irq_chip ecard_chip = {
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100477 .name = "ECARD",
478 .irq_ack = ecard_irq_mask,
479 .irq_mask = ecard_irq_mask,
480 .irq_unmask = ecard_irq_unmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481};
482
483void ecard_enablefiq(unsigned int fiqnr)
484{
485 ecard_t *ec = slot_to_ecard(fiqnr);
486
487 if (ec) {
488 if (!ec->ops)
489 ec->ops = &ecard_default_ops;
490
491 if (ec->claimed && ec->ops->fiqenable)
492 ec->ops->fiqenable(ec, fiqnr);
493 else
494 printk(KERN_ERR "ecard: rejecting request to "
495 "enable FIQs for %d\n", fiqnr);
496 }
497}
498
499void ecard_disablefiq(unsigned int fiqnr)
500{
501 ecard_t *ec = slot_to_ecard(fiqnr);
502
503 if (ec) {
504 if (!ec->ops)
505 ec->ops = &ecard_default_ops;
506
507 if (ec->ops->fiqdisable)
508 ec->ops->fiqdisable(ec, fiqnr);
509 }
510}
511
512static void ecard_dump_irq_state(void)
513{
514 ecard_t *ec;
515
516 printk("Expansion card IRQ state:\n");
517
518 for (ec = cards; ec; ec = ec->next) {
519 if (ec->slot_no == 8)
520 continue;
521
522 printk(" %d: %sclaimed, ",
523 ec->slot_no, ec->claimed ? "" : "not ");
524
525 if (ec->ops && ec->ops->irqpending &&
526 ec->ops != &ecard_default_ops)
527 printk("irq %spending\n",
528 ec->ops->irqpending(ec) ? "" : "not ");
529 else
530 printk("irqaddr %p, mask = %02X, status = %02X\n",
531 ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
532 }
533}
534
Russell King10dd5ce2006-11-23 11:41:32 +0000535static void ecard_check_lockup(struct irq_desc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 static unsigned long last;
538 static int lockup;
539
540 /*
541 * If the timer interrupt has not run since the last million
542 * unrecognised expansion card interrupts, then there is
543 * something seriously wrong. Disable the expansion card
544 * interrupts so at least we can continue.
545 *
546 * Maybe we ought to start a timer to re-enable them some time
547 * later?
548 */
549 if (last == jiffies) {
550 lockup += 1;
551 if (lockup > 1000000) {
552 printk(KERN_ERR "\nInterrupt lockup detected - "
553 "disabling all expansion card interrupts\n");
554
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100555 desc->irq_data.chip->irq_mask(&desc->irq_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 ecard_dump_irq_state();
557 }
558 } else
559 lockup = 0;
560
561 /*
562 * If we did not recognise the source of this interrupt,
563 * warn the user, but don't flood the user with these messages.
564 */
565 if (!last || time_after(jiffies, last + 5*HZ)) {
566 last = jiffies;
567 printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
568 ecard_dump_irq_state();
569 }
570}
571
572static void
Russell King10dd5ce2006-11-23 11:41:32 +0000573ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
575 ecard_t *ec;
576 int called = 0;
577
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100578 desc->irq_data.chip->irq_mask(&desc->irq_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 for (ec = cards; ec; ec = ec->next) {
580 int pending;
581
582 if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8)
583 continue;
584
585 if (ec->ops && ec->ops->irqpending)
586 pending = ec->ops->irqpending(ec);
587 else
588 pending = ecard_default_ops.irqpending(ec);
589
590 if (pending) {
Dmitry Baryshkovd8aa0252008-10-09 13:36:24 +0100591 generic_handle_irq(ec->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 called ++;
593 }
594 }
Lennert Buytenhek4a87bac2010-11-29 10:21:01 +0100595 desc->irq_data.chip->irq_unmask(&desc->irq_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
597 if (called == 0)
598 ecard_check_lockup(desc);
599}
600
601#ifdef HAS_EXPMASK
602static unsigned char priority_masks[] =
603{
604 0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff
605};
606
607static unsigned char first_set[] =
608{
609 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
610 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00
611};
612
613static void
Russell King10dd5ce2006-11-23 11:41:32 +0000614ecard_irqexp_handler(unsigned int irq, struct irq_desc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{
616 const unsigned int statusmask = 15;
617 unsigned int status;
618
619 status = __raw_readb(EXPMASK_STATUS) & statusmask;
620 if (status) {
621 unsigned int slot = first_set[status];
622 ecard_t *ec = slot_to_ecard(slot);
623
624 if (ec->claimed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 /*
626 * this ugly code is so that we can operate a
627 * prioritorising system:
628 *
629 * Card 0 highest priority
630 * Card 1
631 * Card 2
632 * Card 3 lowest priority
633 *
634 * Serial cards should go in 0/1, ethernet/scsi in 2/3
635 * otherwise you will lose serial data at high speeds!
636 */
Dmitry Baryshkovd8aa0252008-10-09 13:36:24 +0100637 generic_handle_irq(ec->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 } else {
639 printk(KERN_WARNING "card%d: interrupt from unclaimed "
640 "card???\n", slot);
641 have_expmask &= ~(1 << slot);
642 __raw_writeb(have_expmask, EXPMASK_ENABLE);
643 }
644 } else
645 printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
646}
647
648static int __init ecard_probeirqhw(void)
649{
650 ecard_t *ec;
651 int found;
652
653 __raw_writeb(0x00, EXPMASK_ENABLE);
654 __raw_writeb(0xff, EXPMASK_STATUS);
655 found = (__raw_readb(EXPMASK_STATUS) & 15) == 0;
656 __raw_writeb(0xff, EXPMASK_ENABLE);
657
658 if (found) {
659 printk(KERN_DEBUG "Expansion card interrupt "
660 "management hardware found\n");
661
662 /* for each card present, set a bit to '1' */
663 have_expmask = 0x80000000;
664
665 for (ec = cards; ec; ec = ec->next)
666 have_expmask |= 1 << ec->slot_no;
667
668 __raw_writeb(have_expmask, EXPMASK_ENABLE);
669 }
670
671 return found;
672}
673#else
674#define ecard_irqexp_handler NULL
675#define ecard_probeirqhw() (0)
676#endif
677
Russell King1ace7562011-07-07 10:56:41 +0100678static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Russell King06cf0b52011-07-07 11:07:36 +0100680 void __iomem *address = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 int slot = ec->slot_no;
682
683 if (ec->slot_no == 8)
Russell King06cf0b52011-07-07 11:07:36 +0100684 return ECARD_MEMC8_BASE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
686 ectcr &= ~(1 << slot);
687
688 switch (type) {
689 case ECARD_MEMC:
690 if (slot < 4)
Russell King06cf0b52011-07-07 11:07:36 +0100691 address = ECARD_MEMC_BASE + (slot << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 break;
693
694 case ECARD_IOC:
695 if (slot < 4)
Russell King06cf0b52011-07-07 11:07:36 +0100696 address = ECARD_IOC_BASE + (slot << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 else
Russell King06cf0b52011-07-07 11:07:36 +0100698 address = ECARD_IOC4_BASE + ((slot - 4) << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (address)
Russell King06cf0b52011-07-07 11:07:36 +0100700 address += speed << 19;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 break;
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 case ECARD_EASI:
Russell King06cf0b52011-07-07 11:07:36 +0100704 address = ECARD_EASI_BASE + (slot << 24);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 if (speed == ECARD_FAST)
706 ectcr |= 1 << slot;
707 break;
Russell King06cf0b52011-07-07 11:07:36 +0100708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 default:
710 break;
711 }
712
713#ifdef IOMD_ECTCR
714 iomd_writeb(ectcr, IOMD_ECTCR);
715#endif
Russell King06cf0b52011-07-07 11:07:36 +0100716 return address;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717}
718
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700719static int ecard_prints(struct seq_file *m, ecard_t *ec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700721 seq_printf(m, " %d: %s ", ec->slot_no, ec->easi ? "EASI" : " ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 if (ec->cid.id == 0) {
724 struct in_chunk_dir incd;
725
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700726 seq_printf(m, "[%04X:%04X] ",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 ec->cid.manufacturer, ec->cid.product);
728
729 if (!ec->card_desc && ec->cid.cd &&
730 ecard_readchunk(&incd, ec, 0xf5, 0)) {
731 ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
732
733 if (ec->card_desc)
734 strcpy((char *)ec->card_desc, incd.d.string);
735 }
736
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700737 seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 } else
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700739 seq_printf(m, "Simple card %d\n", ec->cid.id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700741 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700744static int ecard_devices_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
746 ecard_t *ec = cards;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700748 while (ec) {
749 ecard_prints(m, ec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 ec = ec->next;
751 }
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700752 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700755static int ecard_devices_proc_open(struct inode *inode, struct file *file)
756{
757 return single_open(file, ecard_devices_proc_show, NULL);
758}
759
760static const struct file_operations bus_ecard_proc_fops = {
761 .owner = THIS_MODULE,
762 .open = ecard_devices_proc_open,
763 .read = seq_read,
764 .llseek = seq_lseek,
765 .release = single_release,
766};
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
769
770static void ecard_proc_init(void)
771{
Alexey Dobriyan9c370662008-04-29 01:01:41 -0700772 proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
Alexey Dobriyan9b001212008-04-29 01:01:49 -0700773 proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774}
775
776#define ec_set_resource(ec,nr,st,sz) \
777 do { \
Kay Sievers3f9787042008-05-30 17:42:11 +0200778 (ec)->resource[nr].name = dev_name(&ec->dev); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 (ec)->resource[nr].start = st; \
780 (ec)->resource[nr].end = (st) + (sz) - 1; \
781 (ec)->resource[nr].flags = IORESOURCE_MEM; \
782 } while (0)
783
784static void __init ecard_free_card(struct expansion_card *ec)
785{
786 int i;
787
788 for (i = 0; i < ECARD_NUM_RESOURCES; i++)
789 if (ec->resource[i].flags)
790 release_resource(&ec->resource[i]);
791
792 kfree(ec);
793}
794
795static struct expansion_card *__init ecard_alloc_card(int type, int slot)
796{
797 struct expansion_card *ec;
798 unsigned long base;
799 int i;
800
Russell Kingd2a02b92006-03-20 19:46:41 +0000801 ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 if (!ec) {
803 ec = ERR_PTR(-ENOMEM);
804 goto nomem;
805 }
806
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 ec->slot_no = slot;
Russell King5559bca2007-05-03 10:47:37 +0100808 ec->easi = type == ECARD_EASI;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 ec->irq = NO_IRQ;
810 ec->fiq = NO_IRQ;
811 ec->dma = NO_DMA;
812 ec->ops = &ecard_default_ops;
813
Kay Sievers1d559e22009-01-06 10:44:43 -0800814 dev_set_name(&ec->dev, "ecard%d", slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 ec->dev.parent = NULL;
816 ec->dev.bus = &ecard_bus_type;
817 ec->dev.dma_mask = &ec->dma_mask;
818 ec->dma_mask = (u64)0xffffffff;
Russell King69f4f332007-04-02 13:53:15 +0100819 ec->dev.coherent_dma_mask = ec->dma_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 if (slot < 4) {
822 ec_set_resource(ec, ECARD_RES_MEMC,
823 PODSLOT_MEMC_BASE + (slot << 14),
824 PODSLOT_MEMC_SIZE);
825 base = PODSLOT_IOC0_BASE + (slot << 14);
826 } else
827 base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
828
829#ifdef CONFIG_ARCH_RPC
830 if (slot < 8) {
831 ec_set_resource(ec, ECARD_RES_EASI,
832 PODSLOT_EASI_BASE + (slot << 24),
833 PODSLOT_EASI_SIZE);
834 }
835
836 if (slot == 8) {
837 ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
838 } else
839#endif
840
841 for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
842 ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
843 base + (i << 19), PODSLOT_IOC_SIZE);
844
845 for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
846 if (ec->resource[i].flags &&
847 request_resource(&iomem_resource, &ec->resource[i])) {
Greg Kroah-Hartmanfc3a8822008-05-02 06:02:41 +0200848 dev_err(&ec->dev, "resource(s) not available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 ec->resource[i].end -= ec->resource[i].start;
850 ec->resource[i].start = 0;
851 ec->resource[i].flags = 0;
852 }
853 }
854
855 nomem:
856 return ec;
857}
858
Yani Ioannouff381d22005-05-17 06:40:51 -0400859static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
861 struct expansion_card *ec = ECARD_DEV(dev);
862 return sprintf(buf, "%u\n", ec->irq);
863}
864
Yani Ioannouff381d22005-05-17 06:40:51 -0400865static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866{
867 struct expansion_card *ec = ECARD_DEV(dev);
868 return sprintf(buf, "%u\n", ec->dma);
869}
870
Yani Ioannouff381d22005-05-17 06:40:51 -0400871static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
873 struct expansion_card *ec = ECARD_DEV(dev);
874 char *str = buf;
875 int i;
876
877 for (i = 0; i < ECARD_NUM_RESOURCES; i++)
Russell Kingc9e41432006-07-03 13:29:03 +0100878 str += sprintf(str, "%08x %08x %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 ec->resource[i].start,
880 ec->resource[i].end,
881 ec->resource[i].flags);
882
883 return str - buf;
884}
885
Yani Ioannouff381d22005-05-17 06:40:51 -0400886static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
888 struct expansion_card *ec = ECARD_DEV(dev);
889 return sprintf(buf, "%u\n", ec->cid.manufacturer);
890}
891
Yani Ioannouff381d22005-05-17 06:40:51 -0400892static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893{
894 struct expansion_card *ec = ECARD_DEV(dev);
895 return sprintf(buf, "%u\n", ec->cid.product);
896}
897
Yani Ioannouff381d22005-05-17 06:40:51 -0400898static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
900 struct expansion_card *ec = ECARD_DEV(dev);
Russell King5559bca2007-05-03 10:47:37 +0100901 return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902}
903
904static struct device_attribute ecard_dev_attrs[] = {
905 __ATTR(device, S_IRUGO, ecard_show_device, NULL),
906 __ATTR(dma, S_IRUGO, ecard_show_dma, NULL),
907 __ATTR(irq, S_IRUGO, ecard_show_irq, NULL),
908 __ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
909 __ATTR(type, S_IRUGO, ecard_show_type, NULL),
910 __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL),
911 __ATTR_NULL,
912};
913
914
915int ecard_request_resources(struct expansion_card *ec)
916{
917 int i, err = 0;
918
919 for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
920 if (ecard_resource_end(ec, i) &&
921 !request_mem_region(ecard_resource_start(ec, i),
922 ecard_resource_len(ec, i),
923 ec->dev.driver->name)) {
924 err = -EBUSY;
925 break;
926 }
927 }
928
929 if (err) {
930 while (i--)
931 if (ecard_resource_end(ec, i))
932 release_mem_region(ecard_resource_start(ec, i),
933 ecard_resource_len(ec, i));
934 }
935 return err;
936}
937EXPORT_SYMBOL(ecard_request_resources);
938
939void ecard_release_resources(struct expansion_card *ec)
940{
941 int i;
942
943 for (i = 0; i < ECARD_NUM_RESOURCES; i++)
944 if (ecard_resource_end(ec, i))
945 release_mem_region(ecard_resource_start(ec, i),
946 ecard_resource_len(ec, i));
947}
948EXPORT_SYMBOL(ecard_release_resources);
949
Russell Kingc7b87f32007-05-10 16:46:13 +0100950void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
951{
952 ec->irq_data = irq_data;
953 barrier();
954 ec->ops = ops;
955}
956EXPORT_SYMBOL(ecard_setirq);
957
Russell King10bdaaa2007-05-10 18:40:51 +0100958void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
959 unsigned long offset, unsigned long maxsize)
960{
961 unsigned long start = ecard_resource_start(ec, res);
962 unsigned long end = ecard_resource_end(ec, res);
963
964 if (offset > (end - start))
965 return NULL;
966
967 start += offset;
968 if (maxsize && end - start > maxsize)
969 end = start + maxsize;
970
971 return devm_ioremap(&ec->dev, start, end - start);
972}
973EXPORT_SYMBOL(ecardm_iomap);
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975/*
976 * Probe for an expansion card.
977 *
978 * If bit 1 of the first byte of the card is set, then the
979 * card does not exist.
980 */
Russell Kingb4ac0842012-03-01 17:50:33 +0000981static int __init ecard_probe(int slot, unsigned irq, card_type_t type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
983 ecard_t **ecp;
984 ecard_t *ec;
985 struct ex_ecid cid;
Russell King1ace7562011-07-07 10:56:41 +0100986 void __iomem *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 int i, rc;
988
989 ec = ecard_alloc_card(type, slot);
990 if (IS_ERR(ec)) {
991 rc = PTR_ERR(ec);
992 goto nomem;
993 }
994
995 rc = -ENODEV;
Russell King1ace7562011-07-07 10:56:41 +0100996 if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 goto nodev;
998
999 cid.r_zero = 1;
1000 ecard_readbytes(&cid, ec, 0, 16, 0);
1001 if (cid.r_zero)
1002 goto nodev;
1003
1004 ec->cid.id = cid.r_id;
1005 ec->cid.cd = cid.r_cd;
1006 ec->cid.is = cid.r_is;
1007 ec->cid.w = cid.r_w;
1008 ec->cid.manufacturer = ecard_getu16(cid.r_manu);
1009 ec->cid.product = ecard_getu16(cid.r_prod);
1010 ec->cid.country = cid.r_country;
1011 ec->cid.irqmask = cid.r_irqmask;
1012 ec->cid.irqoff = ecard_gets24(cid.r_irqoff);
1013 ec->cid.fiqmask = cid.r_fiqmask;
1014 ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff);
1015 ec->fiqaddr =
Russell King1ace7562011-07-07 10:56:41 +01001016 ec->irqaddr = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 if (ec->cid.is) {
1019 ec->irqmask = ec->cid.irqmask;
1020 ec->irqaddr += ec->cid.irqoff;
1021 ec->fiqmask = ec->cid.fiqmask;
1022 ec->fiqaddr += ec->cid.fiqoff;
1023 } else {
1024 ec->irqmask = 1;
1025 ec->fiqmask = 4;
1026 }
1027
Ahmed S. Darwisheeea82f2007-02-05 16:10:25 -08001028 for (i = 0; i < ARRAY_SIZE(blacklist); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (blacklist[i].manufacturer == ec->cid.manufacturer &&
1030 blacklist[i].product == ec->cid.product) {
1031 ec->card_desc = blacklist[i].type;
1032 break;
1033 }
1034
Russell Kingb4ac0842012-03-01 17:50:33 +00001035 ec->irq = irq;
1036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 /*
1038 * hook the interrupt handlers
1039 */
1040 if (slot < 8) {
Thomas Gleixnerf38c02f2011-03-24 13:35:09 +01001041 irq_set_chip_and_handler(ec->irq, &ecard_chip,
1042 handle_level_irq);
Russell Kingc402c112012-03-01 17:54:11 +00001043 irq_set_chip_data(ec->irq, ec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 set_irq_flags(ec->irq, IRQF_VALID);
1045 }
1046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047#ifdef CONFIG_ARCH_RPC
1048 /* On RiscPC, only first two slots have DMA capability */
1049 if (slot < 2)
1050 ec->dma = 2 + slot;
1051#endif
1052
1053 for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
1054
1055 *ecp = ec;
1056 slot_to_expcard[slot] = ec;
1057
1058 device_register(&ec->dev);
1059
1060 return 0;
1061
1062 nodev:
1063 ecard_free_card(ec);
1064 nomem:
1065 return rc;
1066}
1067
1068/*
1069 * Initialise the expansion card system.
1070 * Locate all hardware - interrupt management and
1071 * actual cards.
1072 */
1073static int __init ecard_init(void)
1074{
Eric W. Biederman134c99e2007-04-26 00:04:40 -07001075 struct task_struct *task;
Russell Kingb4ac0842012-03-01 17:50:33 +00001076 int slot, irqhw, irqbase;
1077
1078 irqbase = irq_alloc_descs(-1, 0, 8, -1);
1079 if (irqbase < 0)
1080 return irqbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Eric W. Biederman134c99e2007-04-26 00:04:40 -07001082 task = kthread_run(ecard_task, NULL, "kecardd");
1083 if (IS_ERR(task)) {
Russell Kinge6aeb472007-05-03 10:55:46 +01001084 printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
Eric W. Biederman134c99e2007-04-26 00:04:40 -07001085 PTR_ERR(task));
Russell Kingb4ac0842012-03-01 17:50:33 +00001086 irq_free_descs(irqbase, 8);
Eric W. Biederman134c99e2007-04-26 00:04:40 -07001087 return PTR_ERR(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
1089
1090 printk("Probing expansion cards\n");
1091
1092 for (slot = 0; slot < 8; slot ++) {
Russell Kingb4ac0842012-03-01 17:50:33 +00001093 if (ecard_probe(slot, irqbase + slot, ECARD_EASI) == -ENODEV)
1094 ecard_probe(slot, irqbase + slot, ECARD_IOC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096
Russell Kingb4ac0842012-03-01 17:50:33 +00001097 ecard_probe(8, 11, ECARD_IOC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 irqhw = ecard_probeirqhw();
1100
Thomas Gleixner6845664a2011-03-24 13:25:22 +01001101 irq_set_chained_handler(IRQ_EXPANSIONCARD,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 irqhw ? ecard_irqexp_handler : ecard_irq_handler);
1103
1104 ecard_proc_init();
1105
1106 return 0;
1107}
1108
1109subsys_initcall(ecard_init);
1110
1111/*
1112 * ECARD "bus"
1113 */
1114static const struct ecard_id *
1115ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
1116{
1117 int i;
1118
1119 for (i = 0; ids[i].manufacturer != 65535; i++)
1120 if (ec->cid.manufacturer == ids[i].manufacturer &&
1121 ec->cid.product == ids[i].product)
1122 return ids + i;
1123
1124 return NULL;
1125}
1126
1127static int ecard_drv_probe(struct device *dev)
1128{
1129 struct expansion_card *ec = ECARD_DEV(dev);
1130 struct ecard_driver *drv = ECARD_DRV(dev->driver);
1131 const struct ecard_id *id;
1132 int ret;
1133
1134 id = ecard_match_device(drv->id_table, ec);
1135
Russell King9ecba1f2008-04-19 16:01:38 +01001136 ec->claimed = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 ret = drv->probe(ec, id);
1138 if (ret)
Russell King9ecba1f2008-04-19 16:01:38 +01001139 ec->claimed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 return ret;
1141}
1142
1143static int ecard_drv_remove(struct device *dev)
1144{
1145 struct expansion_card *ec = ECARD_DEV(dev);
1146 struct ecard_driver *drv = ECARD_DRV(dev->driver);
1147
1148 drv->remove(ec);
Russell King9ecba1f2008-04-19 16:01:38 +01001149 ec->claimed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Russell Kingc7b87f32007-05-10 16:46:13 +01001151 /*
1152 * Restore the default operations. We ensure that the
1153 * ops are set before we change the data.
1154 */
1155 ec->ops = &ecard_default_ops;
1156 barrier();
1157 ec->irq_data = NULL;
1158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 return 0;
1160}
1161
1162/*
1163 * Before rebooting, we must make sure that the expansion card is in a
1164 * sensible state, so it can be re-detected. This means that the first
1165 * page of the ROM must be visible. We call the expansion cards reset
1166 * handler, if any.
1167 */
1168static void ecard_drv_shutdown(struct device *dev)
1169{
1170 struct expansion_card *ec = ECARD_DEV(dev);
1171 struct ecard_driver *drv = ECARD_DRV(dev->driver);
1172 struct ecard_request req;
1173
Russell Kinge08b7542006-01-05 14:30:57 +00001174 if (dev->driver) {
1175 if (drv->shutdown)
1176 drv->shutdown(ec);
Russell King9ecba1f2008-04-19 16:01:38 +01001177 ec->claimed = 0;
Russell Kinge08b7542006-01-05 14:30:57 +00001178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
1180 /*
1181 * If this card has a loader, call the reset handler.
1182 */
1183 if (ec->loader) {
1184 req.fn = ecard_task_reset;
1185 req.ec = ec;
1186 ecard_call(&req);
1187 }
1188}
1189
1190int ecard_register_driver(struct ecard_driver *drv)
1191{
1192 drv->drv.bus = &ecard_bus_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
1194 return driver_register(&drv->drv);
1195}
1196
1197void ecard_remove_driver(struct ecard_driver *drv)
1198{
1199 driver_unregister(&drv->drv);
1200}
1201
1202static int ecard_match(struct device *_dev, struct device_driver *_drv)
1203{
1204 struct expansion_card *ec = ECARD_DEV(_dev);
1205 struct ecard_driver *drv = ECARD_DRV(_drv);
1206 int ret;
1207
1208 if (drv->id_table) {
1209 ret = ecard_match_device(drv->id_table, ec) != NULL;
1210 } else {
1211 ret = ec->cid.id == drv->id;
1212 }
1213
1214 return ret;
1215}
1216
1217struct bus_type ecard_bus_type = {
1218 .name = "ecard",
1219 .dev_attrs = ecard_dev_attrs,
1220 .match = ecard_match,
Russell Kinge08b7542006-01-05 14:30:57 +00001221 .probe = ecard_drv_probe,
1222 .remove = ecard_drv_remove,
1223 .shutdown = ecard_drv_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224};
1225
1226static int ecard_bus_init(void)
1227{
1228 return bus_register(&ecard_bus_type);
1229}
1230
1231postcore_initcall(ecard_bus_init);
1232
1233EXPORT_SYMBOL(ecard_readchunk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234EXPORT_SYMBOL(ecard_register_driver);
1235EXPORT_SYMBOL(ecard_remove_driver);
1236EXPORT_SYMBOL(ecard_bus_type);