1 /*======================================================================
2 
3     Resource management routines
4 
5     rsrc_mgr.c 1.79 2000/08/30 20:23:58
6 
7     The contents of this file are subject to the Mozilla Public
8     License Version 1.1 (the "License"); you may not use this file
9     except in compliance with the License. You may obtain a copy of
10     the License at http://www.mozilla.org/MPL/
11 
12     Software distributed under the License is distributed on an "AS
13     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     implied. See the License for the specific language governing
15     rights and limitations under the License.
16 
17     The initial developer of the original code is David A. Hinds
18     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
19     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
20 
21     Alternatively, the contents of this file may be used under the
22     terms of the GNU General Public License version 2 (the "GPL"), in which
23     case the provisions of the GPL are applicable instead of the
24     above.  If you wish to allow the use of your version of this file
25     only under the terms of the GPL and not to allow others to use
26     your version of this file under the MPL, indicate your decision
27     by deleting the provisions above and replace them with the notice
28     and other provisions required by the GPL.  If you do not delete
29     the provisions above, a recipient may use your version of this
30     file under either the MPL or the GPL.
31 
32 ======================================================================*/
33 
34 #define __NO_VERSION__
35 
36 #include <linux/config.h>
37 #include <linux/module.h>
38 #include <linux/init.h>
39 #include <linux/sched.h>
40 #include <linux/kernel.h>
41 #include <linux/errno.h>
42 #include <linux/types.h>
43 #include <linux/slab.h>
44 #include <linux/ioport.h>
45 #include <linux/timer.h>
46 #include <linux/proc_fs.h>
47 #include <linux/pci.h>
48 #include <asm/irq.h>
49 #include <asm/io.h>
50 
51 #include <pcmcia/cs_types.h>
52 #include <pcmcia/ss.h>
53 #include <pcmcia/cs.h>
54 #include <pcmcia/bulkmem.h>
55 #include <pcmcia/cistpl.h>
56 #include "cs_internal.h"
57 
58 /*====================================================================*/
59 
60 /* Parameters that can be set with 'insmod' */
61 
62 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
63 
64 INT_MODULE_PARM(probe_mem,	1);		/* memory probe? */
65 #ifdef CONFIG_ISA
66 INT_MODULE_PARM(probe_io,	1);		/* IO port probe? */
67 INT_MODULE_PARM(mem_limit,	0x10000);
68 #endif
69 
70 /*======================================================================
71 
72     The resource_map_t structures are used to track what resources are
73     available for allocation for PC Card devices.
74 
75 ======================================================================*/
76 
77 typedef struct resource_map_t {
78     u_long			base, num;
79     struct resource_map_t	*next;
80 } resource_map_t;
81 
82 /* Memory resource database */
83 static resource_map_t mem_db = { 0, 0, &mem_db };
84 
85 /* IO port resource database */
86 static resource_map_t io_db = { 0, 0, &io_db };
87 
88 #ifdef CONFIG_ISA
89 
90 typedef struct irq_info_t {
91     u_int			Attributes;
92     int				time_share, dyn_share;
93     struct socket_info_t	*Socket;
94 } irq_info_t;
95 
96 /* Table of IRQ assignments */
97 static irq_info_t irq_table[NR_IRQS] = { { 0, 0, 0 }, /* etc */ };
98 
99 #endif
100 
101 /*======================================================================
102 
103     Linux resource management extensions
104 
105 ======================================================================*/
106 
resource_parent(unsigned long b,unsigned long n,int flags,struct pci_dev * dev)107 static struct resource *resource_parent(unsigned long b, unsigned long n,
108 					int flags, struct pci_dev *dev)
109 {
110 #ifdef CONFIG_PCI
111 	struct resource res, *pr;
112 
113 	if (dev != NULL) {
114 		res.start = b;
115 		res.end = b + n - 1;
116 		res.flags = flags;
117 		pr = pci_find_parent_resource(dev, &res);
118 		if (pr)
119 			return pr;
120 	}
121 #endif /* CONFIG_PCI */
122 	if (flags & IORESOURCE_MEM)
123 		return &iomem_resource;
124 	return &ioport_resource;
125 }
126 
check_io_resource(unsigned long b,unsigned long n,struct pci_dev * dev)127 static inline int check_io_resource(unsigned long b, unsigned long n,
128 				    struct pci_dev *dev)
129 {
130 	return check_resource(resource_parent(b, n, IORESOURCE_IO, dev), b, n);
131 }
132 
check_mem_resource(unsigned long b,unsigned long n,struct pci_dev * dev)133 static inline int check_mem_resource(unsigned long b, unsigned long n,
134 				     struct pci_dev *dev)
135 {
136 	return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n);
137 }
138 
make_resource(unsigned long b,unsigned long n,int flags,char * name)139 static struct resource *make_resource(unsigned long b, unsigned long n,
140 				      int flags, char *name)
141 {
142 	struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
143 
144 	if (res) {
145 		memset(res, 0, sizeof(*res));
146 		res->name = name;
147 		res->start = b;
148 		res->end = b + n - 1;
149 		res->flags = flags | IORESOURCE_BUSY;
150 	}
151 	return res;
152 }
153 
request_io_resource(unsigned long b,unsigned long n,char * name,struct pci_dev * dev)154 static int request_io_resource(unsigned long b, unsigned long n,
155 			       char *name, struct pci_dev *dev)
156 {
157 	struct resource *res = make_resource(b, n, IORESOURCE_IO, name);
158 	struct resource *pr = resource_parent(b, n, IORESOURCE_IO, dev);
159 	int err = -ENOMEM;
160 
161 	if (res) {
162 		err = request_resource(pr, res);
163 		if (err)
164 			kfree(res);
165 	}
166 	return err;
167 }
168 
request_mem_resource(unsigned long b,unsigned long n,char * name,struct pci_dev * dev)169 static int request_mem_resource(unsigned long b, unsigned long n,
170 				char *name, struct pci_dev *dev)
171 {
172 	struct resource *res = make_resource(b, n, IORESOURCE_MEM, name);
173 	struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev);
174 	int err = -ENOMEM;
175 
176 	if (res) {
177 		err = request_resource(pr, res);
178 		if (err)
179 			kfree(res);
180 	}
181 	return err;
182 }
183 
184 /*======================================================================
185 
186     These manage the internal databases of available resources.
187 
188 ======================================================================*/
189 
add_interval(resource_map_t * map,u_long base,u_long num)190 static int add_interval(resource_map_t *map, u_long base, u_long num)
191 {
192     resource_map_t *p, *q;
193 
194     for (p = map; ; p = p->next) {
195 	if ((p != map) && (p->base+p->num-1 >= base))
196 	    return -1;
197 	if ((p->next == map) || (p->next->base > base+num-1))
198 	    break;
199     }
200     q = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
201     if (!q) return CS_OUT_OF_RESOURCE;
202     q->base = base; q->num = num;
203     q->next = p->next; p->next = q;
204     return CS_SUCCESS;
205 }
206 
207 /*====================================================================*/
208 
sub_interval(resource_map_t * map,u_long base,u_long num)209 static int sub_interval(resource_map_t *map, u_long base, u_long num)
210 {
211     resource_map_t *p, *q;
212 
213     for (p = map; ; p = q) {
214 	q = p->next;
215 	if (q == map)
216 	    break;
217 	if ((q->base+q->num > base) && (base+num > q->base)) {
218 	    if (q->base >= base) {
219 		if (q->base+q->num <= base+num) {
220 		    /* Delete whole block */
221 		    p->next = q->next;
222 		    kfree(q);
223 		    /* don't advance the pointer yet */
224 		    q = p;
225 		} else {
226 		    /* Cut off bit from the front */
227 		    q->num = q->base + q->num - base - num;
228 		    q->base = base + num;
229 		}
230 	    } else if (q->base+q->num <= base+num) {
231 		/* Cut off bit from the end */
232 		q->num = base - q->base;
233 	    } else {
234 		/* Split the block into two pieces */
235 		p = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
236 		if (!p) return CS_OUT_OF_RESOURCE;
237 		p->base = base+num;
238 		p->num = q->base+q->num - p->base;
239 		q->num = base - q->base;
240 		p->next = q->next ; q->next = p;
241 	    }
242 	}
243     }
244     return CS_SUCCESS;
245 }
246 
247 /*======================================================================
248 
249     These routines examine a region of IO or memory addresses to
250     determine what ranges might be genuinely available.
251 
252 ======================================================================*/
253 
254 #ifdef CONFIG_ISA
do_io_probe(ioaddr_t base,ioaddr_t num)255 static void do_io_probe(ioaddr_t base, ioaddr_t num)
256 {
257 
258     ioaddr_t i, j, bad, any;
259     u_char *b, hole, most;
260 
261     printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:",
262 	   base, base+num-1);
263 
264     /* First, what does a floating port look like? */
265     b = kmalloc(256, GFP_KERNEL);
266     if (!b) {
267             printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes");
268             return;
269     }
270     memset(b, 0, 256);
271     for (i = base, most = 0; i < base+num; i += 8) {
272 	if (check_io_resource(i, 8, NULL))
273 	    continue;
274 	hole = inb(i);
275 	for (j = 1; j < 8; j++)
276 	    if (inb(i+j) != hole) break;
277 	if ((j == 8) && (++b[hole] > b[most]))
278 	    most = hole;
279 	if (b[most] == 127) break;
280     }
281     kfree(b);
282 
283     bad = any = 0;
284     for (i = base; i < base+num; i += 8) {
285 	if (check_io_resource(i, 8, NULL))
286 	    continue;
287 	for (j = 0; j < 8; j++)
288 	    if (inb(i+j) != most) break;
289 	if (j < 8) {
290 	    if (!any)
291 		printk(" excluding");
292 	    if (!bad)
293 		bad = any = i;
294 	} else {
295 	    if (bad) {
296 		sub_interval(&io_db, bad, i-bad);
297 		printk(" %#04x-%#04x", bad, i-1);
298 		bad = 0;
299 	    }
300 	}
301     }
302     if (bad) {
303 	if ((num > 16) && (bad == base) && (i == base+num)) {
304 	    printk(" nothing: probe failed.\n");
305 	    return;
306 	} else {
307 	    sub_interval(&io_db, bad, i-bad);
308 	    printk(" %#04x-%#04x", bad, i-1);
309 	}
310     }
311 
312     printk(any ? "\n" : " clean.\n");
313 }
314 #endif
315 
316 /*======================================================================
317 
318     The memory probe.  If the memory list includes a 64K-aligned block
319     below 1MB, we probe in 64K chunks, and as soon as we accumulate at
320     least mem_limit free space, we quit.
321 
322 ======================================================================*/
323 
do_mem_probe(u_long base,u_long num,int (* is_valid)(u_long),int (* do_cksum)(u_long),socket_info_t * s)324 static int do_mem_probe(u_long base, u_long num,
325 			int (*is_valid)(u_long), int (*do_cksum)(u_long),
326 			socket_info_t *s)
327 {
328     u_long i, j, bad, fail, step;
329 
330     printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
331 	   base, base+num-1);
332     bad = fail = 0;
333     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
334     for (i = j = base; i < base+num; i = j + step) {
335 	if (!fail) {
336 	    for (j = i; j < base+num; j += step)
337 		if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) &&
338 		    is_valid(j))
339 		    break;
340 	    fail = ((i == base) && (j == base+num));
341 	}
342 	if (fail) {
343 	    for (j = i; j < base+num; j += 2*step)
344 		if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) &&
345 		    do_cksum(j) && do_cksum(j+step))
346 		    break;
347 	}
348 	if (i != j) {
349 	    if (!bad) printk(" excluding");
350 	    printk(" %#05lx-%#05lx", i, j-1);
351 	    sub_interval(&mem_db, i, j-i);
352 	    bad += j-i;
353 	}
354     }
355     printk(bad ? "\n" : " clean.\n");
356     return (num - bad);
357 }
358 
359 #ifdef CONFIG_ISA
360 
inv_probe(int (* is_valid)(u_long),int (* do_cksum)(u_long),resource_map_t * m,socket_info_t * s)361 static u_long inv_probe(int (*is_valid)(u_long),
362 			int (*do_cksum)(u_long),
363 			resource_map_t *m, socket_info_t *s)
364 {
365     u_long ok;
366     if (m == &mem_db)
367 	return 0;
368     ok = inv_probe(is_valid, do_cksum, m->next, s);
369     if (ok) {
370 	if (m->base >= 0x100000)
371 	    sub_interval(&mem_db, m->base, m->num);
372 	return ok;
373     }
374     if (m->base < 0x100000)
375 	return 0;
376     return do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
377 }
378 
validate_mem(int (* is_valid)(u_long),int (* do_cksum)(u_long),int force_low,socket_info_t * s)379 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
380 		  int force_low, socket_info_t *s)
381 {
382     resource_map_t *m, mm;
383     static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
384     static int hi = 0, lo = 0;
385     u_long b, i, ok = 0;
386 
387     if (!probe_mem) return;
388     /* We do up to four passes through the list */
389     if (!force_low) {
390 	if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0))
391 	    return;
392 	printk(KERN_NOTICE "cs: warning: no high memory space "
393 	       "available!\n");
394     }
395     if (lo++) return;
396     for (m = mem_db.next; m != &mem_db; m = mm.next) {
397 	mm = *m;
398 	/* Only probe < 1 MB */
399 	if (mm.base >= 0x100000) continue;
400 	if ((mm.base | mm.num) & 0xffff) {
401 	    ok += do_mem_probe(mm.base, mm.num, is_valid, do_cksum, s);
402 	    continue;
403 	}
404 	/* Special probe for 64K-aligned block */
405 	for (i = 0; i < 4; i++) {
406 	    b = order[i] << 12;
407 	    if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
408 		if (ok >= mem_limit)
409 		    sub_interval(&mem_db, b, 0x10000);
410 		else
411 		    ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s);
412 	    }
413 	}
414     }
415 }
416 
417 #else /* CONFIG_ISA */
418 
validate_mem(int (* is_valid)(u_long),int (* do_cksum)(u_long),int force_low,socket_info_t * s)419 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
420 		  int force_low, socket_info_t *s)
421 {
422     resource_map_t *m, *n;
423     static int done = 0;
424 
425     if (!probe_mem || done++)
426 	return;
427 
428     for (m = mem_db.next; m != &mem_db; m = n) {
429 	n = m->next;
430 	if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s))
431 	    return;
432     }
433 }
434 
435 #endif /* CONFIG_ISA */
436 
437 /*======================================================================
438 
439     These find ranges of I/O ports or memory addresses that are not
440     currently allocated by other devices.
441 
442     The 'align' field should reflect the number of bits of address
443     that need to be preserved from the initial value of *base.  It
444     should be a power of two, greater than or equal to 'num'.  A value
445     of 0 means that all bits of *base are significant.  *base should
446     also be strictly less than 'align'.
447 
448 ======================================================================*/
449 
find_io_region(ioaddr_t * base,ioaddr_t num,ioaddr_t align,char * name,socket_info_t * s)450 int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
451 		   char *name, socket_info_t *s)
452 {
453     ioaddr_t try;
454     resource_map_t *m;
455 
456     for (m = io_db.next; m != &io_db; m = m->next) {
457 	try = (m->base & ~(align-1)) + *base;
458 	for (try = (try >= m->base) ? try : try+align;
459 	     (try >= m->base) && (try+num <= m->base+m->num);
460 	     try += align) {
461 	    if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) {
462 		*base = try;
463 		return 0;
464 	    }
465 	    if (!align) break;
466 	}
467     }
468     return -1;
469 }
470 
find_mem_region(u_long * base,u_long num,u_long align,int force_low,char * name,socket_info_t * s)471 int find_mem_region(u_long *base, u_long num, u_long align,
472 		    int force_low, char *name, socket_info_t *s)
473 {
474     u_long try;
475     resource_map_t *m;
476 
477     while (1) {
478 	for (m = mem_db.next; m != &mem_db; m = m->next) {
479 	    /* first pass >1MB, second pass <1MB */
480 	    if ((force_low != 0) ^ (m->base < 0x100000)) continue;
481 	    try = (m->base & ~(align-1)) + *base;
482 	    for (try = (try >= m->base) ? try : try+align;
483 		 (try >= m->base) && (try+num <= m->base+m->num);
484 		 try += align) {
485 		if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) {
486 		    *base = try;
487 		    return 0;
488 		}
489 		if (!align) break;
490 	    }
491 	}
492 	if (force_low) break;
493 	force_low++;
494     }
495     return -1;
496 }
497 
498 /*======================================================================
499 
500     This checks to see if an interrupt is available, with support
501     for interrupt sharing.  We don't support reserving interrupts
502     yet.  If the interrupt is available, we allocate it.
503 
504 ======================================================================*/
505 
506 #ifdef CONFIG_ISA
507 
fake_irq(int i,void * d,struct pt_regs * r)508 static void fake_irq(int i, void *d, struct pt_regs *r) { }
check_irq(int irq)509 static inline int check_irq(int irq)
510 {
511     if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
512 	return -1;
513     free_irq(irq, NULL);
514     return 0;
515 }
516 
try_irq(u_int Attributes,int irq,int specific)517 int try_irq(u_int Attributes, int irq, int specific)
518 {
519     irq_info_t *info = &irq_table[irq];
520     if (info->Attributes & RES_ALLOCATED) {
521 	switch (Attributes & IRQ_TYPE) {
522 	case IRQ_TYPE_EXCLUSIVE:
523 	    return CS_IN_USE;
524 	case IRQ_TYPE_TIME:
525 	    if ((info->Attributes & RES_IRQ_TYPE)
526 		!= RES_IRQ_TYPE_TIME)
527 		return CS_IN_USE;
528 	    if (Attributes & IRQ_FIRST_SHARED)
529 		return CS_BAD_ATTRIBUTE;
530 	    info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
531 	    info->time_share++;
532 	    break;
533 	case IRQ_TYPE_DYNAMIC_SHARING:
534 	    if ((info->Attributes & RES_IRQ_TYPE)
535 		!= RES_IRQ_TYPE_DYNAMIC)
536 		return CS_IN_USE;
537 	    if (Attributes & IRQ_FIRST_SHARED)
538 		return CS_BAD_ATTRIBUTE;
539 	    info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
540 	    info->dyn_share++;
541 	    break;
542 	}
543     } else {
544 	if ((info->Attributes & RES_RESERVED) && !specific)
545 	    return CS_IN_USE;
546 	if (check_irq(irq) != 0)
547 	    return CS_IN_USE;
548 	switch (Attributes & IRQ_TYPE) {
549 	case IRQ_TYPE_EXCLUSIVE:
550 	    info->Attributes |= RES_ALLOCATED;
551 	    break;
552 	case IRQ_TYPE_TIME:
553 	    if (!(Attributes & IRQ_FIRST_SHARED))
554 		return CS_BAD_ATTRIBUTE;
555 	    info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
556 	    info->time_share = 1;
557 	    break;
558 	case IRQ_TYPE_DYNAMIC_SHARING:
559 	    if (!(Attributes & IRQ_FIRST_SHARED))
560 		return CS_BAD_ATTRIBUTE;
561 	    info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
562 	    info->dyn_share = 1;
563 	    break;
564 	}
565     }
566     return 0;
567 }
568 
569 #endif
570 
571 /*====================================================================*/
572 
573 #ifdef CONFIG_ISA
574 
undo_irq(u_int Attributes,int irq)575 void undo_irq(u_int Attributes, int irq)
576 {
577     irq_info_t *info;
578 
579     info = &irq_table[irq];
580     switch (Attributes & IRQ_TYPE) {
581     case IRQ_TYPE_EXCLUSIVE:
582 	info->Attributes &= RES_RESERVED;
583 	break;
584     case IRQ_TYPE_TIME:
585 	info->time_share--;
586 	if (info->time_share == 0)
587 	    info->Attributes &= RES_RESERVED;
588 	break;
589     case IRQ_TYPE_DYNAMIC_SHARING:
590 	info->dyn_share--;
591 	if (info->dyn_share == 0)
592 	    info->Attributes &= RES_RESERVED;
593 	break;
594     }
595 }
596 
597 #endif
598 
599 /*======================================================================
600 
601     The various adjust_* calls form the external interface to the
602     resource database.
603 
604 ======================================================================*/
605 
adjust_memory(adjust_t * adj)606 static int adjust_memory(adjust_t *adj)
607 {
608     u_long base, num;
609     int i, ret;
610 
611     base = adj->resource.memory.Base;
612     num = adj->resource.memory.Size;
613     if ((num == 0) || (base+num-1 < base))
614 	return CS_BAD_SIZE;
615 
616     ret = CS_SUCCESS;
617     switch (adj->Action) {
618     case ADD_MANAGED_RESOURCE:
619 	ret = add_interval(&mem_db, base, num);
620 	break;
621     case REMOVE_MANAGED_RESOURCE:
622 	ret = sub_interval(&mem_db, base, num);
623 	if (ret == CS_SUCCESS) {
624 	    for (i = 0; i < sockets; i++) {
625 		release_cis_mem(socket_table[i]);
626 #ifdef CONFIG_CARDBUS
627 		cb_release_cis_mem(socket_table[i]);
628 #endif
629 	    }
630 	}
631 	break;
632     default:
633 	ret = CS_UNSUPPORTED_FUNCTION;
634     }
635 
636     return ret;
637 }
638 
639 /*====================================================================*/
640 
adjust_io(adjust_t * adj)641 static int adjust_io(adjust_t *adj)
642 {
643     int base, num;
644 
645     base = adj->resource.io.BasePort;
646     num = adj->resource.io.NumPorts;
647     if ((base < 0) || (base > 0xffff))
648 	return CS_BAD_BASE;
649     if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
650 	return CS_BAD_SIZE;
651 
652     switch (adj->Action) {
653     case ADD_MANAGED_RESOURCE:
654 	if (add_interval(&io_db, base, num) != 0)
655 	    return CS_IN_USE;
656 #ifdef CONFIG_ISA
657 	if (probe_io)
658 	    do_io_probe(base, num);
659 #endif
660 	break;
661     case REMOVE_MANAGED_RESOURCE:
662 	sub_interval(&io_db, base, num);
663 	break;
664     default:
665 	return CS_UNSUPPORTED_FUNCTION;
666 	break;
667     }
668 
669     return CS_SUCCESS;
670 }
671 
672 /*====================================================================*/
673 
adjust_irq(adjust_t * adj)674 static int adjust_irq(adjust_t *adj)
675 {
676 #ifdef CONFIG_ISA
677     int irq;
678     irq_info_t *info;
679 
680     irq = adj->resource.irq.IRQ;
681     if ((irq < 0) || (irq > 15))
682 	return CS_BAD_IRQ;
683     info = &irq_table[irq];
684 
685     switch (adj->Action) {
686     case ADD_MANAGED_RESOURCE:
687 	if (info->Attributes & RES_REMOVED)
688 	    info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
689 	else
690 	    if (adj->Attributes & RES_ALLOCATED)
691 		return CS_IN_USE;
692 	if (adj->Attributes & RES_RESERVED)
693 	    info->Attributes |= RES_RESERVED;
694 	else
695 	    info->Attributes &= ~RES_RESERVED;
696 	break;
697     case REMOVE_MANAGED_RESOURCE:
698 	if (info->Attributes & RES_REMOVED)
699 	    return 0;
700 	if (info->Attributes & RES_ALLOCATED)
701 	    return CS_IN_USE;
702 	info->Attributes |= RES_ALLOCATED|RES_REMOVED;
703 	info->Attributes &= ~RES_RESERVED;
704 	break;
705     default:
706 	return CS_UNSUPPORTED_FUNCTION;
707 	break;
708     }
709 #endif
710     return CS_SUCCESS;
711 }
712 
713 /*====================================================================*/
714 
pcmcia_adjust_resource_info(client_handle_t handle,adjust_t * adj)715 int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj)
716 {
717     if (CHECK_HANDLE(handle))
718 	return CS_BAD_HANDLE;
719 
720     switch (adj->Resource) {
721     case RES_MEMORY_RANGE:
722 	return adjust_memory(adj);
723 	break;
724     case RES_IO_RANGE:
725 	return adjust_io(adj);
726 	break;
727     case RES_IRQ:
728 	return adjust_irq(adj);
729 	break;
730     }
731     return CS_UNSUPPORTED_FUNCTION;
732 }
733 
734 /*====================================================================*/
735 
release_resource_db(void)736 void release_resource_db(void)
737 {
738     resource_map_t *p, *q;
739 
740     for (p = mem_db.next; p != &mem_db; p = q) {
741 	q = p->next;
742 	kfree(p);
743     }
744     for (p = io_db.next; p != &io_db; p = q) {
745 	q = p->next;
746 	kfree(p);
747     }
748 }
749