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