ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / pcmcia / rsrc_mgr.c
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 #include <linux/config.h>
35 #include <linux/module.h>
36 #include <linux/moduleparam.h>
37 #include <linux/init.h>
38 #include <linux/interrupt.h>
39 #include <linux/kernel.h>
40 #include <linux/errno.h>
41 #include <linux/types.h>
42 #include <linux/slab.h>
43 #include <linux/ioport.h>
44 #include <linux/timer.h>
45 #include <linux/pci.h>
46 #include <asm/irq.h>
47 #include <asm/io.h>
48
49 #include <pcmcia/cs_types.h>
50 #include <pcmcia/ss.h>
51 #include <pcmcia/cs.h>
52 #include <pcmcia/bulkmem.h>
53 #include <pcmcia/cistpl.h>
54 #include "cs_internal.h"
55
56 /*====================================================================*/
57
58 /* Parameters that can be set with 'insmod' */
59
60 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
61
62 INT_MODULE_PARM(probe_mem,      1);             /* memory probe? */
63 #ifdef CONFIG_PCMCIA_PROBE
64 INT_MODULE_PARM(probe_io,       1);             /* IO port probe? */
65 INT_MODULE_PARM(mem_limit,      0x10000);
66 #endif
67
68 /*======================================================================
69
70     The resource_map_t structures are used to track what resources are
71     available for allocation for PC Card devices.
72
73 ======================================================================*/
74
75 typedef struct resource_map_t {
76     u_long                      base, num;
77     struct resource_map_t       *next;
78 } resource_map_t;
79
80 /* Memory resource database */
81 static resource_map_t mem_db = {
82         .next   = &mem_db,
83 };
84
85 /* IO port resource database */
86 static resource_map_t io_db = {
87         .next   = &io_db,
88 };
89
90 static DECLARE_MUTEX(rsrc_sem);
91
92 #ifdef CONFIG_PCMCIA_PROBE
93
94 typedef struct irq_info_t {
95     u_int                       Attributes;
96     int                         time_share, dyn_share;
97     struct pcmcia_socket        *Socket;
98 } irq_info_t;
99
100 /* Table of IRQ assignments */
101 static irq_info_t irq_table[NR_IRQS];
102
103 #endif
104
105 /*======================================================================
106
107     Linux resource management extensions
108
109 ======================================================================*/
110
111 static struct resource *
112 make_resource(unsigned long b, unsigned long n, int flags, char *name)
113 {
114         struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
115
116         if (res) {
117                 memset(res, 0, sizeof(*res));
118                 res->name = name;
119                 res->start = b;
120                 res->end = b + n - 1;
121                 res->flags = flags | IORESOURCE_BUSY;
122         }
123         return res;
124 }
125
126 static struct resource *
127 claim_region(struct pcmcia_socket *s, unsigned long base, unsigned long size,
128              int type, char *name)
129 {
130         struct resource *res, *parent;
131
132         parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
133         res = make_resource(base, size, type | IORESOURCE_BUSY, name);
134
135         if (res) {
136 #ifdef CONFIG_PCI
137                 if (s && s->cb_dev)
138                         parent = pci_find_parent_resource(s->cb_dev, res);
139 #endif
140                 if (!parent || request_resource(parent, res)) {
141                         kfree(res);
142                         res = NULL;
143                 }
144         }
145         return res;
146 }
147
148 static void free_region(struct resource *res)
149 {
150         if (res) {
151                 release_resource(res);
152                 kfree(res);
153         }
154 }
155
156 /*======================================================================
157
158     These manage the internal databases of available resources.
159     
160 ======================================================================*/
161
162 static int add_interval(resource_map_t *map, u_long base, u_long num)
163 {
164     resource_map_t *p, *q;
165
166     for (p = map; ; p = p->next) {
167         if ((p != map) && (p->base+p->num-1 >= base))
168             return -1;
169         if ((p->next == map) || (p->next->base > base+num-1))
170             break;
171     }
172     q = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
173     if (!q) return CS_OUT_OF_RESOURCE;
174     q->base = base; q->num = num;
175     q->next = p->next; p->next = q;
176     return CS_SUCCESS;
177 }
178
179 /*====================================================================*/
180
181 static int sub_interval(resource_map_t *map, u_long base, u_long num)
182 {
183     resource_map_t *p, *q;
184
185     for (p = map; ; p = q) {
186         q = p->next;
187         if (q == map)
188             break;
189         if ((q->base+q->num > base) && (base+num > q->base)) {
190             if (q->base >= base) {
191                 if (q->base+q->num <= base+num) {
192                     /* Delete whole block */
193                     p->next = q->next;
194                     kfree(q);
195                     /* don't advance the pointer yet */
196                     q = p;
197                 } else {
198                     /* Cut off bit from the front */
199                     q->num = q->base + q->num - base - num;
200                     q->base = base + num;
201                 }
202             } else if (q->base+q->num <= base+num) {
203                 /* Cut off bit from the end */
204                 q->num = base - q->base;
205             } else {
206                 /* Split the block into two pieces */
207                 p = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
208                 if (!p) return CS_OUT_OF_RESOURCE;
209                 p->base = base+num;
210                 p->num = q->base+q->num - p->base;
211                 q->num = base - q->base;
212                 p->next = q->next ; q->next = p;
213             }
214         }
215     }
216     return CS_SUCCESS;
217 }
218
219 /*======================================================================
220
221     These routines examine a region of IO or memory addresses to
222     determine what ranges might be genuinely available.
223     
224 ======================================================================*/
225
226 #ifdef CONFIG_PCMCIA_PROBE
227 static void do_io_probe(ioaddr_t base, ioaddr_t num)
228 {
229     struct resource *res;
230     ioaddr_t i, j, bad, any;
231     u_char *b, hole, most;
232     
233     printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:",
234            base, base+num-1);
235     
236     /* First, what does a floating port look like? */
237     b = kmalloc(256, GFP_KERNEL);
238     if (!b) {
239             printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes");
240             return;
241     }   
242     memset(b, 0, 256);
243     for (i = base, most = 0; i < base+num; i += 8) {
244         res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe");
245         if (!res)
246             continue;
247         hole = inb(i);
248         for (j = 1; j < 8; j++)
249             if (inb(i+j) != hole) break;
250         free_region(res);
251         if ((j == 8) && (++b[hole] > b[most]))
252             most = hole;
253         if (b[most] == 127) break;
254     }
255     kfree(b);
256
257     bad = any = 0;
258     for (i = base; i < base+num; i += 8) {
259         res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe");
260         if (!res)
261             continue;
262         for (j = 0; j < 8; j++)
263             if (inb(i+j) != most) break;
264         free_region(res);
265         if (j < 8) {
266             if (!any)
267                 printk(" excluding");
268             if (!bad)
269                 bad = any = i;
270         } else {
271             if (bad) {
272                 sub_interval(&io_db, bad, i-bad);
273                 printk(" %#04x-%#04x", bad, i-1);
274                 bad = 0;
275             }
276         }
277     }
278     if (bad) {
279         if ((num > 16) && (bad == base) && (i == base+num)) {
280             printk(" nothing: probe failed.\n");
281             return;
282         } else {
283             sub_interval(&io_db, bad, i-bad);
284             printk(" %#04x-%#04x", bad, i-1);
285         }
286     }
287     
288     printk(any ? "\n" : " clean.\n");
289 }
290 #endif
291
292 /*======================================================================
293
294     This is tricky... when we set up CIS memory, we try to validate
295     the memory window space allocations.
296     
297 ======================================================================*/
298
299 /* Validation function for cards with a valid CIS */
300 static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *info)
301 {
302         int ret = -1;
303
304         s->cis_mem.sys_start = res->start;
305         s->cis_mem.sys_stop = res->end;
306         s->cis_virt = ioremap(res->start, s->map_size);
307         if (s->cis_virt) {
308                 ret = pcmcia_validate_cis(s->clients, info);
309                 /* invalidate mapping and CIS cache */
310                 iounmap(s->cis_virt);
311                 s->cis_virt = NULL;
312                 destroy_cis_cache(s);
313         }
314         s->cis_mem.sys_start = 0;
315         s->cis_mem.sys_stop = 0;
316         if ((ret != 0) || (info->Chains == 0))
317                 return 0;
318         return 1;
319 }
320
321 /* Validation function for simple memory cards */
322 static int checksum(struct pcmcia_socket *s, struct resource *res)
323 {
324         pccard_mem_map map;
325         int i, a = 0, b = -1, d;
326         void *virt;
327
328         virt = ioremap(res->start, s->map_size);
329         if (virt) {
330                 map.map = 0;
331                 map.flags = MAP_ACTIVE;
332                 map.speed = 0;
333                 map.sys_start = res->start;
334                 map.sys_stop = res->end;
335                 map.card_start = 0;
336                 s->ops->set_mem_map(s, &map);
337
338                 /* Don't bother checking every word... */
339                 for (i = 0; i < s->map_size; i += 44) {
340                         d = readl(virt+i);
341                         a += d;
342                         b &= d;
343                 }
344
345                 map.flags = 0;
346                 s->ops->set_mem_map(s, &map);
347
348                 iounmap(virt);
349         }
350
351         return (b == -1) ? -1 : (a>>1);
352 }
353
354 static int
355 cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size)
356 {
357         struct resource *res1, *res2;
358         cisinfo_t info1, info2;
359         int ret = 0;
360
361         res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe");
362         res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "cs memory probe");
363
364         if (res1 && res2) {
365                 ret = readable(s, res1, &info1);
366                 ret += readable(s, res2, &info2);
367         }
368
369         free_region(res2);
370         free_region(res1);
371
372         return (ret == 2) && (info1.Chains == info2.Chains);
373 }
374
375 static int
376 checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size)
377 {
378         struct resource *res1, *res2;
379         int a = -1, b = -1;
380
381         res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe");
382         res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "cs memory probe");
383
384         if (res1 && res2) {
385                 a = checksum(s, res1);
386                 b = checksum(s, res2);
387         }
388
389         free_region(res2);
390         free_region(res1);
391
392         return (a == b) && (a >= 0);
393 }
394
395 /*======================================================================
396
397     The memory probe.  If the memory list includes a 64K-aligned block
398     below 1MB, we probe in 64K chunks, and as soon as we accumulate at
399     least mem_limit free space, we quit.
400     
401 ======================================================================*/
402
403 static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
404 {
405     u_long i, j, bad, fail, step;
406
407     printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
408            base, base+num-1);
409     bad = fail = 0;
410     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
411     /* cis_readable wants to map 2x map_size */
412     if (step < 2 * s->map_size)
413         step = 2 * s->map_size;
414     for (i = j = base; i < base+num; i = j + step) {
415         if (!fail) {    
416             for (j = i; j < base+num; j += step) {
417                 if (cis_readable(s, j, step))
418                     break;
419             }
420             fail = ((i == base) && (j == base+num));
421         }
422         if (fail) {
423             for (j = i; j < base+num; j += 2*step)
424                 if (checksum_match(s, j, step) &&
425                     checksum_match(s, j + step, step))
426                     break;
427         }
428         if (i != j) {
429             if (!bad) printk(" excluding");
430             printk(" %#05lx-%#05lx", i, j-1);
431             sub_interval(&mem_db, i, j-i);
432             bad += j-i;
433         }
434     }
435     printk(bad ? "\n" : " clean.\n");
436     return (num - bad);
437 }
438
439 #ifdef CONFIG_PCMCIA_PROBE
440
441 static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s)
442 {
443     u_long ok;
444     if (m == &mem_db)
445         return 0;
446     ok = inv_probe(m->next, s);
447     if (ok) {
448         if (m->base >= 0x100000)
449             sub_interval(&mem_db, m->base, m->num);
450         return ok;
451     }
452     if (m->base < 0x100000)
453         return 0;
454     return do_mem_probe(m->base, m->num, s);
455 }
456
457 void validate_mem(struct pcmcia_socket *s)
458 {
459     resource_map_t *m, mm;
460     static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
461     static int hi = 0, lo = 0;
462     u_long b, i, ok = 0;
463     int force_low = !(s->features & SS_CAP_PAGE_REGS);
464
465     if (!probe_mem)
466         return;
467
468     down(&rsrc_sem);
469     /* We do up to four passes through the list */
470     if (!force_low) {
471         if (hi++ || (inv_probe(mem_db.next, s) > 0))
472             goto out;
473         printk(KERN_NOTICE "cs: warning: no high memory space "
474                "available!\n");
475     }
476     if (lo++)
477         goto out;
478     for (m = mem_db.next; m != &mem_db; m = mm.next) {
479         mm = *m;
480         /* Only probe < 1 MB */
481         if (mm.base >= 0x100000) continue;
482         if ((mm.base | mm.num) & 0xffff) {
483             ok += do_mem_probe(mm.base, mm.num, s);
484             continue;
485         }
486         /* Special probe for 64K-aligned block */
487         for (i = 0; i < 4; i++) {
488             b = order[i] << 12;
489             if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
490                 if (ok >= mem_limit)
491                     sub_interval(&mem_db, b, 0x10000);
492                 else
493                     ok += do_mem_probe(b, 0x10000, s);
494             }
495         }
496     }
497  out:
498     up(&rsrc_sem);
499 }
500
501 #else /* CONFIG_PCMCIA_PROBE */
502
503 void validate_mem(struct pcmcia_socket *s)
504 {
505     resource_map_t *m, mm;
506     static int done = 0;
507     
508     if (probe_mem && done++ == 0) {
509         down(&rsrc_sem);
510         for (m = mem_db.next; m != &mem_db; m = mm.next) {
511             mm = *m;
512             if (do_mem_probe(mm.base, mm.num, s))
513                 break;
514         }
515         up(&rsrc_sem);
516     }
517 }
518
519 #endif /* CONFIG_PCMCIA_PROBE */
520
521 struct pcmcia_align_data {
522         unsigned long   mask;
523         unsigned long   offset;
524         resource_map_t  *map;
525 };
526
527 static void
528 pcmcia_common_align(void *align_data, struct resource *res,
529                     unsigned long size, unsigned long align)
530 {
531         struct pcmcia_align_data *data = align_data;
532         unsigned long start;
533         /*
534          * Ensure that we have the correct start address
535          */
536         start = (res->start & ~data->mask) + data->offset;
537         if (start < res->start)
538                 start += data->mask + 1;
539         res->start = start;
540 }
541
542 static void
543 pcmcia_align(void *align_data, struct resource *res,
544              unsigned long size, unsigned long align)
545 {
546         struct pcmcia_align_data *data = align_data;
547         resource_map_t *m;
548
549         pcmcia_common_align(data, res, size, align);
550
551         for (m = data->map->next; m != data->map; m = m->next) {
552                 unsigned long start = m->base;
553                 unsigned long end = m->base + m->num;
554
555                 /*
556                  * If the lower resources are not available, try aligning
557                  * to this entry of the resource database to see if it'll
558                  * fit here.
559                  */
560                 if (res->start < start) {
561                         res->start = start;
562                         pcmcia_common_align(data, res, size, align);
563                 }
564
565                 /*
566                  * If we're above the area which was passed in, there's
567                  * no point proceeding.
568                  */
569                 if (res->start >= res->end)
570                         break;
571
572                 if ((res->start + size) <= end)
573                         break;
574         }
575
576         /*
577          * If we failed to find something suitable, ensure we fail.
578          */
579         if (m == data->map)
580                 res->start = res->end;
581 }
582
583 /*======================================================================
584
585     These find ranges of I/O ports or memory addresses that are not
586     currently allocated by other devices.
587
588     The 'align' field should reflect the number of bits of address
589     that need to be preserved from the initial value of *base.  It
590     should be a power of two, greater than or equal to 'num'.  A value
591     of 0 means that all bits of *base are significant.  *base should
592     also be strictly less than 'align'.
593     
594 ======================================================================*/
595
596 int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align,
597                    char *name, struct pcmcia_socket *s)
598 {
599         struct resource *res = make_resource(0, num, IORESOURCE_IO, name);
600         struct pcmcia_align_data data;
601         unsigned long min = *base;
602         int ret;
603
604         if (align == 0)
605                 align = 0x10000;
606
607         data.mask = align - 1;
608         data.offset = *base & data.mask;
609         data.map = &io_db;
610
611 #ifdef CONFIG_PCI
612         if (s->cb_dev) {
613                 ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
614                                              min, 0, pcmcia_align, &data);
615         } else
616 #endif
617         {
618                 down(&rsrc_sem);
619                 ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, 0,
620                                         pcmcia_align, &data);
621                 up(&rsrc_sem);
622         }
623
624         if (ret != 0) {
625                 kfree(res);
626         } else {
627                 *base = res->start;
628         }
629         return ret;
630 }
631
632 int find_mem_region(u_long *base, u_long num, u_long align,
633                     int low, char *name, struct pcmcia_socket *s)
634 {
635         struct resource *res = make_resource(0, num, IORESOURCE_MEM, name);
636         struct pcmcia_align_data data;
637         unsigned long min, max;
638         int ret, i;
639
640         low = low || !(s->features & SS_CAP_PAGE_REGS);
641
642         data.mask = align - 1;
643         data.offset = *base & data.mask;
644         data.map = &mem_db;
645
646         for (i = 0; i < 2; i++) {
647                 if (low) {
648                         max = 0x100000UL;
649                         min = *base < max ? *base : 0;
650                 } else {
651                         max = ~0UL;
652                         min = 0x100000UL + *base;
653                 }
654
655 #ifdef CONFIG_PCI
656                 if (s->cb_dev) {
657                         ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
658                                                      1, min, 0,
659                                                      pcmcia_align, &data);
660                 } else
661 #endif
662                 {
663                         down(&rsrc_sem);
664                         ret = allocate_resource(&iomem_resource, res, num, min,
665                                                 max, 0, pcmcia_align, &data);
666                         up(&rsrc_sem);
667                 }
668                 if (ret == 0 || low)
669                         break;
670                 low = 1;
671         }
672
673         if (ret != 0) {
674                 kfree(res);
675         } else {
676                 *base = res->start;
677         }
678         return ret;
679 }
680
681 /*======================================================================
682
683     This checks to see if an interrupt is available, with support
684     for interrupt sharing.  We don't support reserving interrupts
685     yet.  If the interrupt is available, we allocate it.
686     
687 ======================================================================*/
688
689 #ifdef CONFIG_PCMCIA_PROBE
690
691 static irqreturn_t fake_irq(int i, void *d, struct pt_regs *r) { return IRQ_NONE; }
692 static inline int check_irq(int irq)
693 {
694     if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
695         return -1;
696     free_irq(irq, NULL);
697     return 0;
698 }
699
700 int try_irq(u_int Attributes, int irq, int specific)
701 {
702     irq_info_t *info = &irq_table[irq];
703     int ret = 0;
704
705     down(&rsrc_sem);
706     if (info->Attributes & RES_ALLOCATED) {
707         switch (Attributes & IRQ_TYPE) {
708         case IRQ_TYPE_EXCLUSIVE:
709             ret = CS_IN_USE;
710             break;
711         case IRQ_TYPE_TIME:
712             if ((info->Attributes & RES_IRQ_TYPE)
713                 != RES_IRQ_TYPE_TIME) {
714                 ret = CS_IN_USE;
715                 break;
716             }
717             if (Attributes & IRQ_FIRST_SHARED) {
718                 ret = CS_BAD_ATTRIBUTE;
719                 break;
720             }
721             info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
722             info->time_share++;
723             break;
724         case IRQ_TYPE_DYNAMIC_SHARING:
725             if ((info->Attributes & RES_IRQ_TYPE)
726                 != RES_IRQ_TYPE_DYNAMIC) {
727                 ret = CS_IN_USE;
728                 break;
729             }
730             if (Attributes & IRQ_FIRST_SHARED) {
731                 ret = CS_BAD_ATTRIBUTE;
732                 break;
733             }
734             info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
735             info->dyn_share++;
736             break;
737         }
738     } else {
739         if ((info->Attributes & RES_RESERVED) && !specific) {
740             ret = CS_IN_USE;
741             goto out;
742         }
743         if (check_irq(irq) != 0) {
744             ret = CS_IN_USE;
745             goto out;
746         }
747         switch (Attributes & IRQ_TYPE) {
748         case IRQ_TYPE_EXCLUSIVE:
749             info->Attributes |= RES_ALLOCATED;
750             break;
751         case IRQ_TYPE_TIME:
752             if (!(Attributes & IRQ_FIRST_SHARED)) {
753                 ret = CS_BAD_ATTRIBUTE;
754                 break;
755             }
756             info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
757             info->time_share = 1;
758             break;
759         case IRQ_TYPE_DYNAMIC_SHARING:
760             if (!(Attributes & IRQ_FIRST_SHARED)) {
761                 ret = CS_BAD_ATTRIBUTE;
762                 break;
763             }
764             info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
765             info->dyn_share = 1;
766             break;
767         }
768     }
769  out:
770     up(&rsrc_sem);
771     return ret;
772 }
773
774 #endif
775
776 /*====================================================================*/
777
778 #ifdef CONFIG_PCMCIA_PROBE
779
780 void undo_irq(u_int Attributes, int irq)
781 {
782     irq_info_t *info;
783
784     info = &irq_table[irq];
785     down(&rsrc_sem);
786     switch (Attributes & IRQ_TYPE) {
787     case IRQ_TYPE_EXCLUSIVE:
788         info->Attributes &= RES_RESERVED;
789         break;
790     case IRQ_TYPE_TIME:
791         info->time_share--;
792         if (info->time_share == 0)
793             info->Attributes &= RES_RESERVED;
794         break;
795     case IRQ_TYPE_DYNAMIC_SHARING:
796         info->dyn_share--;
797         if (info->dyn_share == 0)
798             info->Attributes &= RES_RESERVED;
799         break;
800     }
801     up(&rsrc_sem);
802 }
803
804 #endif
805
806 /*======================================================================
807
808     The various adjust_* calls form the external interface to the
809     resource database.
810     
811 ======================================================================*/
812
813 static int adjust_memory(adjust_t *adj)
814 {
815     u_long base, num;
816     int ret;
817
818     base = adj->resource.memory.Base;
819     num = adj->resource.memory.Size;
820     if ((num == 0) || (base+num-1 < base))
821         return CS_BAD_SIZE;
822
823     ret = CS_SUCCESS;
824
825     down(&rsrc_sem);
826     switch (adj->Action) {
827     case ADD_MANAGED_RESOURCE:
828         ret = add_interval(&mem_db, base, num);
829         break;
830     case REMOVE_MANAGED_RESOURCE:
831         ret = sub_interval(&mem_db, base, num);
832         if (ret == CS_SUCCESS) {
833                 struct pcmcia_socket *socket;
834                 down_read(&pcmcia_socket_list_rwsem);
835                 list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
836                         release_cis_mem(socket);
837                 up_read(&pcmcia_socket_list_rwsem);
838         }
839         break;
840     default:
841         ret = CS_UNSUPPORTED_FUNCTION;
842     }
843     up(&rsrc_sem);
844     
845     return ret;
846 }
847
848 /*====================================================================*/
849
850 static int adjust_io(adjust_t *adj)
851 {
852     int base, num, ret = CS_SUCCESS;
853     
854     base = adj->resource.io.BasePort;
855     num = adj->resource.io.NumPorts;
856     if ((base < 0) || (base > 0xffff))
857         return CS_BAD_BASE;
858     if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
859         return CS_BAD_SIZE;
860
861     down(&rsrc_sem);
862     switch (adj->Action) {
863     case ADD_MANAGED_RESOURCE:
864         if (add_interval(&io_db, base, num) != 0) {
865             ret = CS_IN_USE;
866             break;
867         }
868 #ifdef CONFIG_PCMCIA_PROBE
869         if (probe_io)
870             do_io_probe(base, num);
871 #endif
872         break;
873     case REMOVE_MANAGED_RESOURCE:
874         sub_interval(&io_db, base, num);
875         break;
876     default:
877         ret = CS_UNSUPPORTED_FUNCTION;
878         break;
879     }
880     up(&rsrc_sem);
881
882     return ret;
883 }
884
885 /*====================================================================*/
886
887 static int adjust_irq(adjust_t *adj)
888 {
889     int ret = CS_SUCCESS;
890 #ifdef CONFIG_PCMCIA_PROBE
891     int irq;
892     irq_info_t *info;
893     
894     irq = adj->resource.irq.IRQ;
895     if ((irq < 0) || (irq > 15))
896         return CS_BAD_IRQ;
897     info = &irq_table[irq];
898
899     down(&rsrc_sem);
900     switch (adj->Action) {
901     case ADD_MANAGED_RESOURCE:
902         if (info->Attributes & RES_REMOVED)
903             info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
904         else
905             if (adj->Attributes & RES_ALLOCATED) {
906                 ret = CS_IN_USE;
907                 break;
908             }
909         if (adj->Attributes & RES_RESERVED)
910             info->Attributes |= RES_RESERVED;
911         else
912             info->Attributes &= ~RES_RESERVED;
913         break;
914     case REMOVE_MANAGED_RESOURCE:
915         if (info->Attributes & RES_REMOVED) {
916             ret = 0;
917             break;
918         }
919         if (info->Attributes & RES_ALLOCATED) {
920             ret = CS_IN_USE;
921             break;
922         }
923         info->Attributes |= RES_ALLOCATED|RES_REMOVED;
924         info->Attributes &= ~RES_RESERVED;
925         break;
926     default:
927         ret = CS_UNSUPPORTED_FUNCTION;
928         break;
929     }
930     up(&rsrc_sem);
931 #endif
932     return ret;
933 }
934
935 /*====================================================================*/
936
937 int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj)
938 {
939     if (CHECK_HANDLE(handle))
940         return CS_BAD_HANDLE;
941     
942     switch (adj->Resource) {
943     case RES_MEMORY_RANGE:
944         return adjust_memory(adj);
945         break;
946     case RES_IO_RANGE:
947         return adjust_io(adj);
948         break;
949     case RES_IRQ:
950         return adjust_irq(adj);
951         break;
952     }
953     return CS_UNSUPPORTED_FUNCTION;
954 }
955
956 /*====================================================================*/
957
958 void release_resource_db(void)
959 {
960     resource_map_t *p, *q;
961     
962     for (p = mem_db.next; p != &mem_db; p = q) {
963         q = p->next;
964         kfree(p);
965     }
966     for (p = io_db.next; p != &io_db; p = q) {
967         q = p->next;
968         kfree(p);
969     }
970 }