xref: /OK3568_Linux_fs/kernel/arch/arm/mach-rpc/ecard.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  linux/arch/arm/kernel/ecard.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright 1995-2001 Russell King
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *  Find all installed expansion cards, and handle interrupts from them.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *  Created from information from Acorns RiscOS3 PRMs
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *  08-Dec-1996	RMK	Added code for the 9'th expansion card - the ether
12*4882a593Smuzhiyun  *			podule slot.
13*4882a593Smuzhiyun  *  06-May-1997	RMK	Added blacklist for cards whose loader doesn't work.
14*4882a593Smuzhiyun  *  12-Sep-1997	RMK	Created new handling of interrupt enables/disables
15*4882a593Smuzhiyun  *			- cards can now register their own routine to control
16*4882a593Smuzhiyun  *			interrupts (recommended).
17*4882a593Smuzhiyun  *  29-Sep-1997	RMK	Expansion card interrupt hardware not being re-enabled
18*4882a593Smuzhiyun  *			on reset from Linux. (Caused cards not to respond
19*4882a593Smuzhiyun  *			under RiscOS without hard reset).
20*4882a593Smuzhiyun  *  15-Feb-1998	RMK	Added DMA support
21*4882a593Smuzhiyun  *  12-Sep-1998	RMK	Added EASI support
22*4882a593Smuzhiyun  *  10-Jan-1999	RMK	Run loaders in a simulated RISC OS environment.
23*4882a593Smuzhiyun  *  17-Apr-1999	RMK	Support for EASI Type C cycles.
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun #define ECARD_C
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include <linux/module.h>
28*4882a593Smuzhiyun #include <linux/kernel.h>
29*4882a593Smuzhiyun #include <linux/types.h>
30*4882a593Smuzhiyun #include <linux/sched.h>
31*4882a593Smuzhiyun #include <linux/sched/mm.h>
32*4882a593Smuzhiyun #include <linux/interrupt.h>
33*4882a593Smuzhiyun #include <linux/completion.h>
34*4882a593Smuzhiyun #include <linux/reboot.h>
35*4882a593Smuzhiyun #include <linux/mm.h>
36*4882a593Smuzhiyun #include <linux/slab.h>
37*4882a593Smuzhiyun #include <linux/proc_fs.h>
38*4882a593Smuzhiyun #include <linux/seq_file.h>
39*4882a593Smuzhiyun #include <linux/device.h>
40*4882a593Smuzhiyun #include <linux/init.h>
41*4882a593Smuzhiyun #include <linux/mutex.h>
42*4882a593Smuzhiyun #include <linux/kthread.h>
43*4882a593Smuzhiyun #include <linux/irq.h>
44*4882a593Smuzhiyun #include <linux/io.h>
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #include <asm/dma.h>
47*4882a593Smuzhiyun #include <asm/ecard.h>
48*4882a593Smuzhiyun #include <mach/hardware.h>
49*4882a593Smuzhiyun #include <asm/irq.h>
50*4882a593Smuzhiyun #include <asm/mmu_context.h>
51*4882a593Smuzhiyun #include <asm/mach/irq.h>
52*4882a593Smuzhiyun #include <asm/tlbflush.h>
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #include "ecard.h"
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun struct ecard_request {
57*4882a593Smuzhiyun 	void		(*fn)(struct ecard_request *);
58*4882a593Smuzhiyun 	ecard_t		*ec;
59*4882a593Smuzhiyun 	unsigned int	address;
60*4882a593Smuzhiyun 	unsigned int	length;
61*4882a593Smuzhiyun 	unsigned int	use_loader;
62*4882a593Smuzhiyun 	void		*buffer;
63*4882a593Smuzhiyun 	struct completion *complete;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun struct expcard_quirklist {
67*4882a593Smuzhiyun 	unsigned short	 manufacturer;
68*4882a593Smuzhiyun 	unsigned short	 product;
69*4882a593Smuzhiyun 	const char	*type;
70*4882a593Smuzhiyun 	void (*init)(ecard_t *ec);
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static ecard_t *cards;
74*4882a593Smuzhiyun static ecard_t *slot_to_expcard[MAX_ECARDS];
75*4882a593Smuzhiyun static unsigned int ectcr;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun static void atomwide_3p_quirk(ecard_t *ec);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun /* List of descriptions of cards which don't have an extended
80*4882a593Smuzhiyun  * identification, or chunk directories containing a description.
81*4882a593Smuzhiyun  */
82*4882a593Smuzhiyun static struct expcard_quirklist quirklist[] __initdata = {
83*4882a593Smuzhiyun 	{ MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" },
84*4882a593Smuzhiyun 	{ MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, NULL, atomwide_3p_quirk },
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun asmlinkage extern int
88*4882a593Smuzhiyun ecard_loader_reset(unsigned long base, loader_t loader);
89*4882a593Smuzhiyun asmlinkage extern int
90*4882a593Smuzhiyun ecard_loader_read(int off, unsigned long base, loader_t loader);
91*4882a593Smuzhiyun 
ecard_getu16(unsigned char * v)92*4882a593Smuzhiyun static inline unsigned short ecard_getu16(unsigned char *v)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	return v[0] | v[1] << 8;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
ecard_gets24(unsigned char * v)97*4882a593Smuzhiyun static inline signed long ecard_gets24(unsigned char *v)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
slot_to_ecard(unsigned int slot)102*4882a593Smuzhiyun static inline ecard_t *slot_to_ecard(unsigned int slot)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun /* ===================== Expansion card daemon ======================== */
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun  * Since the loader programs on the expansion cards need to be run
110*4882a593Smuzhiyun  * in a specific environment, create a separate task with this
111*4882a593Smuzhiyun  * environment up, and pass requests to this task as and when we
112*4882a593Smuzhiyun  * need to.
113*4882a593Smuzhiyun  *
114*4882a593Smuzhiyun  * This should allow 99% of loaders to be called from Linux.
115*4882a593Smuzhiyun  *
116*4882a593Smuzhiyun  * From a security standpoint, we trust the card vendors.  This
117*4882a593Smuzhiyun  * may be a misplaced trust.
118*4882a593Smuzhiyun  */
ecard_task_reset(struct ecard_request * req)119*4882a593Smuzhiyun static void ecard_task_reset(struct ecard_request *req)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	struct expansion_card *ec = req->ec;
122*4882a593Smuzhiyun 	struct resource *res;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	res = ec->slot_no == 8
125*4882a593Smuzhiyun 		? &ec->resource[ECARD_RES_MEMC]
126*4882a593Smuzhiyun 		: ec->easi
127*4882a593Smuzhiyun 		  ? &ec->resource[ECARD_RES_EASI]
128*4882a593Smuzhiyun 		  : &ec->resource[ECARD_RES_IOCSYNC];
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	ecard_loader_reset(res->start, ec->loader);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
ecard_task_readbytes(struct ecard_request * req)133*4882a593Smuzhiyun static void ecard_task_readbytes(struct ecard_request *req)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	struct expansion_card *ec = req->ec;
136*4882a593Smuzhiyun 	unsigned char *buf = req->buffer;
137*4882a593Smuzhiyun 	unsigned int len = req->length;
138*4882a593Smuzhiyun 	unsigned int off = req->address;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	if (ec->slot_no == 8) {
141*4882a593Smuzhiyun 		void __iomem *base = (void __iomem *)
142*4882a593Smuzhiyun 				ec->resource[ECARD_RES_MEMC].start;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 		/*
145*4882a593Smuzhiyun 		 * The card maintains an index which increments the address
146*4882a593Smuzhiyun 		 * into a 4096-byte page on each access.  We need to keep
147*4882a593Smuzhiyun 		 * track of the counter.
148*4882a593Smuzhiyun 		 */
149*4882a593Smuzhiyun 		static unsigned int index;
150*4882a593Smuzhiyun 		unsigned int page;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		page = (off >> 12) * 4;
153*4882a593Smuzhiyun 		if (page > 256 * 4)
154*4882a593Smuzhiyun 			return;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 		off &= 4095;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 		/*
159*4882a593Smuzhiyun 		 * If we are reading offset 0, or our current index is
160*4882a593Smuzhiyun 		 * greater than the offset, reset the hardware index counter.
161*4882a593Smuzhiyun 		 */
162*4882a593Smuzhiyun 		if (off == 0 || index > off) {
163*4882a593Smuzhiyun 			writeb(0, base);
164*4882a593Smuzhiyun 			index = 0;
165*4882a593Smuzhiyun 		}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 		/*
168*4882a593Smuzhiyun 		 * Increment the hardware index counter until we get to the
169*4882a593Smuzhiyun 		 * required offset.  The read bytes are discarded.
170*4882a593Smuzhiyun 		 */
171*4882a593Smuzhiyun 		while (index < off) {
172*4882a593Smuzhiyun 			readb(base + page);
173*4882a593Smuzhiyun 			index += 1;
174*4882a593Smuzhiyun 		}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		while (len--) {
177*4882a593Smuzhiyun 			*buf++ = readb(base + page);
178*4882a593Smuzhiyun 			index += 1;
179*4882a593Smuzhiyun 		}
180*4882a593Smuzhiyun 	} else {
181*4882a593Smuzhiyun 		unsigned long base = (ec->easi
182*4882a593Smuzhiyun 			 ? &ec->resource[ECARD_RES_EASI]
183*4882a593Smuzhiyun 			 : &ec->resource[ECARD_RES_IOCSYNC])->start;
184*4882a593Smuzhiyun 		void __iomem *pbase = (void __iomem *)base;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		if (!req->use_loader || !ec->loader) {
187*4882a593Smuzhiyun 			off *= 4;
188*4882a593Smuzhiyun 			while (len--) {
189*4882a593Smuzhiyun 				*buf++ = readb(pbase + off);
190*4882a593Smuzhiyun 				off += 4;
191*4882a593Smuzhiyun 			}
192*4882a593Smuzhiyun 		} else {
193*4882a593Smuzhiyun 			while(len--) {
194*4882a593Smuzhiyun 				/*
195*4882a593Smuzhiyun 				 * The following is required by some
196*4882a593Smuzhiyun 				 * expansion card loader programs.
197*4882a593Smuzhiyun 				 */
198*4882a593Smuzhiyun 				*(unsigned long *)0x108 = 0;
199*4882a593Smuzhiyun 				*buf++ = ecard_loader_read(off++, base,
200*4882a593Smuzhiyun 							   ec->loader);
201*4882a593Smuzhiyun 			}
202*4882a593Smuzhiyun 		}
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
208*4882a593Smuzhiyun static struct ecard_request *ecard_req;
209*4882a593Smuzhiyun static DEFINE_MUTEX(ecard_mutex);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun /*
212*4882a593Smuzhiyun  * Set up the expansion card daemon's page tables.
213*4882a593Smuzhiyun  */
ecard_init_pgtables(struct mm_struct * mm)214*4882a593Smuzhiyun static void ecard_init_pgtables(struct mm_struct *mm)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	struct vm_area_struct vma = TLB_FLUSH_VMA(mm, VM_EXEC);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	/* We want to set up the page tables for the following mapping:
219*4882a593Smuzhiyun 	 *  Virtual	Physical
220*4882a593Smuzhiyun 	 *  0x03000000	0x03000000
221*4882a593Smuzhiyun 	 *  0x03010000	unmapped
222*4882a593Smuzhiyun 	 *  0x03210000	0x03210000
223*4882a593Smuzhiyun 	 *  0x03400000	unmapped
224*4882a593Smuzhiyun 	 *  0x08000000	0x08000000
225*4882a593Smuzhiyun 	 *  0x10000000	unmapped
226*4882a593Smuzhiyun 	 *
227*4882a593Smuzhiyun 	 * FIXME: we don't follow this 100% yet.
228*4882a593Smuzhiyun 	 */
229*4882a593Smuzhiyun 	pgd_t *src_pgd, *dst_pgd;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
232*4882a593Smuzhiyun 	dst_pgd = pgd_offset(mm, IO_START);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE);
237*4882a593Smuzhiyun 	dst_pgd = pgd_offset(mm, EASI_START);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
242*4882a593Smuzhiyun 	flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
ecard_init_mm(void)245*4882a593Smuzhiyun static int ecard_init_mm(void)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	struct mm_struct * mm = mm_alloc();
248*4882a593Smuzhiyun 	struct mm_struct *active_mm = current->active_mm;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	if (!mm)
251*4882a593Smuzhiyun 		return -ENOMEM;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	current->mm = mm;
254*4882a593Smuzhiyun 	current->active_mm = mm;
255*4882a593Smuzhiyun 	activate_mm(active_mm, mm);
256*4882a593Smuzhiyun 	mmdrop(active_mm);
257*4882a593Smuzhiyun 	ecard_init_pgtables(mm);
258*4882a593Smuzhiyun 	return 0;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun static int
ecard_task(void * unused)262*4882a593Smuzhiyun ecard_task(void * unused)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	/*
265*4882a593Smuzhiyun 	 * Allocate a mm.  We're not a lazy-TLB kernel task since we need
266*4882a593Smuzhiyun 	 * to set page table entries where the user space would be.  Note
267*4882a593Smuzhiyun 	 * that this also creates the page tables.  Failure is not an
268*4882a593Smuzhiyun 	 * option here.
269*4882a593Smuzhiyun 	 */
270*4882a593Smuzhiyun 	if (ecard_init_mm())
271*4882a593Smuzhiyun 		panic("kecardd: unable to alloc mm\n");
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	while (1) {
274*4882a593Smuzhiyun 		struct ecard_request *req;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 		wait_event_interruptible(ecard_wait, ecard_req != NULL);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		req = xchg(&ecard_req, NULL);
279*4882a593Smuzhiyun 		if (req != NULL) {
280*4882a593Smuzhiyun 			req->fn(req);
281*4882a593Smuzhiyun 			complete(req->complete);
282*4882a593Smuzhiyun 		}
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun /*
287*4882a593Smuzhiyun  * Wake the expansion card daemon to action our request.
288*4882a593Smuzhiyun  *
289*4882a593Smuzhiyun  * FIXME: The test here is not sufficient to detect if the
290*4882a593Smuzhiyun  * kcardd is running.
291*4882a593Smuzhiyun  */
ecard_call(struct ecard_request * req)292*4882a593Smuzhiyun static void ecard_call(struct ecard_request *req)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	DECLARE_COMPLETION_ONSTACK(completion);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	req->complete = &completion;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	mutex_lock(&ecard_mutex);
299*4882a593Smuzhiyun 	ecard_req = req;
300*4882a593Smuzhiyun 	wake_up(&ecard_wait);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	/*
303*4882a593Smuzhiyun 	 * Now wait for kecardd to run.
304*4882a593Smuzhiyun 	 */
305*4882a593Smuzhiyun 	wait_for_completion(&completion);
306*4882a593Smuzhiyun 	mutex_unlock(&ecard_mutex);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun /* ======================= Mid-level card control ===================== */
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun static void
ecard_readbytes(void * addr,ecard_t * ec,int off,int len,int useld)312*4882a593Smuzhiyun ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	struct ecard_request req;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	req.fn		= ecard_task_readbytes;
317*4882a593Smuzhiyun 	req.ec		= ec;
318*4882a593Smuzhiyun 	req.address	= off;
319*4882a593Smuzhiyun 	req.length	= len;
320*4882a593Smuzhiyun 	req.use_loader	= useld;
321*4882a593Smuzhiyun 	req.buffer	= addr;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	ecard_call(&req);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun 
ecard_readchunk(struct in_chunk_dir * cd,ecard_t * ec,int id,int num)326*4882a593Smuzhiyun int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	struct ex_chunk_dir excd;
329*4882a593Smuzhiyun 	int index = 16;
330*4882a593Smuzhiyun 	int useld = 0;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	if (!ec->cid.cd)
333*4882a593Smuzhiyun 		return 0;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	while(1) {
336*4882a593Smuzhiyun 		ecard_readbytes(&excd, ec, index, 8, useld);
337*4882a593Smuzhiyun 		index += 8;
338*4882a593Smuzhiyun 		if (c_id(&excd) == 0) {
339*4882a593Smuzhiyun 			if (!useld && ec->loader) {
340*4882a593Smuzhiyun 				useld = 1;
341*4882a593Smuzhiyun 				index = 0;
342*4882a593Smuzhiyun 				continue;
343*4882a593Smuzhiyun 			}
344*4882a593Smuzhiyun 			return 0;
345*4882a593Smuzhiyun 		}
346*4882a593Smuzhiyun 		if (c_id(&excd) == 0xf0) { /* link */
347*4882a593Smuzhiyun 			index = c_start(&excd);
348*4882a593Smuzhiyun 			continue;
349*4882a593Smuzhiyun 		}
350*4882a593Smuzhiyun 		if (c_id(&excd) == 0x80) { /* loader */
351*4882a593Smuzhiyun 			if (!ec->loader) {
352*4882a593Smuzhiyun 				ec->loader = kmalloc(c_len(&excd),
353*4882a593Smuzhiyun 							       GFP_KERNEL);
354*4882a593Smuzhiyun 				if (ec->loader)
355*4882a593Smuzhiyun 					ecard_readbytes(ec->loader, ec,
356*4882a593Smuzhiyun 							(int)c_start(&excd),
357*4882a593Smuzhiyun 							c_len(&excd), useld);
358*4882a593Smuzhiyun 				else
359*4882a593Smuzhiyun 					return 0;
360*4882a593Smuzhiyun 			}
361*4882a593Smuzhiyun 			continue;
362*4882a593Smuzhiyun 		}
363*4882a593Smuzhiyun 		if (c_id(&excd) == id && num-- == 0)
364*4882a593Smuzhiyun 			break;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	if (c_id(&excd) & 0x80) {
368*4882a593Smuzhiyun 		switch (c_id(&excd) & 0x70) {
369*4882a593Smuzhiyun 		case 0x70:
370*4882a593Smuzhiyun 			ecard_readbytes((unsigned char *)excd.d.string, ec,
371*4882a593Smuzhiyun 					(int)c_start(&excd), c_len(&excd),
372*4882a593Smuzhiyun 					useld);
373*4882a593Smuzhiyun 			break;
374*4882a593Smuzhiyun 		case 0x00:
375*4882a593Smuzhiyun 			break;
376*4882a593Smuzhiyun 		}
377*4882a593Smuzhiyun 	}
378*4882a593Smuzhiyun 	cd->start_offset = c_start(&excd);
379*4882a593Smuzhiyun 	memcpy(cd->d.string, excd.d.string, 256);
380*4882a593Smuzhiyun 	return 1;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun /* ======================= Interrupt control ============================ */
384*4882a593Smuzhiyun 
ecard_def_irq_enable(ecard_t * ec,int irqnr)385*4882a593Smuzhiyun static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun 
ecard_def_irq_disable(ecard_t * ec,int irqnr)389*4882a593Smuzhiyun static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun 
ecard_def_irq_pending(ecard_t * ec)393*4882a593Smuzhiyun static int ecard_def_irq_pending(ecard_t *ec)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun 
ecard_def_fiq_enable(ecard_t * ec,int fiqnr)398*4882a593Smuzhiyun static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	panic("ecard_def_fiq_enable called - impossible");
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun 
ecard_def_fiq_disable(ecard_t * ec,int fiqnr)403*4882a593Smuzhiyun static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	panic("ecard_def_fiq_disable called - impossible");
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
ecard_def_fiq_pending(ecard_t * ec)408*4882a593Smuzhiyun static int ecard_def_fiq_pending(ecard_t *ec)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun 	return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun static expansioncard_ops_t ecard_default_ops = {
414*4882a593Smuzhiyun 	ecard_def_irq_enable,
415*4882a593Smuzhiyun 	ecard_def_irq_disable,
416*4882a593Smuzhiyun 	ecard_def_irq_pending,
417*4882a593Smuzhiyun 	ecard_def_fiq_enable,
418*4882a593Smuzhiyun 	ecard_def_fiq_disable,
419*4882a593Smuzhiyun 	ecard_def_fiq_pending
420*4882a593Smuzhiyun };
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun /*
423*4882a593Smuzhiyun  * Enable and disable interrupts from expansion cards.
424*4882a593Smuzhiyun  * (interrupts are disabled for these functions).
425*4882a593Smuzhiyun  *
426*4882a593Smuzhiyun  * They are not meant to be called directly, but via enable/disable_irq.
427*4882a593Smuzhiyun  */
ecard_irq_unmask(struct irq_data * d)428*4882a593Smuzhiyun static void ecard_irq_unmask(struct irq_data *d)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun 	ecard_t *ec = irq_data_get_irq_chip_data(d);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	if (ec) {
433*4882a593Smuzhiyun 		if (!ec->ops)
434*4882a593Smuzhiyun 			ec->ops = &ecard_default_ops;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 		if (ec->claimed && ec->ops->irqenable)
437*4882a593Smuzhiyun 			ec->ops->irqenable(ec, d->irq);
438*4882a593Smuzhiyun 		else
439*4882a593Smuzhiyun 			printk(KERN_ERR "ecard: rejecting request to "
440*4882a593Smuzhiyun 				"enable IRQs for %d\n", d->irq);
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
ecard_irq_mask(struct irq_data * d)444*4882a593Smuzhiyun static void ecard_irq_mask(struct irq_data *d)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	ecard_t *ec = irq_data_get_irq_chip_data(d);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	if (ec) {
449*4882a593Smuzhiyun 		if (!ec->ops)
450*4882a593Smuzhiyun 			ec->ops = &ecard_default_ops;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 		if (ec->ops && ec->ops->irqdisable)
453*4882a593Smuzhiyun 			ec->ops->irqdisable(ec, d->irq);
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun static struct irq_chip ecard_chip = {
458*4882a593Smuzhiyun 	.name		= "ECARD",
459*4882a593Smuzhiyun 	.irq_ack	= ecard_irq_mask,
460*4882a593Smuzhiyun 	.irq_mask	= ecard_irq_mask,
461*4882a593Smuzhiyun 	.irq_unmask	= ecard_irq_unmask,
462*4882a593Smuzhiyun };
463*4882a593Smuzhiyun 
ecard_enablefiq(unsigned int fiqnr)464*4882a593Smuzhiyun void ecard_enablefiq(unsigned int fiqnr)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun 	ecard_t *ec = slot_to_ecard(fiqnr);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	if (ec) {
469*4882a593Smuzhiyun 		if (!ec->ops)
470*4882a593Smuzhiyun 			ec->ops = &ecard_default_ops;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 		if (ec->claimed && ec->ops->fiqenable)
473*4882a593Smuzhiyun 			ec->ops->fiqenable(ec, fiqnr);
474*4882a593Smuzhiyun 		else
475*4882a593Smuzhiyun 			printk(KERN_ERR "ecard: rejecting request to "
476*4882a593Smuzhiyun 				"enable FIQs for %d\n", fiqnr);
477*4882a593Smuzhiyun 	}
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
ecard_disablefiq(unsigned int fiqnr)480*4882a593Smuzhiyun void ecard_disablefiq(unsigned int fiqnr)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	ecard_t *ec = slot_to_ecard(fiqnr);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	if (ec) {
485*4882a593Smuzhiyun 		if (!ec->ops)
486*4882a593Smuzhiyun 			ec->ops = &ecard_default_ops;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 		if (ec->ops->fiqdisable)
489*4882a593Smuzhiyun 			ec->ops->fiqdisable(ec, fiqnr);
490*4882a593Smuzhiyun 	}
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
ecard_dump_irq_state(void)493*4882a593Smuzhiyun static void ecard_dump_irq_state(void)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	ecard_t *ec;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	printk("Expansion card IRQ state:\n");
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	for (ec = cards; ec; ec = ec->next) {
500*4882a593Smuzhiyun 		const char *claimed;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 		if (ec->slot_no == 8)
503*4882a593Smuzhiyun 			continue;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 		claimed = ec->claimed ? "" : "not ";
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 		if (ec->ops && ec->ops->irqpending &&
508*4882a593Smuzhiyun 		    ec->ops != &ecard_default_ops)
509*4882a593Smuzhiyun 			printk("  %d: %sclaimed irq %spending\n",
510*4882a593Smuzhiyun 			       ec->slot_no, claimed,
511*4882a593Smuzhiyun 			       ec->ops->irqpending(ec) ? "" : "not ");
512*4882a593Smuzhiyun 		else
513*4882a593Smuzhiyun 			printk("  %d: %sclaimed irqaddr %p, mask = %02X, status = %02X\n",
514*4882a593Smuzhiyun 			       ec->slot_no, claimed,
515*4882a593Smuzhiyun 			       ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun 
ecard_check_lockup(struct irq_desc * desc)519*4882a593Smuzhiyun static void ecard_check_lockup(struct irq_desc *desc)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun 	static unsigned long last;
522*4882a593Smuzhiyun 	static int lockup;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	/*
525*4882a593Smuzhiyun 	 * If the timer interrupt has not run since the last million
526*4882a593Smuzhiyun 	 * unrecognised expansion card interrupts, then there is
527*4882a593Smuzhiyun 	 * something seriously wrong.  Disable the expansion card
528*4882a593Smuzhiyun 	 * interrupts so at least we can continue.
529*4882a593Smuzhiyun 	 *
530*4882a593Smuzhiyun 	 * Maybe we ought to start a timer to re-enable them some time
531*4882a593Smuzhiyun 	 * later?
532*4882a593Smuzhiyun 	 */
533*4882a593Smuzhiyun 	if (last == jiffies) {
534*4882a593Smuzhiyun 		lockup += 1;
535*4882a593Smuzhiyun 		if (lockup > 1000000) {
536*4882a593Smuzhiyun 			printk(KERN_ERR "\nInterrupt lockup detected - "
537*4882a593Smuzhiyun 			       "disabling all expansion card interrupts\n");
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 			desc->irq_data.chip->irq_mask(&desc->irq_data);
540*4882a593Smuzhiyun 			ecard_dump_irq_state();
541*4882a593Smuzhiyun 		}
542*4882a593Smuzhiyun 	} else
543*4882a593Smuzhiyun 		lockup = 0;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	/*
546*4882a593Smuzhiyun 	 * If we did not recognise the source of this interrupt,
547*4882a593Smuzhiyun 	 * warn the user, but don't flood the user with these messages.
548*4882a593Smuzhiyun 	 */
549*4882a593Smuzhiyun 	if (!last || time_after(jiffies, last + 5*HZ)) {
550*4882a593Smuzhiyun 		last = jiffies;
551*4882a593Smuzhiyun 		printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
552*4882a593Smuzhiyun 		ecard_dump_irq_state();
553*4882a593Smuzhiyun 	}
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun 
ecard_irq_handler(struct irq_desc * desc)556*4882a593Smuzhiyun static void ecard_irq_handler(struct irq_desc *desc)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	ecard_t *ec;
559*4882a593Smuzhiyun 	int called = 0;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	desc->irq_data.chip->irq_mask(&desc->irq_data);
562*4882a593Smuzhiyun 	for (ec = cards; ec; ec = ec->next) {
563*4882a593Smuzhiyun 		int pending;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 		if (!ec->claimed || !ec->irq || ec->slot_no == 8)
566*4882a593Smuzhiyun 			continue;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 		if (ec->ops && ec->ops->irqpending)
569*4882a593Smuzhiyun 			pending = ec->ops->irqpending(ec);
570*4882a593Smuzhiyun 		else
571*4882a593Smuzhiyun 			pending = ecard_default_ops.irqpending(ec);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 		if (pending) {
574*4882a593Smuzhiyun 			generic_handle_irq(ec->irq);
575*4882a593Smuzhiyun 			called ++;
576*4882a593Smuzhiyun 		}
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 	desc->irq_data.chip->irq_unmask(&desc->irq_data);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	if (called == 0)
581*4882a593Smuzhiyun 		ecard_check_lockup(desc);
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun 
__ecard_address(ecard_t * ec,card_type_t type,card_speed_t speed)584*4882a593Smuzhiyun static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	void __iomem *address = NULL;
587*4882a593Smuzhiyun 	int slot = ec->slot_no;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	if (ec->slot_no == 8)
590*4882a593Smuzhiyun 		return ECARD_MEMC8_BASE;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	ectcr &= ~(1 << slot);
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	switch (type) {
595*4882a593Smuzhiyun 	case ECARD_MEMC:
596*4882a593Smuzhiyun 		if (slot < 4)
597*4882a593Smuzhiyun 			address = ECARD_MEMC_BASE + (slot << 14);
598*4882a593Smuzhiyun 		break;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	case ECARD_IOC:
601*4882a593Smuzhiyun 		if (slot < 4)
602*4882a593Smuzhiyun 			address = ECARD_IOC_BASE + (slot << 14);
603*4882a593Smuzhiyun 		else
604*4882a593Smuzhiyun 			address = ECARD_IOC4_BASE + ((slot - 4) << 14);
605*4882a593Smuzhiyun 		if (address)
606*4882a593Smuzhiyun 			address += speed << 19;
607*4882a593Smuzhiyun 		break;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	case ECARD_EASI:
610*4882a593Smuzhiyun 		address = ECARD_EASI_BASE + (slot << 24);
611*4882a593Smuzhiyun 		if (speed == ECARD_FAST)
612*4882a593Smuzhiyun 			ectcr |= 1 << slot;
613*4882a593Smuzhiyun 		break;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	default:
616*4882a593Smuzhiyun 		break;
617*4882a593Smuzhiyun 	}
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun #ifdef IOMD_ECTCR
620*4882a593Smuzhiyun 	iomd_writeb(ectcr, IOMD_ECTCR);
621*4882a593Smuzhiyun #endif
622*4882a593Smuzhiyun 	return address;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun 
ecard_prints(struct seq_file * m,ecard_t * ec)625*4882a593Smuzhiyun static int ecard_prints(struct seq_file *m, ecard_t *ec)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun 	seq_printf(m, "  %d: %s ", ec->slot_no, ec->easi ? "EASI" : "    ");
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	if (ec->cid.id == 0) {
630*4882a593Smuzhiyun 		struct in_chunk_dir incd;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 		seq_printf(m, "[%04X:%04X] ",
633*4882a593Smuzhiyun 			ec->cid.manufacturer, ec->cid.product);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 		if (!ec->card_desc && ec->cid.cd &&
636*4882a593Smuzhiyun 		    ecard_readchunk(&incd, ec, 0xf5, 0)) {
637*4882a593Smuzhiyun 			ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 			if (ec->card_desc)
640*4882a593Smuzhiyun 				strcpy((char *)ec->card_desc, incd.d.string);
641*4882a593Smuzhiyun 		}
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 		seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
644*4882a593Smuzhiyun 	} else
645*4882a593Smuzhiyun 		seq_printf(m, "Simple card %d\n", ec->cid.id);
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	return 0;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun 
ecard_devices_proc_show(struct seq_file * m,void * v)650*4882a593Smuzhiyun static int ecard_devices_proc_show(struct seq_file *m, void *v)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun 	ecard_t *ec = cards;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	while (ec) {
655*4882a593Smuzhiyun 		ecard_prints(m, ec);
656*4882a593Smuzhiyun 		ec = ec->next;
657*4882a593Smuzhiyun 	}
658*4882a593Smuzhiyun 	return 0;
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
662*4882a593Smuzhiyun 
ecard_proc_init(void)663*4882a593Smuzhiyun static void ecard_proc_init(void)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
666*4882a593Smuzhiyun 	proc_create_single("devices", 0, proc_bus_ecard_dir,
667*4882a593Smuzhiyun 			ecard_devices_proc_show);
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun #define ec_set_resource(ec,nr,st,sz)				\
671*4882a593Smuzhiyun 	do {							\
672*4882a593Smuzhiyun 		(ec)->resource[nr].name = dev_name(&ec->dev);	\
673*4882a593Smuzhiyun 		(ec)->resource[nr].start = st;			\
674*4882a593Smuzhiyun 		(ec)->resource[nr].end = (st) + (sz) - 1;	\
675*4882a593Smuzhiyun 		(ec)->resource[nr].flags = IORESOURCE_MEM;	\
676*4882a593Smuzhiyun 	} while (0)
677*4882a593Smuzhiyun 
ecard_free_card(struct expansion_card * ec)678*4882a593Smuzhiyun static void __init ecard_free_card(struct expansion_card *ec)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	int i;
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
683*4882a593Smuzhiyun 		if (ec->resource[i].flags)
684*4882a593Smuzhiyun 			release_resource(&ec->resource[i]);
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	kfree(ec);
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun 
ecard_alloc_card(int type,int slot)689*4882a593Smuzhiyun static struct expansion_card *__init ecard_alloc_card(int type, int slot)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun 	struct expansion_card *ec;
692*4882a593Smuzhiyun 	unsigned long base;
693*4882a593Smuzhiyun 	int i;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
696*4882a593Smuzhiyun 	if (!ec) {
697*4882a593Smuzhiyun 		ec = ERR_PTR(-ENOMEM);
698*4882a593Smuzhiyun 		goto nomem;
699*4882a593Smuzhiyun 	}
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	ec->slot_no = slot;
702*4882a593Smuzhiyun 	ec->easi = type == ECARD_EASI;
703*4882a593Smuzhiyun 	ec->irq = 0;
704*4882a593Smuzhiyun 	ec->fiq = 0;
705*4882a593Smuzhiyun 	ec->dma = NO_DMA;
706*4882a593Smuzhiyun 	ec->ops = &ecard_default_ops;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	dev_set_name(&ec->dev, "ecard%d", slot);
709*4882a593Smuzhiyun 	ec->dev.parent = NULL;
710*4882a593Smuzhiyun 	ec->dev.bus = &ecard_bus_type;
711*4882a593Smuzhiyun 	ec->dev.dma_mask = &ec->dma_mask;
712*4882a593Smuzhiyun 	ec->dma_mask = (u64)0xffffffff;
713*4882a593Smuzhiyun 	ec->dev.coherent_dma_mask = ec->dma_mask;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	if (slot < 4) {
716*4882a593Smuzhiyun 		ec_set_resource(ec, ECARD_RES_MEMC,
717*4882a593Smuzhiyun 				PODSLOT_MEMC_BASE + (slot << 14),
718*4882a593Smuzhiyun 				PODSLOT_MEMC_SIZE);
719*4882a593Smuzhiyun 		base = PODSLOT_IOC0_BASE + (slot << 14);
720*4882a593Smuzhiyun 	} else
721*4882a593Smuzhiyun 		base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun #ifdef CONFIG_ARCH_RPC
724*4882a593Smuzhiyun 	if (slot < 8) {
725*4882a593Smuzhiyun 		ec_set_resource(ec, ECARD_RES_EASI,
726*4882a593Smuzhiyun 				PODSLOT_EASI_BASE + (slot << 24),
727*4882a593Smuzhiyun 				PODSLOT_EASI_SIZE);
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	if (slot == 8) {
731*4882a593Smuzhiyun 		ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
732*4882a593Smuzhiyun 	} else
733*4882a593Smuzhiyun #endif
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
736*4882a593Smuzhiyun 		ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
737*4882a593Smuzhiyun 				base + (i << 19), PODSLOT_IOC_SIZE);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
740*4882a593Smuzhiyun 		if (ec->resource[i].flags &&
741*4882a593Smuzhiyun 		    request_resource(&iomem_resource, &ec->resource[i])) {
742*4882a593Smuzhiyun 			dev_err(&ec->dev, "resource(s) not available\n");
743*4882a593Smuzhiyun 			ec->resource[i].end -= ec->resource[i].start;
744*4882a593Smuzhiyun 			ec->resource[i].start = 0;
745*4882a593Smuzhiyun 			ec->resource[i].flags = 0;
746*4882a593Smuzhiyun 		}
747*4882a593Smuzhiyun 	}
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun  nomem:
750*4882a593Smuzhiyun 	return ec;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun 
irq_show(struct device * dev,struct device_attribute * attr,char * buf)753*4882a593Smuzhiyun static ssize_t irq_show(struct device *dev, struct device_attribute *attr, char *buf)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
756*4882a593Smuzhiyun 	return sprintf(buf, "%u\n", ec->irq);
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun static DEVICE_ATTR_RO(irq);
759*4882a593Smuzhiyun 
dma_show(struct device * dev,struct device_attribute * attr,char * buf)760*4882a593Smuzhiyun static ssize_t dma_show(struct device *dev, struct device_attribute *attr, char *buf)
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
763*4882a593Smuzhiyun 	return sprintf(buf, "%u\n", ec->dma);
764*4882a593Smuzhiyun }
765*4882a593Smuzhiyun static DEVICE_ATTR_RO(dma);
766*4882a593Smuzhiyun 
resource_show(struct device * dev,struct device_attribute * attr,char * buf)767*4882a593Smuzhiyun static ssize_t resource_show(struct device *dev, struct device_attribute *attr, char *buf)
768*4882a593Smuzhiyun {
769*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
770*4882a593Smuzhiyun 	char *str = buf;
771*4882a593Smuzhiyun 	int i;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
774*4882a593Smuzhiyun 		str += sprintf(str, "%08x %08x %08lx\n",
775*4882a593Smuzhiyun 				ec->resource[i].start,
776*4882a593Smuzhiyun 				ec->resource[i].end,
777*4882a593Smuzhiyun 				ec->resource[i].flags);
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	return str - buf;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun static DEVICE_ATTR_RO(resource);
782*4882a593Smuzhiyun 
vendor_show(struct device * dev,struct device_attribute * attr,char * buf)783*4882a593Smuzhiyun static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
784*4882a593Smuzhiyun {
785*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
786*4882a593Smuzhiyun 	return sprintf(buf, "%u\n", ec->cid.manufacturer);
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun static DEVICE_ATTR_RO(vendor);
789*4882a593Smuzhiyun 
device_show(struct device * dev,struct device_attribute * attr,char * buf)790*4882a593Smuzhiyun static ssize_t device_show(struct device *dev, struct device_attribute *attr, char *buf)
791*4882a593Smuzhiyun {
792*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
793*4882a593Smuzhiyun 	return sprintf(buf, "%u\n", ec->cid.product);
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun static DEVICE_ATTR_RO(device);
796*4882a593Smuzhiyun 
type_show(struct device * dev,struct device_attribute * attr,char * buf)797*4882a593Smuzhiyun static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf)
798*4882a593Smuzhiyun {
799*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
800*4882a593Smuzhiyun 	return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun static DEVICE_ATTR_RO(type);
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun static struct attribute *ecard_dev_attrs[] = {
805*4882a593Smuzhiyun 	&dev_attr_device.attr,
806*4882a593Smuzhiyun 	&dev_attr_dma.attr,
807*4882a593Smuzhiyun 	&dev_attr_irq.attr,
808*4882a593Smuzhiyun 	&dev_attr_resource.attr,
809*4882a593Smuzhiyun 	&dev_attr_type.attr,
810*4882a593Smuzhiyun 	&dev_attr_vendor.attr,
811*4882a593Smuzhiyun 	NULL,
812*4882a593Smuzhiyun };
813*4882a593Smuzhiyun ATTRIBUTE_GROUPS(ecard_dev);
814*4882a593Smuzhiyun 
ecard_request_resources(struct expansion_card * ec)815*4882a593Smuzhiyun int ecard_request_resources(struct expansion_card *ec)
816*4882a593Smuzhiyun {
817*4882a593Smuzhiyun 	int i, err = 0;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
820*4882a593Smuzhiyun 		if (ecard_resource_end(ec, i) &&
821*4882a593Smuzhiyun 		    !request_mem_region(ecard_resource_start(ec, i),
822*4882a593Smuzhiyun 					ecard_resource_len(ec, i),
823*4882a593Smuzhiyun 					ec->dev.driver->name)) {
824*4882a593Smuzhiyun 			err = -EBUSY;
825*4882a593Smuzhiyun 			break;
826*4882a593Smuzhiyun 		}
827*4882a593Smuzhiyun 	}
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	if (err) {
830*4882a593Smuzhiyun 		while (i--)
831*4882a593Smuzhiyun 			if (ecard_resource_end(ec, i))
832*4882a593Smuzhiyun 				release_mem_region(ecard_resource_start(ec, i),
833*4882a593Smuzhiyun 						   ecard_resource_len(ec, i));
834*4882a593Smuzhiyun 	}
835*4882a593Smuzhiyun 	return err;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun EXPORT_SYMBOL(ecard_request_resources);
838*4882a593Smuzhiyun 
ecard_release_resources(struct expansion_card * ec)839*4882a593Smuzhiyun void ecard_release_resources(struct expansion_card *ec)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun 	int i;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
844*4882a593Smuzhiyun 		if (ecard_resource_end(ec, i))
845*4882a593Smuzhiyun 			release_mem_region(ecard_resource_start(ec, i),
846*4882a593Smuzhiyun 					   ecard_resource_len(ec, i));
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun EXPORT_SYMBOL(ecard_release_resources);
849*4882a593Smuzhiyun 
ecard_setirq(struct expansion_card * ec,const struct expansion_card_ops * ops,void * irq_data)850*4882a593Smuzhiyun void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
851*4882a593Smuzhiyun {
852*4882a593Smuzhiyun 	ec->irq_data = irq_data;
853*4882a593Smuzhiyun 	barrier();
854*4882a593Smuzhiyun 	ec->ops = ops;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun EXPORT_SYMBOL(ecard_setirq);
857*4882a593Smuzhiyun 
ecardm_iomap(struct expansion_card * ec,unsigned int res,unsigned long offset,unsigned long maxsize)858*4882a593Smuzhiyun void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
859*4882a593Smuzhiyun 			   unsigned long offset, unsigned long maxsize)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun 	unsigned long start = ecard_resource_start(ec, res);
862*4882a593Smuzhiyun 	unsigned long end = ecard_resource_end(ec, res);
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	if (offset > (end - start))
865*4882a593Smuzhiyun 		return NULL;
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	start += offset;
868*4882a593Smuzhiyun 	if (maxsize && end - start > maxsize)
869*4882a593Smuzhiyun 		end = start + maxsize;
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	return devm_ioremap(&ec->dev, start, end - start);
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun EXPORT_SYMBOL(ecardm_iomap);
874*4882a593Smuzhiyun 
atomwide_3p_quirk(ecard_t * ec)875*4882a593Smuzhiyun static void atomwide_3p_quirk(ecard_t *ec)
876*4882a593Smuzhiyun {
877*4882a593Smuzhiyun 	void __iomem *addr = __ecard_address(ec, ECARD_IOC, ECARD_SYNC);
878*4882a593Smuzhiyun 	unsigned int i;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	/* Disable interrupts on each port */
881*4882a593Smuzhiyun 	for (i = 0x2000; i <= 0x2800; i += 0x0400)
882*4882a593Smuzhiyun 		writeb(0, addr + i + 4);
883*4882a593Smuzhiyun }
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun /*
886*4882a593Smuzhiyun  * Probe for an expansion card.
887*4882a593Smuzhiyun  *
888*4882a593Smuzhiyun  * If bit 1 of the first byte of the card is set, then the
889*4882a593Smuzhiyun  * card does not exist.
890*4882a593Smuzhiyun  */
ecard_probe(int slot,unsigned irq,card_type_t type)891*4882a593Smuzhiyun static int __init ecard_probe(int slot, unsigned irq, card_type_t type)
892*4882a593Smuzhiyun {
893*4882a593Smuzhiyun 	ecard_t **ecp;
894*4882a593Smuzhiyun 	ecard_t *ec;
895*4882a593Smuzhiyun 	struct ex_ecid cid;
896*4882a593Smuzhiyun 	void __iomem *addr;
897*4882a593Smuzhiyun 	int i, rc;
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	ec = ecard_alloc_card(type, slot);
900*4882a593Smuzhiyun 	if (IS_ERR(ec)) {
901*4882a593Smuzhiyun 		rc = PTR_ERR(ec);
902*4882a593Smuzhiyun 		goto nomem;
903*4882a593Smuzhiyun 	}
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	rc = -ENODEV;
906*4882a593Smuzhiyun 	if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL)
907*4882a593Smuzhiyun 		goto nodev;
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	cid.r_zero = 1;
910*4882a593Smuzhiyun 	ecard_readbytes(&cid, ec, 0, 16, 0);
911*4882a593Smuzhiyun 	if (cid.r_zero)
912*4882a593Smuzhiyun 		goto nodev;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	ec->cid.id	= cid.r_id;
915*4882a593Smuzhiyun 	ec->cid.cd	= cid.r_cd;
916*4882a593Smuzhiyun 	ec->cid.is	= cid.r_is;
917*4882a593Smuzhiyun 	ec->cid.w	= cid.r_w;
918*4882a593Smuzhiyun 	ec->cid.manufacturer = ecard_getu16(cid.r_manu);
919*4882a593Smuzhiyun 	ec->cid.product = ecard_getu16(cid.r_prod);
920*4882a593Smuzhiyun 	ec->cid.country = cid.r_country;
921*4882a593Smuzhiyun 	ec->cid.irqmask = cid.r_irqmask;
922*4882a593Smuzhiyun 	ec->cid.irqoff  = ecard_gets24(cid.r_irqoff);
923*4882a593Smuzhiyun 	ec->cid.fiqmask = cid.r_fiqmask;
924*4882a593Smuzhiyun 	ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
925*4882a593Smuzhiyun 	ec->fiqaddr	=
926*4882a593Smuzhiyun 	ec->irqaddr	= addr;
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	if (ec->cid.is) {
929*4882a593Smuzhiyun 		ec->irqmask = ec->cid.irqmask;
930*4882a593Smuzhiyun 		ec->irqaddr += ec->cid.irqoff;
931*4882a593Smuzhiyun 		ec->fiqmask = ec->cid.fiqmask;
932*4882a593Smuzhiyun 		ec->fiqaddr += ec->cid.fiqoff;
933*4882a593Smuzhiyun 	} else {
934*4882a593Smuzhiyun 		ec->irqmask = 1;
935*4882a593Smuzhiyun 		ec->fiqmask = 4;
936*4882a593Smuzhiyun 	}
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(quirklist); i++)
939*4882a593Smuzhiyun 		if (quirklist[i].manufacturer == ec->cid.manufacturer &&
940*4882a593Smuzhiyun 		    quirklist[i].product == ec->cid.product) {
941*4882a593Smuzhiyun 			if (quirklist[i].type)
942*4882a593Smuzhiyun 				ec->card_desc = quirklist[i].type;
943*4882a593Smuzhiyun 			if (quirklist[i].init)
944*4882a593Smuzhiyun 				quirklist[i].init(ec);
945*4882a593Smuzhiyun 			break;
946*4882a593Smuzhiyun 		}
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	ec->irq = irq;
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	/*
951*4882a593Smuzhiyun 	 * hook the interrupt handlers
952*4882a593Smuzhiyun 	 */
953*4882a593Smuzhiyun 	if (slot < 8) {
954*4882a593Smuzhiyun 		irq_set_chip_and_handler(ec->irq, &ecard_chip,
955*4882a593Smuzhiyun 					 handle_level_irq);
956*4882a593Smuzhiyun 		irq_set_chip_data(ec->irq, ec);
957*4882a593Smuzhiyun 		irq_clear_status_flags(ec->irq, IRQ_NOREQUEST);
958*4882a593Smuzhiyun 	}
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun #ifdef CONFIG_ARCH_RPC
961*4882a593Smuzhiyun 	/* On RiscPC, only first two slots have DMA capability */
962*4882a593Smuzhiyun 	if (slot < 2)
963*4882a593Smuzhiyun 		ec->dma = 2 + slot;
964*4882a593Smuzhiyun #endif
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 	*ecp = ec;
969*4882a593Smuzhiyun 	slot_to_expcard[slot] = ec;
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	rc = device_register(&ec->dev);
972*4882a593Smuzhiyun 	if (rc)
973*4882a593Smuzhiyun 		goto nodev;
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 	return 0;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun  nodev:
978*4882a593Smuzhiyun 	ecard_free_card(ec);
979*4882a593Smuzhiyun  nomem:
980*4882a593Smuzhiyun 	return rc;
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun /*
984*4882a593Smuzhiyun  * Initialise the expansion card system.
985*4882a593Smuzhiyun  * Locate all hardware - interrupt management and
986*4882a593Smuzhiyun  * actual cards.
987*4882a593Smuzhiyun  */
ecard_init(void)988*4882a593Smuzhiyun static int __init ecard_init(void)
989*4882a593Smuzhiyun {
990*4882a593Smuzhiyun 	struct task_struct *task;
991*4882a593Smuzhiyun 	int slot, irqbase;
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun 	irqbase = irq_alloc_descs(-1, 0, 8, -1);
994*4882a593Smuzhiyun 	if (irqbase < 0)
995*4882a593Smuzhiyun 		return irqbase;
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	task = kthread_run(ecard_task, NULL, "kecardd");
998*4882a593Smuzhiyun 	if (IS_ERR(task)) {
999*4882a593Smuzhiyun 		printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
1000*4882a593Smuzhiyun 		       PTR_ERR(task));
1001*4882a593Smuzhiyun 		irq_free_descs(irqbase, 8);
1002*4882a593Smuzhiyun 		return PTR_ERR(task);
1003*4882a593Smuzhiyun 	}
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	printk("Probing expansion cards\n");
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	for (slot = 0; slot < 8; slot ++) {
1008*4882a593Smuzhiyun 		if (ecard_probe(slot, irqbase + slot, ECARD_EASI) == -ENODEV)
1009*4882a593Smuzhiyun 			ecard_probe(slot, irqbase + slot, ECARD_IOC);
1010*4882a593Smuzhiyun 	}
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	ecard_probe(8, 11, ECARD_IOC);
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	irq_set_chained_handler(IRQ_EXPANSIONCARD, ecard_irq_handler);
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	ecard_proc_init();
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	return 0;
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun subsys_initcall(ecard_init);
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun /*
1024*4882a593Smuzhiyun  *	ECARD "bus"
1025*4882a593Smuzhiyun  */
1026*4882a593Smuzhiyun static const struct ecard_id *
ecard_match_device(const struct ecard_id * ids,struct expansion_card * ec)1027*4882a593Smuzhiyun ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
1028*4882a593Smuzhiyun {
1029*4882a593Smuzhiyun 	int i;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	for (i = 0; ids[i].manufacturer != 65535; i++)
1032*4882a593Smuzhiyun 		if (ec->cid.manufacturer == ids[i].manufacturer &&
1033*4882a593Smuzhiyun 		    ec->cid.product == ids[i].product)
1034*4882a593Smuzhiyun 			return ids + i;
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	return NULL;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun 
ecard_drv_probe(struct device * dev)1039*4882a593Smuzhiyun static int ecard_drv_probe(struct device *dev)
1040*4882a593Smuzhiyun {
1041*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
1042*4882a593Smuzhiyun 	struct ecard_driver *drv = ECARD_DRV(dev->driver);
1043*4882a593Smuzhiyun 	const struct ecard_id *id;
1044*4882a593Smuzhiyun 	int ret;
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 	id = ecard_match_device(drv->id_table, ec);
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	ec->claimed = 1;
1049*4882a593Smuzhiyun 	ret = drv->probe(ec, id);
1050*4882a593Smuzhiyun 	if (ret)
1051*4882a593Smuzhiyun 		ec->claimed = 0;
1052*4882a593Smuzhiyun 	return ret;
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun 
ecard_drv_remove(struct device * dev)1055*4882a593Smuzhiyun static int ecard_drv_remove(struct device *dev)
1056*4882a593Smuzhiyun {
1057*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
1058*4882a593Smuzhiyun 	struct ecard_driver *drv = ECARD_DRV(dev->driver);
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	drv->remove(ec);
1061*4882a593Smuzhiyun 	ec->claimed = 0;
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun 	/*
1064*4882a593Smuzhiyun 	 * Restore the default operations.  We ensure that the
1065*4882a593Smuzhiyun 	 * ops are set before we change the data.
1066*4882a593Smuzhiyun 	 */
1067*4882a593Smuzhiyun 	ec->ops = &ecard_default_ops;
1068*4882a593Smuzhiyun 	barrier();
1069*4882a593Smuzhiyun 	ec->irq_data = NULL;
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	return 0;
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun /*
1075*4882a593Smuzhiyun  * Before rebooting, we must make sure that the expansion card is in a
1076*4882a593Smuzhiyun  * sensible state, so it can be re-detected.  This means that the first
1077*4882a593Smuzhiyun  * page of the ROM must be visible.  We call the expansion cards reset
1078*4882a593Smuzhiyun  * handler, if any.
1079*4882a593Smuzhiyun  */
ecard_drv_shutdown(struct device * dev)1080*4882a593Smuzhiyun static void ecard_drv_shutdown(struct device *dev)
1081*4882a593Smuzhiyun {
1082*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(dev);
1083*4882a593Smuzhiyun 	struct ecard_driver *drv = ECARD_DRV(dev->driver);
1084*4882a593Smuzhiyun 	struct ecard_request req;
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	if (dev->driver) {
1087*4882a593Smuzhiyun 		if (drv->shutdown)
1088*4882a593Smuzhiyun 			drv->shutdown(ec);
1089*4882a593Smuzhiyun 		ec->claimed = 0;
1090*4882a593Smuzhiyun 	}
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	/*
1093*4882a593Smuzhiyun 	 * If this card has a loader, call the reset handler.
1094*4882a593Smuzhiyun 	 */
1095*4882a593Smuzhiyun 	if (ec->loader) {
1096*4882a593Smuzhiyun 		req.fn = ecard_task_reset;
1097*4882a593Smuzhiyun 		req.ec = ec;
1098*4882a593Smuzhiyun 		ecard_call(&req);
1099*4882a593Smuzhiyun 	}
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun 
ecard_register_driver(struct ecard_driver * drv)1102*4882a593Smuzhiyun int ecard_register_driver(struct ecard_driver *drv)
1103*4882a593Smuzhiyun {
1104*4882a593Smuzhiyun 	drv->drv.bus = &ecard_bus_type;
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun 	return driver_register(&drv->drv);
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun 
ecard_remove_driver(struct ecard_driver * drv)1109*4882a593Smuzhiyun void ecard_remove_driver(struct ecard_driver *drv)
1110*4882a593Smuzhiyun {
1111*4882a593Smuzhiyun 	driver_unregister(&drv->drv);
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun 
ecard_match(struct device * _dev,struct device_driver * _drv)1114*4882a593Smuzhiyun static int ecard_match(struct device *_dev, struct device_driver *_drv)
1115*4882a593Smuzhiyun {
1116*4882a593Smuzhiyun 	struct expansion_card *ec = ECARD_DEV(_dev);
1117*4882a593Smuzhiyun 	struct ecard_driver *drv = ECARD_DRV(_drv);
1118*4882a593Smuzhiyun 	int ret;
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	if (drv->id_table) {
1121*4882a593Smuzhiyun 		ret = ecard_match_device(drv->id_table, ec) != NULL;
1122*4882a593Smuzhiyun 	} else {
1123*4882a593Smuzhiyun 		ret = ec->cid.id == drv->id;
1124*4882a593Smuzhiyun 	}
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 	return ret;
1127*4882a593Smuzhiyun }
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun struct bus_type ecard_bus_type = {
1130*4882a593Smuzhiyun 	.name		= "ecard",
1131*4882a593Smuzhiyun 	.dev_groups	= ecard_dev_groups,
1132*4882a593Smuzhiyun 	.match		= ecard_match,
1133*4882a593Smuzhiyun 	.probe		= ecard_drv_probe,
1134*4882a593Smuzhiyun 	.remove		= ecard_drv_remove,
1135*4882a593Smuzhiyun 	.shutdown	= ecard_drv_shutdown,
1136*4882a593Smuzhiyun };
1137*4882a593Smuzhiyun 
ecard_bus_init(void)1138*4882a593Smuzhiyun static int ecard_bus_init(void)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun 	return bus_register(&ecard_bus_type);
1141*4882a593Smuzhiyun }
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun postcore_initcall(ecard_bus_init);
1144*4882a593Smuzhiyun 
1145*4882a593Smuzhiyun EXPORT_SYMBOL(ecard_readchunk);
1146*4882a593Smuzhiyun EXPORT_SYMBOL(ecard_register_driver);
1147*4882a593Smuzhiyun EXPORT_SYMBOL(ecard_remove_driver);
1148*4882a593Smuzhiyun EXPORT_SYMBOL(ecard_bus_type);
1149