xref: /OK3568_Linux_fs/kernel/drivers/pcmcia/rsrc_nonstatic.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * The initial developer of the original code is David A. Hinds
6*4882a593Smuzhiyun  * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
7*4882a593Smuzhiyun  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * (C) 1999		David A. Hinds
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/moduleparam.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/interrupt.h>
16*4882a593Smuzhiyun #include <linux/kernel.h>
17*4882a593Smuzhiyun #include <linux/errno.h>
18*4882a593Smuzhiyun #include <linux/types.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/ioport.h>
21*4882a593Smuzhiyun #include <linux/timer.h>
22*4882a593Smuzhiyun #include <linux/pci.h>
23*4882a593Smuzhiyun #include <linux/device.h>
24*4882a593Smuzhiyun #include <linux/io.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <asm/irq.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <pcmcia/ss.h>
29*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
30*4882a593Smuzhiyun #include "cs_internal.h"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /* moved to rsrc_mgr.c
33*4882a593Smuzhiyun MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
34*4882a593Smuzhiyun MODULE_LICENSE("GPL");
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* Parameters that can be set with 'insmod' */
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun INT_MODULE_PARM(probe_mem,	1);		/* memory probe? */
42*4882a593Smuzhiyun #ifdef CONFIG_PCMCIA_PROBE
43*4882a593Smuzhiyun INT_MODULE_PARM(probe_io,	1);		/* IO port probe? */
44*4882a593Smuzhiyun INT_MODULE_PARM(mem_limit,	0x10000);
45*4882a593Smuzhiyun #endif
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /* for io_db and mem_db */
48*4882a593Smuzhiyun struct resource_map {
49*4882a593Smuzhiyun 	u_long			base, num;
50*4882a593Smuzhiyun 	struct resource_map	*next;
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun struct socket_data {
54*4882a593Smuzhiyun 	struct resource_map		mem_db;
55*4882a593Smuzhiyun 	struct resource_map		mem_db_valid;
56*4882a593Smuzhiyun 	struct resource_map		io_db;
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define MEM_PROBE_LOW	(1 << 0)
60*4882a593Smuzhiyun #define MEM_PROBE_HIGH	(1 << 1)
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /* Action field */
63*4882a593Smuzhiyun #define REMOVE_MANAGED_RESOURCE		1
64*4882a593Smuzhiyun #define ADD_MANAGED_RESOURCE		2
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /*======================================================================
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun     Linux resource management extensions
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun ======================================================================*/
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun static struct resource *
claim_region(struct pcmcia_socket * s,resource_size_t base,resource_size_t size,int type,char * name)73*4882a593Smuzhiyun claim_region(struct pcmcia_socket *s, resource_size_t base,
74*4882a593Smuzhiyun 		resource_size_t size, int type, char *name)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	struct resource *res, *parent;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
79*4882a593Smuzhiyun 	res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	if (res) {
82*4882a593Smuzhiyun #ifdef CONFIG_PCI
83*4882a593Smuzhiyun 		if (s && s->cb_dev)
84*4882a593Smuzhiyun 			parent = pci_find_parent_resource(s->cb_dev, res);
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun 		if (!parent || request_resource(parent, res)) {
87*4882a593Smuzhiyun 			kfree(res);
88*4882a593Smuzhiyun 			res = NULL;
89*4882a593Smuzhiyun 		}
90*4882a593Smuzhiyun 	}
91*4882a593Smuzhiyun 	return res;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
free_region(struct resource * res)94*4882a593Smuzhiyun static void free_region(struct resource *res)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	if (res) {
97*4882a593Smuzhiyun 		release_resource(res);
98*4882a593Smuzhiyun 		kfree(res);
99*4882a593Smuzhiyun 	}
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /*======================================================================
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun     These manage the internal databases of available resources.
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun ======================================================================*/
107*4882a593Smuzhiyun 
add_interval(struct resource_map * map,u_long base,u_long num)108*4882a593Smuzhiyun static int add_interval(struct resource_map *map, u_long base, u_long num)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	struct resource_map *p, *q;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	for (p = map; ; p = p->next) {
113*4882a593Smuzhiyun 		if ((p != map) && (p->base+p->num >= base)) {
114*4882a593Smuzhiyun 			p->num = max(num + base - p->base, p->num);
115*4882a593Smuzhiyun 			return 0;
116*4882a593Smuzhiyun 		}
117*4882a593Smuzhiyun 		if ((p->next == map) || (p->next->base > base+num-1))
118*4882a593Smuzhiyun 			break;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 	q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
121*4882a593Smuzhiyun 	if (!q) {
122*4882a593Smuzhiyun 		printk(KERN_WARNING "out of memory to update resources\n");
123*4882a593Smuzhiyun 		return -ENOMEM;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	q->base = base; q->num = num;
126*4882a593Smuzhiyun 	q->next = p->next; p->next = q;
127*4882a593Smuzhiyun 	return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun /*====================================================================*/
131*4882a593Smuzhiyun 
sub_interval(struct resource_map * map,u_long base,u_long num)132*4882a593Smuzhiyun static int sub_interval(struct resource_map *map, u_long base, u_long num)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	struct resource_map *p, *q;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	for (p = map; ; p = q) {
137*4882a593Smuzhiyun 		q = p->next;
138*4882a593Smuzhiyun 		if (q == map)
139*4882a593Smuzhiyun 			break;
140*4882a593Smuzhiyun 		if ((q->base+q->num > base) && (base+num > q->base)) {
141*4882a593Smuzhiyun 			if (q->base >= base) {
142*4882a593Smuzhiyun 				if (q->base+q->num <= base+num) {
143*4882a593Smuzhiyun 					/* Delete whole block */
144*4882a593Smuzhiyun 					p->next = q->next;
145*4882a593Smuzhiyun 					kfree(q);
146*4882a593Smuzhiyun 					/* don't advance the pointer yet */
147*4882a593Smuzhiyun 					q = p;
148*4882a593Smuzhiyun 				} else {
149*4882a593Smuzhiyun 					/* Cut off bit from the front */
150*4882a593Smuzhiyun 					q->num = q->base + q->num - base - num;
151*4882a593Smuzhiyun 					q->base = base + num;
152*4882a593Smuzhiyun 				}
153*4882a593Smuzhiyun 			} else if (q->base+q->num <= base+num) {
154*4882a593Smuzhiyun 				/* Cut off bit from the end */
155*4882a593Smuzhiyun 				q->num = base - q->base;
156*4882a593Smuzhiyun 			} else {
157*4882a593Smuzhiyun 				/* Split the block into two pieces */
158*4882a593Smuzhiyun 				p = kmalloc(sizeof(struct resource_map),
159*4882a593Smuzhiyun 					GFP_KERNEL);
160*4882a593Smuzhiyun 				if (!p) {
161*4882a593Smuzhiyun 					printk(KERN_WARNING "out of memory to update resources\n");
162*4882a593Smuzhiyun 					return -ENOMEM;
163*4882a593Smuzhiyun 				}
164*4882a593Smuzhiyun 				p->base = base+num;
165*4882a593Smuzhiyun 				p->num = q->base+q->num - p->base;
166*4882a593Smuzhiyun 				q->num = base - q->base;
167*4882a593Smuzhiyun 				p->next = q->next ; q->next = p;
168*4882a593Smuzhiyun 			}
169*4882a593Smuzhiyun 		}
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 	return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun /*======================================================================
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun     These routines examine a region of IO or memory addresses to
177*4882a593Smuzhiyun     determine what ranges might be genuinely available.
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun ======================================================================*/
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun #ifdef CONFIG_PCMCIA_PROBE
do_io_probe(struct pcmcia_socket * s,unsigned int base,unsigned int num)182*4882a593Smuzhiyun static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
183*4882a593Smuzhiyun 			unsigned int num)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	struct resource *res;
186*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
187*4882a593Smuzhiyun 	unsigned int i, j, bad;
188*4882a593Smuzhiyun 	int any;
189*4882a593Smuzhiyun 	u_char *b, hole, most;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	/* First, what does a floating port look like? */
194*4882a593Smuzhiyun 	b = kzalloc(256, GFP_KERNEL);
195*4882a593Smuzhiyun 	if (!b) {
196*4882a593Smuzhiyun 		pr_cont("\n");
197*4882a593Smuzhiyun 		dev_err(&s->dev, "do_io_probe: unable to kmalloc 256 bytes\n");
198*4882a593Smuzhiyun 		return;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 	for (i = base, most = 0; i < base+num; i += 8) {
201*4882a593Smuzhiyun 		res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
202*4882a593Smuzhiyun 		if (!res)
203*4882a593Smuzhiyun 			continue;
204*4882a593Smuzhiyun 		hole = inb(i);
205*4882a593Smuzhiyun 		for (j = 1; j < 8; j++)
206*4882a593Smuzhiyun 			if (inb(i+j) != hole)
207*4882a593Smuzhiyun 				break;
208*4882a593Smuzhiyun 		free_region(res);
209*4882a593Smuzhiyun 		if ((j == 8) && (++b[hole] > b[most]))
210*4882a593Smuzhiyun 			most = hole;
211*4882a593Smuzhiyun 		if (b[most] == 127)
212*4882a593Smuzhiyun 			break;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 	kfree(b);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	bad = any = 0;
217*4882a593Smuzhiyun 	for (i = base; i < base+num; i += 8) {
218*4882a593Smuzhiyun 		res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
219*4882a593Smuzhiyun 		if (!res) {
220*4882a593Smuzhiyun 			if (!any)
221*4882a593Smuzhiyun 				pr_cont(" excluding");
222*4882a593Smuzhiyun 			if (!bad)
223*4882a593Smuzhiyun 				bad = any = i;
224*4882a593Smuzhiyun 			continue;
225*4882a593Smuzhiyun 		}
226*4882a593Smuzhiyun 		for (j = 0; j < 8; j++)
227*4882a593Smuzhiyun 			if (inb(i+j) != most)
228*4882a593Smuzhiyun 				break;
229*4882a593Smuzhiyun 		free_region(res);
230*4882a593Smuzhiyun 		if (j < 8) {
231*4882a593Smuzhiyun 			if (!any)
232*4882a593Smuzhiyun 				pr_cont(" excluding");
233*4882a593Smuzhiyun 			if (!bad)
234*4882a593Smuzhiyun 				bad = any = i;
235*4882a593Smuzhiyun 		} else {
236*4882a593Smuzhiyun 			if (bad) {
237*4882a593Smuzhiyun 				sub_interval(&s_data->io_db, bad, i-bad);
238*4882a593Smuzhiyun 				pr_cont(" %#x-%#x", bad, i-1);
239*4882a593Smuzhiyun 				bad = 0;
240*4882a593Smuzhiyun 			}
241*4882a593Smuzhiyun 		}
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 	if (bad) {
244*4882a593Smuzhiyun 		if ((num > 16) && (bad == base) && (i == base+num)) {
245*4882a593Smuzhiyun 			sub_interval(&s_data->io_db, bad, i-bad);
246*4882a593Smuzhiyun 			pr_cont(" nothing: probe failed.\n");
247*4882a593Smuzhiyun 			return;
248*4882a593Smuzhiyun 		} else {
249*4882a593Smuzhiyun 			sub_interval(&s_data->io_db, bad, i-bad);
250*4882a593Smuzhiyun 			pr_cont(" %#x-%#x", bad, i-1);
251*4882a593Smuzhiyun 		}
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	pr_cont("%s\n", !any ? " clean" : "");
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun #endif
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun /*======================================================================*/
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun /**
261*4882a593Smuzhiyun  * readable() - iomem validation function for cards with a valid CIS
262*4882a593Smuzhiyun  */
readable(struct pcmcia_socket * s,struct resource * res,unsigned int * count)263*4882a593Smuzhiyun static int readable(struct pcmcia_socket *s, struct resource *res,
264*4882a593Smuzhiyun 		    unsigned int *count)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	int ret = -EINVAL;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	if (s->fake_cis) {
269*4882a593Smuzhiyun 		dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
270*4882a593Smuzhiyun 		return 0;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	s->cis_mem.res = res;
274*4882a593Smuzhiyun 	s->cis_virt = ioremap(res->start, s->map_size);
275*4882a593Smuzhiyun 	if (s->cis_virt) {
276*4882a593Smuzhiyun 		mutex_unlock(&s->ops_mutex);
277*4882a593Smuzhiyun 		/* as we're only called from pcmcia.c, we're safe */
278*4882a593Smuzhiyun 		if (s->callback->validate)
279*4882a593Smuzhiyun 			ret = s->callback->validate(s, count);
280*4882a593Smuzhiyun 		/* invalidate mapping */
281*4882a593Smuzhiyun 		mutex_lock(&s->ops_mutex);
282*4882a593Smuzhiyun 		iounmap(s->cis_virt);
283*4882a593Smuzhiyun 		s->cis_virt = NULL;
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 	s->cis_mem.res = NULL;
286*4882a593Smuzhiyun 	if ((ret) || (*count == 0))
287*4882a593Smuzhiyun 		return -EINVAL;
288*4882a593Smuzhiyun 	return 0;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun /**
292*4882a593Smuzhiyun  * checksum() - iomem validation function for simple memory cards
293*4882a593Smuzhiyun  */
checksum(struct pcmcia_socket * s,struct resource * res,unsigned int * value)294*4882a593Smuzhiyun static int checksum(struct pcmcia_socket *s, struct resource *res,
295*4882a593Smuzhiyun 		    unsigned int *value)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun 	pccard_mem_map map;
298*4882a593Smuzhiyun 	int i, a = 0, b = -1, d;
299*4882a593Smuzhiyun 	void __iomem *virt;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	virt = ioremap(res->start, s->map_size);
302*4882a593Smuzhiyun 	if (virt) {
303*4882a593Smuzhiyun 		map.map = 0;
304*4882a593Smuzhiyun 		map.flags = MAP_ACTIVE;
305*4882a593Smuzhiyun 		map.speed = 0;
306*4882a593Smuzhiyun 		map.res = res;
307*4882a593Smuzhiyun 		map.card_start = 0;
308*4882a593Smuzhiyun 		s->ops->set_mem_map(s, &map);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 		/* Don't bother checking every word... */
311*4882a593Smuzhiyun 		for (i = 0; i < s->map_size; i += 44) {
312*4882a593Smuzhiyun 			d = readl(virt+i);
313*4882a593Smuzhiyun 			a += d;
314*4882a593Smuzhiyun 			b &= d;
315*4882a593Smuzhiyun 		}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 		map.flags = 0;
318*4882a593Smuzhiyun 		s->ops->set_mem_map(s, &map);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 		iounmap(virt);
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	if (b == -1)
324*4882a593Smuzhiyun 		return -EINVAL;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	*value = a;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	return 0;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun /**
332*4882a593Smuzhiyun  * do_validate_mem() - low level validate a memory region for PCMCIA use
333*4882a593Smuzhiyun  * @s:		PCMCIA socket to validate
334*4882a593Smuzhiyun  * @base:	start address of resource to check
335*4882a593Smuzhiyun  * @size:	size of resource to check
336*4882a593Smuzhiyun  * @validate:	validation function to use
337*4882a593Smuzhiyun  *
338*4882a593Smuzhiyun  * do_validate_mem() splits up the memory region which is to be checked
339*4882a593Smuzhiyun  * into two parts. Both are passed to the @validate() function. If
340*4882a593Smuzhiyun  * @validate() returns non-zero, or the value parameter to @validate()
341*4882a593Smuzhiyun  * is zero, or the value parameter is different between both calls,
342*4882a593Smuzhiyun  * the check fails, and -EINVAL is returned. Else, 0 is returned.
343*4882a593Smuzhiyun  */
do_validate_mem(struct pcmcia_socket * s,unsigned long base,unsigned long size,int validate (struct pcmcia_socket * s,struct resource * res,unsigned int * value))344*4882a593Smuzhiyun static int do_validate_mem(struct pcmcia_socket *s,
345*4882a593Smuzhiyun 			   unsigned long base, unsigned long size,
346*4882a593Smuzhiyun 			   int validate (struct pcmcia_socket *s,
347*4882a593Smuzhiyun 					 struct resource *res,
348*4882a593Smuzhiyun 					 unsigned int *value))
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
351*4882a593Smuzhiyun 	struct resource *res1, *res2;
352*4882a593Smuzhiyun 	unsigned int info1 = 1, info2 = 1;
353*4882a593Smuzhiyun 	int ret = -EINVAL;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
356*4882a593Smuzhiyun 	res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
357*4882a593Smuzhiyun 			"PCMCIA memprobe");
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	if (res1 && res2) {
360*4882a593Smuzhiyun 		ret = 0;
361*4882a593Smuzhiyun 		if (validate) {
362*4882a593Smuzhiyun 			ret = validate(s, res1, &info1);
363*4882a593Smuzhiyun 			ret += validate(s, res2, &info2);
364*4882a593Smuzhiyun 		}
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %pr %pr %u %u %u",
368*4882a593Smuzhiyun 		base, base+size-1, res1, res2, ret, info1, info2);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	free_region(res2);
371*4882a593Smuzhiyun 	free_region(res1);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if ((ret) || (info1 != info2) || (info1 == 0))
374*4882a593Smuzhiyun 		return -EINVAL;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	if (validate && !s->fake_cis) {
377*4882a593Smuzhiyun 		/* move it to the validated data set */
378*4882a593Smuzhiyun 		add_interval(&s_data->mem_db_valid, base, size);
379*4882a593Smuzhiyun 		sub_interval(&s_data->mem_db, base, size);
380*4882a593Smuzhiyun 	}
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	return 0;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun /**
387*4882a593Smuzhiyun  * do_mem_probe() - validate a memory region for PCMCIA use
388*4882a593Smuzhiyun  * @s:		PCMCIA socket to validate
389*4882a593Smuzhiyun  * @base:	start address of resource to check
390*4882a593Smuzhiyun  * @num:	size of resource to check
391*4882a593Smuzhiyun  * @validate:	validation function to use
392*4882a593Smuzhiyun  * @fallback:	validation function to use if validate fails
393*4882a593Smuzhiyun  *
394*4882a593Smuzhiyun  * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
395*4882a593Smuzhiyun  * To do so, the area is split up into sensible parts, and then passed
396*4882a593Smuzhiyun  * into the @validate() function. Only if @validate() and @fallback() fail,
397*4882a593Smuzhiyun  * the area is marked as unavaibale for use by the PCMCIA subsystem. The
398*4882a593Smuzhiyun  * function returns the size of the usable memory area.
399*4882a593Smuzhiyun  */
do_mem_probe(struct pcmcia_socket * s,u_long base,u_long num,int validate (struct pcmcia_socket * s,struct resource * res,unsigned int * value),int fallback (struct pcmcia_socket * s,struct resource * res,unsigned int * value))400*4882a593Smuzhiyun static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
401*4882a593Smuzhiyun 			int validate (struct pcmcia_socket *s,
402*4882a593Smuzhiyun 				      struct resource *res,
403*4882a593Smuzhiyun 				      unsigned int *value),
404*4882a593Smuzhiyun 			int fallback (struct pcmcia_socket *s,
405*4882a593Smuzhiyun 				      struct resource *res,
406*4882a593Smuzhiyun 				      unsigned int *value))
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
409*4882a593Smuzhiyun 	u_long i, j, bad, fail, step;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
412*4882a593Smuzhiyun 		 base, base+num-1);
413*4882a593Smuzhiyun 	bad = fail = 0;
414*4882a593Smuzhiyun 	step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
415*4882a593Smuzhiyun 	/* don't allow too large steps */
416*4882a593Smuzhiyun 	if (step > 0x800000)
417*4882a593Smuzhiyun 		step = 0x800000;
418*4882a593Smuzhiyun 	/* cis_readable wants to map 2x map_size */
419*4882a593Smuzhiyun 	if (step < 2 * s->map_size)
420*4882a593Smuzhiyun 		step = 2 * s->map_size;
421*4882a593Smuzhiyun 	for (i = j = base; i < base+num; i = j + step) {
422*4882a593Smuzhiyun 		if (!fail) {
423*4882a593Smuzhiyun 			for (j = i; j < base+num; j += step) {
424*4882a593Smuzhiyun 				if (!do_validate_mem(s, j, step, validate))
425*4882a593Smuzhiyun 					break;
426*4882a593Smuzhiyun 			}
427*4882a593Smuzhiyun 			fail = ((i == base) && (j == base+num));
428*4882a593Smuzhiyun 		}
429*4882a593Smuzhiyun 		if ((fail) && (fallback)) {
430*4882a593Smuzhiyun 			for (j = i; j < base+num; j += step)
431*4882a593Smuzhiyun 				if (!do_validate_mem(s, j, step, fallback))
432*4882a593Smuzhiyun 					break;
433*4882a593Smuzhiyun 		}
434*4882a593Smuzhiyun 		if (i != j) {
435*4882a593Smuzhiyun 			if (!bad)
436*4882a593Smuzhiyun 				pr_cont(" excluding");
437*4882a593Smuzhiyun 			pr_cont(" %#05lx-%#05lx", i, j-1);
438*4882a593Smuzhiyun 			sub_interval(&s_data->mem_db, i, j-i);
439*4882a593Smuzhiyun 			bad += j-i;
440*4882a593Smuzhiyun 		}
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun 	pr_cont("%s\n", !bad ? " clean" : "");
443*4882a593Smuzhiyun 	return num - bad;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun #ifdef CONFIG_PCMCIA_PROBE
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun /**
450*4882a593Smuzhiyun  * inv_probe() - top-to-bottom search for one usuable high memory area
451*4882a593Smuzhiyun  * @s:		PCMCIA socket to validate
452*4882a593Smuzhiyun  * @m:		resource_map to check
453*4882a593Smuzhiyun  */
inv_probe(struct resource_map * m,struct pcmcia_socket * s)454*4882a593Smuzhiyun static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
457*4882a593Smuzhiyun 	u_long ok;
458*4882a593Smuzhiyun 	if (m == &s_data->mem_db)
459*4882a593Smuzhiyun 		return 0;
460*4882a593Smuzhiyun 	ok = inv_probe(m->next, s);
461*4882a593Smuzhiyun 	if (ok) {
462*4882a593Smuzhiyun 		if (m->base >= 0x100000)
463*4882a593Smuzhiyun 			sub_interval(&s_data->mem_db, m->base, m->num);
464*4882a593Smuzhiyun 		return ok;
465*4882a593Smuzhiyun 	}
466*4882a593Smuzhiyun 	if (m->base < 0x100000)
467*4882a593Smuzhiyun 		return 0;
468*4882a593Smuzhiyun 	return do_mem_probe(s, m->base, m->num, readable, checksum);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun /**
472*4882a593Smuzhiyun  * validate_mem() - memory probe function
473*4882a593Smuzhiyun  * @s:		PCMCIA socket to validate
474*4882a593Smuzhiyun  * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
475*4882a593Smuzhiyun  *
476*4882a593Smuzhiyun  * The memory probe.  If the memory list includes a 64K-aligned block
477*4882a593Smuzhiyun  * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
478*4882a593Smuzhiyun  * least mem_limit free space, we quit. Returns 0 on usuable ports.
479*4882a593Smuzhiyun  */
validate_mem(struct pcmcia_socket * s,unsigned int probe_mask)480*4882a593Smuzhiyun static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	struct resource_map *m, mm;
483*4882a593Smuzhiyun 	static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
484*4882a593Smuzhiyun 	unsigned long b, i, ok = 0;
485*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	/* We do up to four passes through the list */
488*4882a593Smuzhiyun 	if (probe_mask & MEM_PROBE_HIGH) {
489*4882a593Smuzhiyun 		if (inv_probe(s_data->mem_db.next, s) > 0)
490*4882a593Smuzhiyun 			return 0;
491*4882a593Smuzhiyun 		if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
492*4882a593Smuzhiyun 			return 0;
493*4882a593Smuzhiyun 		dev_notice(&s->dev,
494*4882a593Smuzhiyun 			   "cs: warning: no high memory space available!\n");
495*4882a593Smuzhiyun 		return -ENODEV;
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
499*4882a593Smuzhiyun 		mm = *m;
500*4882a593Smuzhiyun 		/* Only probe < 1 MB */
501*4882a593Smuzhiyun 		if (mm.base >= 0x100000)
502*4882a593Smuzhiyun 			continue;
503*4882a593Smuzhiyun 		if ((mm.base | mm.num) & 0xffff) {
504*4882a593Smuzhiyun 			ok += do_mem_probe(s, mm.base, mm.num, readable,
505*4882a593Smuzhiyun 					   checksum);
506*4882a593Smuzhiyun 			continue;
507*4882a593Smuzhiyun 		}
508*4882a593Smuzhiyun 		/* Special probe for 64K-aligned block */
509*4882a593Smuzhiyun 		for (i = 0; i < 4; i++) {
510*4882a593Smuzhiyun 			b = order[i] << 12;
511*4882a593Smuzhiyun 			if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
512*4882a593Smuzhiyun 				if (ok >= mem_limit)
513*4882a593Smuzhiyun 					sub_interval(&s_data->mem_db, b, 0x10000);
514*4882a593Smuzhiyun 				else
515*4882a593Smuzhiyun 					ok += do_mem_probe(s, b, 0x10000,
516*4882a593Smuzhiyun 							   readable, checksum);
517*4882a593Smuzhiyun 			}
518*4882a593Smuzhiyun 		}
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (ok > 0)
522*4882a593Smuzhiyun 		return 0;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	return -ENODEV;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun #else /* CONFIG_PCMCIA_PROBE */
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun /**
530*4882a593Smuzhiyun  * validate_mem() - memory probe function
531*4882a593Smuzhiyun  * @s:		PCMCIA socket to validate
532*4882a593Smuzhiyun  * @probe_mask: ignored
533*4882a593Smuzhiyun  *
534*4882a593Smuzhiyun  * Returns 0 on usuable ports.
535*4882a593Smuzhiyun  */
validate_mem(struct pcmcia_socket * s,unsigned int probe_mask)536*4882a593Smuzhiyun static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun 	struct resource_map *m, mm;
539*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
540*4882a593Smuzhiyun 	unsigned long ok = 0;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
543*4882a593Smuzhiyun 		mm = *m;
544*4882a593Smuzhiyun 		ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 	if (ok > 0)
547*4882a593Smuzhiyun 		return 0;
548*4882a593Smuzhiyun 	return -ENODEV;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun #endif /* CONFIG_PCMCIA_PROBE */
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun /**
555*4882a593Smuzhiyun  * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
556*4882a593Smuzhiyun  * @s:		PCMCIA socket to validate
557*4882a593Smuzhiyun  *
558*4882a593Smuzhiyun  * This is tricky... when we set up CIS memory, we try to validate
559*4882a593Smuzhiyun  * the memory window space allocations.
560*4882a593Smuzhiyun  *
561*4882a593Smuzhiyun  * Locking note: Must be called with skt_mutex held!
562*4882a593Smuzhiyun  */
pcmcia_nonstatic_validate_mem(struct pcmcia_socket * s)563*4882a593Smuzhiyun static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
566*4882a593Smuzhiyun 	unsigned int probe_mask = MEM_PROBE_LOW;
567*4882a593Smuzhiyun 	int ret;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	if (!probe_mem || !(s->state & SOCKET_PRESENT))
570*4882a593Smuzhiyun 		return 0;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	if (s->features & SS_CAP_PAGE_REGS)
573*4882a593Smuzhiyun 		probe_mask = MEM_PROBE_HIGH;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	ret = validate_mem(s, probe_mask);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
578*4882a593Smuzhiyun 		return 0;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	return ret;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun struct pcmcia_align_data {
584*4882a593Smuzhiyun 	unsigned long	mask;
585*4882a593Smuzhiyun 	unsigned long	offset;
586*4882a593Smuzhiyun 	struct resource_map	*map;
587*4882a593Smuzhiyun };
588*4882a593Smuzhiyun 
pcmcia_common_align(struct pcmcia_align_data * align_data,resource_size_t start)589*4882a593Smuzhiyun static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
590*4882a593Smuzhiyun 					resource_size_t start)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun 	resource_size_t ret;
593*4882a593Smuzhiyun 	/*
594*4882a593Smuzhiyun 	 * Ensure that we have the correct start address
595*4882a593Smuzhiyun 	 */
596*4882a593Smuzhiyun 	ret = (start & ~align_data->mask) + align_data->offset;
597*4882a593Smuzhiyun 	if (ret < start)
598*4882a593Smuzhiyun 		ret += align_data->mask + 1;
599*4882a593Smuzhiyun 	return ret;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun static resource_size_t
pcmcia_align(void * align_data,const struct resource * res,resource_size_t size,resource_size_t align)603*4882a593Smuzhiyun pcmcia_align(void *align_data, const struct resource *res,
604*4882a593Smuzhiyun 	resource_size_t size, resource_size_t align)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct pcmcia_align_data *data = align_data;
607*4882a593Smuzhiyun 	struct resource_map *m;
608*4882a593Smuzhiyun 	resource_size_t start;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	start = pcmcia_common_align(data, res->start);
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	for (m = data->map->next; m != data->map; m = m->next) {
613*4882a593Smuzhiyun 		unsigned long map_start = m->base;
614*4882a593Smuzhiyun 		unsigned long map_end = m->base + m->num - 1;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 		/*
617*4882a593Smuzhiyun 		 * If the lower resources are not available, try aligning
618*4882a593Smuzhiyun 		 * to this entry of the resource database to see if it'll
619*4882a593Smuzhiyun 		 * fit here.
620*4882a593Smuzhiyun 		 */
621*4882a593Smuzhiyun 		if (start < map_start)
622*4882a593Smuzhiyun 			start = pcmcia_common_align(data, map_start);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 		/*
625*4882a593Smuzhiyun 		 * If we're above the area which was passed in, there's
626*4882a593Smuzhiyun 		 * no point proceeding.
627*4882a593Smuzhiyun 		 */
628*4882a593Smuzhiyun 		if (start >= res->end)
629*4882a593Smuzhiyun 			break;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 		if ((start + size - 1) <= map_end)
632*4882a593Smuzhiyun 			break;
633*4882a593Smuzhiyun 	}
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	/*
636*4882a593Smuzhiyun 	 * If we failed to find something suitable, ensure we fail.
637*4882a593Smuzhiyun 	 */
638*4882a593Smuzhiyun 	if (m == data->map)
639*4882a593Smuzhiyun 		start = res->end;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	return start;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun /*
645*4882a593Smuzhiyun  * Adjust an existing IO region allocation, but making sure that we don't
646*4882a593Smuzhiyun  * encroach outside the resources which the user supplied.
647*4882a593Smuzhiyun  */
__nonstatic_adjust_io_region(struct pcmcia_socket * s,unsigned long r_start,unsigned long r_end)648*4882a593Smuzhiyun static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
649*4882a593Smuzhiyun 					unsigned long r_start,
650*4882a593Smuzhiyun 					unsigned long r_end)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun 	struct resource_map *m;
653*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
654*4882a593Smuzhiyun 	int ret = -ENOMEM;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
657*4882a593Smuzhiyun 		unsigned long start = m->base;
658*4882a593Smuzhiyun 		unsigned long end = m->base + m->num - 1;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 		if (start > r_start || r_end > end)
661*4882a593Smuzhiyun 			continue;
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 		ret = 0;
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	return ret;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun /*======================================================================
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun     These find ranges of I/O ports or memory addresses that are not
672*4882a593Smuzhiyun     currently allocated by other devices.
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun     The 'align' field should reflect the number of bits of address
675*4882a593Smuzhiyun     that need to be preserved from the initial value of *base.  It
676*4882a593Smuzhiyun     should be a power of two, greater than or equal to 'num'.  A value
677*4882a593Smuzhiyun     of 0 means that all bits of *base are significant.  *base should
678*4882a593Smuzhiyun     also be strictly less than 'align'.
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun ======================================================================*/
681*4882a593Smuzhiyun 
__nonstatic_find_io_region(struct pcmcia_socket * s,unsigned long base,int num,unsigned long align)682*4882a593Smuzhiyun static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
683*4882a593Smuzhiyun 						unsigned long base, int num,
684*4882a593Smuzhiyun 						unsigned long align)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun 	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
687*4882a593Smuzhiyun 						dev_name(&s->dev));
688*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
689*4882a593Smuzhiyun 	struct pcmcia_align_data data;
690*4882a593Smuzhiyun 	unsigned long min = base;
691*4882a593Smuzhiyun 	int ret;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	if (!res)
694*4882a593Smuzhiyun 		return NULL;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	data.mask = align - 1;
697*4882a593Smuzhiyun 	data.offset = base & data.mask;
698*4882a593Smuzhiyun 	data.map = &s_data->io_db;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun #ifdef CONFIG_PCI
701*4882a593Smuzhiyun 	if (s->cb_dev) {
702*4882a593Smuzhiyun 		ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
703*4882a593Smuzhiyun 					     min, 0, pcmcia_align, &data);
704*4882a593Smuzhiyun 	} else
705*4882a593Smuzhiyun #endif
706*4882a593Smuzhiyun 		ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
707*4882a593Smuzhiyun 					1, pcmcia_align, &data);
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	if (ret != 0) {
710*4882a593Smuzhiyun 		kfree(res);
711*4882a593Smuzhiyun 		res = NULL;
712*4882a593Smuzhiyun 	}
713*4882a593Smuzhiyun 	return res;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun 
nonstatic_find_io(struct pcmcia_socket * s,unsigned int attr,unsigned int * base,unsigned int num,unsigned int align,struct resource ** parent)716*4882a593Smuzhiyun static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
717*4882a593Smuzhiyun 			unsigned int *base, unsigned int num,
718*4882a593Smuzhiyun 			unsigned int align, struct resource **parent)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun 	int i, ret = 0;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	/* Check for an already-allocated window that must conflict with
723*4882a593Smuzhiyun 	 * what was asked for.  It is a hack because it does not catch all
724*4882a593Smuzhiyun 	 * potential conflicts, just the most obvious ones.
725*4882a593Smuzhiyun 	 */
726*4882a593Smuzhiyun 	for (i = 0; i < MAX_IO_WIN; i++) {
727*4882a593Smuzhiyun 		if (!s->io[i].res)
728*4882a593Smuzhiyun 			continue;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 		if (!*base)
731*4882a593Smuzhiyun 			continue;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 		if ((s->io[i].res->start & (align-1)) == *base)
734*4882a593Smuzhiyun 			return -EBUSY;
735*4882a593Smuzhiyun 	}
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	for (i = 0; i < MAX_IO_WIN; i++) {
738*4882a593Smuzhiyun 		struct resource *res = s->io[i].res;
739*4882a593Smuzhiyun 		unsigned int try;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 		if (res && (res->flags & IORESOURCE_BITS) !=
742*4882a593Smuzhiyun 			(attr & IORESOURCE_BITS))
743*4882a593Smuzhiyun 			continue;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 		if (!res) {
746*4882a593Smuzhiyun 			if (align == 0)
747*4882a593Smuzhiyun 				align = 0x10000;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 			res = s->io[i].res = __nonstatic_find_io_region(s,
750*4882a593Smuzhiyun 								*base, num,
751*4882a593Smuzhiyun 								align);
752*4882a593Smuzhiyun 			if (!res)
753*4882a593Smuzhiyun 				return -EINVAL;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 			*base = res->start;
756*4882a593Smuzhiyun 			s->io[i].res->flags =
757*4882a593Smuzhiyun 				((res->flags & ~IORESOURCE_BITS) |
758*4882a593Smuzhiyun 					(attr & IORESOURCE_BITS));
759*4882a593Smuzhiyun 			s->io[i].InUse = num;
760*4882a593Smuzhiyun 			*parent = res;
761*4882a593Smuzhiyun 			return 0;
762*4882a593Smuzhiyun 		}
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 		/* Try to extend top of window */
765*4882a593Smuzhiyun 		try = res->end + 1;
766*4882a593Smuzhiyun 		if ((*base == 0) || (*base == try)) {
767*4882a593Smuzhiyun 			ret =  __nonstatic_adjust_io_region(s, res->start,
768*4882a593Smuzhiyun 							res->end + num);
769*4882a593Smuzhiyun 			if (!ret) {
770*4882a593Smuzhiyun 				ret = adjust_resource(s->io[i].res, res->start,
771*4882a593Smuzhiyun 						      resource_size(res) + num);
772*4882a593Smuzhiyun 				if (ret)
773*4882a593Smuzhiyun 					continue;
774*4882a593Smuzhiyun 				*base = try;
775*4882a593Smuzhiyun 				s->io[i].InUse += num;
776*4882a593Smuzhiyun 				*parent = res;
777*4882a593Smuzhiyun 				return 0;
778*4882a593Smuzhiyun 			}
779*4882a593Smuzhiyun 		}
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 		/* Try to extend bottom of window */
782*4882a593Smuzhiyun 		try = res->start - num;
783*4882a593Smuzhiyun 		if ((*base == 0) || (*base == try)) {
784*4882a593Smuzhiyun 			ret =  __nonstatic_adjust_io_region(s,
785*4882a593Smuzhiyun 							res->start - num,
786*4882a593Smuzhiyun 							res->end);
787*4882a593Smuzhiyun 			if (!ret) {
788*4882a593Smuzhiyun 				ret = adjust_resource(s->io[i].res,
789*4882a593Smuzhiyun 						      res->start - num,
790*4882a593Smuzhiyun 						      resource_size(res) + num);
791*4882a593Smuzhiyun 				if (ret)
792*4882a593Smuzhiyun 					continue;
793*4882a593Smuzhiyun 				*base = try;
794*4882a593Smuzhiyun 				s->io[i].InUse += num;
795*4882a593Smuzhiyun 				*parent = res;
796*4882a593Smuzhiyun 				return 0;
797*4882a593Smuzhiyun 			}
798*4882a593Smuzhiyun 		}
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	return -EINVAL;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 
nonstatic_find_mem_region(u_long base,u_long num,u_long align,int low,struct pcmcia_socket * s)805*4882a593Smuzhiyun static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
806*4882a593Smuzhiyun 		u_long align, int low, struct pcmcia_socket *s)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun 	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
809*4882a593Smuzhiyun 						dev_name(&s->dev));
810*4882a593Smuzhiyun 	struct socket_data *s_data = s->resource_data;
811*4882a593Smuzhiyun 	struct pcmcia_align_data data;
812*4882a593Smuzhiyun 	unsigned long min, max;
813*4882a593Smuzhiyun 	int ret, i, j;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	if (!res)
816*4882a593Smuzhiyun 		return NULL;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	low = low || !(s->features & SS_CAP_PAGE_REGS);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	data.mask = align - 1;
821*4882a593Smuzhiyun 	data.offset = base & data.mask;
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	for (i = 0; i < 2; i++) {
824*4882a593Smuzhiyun 		data.map = &s_data->mem_db_valid;
825*4882a593Smuzhiyun 		if (low) {
826*4882a593Smuzhiyun 			max = 0x100000UL;
827*4882a593Smuzhiyun 			min = base < max ? base : 0;
828*4882a593Smuzhiyun 		} else {
829*4882a593Smuzhiyun 			max = ~0UL;
830*4882a593Smuzhiyun 			min = 0x100000UL + base;
831*4882a593Smuzhiyun 		}
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 		for (j = 0; j < 2; j++) {
834*4882a593Smuzhiyun #ifdef CONFIG_PCI
835*4882a593Smuzhiyun 			if (s->cb_dev) {
836*4882a593Smuzhiyun 				ret = pci_bus_alloc_resource(s->cb_dev->bus,
837*4882a593Smuzhiyun 							res, num, 1, min, 0,
838*4882a593Smuzhiyun 							pcmcia_align, &data);
839*4882a593Smuzhiyun 			} else
840*4882a593Smuzhiyun #endif
841*4882a593Smuzhiyun 			{
842*4882a593Smuzhiyun 				ret = allocate_resource(&iomem_resource,
843*4882a593Smuzhiyun 							res, num, min, max, 1,
844*4882a593Smuzhiyun 							pcmcia_align, &data);
845*4882a593Smuzhiyun 			}
846*4882a593Smuzhiyun 			if (ret == 0)
847*4882a593Smuzhiyun 				break;
848*4882a593Smuzhiyun 			data.map = &s_data->mem_db;
849*4882a593Smuzhiyun 		}
850*4882a593Smuzhiyun 		if (ret == 0 || low)
851*4882a593Smuzhiyun 			break;
852*4882a593Smuzhiyun 		low = 1;
853*4882a593Smuzhiyun 	}
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	if (ret != 0) {
856*4882a593Smuzhiyun 		kfree(res);
857*4882a593Smuzhiyun 		res = NULL;
858*4882a593Smuzhiyun 	}
859*4882a593Smuzhiyun 	return res;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 
adjust_memory(struct pcmcia_socket * s,unsigned int action,unsigned long start,unsigned long end)863*4882a593Smuzhiyun static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
864*4882a593Smuzhiyun {
865*4882a593Smuzhiyun 	struct socket_data *data = s->resource_data;
866*4882a593Smuzhiyun 	unsigned long size = end - start + 1;
867*4882a593Smuzhiyun 	int ret = 0;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	if (end < start)
870*4882a593Smuzhiyun 		return -EINVAL;
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 	switch (action) {
873*4882a593Smuzhiyun 	case ADD_MANAGED_RESOURCE:
874*4882a593Smuzhiyun 		ret = add_interval(&data->mem_db, start, size);
875*4882a593Smuzhiyun 		if (!ret)
876*4882a593Smuzhiyun 			do_mem_probe(s, start, size, NULL, NULL);
877*4882a593Smuzhiyun 		break;
878*4882a593Smuzhiyun 	case REMOVE_MANAGED_RESOURCE:
879*4882a593Smuzhiyun 		ret = sub_interval(&data->mem_db, start, size);
880*4882a593Smuzhiyun 		break;
881*4882a593Smuzhiyun 	default:
882*4882a593Smuzhiyun 		ret = -EINVAL;
883*4882a593Smuzhiyun 	}
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	return ret;
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 
adjust_io(struct pcmcia_socket * s,unsigned int action,unsigned long start,unsigned long end)889*4882a593Smuzhiyun static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun 	struct socket_data *data = s->resource_data;
892*4882a593Smuzhiyun 	unsigned long size;
893*4882a593Smuzhiyun 	int ret = 0;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun #if defined(CONFIG_X86)
896*4882a593Smuzhiyun 	/* on x86, avoid anything < 0x100 for it is often used for
897*4882a593Smuzhiyun 	 * legacy platform devices */
898*4882a593Smuzhiyun 	if (start < 0x100)
899*4882a593Smuzhiyun 		start = 0x100;
900*4882a593Smuzhiyun #endif
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	size = end - start + 1;
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	if (end < start)
905*4882a593Smuzhiyun 		return -EINVAL;
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	if (end > IO_SPACE_LIMIT)
908*4882a593Smuzhiyun 		return -EINVAL;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	switch (action) {
911*4882a593Smuzhiyun 	case ADD_MANAGED_RESOURCE:
912*4882a593Smuzhiyun 		if (add_interval(&data->io_db, start, size) != 0) {
913*4882a593Smuzhiyun 			ret = -EBUSY;
914*4882a593Smuzhiyun 			break;
915*4882a593Smuzhiyun 		}
916*4882a593Smuzhiyun #ifdef CONFIG_PCMCIA_PROBE
917*4882a593Smuzhiyun 		if (probe_io)
918*4882a593Smuzhiyun 			do_io_probe(s, start, size);
919*4882a593Smuzhiyun #endif
920*4882a593Smuzhiyun 		break;
921*4882a593Smuzhiyun 	case REMOVE_MANAGED_RESOURCE:
922*4882a593Smuzhiyun 		sub_interval(&data->io_db, start, size);
923*4882a593Smuzhiyun 		break;
924*4882a593Smuzhiyun 	default:
925*4882a593Smuzhiyun 		ret = -EINVAL;
926*4882a593Smuzhiyun 		break;
927*4882a593Smuzhiyun 	}
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	return ret;
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun #ifdef CONFIG_PCI
nonstatic_autoadd_resources(struct pcmcia_socket * s)934*4882a593Smuzhiyun static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun 	struct resource *res;
937*4882a593Smuzhiyun 	int i, done = 0;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	if (!s->cb_dev || !s->cb_dev->bus)
940*4882a593Smuzhiyun 		return -ENODEV;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun #if defined(CONFIG_X86)
943*4882a593Smuzhiyun 	/* If this is the root bus, the risk of hitting some strange
944*4882a593Smuzhiyun 	 * system devices is too high: If a driver isn't loaded, the
945*4882a593Smuzhiyun 	 * resources are not claimed; even if a driver is loaded, it
946*4882a593Smuzhiyun 	 * may not request all resources or even the wrong one. We
947*4882a593Smuzhiyun 	 * can neither trust the rest of the kernel nor ACPI/PNP and
948*4882a593Smuzhiyun 	 * CRS parsing to get it right. Therefore, use several
949*4882a593Smuzhiyun 	 * safeguards:
950*4882a593Smuzhiyun 	 *
951*4882a593Smuzhiyun 	 * - Do not auto-add resources if the CardBus bridge is on
952*4882a593Smuzhiyun 	 *   the PCI root bus
953*4882a593Smuzhiyun 	 *
954*4882a593Smuzhiyun 	 * - Avoid any I/O ports < 0x100.
955*4882a593Smuzhiyun 	 *
956*4882a593Smuzhiyun 	 * - On PCI-PCI bridges, only use resources which are set up
957*4882a593Smuzhiyun 	 *   exclusively for the secondary PCI bus: the risk of hitting
958*4882a593Smuzhiyun 	 *   system devices is quite low, as they usually aren't
959*4882a593Smuzhiyun 	 *   connected to the secondary PCI bus.
960*4882a593Smuzhiyun 	 */
961*4882a593Smuzhiyun 	if (s->cb_dev->bus->number == 0)
962*4882a593Smuzhiyun 		return -EINVAL;
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
965*4882a593Smuzhiyun 		res = s->cb_dev->bus->resource[i];
966*4882a593Smuzhiyun #else
967*4882a593Smuzhiyun 	pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
968*4882a593Smuzhiyun #endif
969*4882a593Smuzhiyun 		if (!res)
970*4882a593Smuzhiyun 			continue;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 		if (res->flags & IORESOURCE_IO) {
973*4882a593Smuzhiyun 			/* safeguard against the root resource, where the
974*4882a593Smuzhiyun 			 * risk of hitting any other device would be too
975*4882a593Smuzhiyun 			 * high */
976*4882a593Smuzhiyun 			if (res == &ioport_resource)
977*4882a593Smuzhiyun 				continue;
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun 			dev_info(&s->cb_dev->dev,
980*4882a593Smuzhiyun 				 "pcmcia: parent PCI bridge window: %pR\n",
981*4882a593Smuzhiyun 				 res);
982*4882a593Smuzhiyun 			if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
983*4882a593Smuzhiyun 				done |= IORESOURCE_IO;
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 		}
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 		if (res->flags & IORESOURCE_MEM) {
988*4882a593Smuzhiyun 			/* safeguard against the root resource, where the
989*4882a593Smuzhiyun 			 * risk of hitting any other device would be too
990*4882a593Smuzhiyun 			 * high */
991*4882a593Smuzhiyun 			if (res == &iomem_resource)
992*4882a593Smuzhiyun 				continue;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 			dev_info(&s->cb_dev->dev,
995*4882a593Smuzhiyun 				 "pcmcia: parent PCI bridge window: %pR\n",
996*4882a593Smuzhiyun 				 res);
997*4882a593Smuzhiyun 			if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
998*4882a593Smuzhiyun 				done |= IORESOURCE_MEM;
999*4882a593Smuzhiyun 		}
1000*4882a593Smuzhiyun 	}
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	/* if we got at least one of IO, and one of MEM, we can be glad and
1003*4882a593Smuzhiyun 	 * activate the PCMCIA subsystem */
1004*4882a593Smuzhiyun 	if (done == (IORESOURCE_MEM | IORESOURCE_IO))
1005*4882a593Smuzhiyun 		s->resource_setup_done = 1;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	return 0;
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun #else
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
1013*4882a593Smuzhiyun {
1014*4882a593Smuzhiyun 	return -ENODEV;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun #endif
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun static int nonstatic_init(struct pcmcia_socket *s)
1021*4882a593Smuzhiyun {
1022*4882a593Smuzhiyun 	struct socket_data *data;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
1025*4882a593Smuzhiyun 	if (!data)
1026*4882a593Smuzhiyun 		return -ENOMEM;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	data->mem_db.next = &data->mem_db;
1029*4882a593Smuzhiyun 	data->mem_db_valid.next = &data->mem_db_valid;
1030*4882a593Smuzhiyun 	data->io_db.next = &data->io_db;
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	s->resource_data = (void *) data;
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	nonstatic_autoadd_resources(s);
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	return 0;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun static void nonstatic_release_resource_db(struct pcmcia_socket *s)
1040*4882a593Smuzhiyun {
1041*4882a593Smuzhiyun 	struct socket_data *data = s->resource_data;
1042*4882a593Smuzhiyun 	struct resource_map *p, *q;
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 	for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
1045*4882a593Smuzhiyun 		q = p->next;
1046*4882a593Smuzhiyun 		kfree(p);
1047*4882a593Smuzhiyun 	}
1048*4882a593Smuzhiyun 	for (p = data->mem_db.next; p != &data->mem_db; p = q) {
1049*4882a593Smuzhiyun 		q = p->next;
1050*4882a593Smuzhiyun 		kfree(p);
1051*4882a593Smuzhiyun 	}
1052*4882a593Smuzhiyun 	for (p = data->io_db.next; p != &data->io_db; p = q) {
1053*4882a593Smuzhiyun 		q = p->next;
1054*4882a593Smuzhiyun 		kfree(p);
1055*4882a593Smuzhiyun 	}
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun struct pccard_resource_ops pccard_nonstatic_ops = {
1060*4882a593Smuzhiyun 	.validate_mem = pcmcia_nonstatic_validate_mem,
1061*4882a593Smuzhiyun 	.find_io = nonstatic_find_io,
1062*4882a593Smuzhiyun 	.find_mem = nonstatic_find_mem_region,
1063*4882a593Smuzhiyun 	.init = nonstatic_init,
1064*4882a593Smuzhiyun 	.exit = nonstatic_release_resource_db,
1065*4882a593Smuzhiyun };
1066*4882a593Smuzhiyun EXPORT_SYMBOL(pccard_nonstatic_ops);
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun /* sysfs interface to the resource database */
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun static ssize_t show_io_db(struct device *dev,
1072*4882a593Smuzhiyun 			  struct device_attribute *attr, char *buf)
1073*4882a593Smuzhiyun {
1074*4882a593Smuzhiyun 	struct pcmcia_socket *s = dev_get_drvdata(dev);
1075*4882a593Smuzhiyun 	struct socket_data *data;
1076*4882a593Smuzhiyun 	struct resource_map *p;
1077*4882a593Smuzhiyun 	ssize_t ret = 0;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	mutex_lock(&s->ops_mutex);
1080*4882a593Smuzhiyun 	data = s->resource_data;
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	for (p = data->io_db.next; p != &data->io_db; p = p->next) {
1083*4882a593Smuzhiyun 		if (ret > (PAGE_SIZE - 10))
1084*4882a593Smuzhiyun 			continue;
1085*4882a593Smuzhiyun 		ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1086*4882a593Smuzhiyun 				"0x%08lx - 0x%08lx\n",
1087*4882a593Smuzhiyun 				((unsigned long) p->base),
1088*4882a593Smuzhiyun 				((unsigned long) p->base + p->num - 1));
1089*4882a593Smuzhiyun 	}
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	mutex_unlock(&s->ops_mutex);
1092*4882a593Smuzhiyun 	return ret;
1093*4882a593Smuzhiyun }
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun static ssize_t store_io_db(struct device *dev,
1096*4882a593Smuzhiyun 			   struct device_attribute *attr,
1097*4882a593Smuzhiyun 			   const char *buf, size_t count)
1098*4882a593Smuzhiyun {
1099*4882a593Smuzhiyun 	struct pcmcia_socket *s = dev_get_drvdata(dev);
1100*4882a593Smuzhiyun 	unsigned long start_addr, end_addr;
1101*4882a593Smuzhiyun 	unsigned int add = ADD_MANAGED_RESOURCE;
1102*4882a593Smuzhiyun 	ssize_t ret = 0;
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
1105*4882a593Smuzhiyun 	if (ret != 2) {
1106*4882a593Smuzhiyun 		ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
1107*4882a593Smuzhiyun 		add = REMOVE_MANAGED_RESOURCE;
1108*4882a593Smuzhiyun 		if (ret != 2) {
1109*4882a593Smuzhiyun 			ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
1110*4882a593Smuzhiyun 				&end_addr);
1111*4882a593Smuzhiyun 			add = ADD_MANAGED_RESOURCE;
1112*4882a593Smuzhiyun 			if (ret != 2)
1113*4882a593Smuzhiyun 				return -EINVAL;
1114*4882a593Smuzhiyun 		}
1115*4882a593Smuzhiyun 	}
1116*4882a593Smuzhiyun 	if (end_addr < start_addr)
1117*4882a593Smuzhiyun 		return -EINVAL;
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 	mutex_lock(&s->ops_mutex);
1120*4882a593Smuzhiyun 	ret = adjust_io(s, add, start_addr, end_addr);
1121*4882a593Smuzhiyun 	mutex_unlock(&s->ops_mutex);
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	return ret ? ret : count;
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun static ssize_t show_mem_db(struct device *dev,
1128*4882a593Smuzhiyun 			   struct device_attribute *attr, char *buf)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun 	struct pcmcia_socket *s = dev_get_drvdata(dev);
1131*4882a593Smuzhiyun 	struct socket_data *data;
1132*4882a593Smuzhiyun 	struct resource_map *p;
1133*4882a593Smuzhiyun 	ssize_t ret = 0;
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 	mutex_lock(&s->ops_mutex);
1136*4882a593Smuzhiyun 	data = s->resource_data;
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
1139*4882a593Smuzhiyun 	     p = p->next) {
1140*4882a593Smuzhiyun 		if (ret > (PAGE_SIZE - 10))
1141*4882a593Smuzhiyun 			continue;
1142*4882a593Smuzhiyun 		ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1143*4882a593Smuzhiyun 				"0x%08lx - 0x%08lx\n",
1144*4882a593Smuzhiyun 				((unsigned long) p->base),
1145*4882a593Smuzhiyun 				((unsigned long) p->base + p->num - 1));
1146*4882a593Smuzhiyun 	}
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun 	for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
1149*4882a593Smuzhiyun 		if (ret > (PAGE_SIZE - 10))
1150*4882a593Smuzhiyun 			continue;
1151*4882a593Smuzhiyun 		ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1152*4882a593Smuzhiyun 				"0x%08lx - 0x%08lx\n",
1153*4882a593Smuzhiyun 				((unsigned long) p->base),
1154*4882a593Smuzhiyun 				((unsigned long) p->base + p->num - 1));
1155*4882a593Smuzhiyun 	}
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	mutex_unlock(&s->ops_mutex);
1158*4882a593Smuzhiyun 	return ret;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun static ssize_t store_mem_db(struct device *dev,
1162*4882a593Smuzhiyun 			    struct device_attribute *attr,
1163*4882a593Smuzhiyun 			    const char *buf, size_t count)
1164*4882a593Smuzhiyun {
1165*4882a593Smuzhiyun 	struct pcmcia_socket *s = dev_get_drvdata(dev);
1166*4882a593Smuzhiyun 	unsigned long start_addr, end_addr;
1167*4882a593Smuzhiyun 	unsigned int add = ADD_MANAGED_RESOURCE;
1168*4882a593Smuzhiyun 	ssize_t ret = 0;
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
1171*4882a593Smuzhiyun 	if (ret != 2) {
1172*4882a593Smuzhiyun 		ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
1173*4882a593Smuzhiyun 		add = REMOVE_MANAGED_RESOURCE;
1174*4882a593Smuzhiyun 		if (ret != 2) {
1175*4882a593Smuzhiyun 			ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
1176*4882a593Smuzhiyun 				&end_addr);
1177*4882a593Smuzhiyun 			add = ADD_MANAGED_RESOURCE;
1178*4882a593Smuzhiyun 			if (ret != 2)
1179*4882a593Smuzhiyun 				return -EINVAL;
1180*4882a593Smuzhiyun 		}
1181*4882a593Smuzhiyun 	}
1182*4882a593Smuzhiyun 	if (end_addr < start_addr)
1183*4882a593Smuzhiyun 		return -EINVAL;
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 	mutex_lock(&s->ops_mutex);
1186*4882a593Smuzhiyun 	ret = adjust_memory(s, add, start_addr, end_addr);
1187*4882a593Smuzhiyun 	mutex_unlock(&s->ops_mutex);
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	return ret ? ret : count;
1190*4882a593Smuzhiyun }
1191*4882a593Smuzhiyun static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun static struct attribute *pccard_rsrc_attributes[] = {
1194*4882a593Smuzhiyun 	&dev_attr_available_resources_io.attr,
1195*4882a593Smuzhiyun 	&dev_attr_available_resources_mem.attr,
1196*4882a593Smuzhiyun 	NULL,
1197*4882a593Smuzhiyun };
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun static const struct attribute_group rsrc_attributes = {
1200*4882a593Smuzhiyun 	.attrs = pccard_rsrc_attributes,
1201*4882a593Smuzhiyun };
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun static int pccard_sysfs_add_rsrc(struct device *dev,
1204*4882a593Smuzhiyun 					   struct class_interface *class_intf)
1205*4882a593Smuzhiyun {
1206*4882a593Smuzhiyun 	struct pcmcia_socket *s = dev_get_drvdata(dev);
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	if (s->resource_ops != &pccard_nonstatic_ops)
1209*4882a593Smuzhiyun 		return 0;
1210*4882a593Smuzhiyun 	return sysfs_create_group(&dev->kobj, &rsrc_attributes);
1211*4882a593Smuzhiyun }
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun static void pccard_sysfs_remove_rsrc(struct device *dev,
1214*4882a593Smuzhiyun 					       struct class_interface *class_intf)
1215*4882a593Smuzhiyun {
1216*4882a593Smuzhiyun 	struct pcmcia_socket *s = dev_get_drvdata(dev);
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	if (s->resource_ops != &pccard_nonstatic_ops)
1219*4882a593Smuzhiyun 		return;
1220*4882a593Smuzhiyun 	sysfs_remove_group(&dev->kobj, &rsrc_attributes);
1221*4882a593Smuzhiyun }
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun static struct class_interface pccard_rsrc_interface __refdata = {
1224*4882a593Smuzhiyun 	.class = &pcmcia_socket_class,
1225*4882a593Smuzhiyun 	.add_dev = &pccard_sysfs_add_rsrc,
1226*4882a593Smuzhiyun 	.remove_dev = &pccard_sysfs_remove_rsrc,
1227*4882a593Smuzhiyun };
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun static int __init nonstatic_sysfs_init(void)
1230*4882a593Smuzhiyun {
1231*4882a593Smuzhiyun 	return class_interface_register(&pccard_rsrc_interface);
1232*4882a593Smuzhiyun }
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun static void __exit nonstatic_sysfs_exit(void)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun 	class_interface_unregister(&pccard_rsrc_interface);
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun module_init(nonstatic_sysfs_init);
1240*4882a593Smuzhiyun module_exit(nonstatic_sysfs_exit);
1241