patch-2_6_7-vs1_9_1_12
[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 - 1;
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 - 1) <= 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  * Adjust an existing IO region allocation, but making sure that we don't
585  * encroach outside the resources which the user supplied.
586  */
587 int adjust_io_region(struct resource *res, unsigned long r_start,
588                      unsigned long r_end, struct pcmcia_socket *s)
589 {
590         resource_map_t *m;
591         int ret = -ENOMEM;
592
593         down(&rsrc_sem);
594         for (m = io_db.next; m != &io_db; m = m->next) {
595                 unsigned long start = m->base;
596                 unsigned long end = m->base + m->num - 1;
597
598                 if (start > r_start || r_end > end)
599                         continue;
600
601                 ret = adjust_resource(res, r_start, r_end - r_start + 1);
602                 break;
603         }
604         up(&rsrc_sem);
605
606         return ret;
607 }
608
609 /*======================================================================
610
611     These find ranges of I/O ports or memory addresses that are not
612     currently allocated by other devices.
613
614     The 'align' field should reflect the number of bits of address
615     that need to be preserved from the initial value of *base.  It
616     should be a power of two, greater than or equal to 'num'.  A value
617     of 0 means that all bits of *base are significant.  *base should
618     also be strictly less than 'align'.
619     
620 ======================================================================*/
621
622 struct resource *find_io_region(unsigned long base, int num,
623                    unsigned long align, char *name, struct pcmcia_socket *s)
624 {
625         struct resource *res = make_resource(0, num, IORESOURCE_IO, name);
626         struct pcmcia_align_data data;
627         unsigned long min = base;
628         int ret;
629
630         if (align == 0)
631                 align = 0x10000;
632
633         data.mask = align - 1;
634         data.offset = base & data.mask;
635         data.map = &io_db;
636
637         down(&rsrc_sem);
638 #ifdef CONFIG_PCI
639         if (s->cb_dev) {
640                 ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
641                                              min, 0, pcmcia_align, &data);
642         } else
643 #endif
644                 ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, 0,
645                                         pcmcia_align, &data);
646         up(&rsrc_sem);
647
648         if (ret != 0) {
649                 kfree(res);
650                 res = NULL;
651         }
652         return res;
653 }
654
655 int find_mem_region(u_long *base, u_long num, u_long align,
656                     int low, char *name, struct pcmcia_socket *s)
657 {
658         struct resource *res = make_resource(0, num, IORESOURCE_MEM, name);
659         struct pcmcia_align_data data;
660         unsigned long min, max;
661         int ret, i;
662
663         low = low || !(s->features & SS_CAP_PAGE_REGS);
664
665         data.mask = align - 1;
666         data.offset = *base & data.mask;
667         data.map = &mem_db;
668
669         for (i = 0; i < 2; i++) {
670                 if (low) {
671                         max = 0x100000UL;
672                         min = *base < max ? *base : 0;
673                 } else {
674                         max = ~0UL;
675                         min = 0x100000UL + *base;
676                 }
677
678                 down(&rsrc_sem);
679 #ifdef CONFIG_PCI
680                 if (s->cb_dev) {
681                         ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
682                                                      1, min, 0,
683                                                      pcmcia_align, &data);
684                 } else
685 #endif
686                         ret = allocate_resource(&iomem_resource, res, num, min,
687                                                 max, 0, pcmcia_align, &data);
688                 up(&rsrc_sem);
689                 if (ret == 0 || low)
690                         break;
691                 low = 1;
692         }
693
694         if (ret != 0) {
695                 kfree(res);
696         } else {
697                 *base = res->start;
698         }
699         return ret;
700 }
701
702 /*======================================================================
703
704     This checks to see if an interrupt is available, with support
705     for interrupt sharing.  We don't support reserving interrupts
706     yet.  If the interrupt is available, we allocate it.
707     
708 ======================================================================*/
709
710 #ifdef CONFIG_PCMCIA_PROBE
711
712 static irqreturn_t fake_irq(int i, void *d, struct pt_regs *r) { return IRQ_NONE; }
713 static inline int check_irq(int irq)
714 {
715     if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
716         return -1;
717     free_irq(irq, NULL);
718     return 0;
719 }
720
721 int try_irq(u_int Attributes, int irq, int specific)
722 {
723     irq_info_t *info = &irq_table[irq];
724     int ret = 0;
725
726     down(&rsrc_sem);
727     if (info->Attributes & RES_ALLOCATED) {
728         switch (Attributes & IRQ_TYPE) {
729         case IRQ_TYPE_EXCLUSIVE:
730             ret = CS_IN_USE;
731             break;
732         case IRQ_TYPE_TIME:
733             if ((info->Attributes & RES_IRQ_TYPE)
734                 != RES_IRQ_TYPE_TIME) {
735                 ret = CS_IN_USE;
736                 break;
737             }
738             if (Attributes & IRQ_FIRST_SHARED) {
739                 ret = CS_BAD_ATTRIBUTE;
740                 break;
741             }
742             info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
743             info->time_share++;
744             break;
745         case IRQ_TYPE_DYNAMIC_SHARING:
746             if ((info->Attributes & RES_IRQ_TYPE)
747                 != RES_IRQ_TYPE_DYNAMIC) {
748                 ret = CS_IN_USE;
749                 break;
750             }
751             if (Attributes & IRQ_FIRST_SHARED) {
752                 ret = CS_BAD_ATTRIBUTE;
753                 break;
754             }
755             info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
756             info->dyn_share++;
757             break;
758         }
759     } else {
760         if ((info->Attributes & RES_RESERVED) && !specific) {
761             ret = CS_IN_USE;
762             goto out;
763         }
764         if (check_irq(irq) != 0) {
765             ret = CS_IN_USE;
766             goto out;
767         }
768         switch (Attributes & IRQ_TYPE) {
769         case IRQ_TYPE_EXCLUSIVE:
770             info->Attributes |= RES_ALLOCATED;
771             break;
772         case IRQ_TYPE_TIME:
773             if (!(Attributes & IRQ_FIRST_SHARED)) {
774                 ret = CS_BAD_ATTRIBUTE;
775                 break;
776             }
777             info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
778             info->time_share = 1;
779             break;
780         case IRQ_TYPE_DYNAMIC_SHARING:
781             if (!(Attributes & IRQ_FIRST_SHARED)) {
782                 ret = CS_BAD_ATTRIBUTE;
783                 break;
784             }
785             info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
786             info->dyn_share = 1;
787             break;
788         }
789     }
790  out:
791     up(&rsrc_sem);
792     return ret;
793 }
794
795 #endif
796
797 /*====================================================================*/
798
799 #ifdef CONFIG_PCMCIA_PROBE
800
801 void undo_irq(u_int Attributes, int irq)
802 {
803     irq_info_t *info;
804
805     info = &irq_table[irq];
806     down(&rsrc_sem);
807     switch (Attributes & IRQ_TYPE) {
808     case IRQ_TYPE_EXCLUSIVE:
809         info->Attributes &= RES_RESERVED;
810         break;
811     case IRQ_TYPE_TIME:
812         info->time_share--;
813         if (info->time_share == 0)
814             info->Attributes &= RES_RESERVED;
815         break;
816     case IRQ_TYPE_DYNAMIC_SHARING:
817         info->dyn_share--;
818         if (info->dyn_share == 0)
819             info->Attributes &= RES_RESERVED;
820         break;
821     }
822     up(&rsrc_sem);
823 }
824
825 #endif
826
827 /*======================================================================
828
829     The various adjust_* calls form the external interface to the
830     resource database.
831     
832 ======================================================================*/
833
834 static int adjust_memory(adjust_t *adj)
835 {
836     u_long base, num;
837     int ret;
838
839     base = adj->resource.memory.Base;
840     num = adj->resource.memory.Size;
841     if ((num == 0) || (base+num-1 < base))
842         return CS_BAD_SIZE;
843
844     ret = CS_SUCCESS;
845
846     down(&rsrc_sem);
847     switch (adj->Action) {
848     case ADD_MANAGED_RESOURCE:
849         ret = add_interval(&mem_db, base, num);
850         break;
851     case REMOVE_MANAGED_RESOURCE:
852         ret = sub_interval(&mem_db, base, num);
853         if (ret == CS_SUCCESS) {
854                 struct pcmcia_socket *socket;
855                 down_read(&pcmcia_socket_list_rwsem);
856                 list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
857                         release_cis_mem(socket);
858                 up_read(&pcmcia_socket_list_rwsem);
859         }
860         break;
861     default:
862         ret = CS_UNSUPPORTED_FUNCTION;
863     }
864     up(&rsrc_sem);
865     
866     return ret;
867 }
868
869 /*====================================================================*/
870
871 static int adjust_io(adjust_t *adj)
872 {
873     int base, num, ret = CS_SUCCESS;
874     
875     base = adj->resource.io.BasePort;
876     num = adj->resource.io.NumPorts;
877     if ((base < 0) || (base > 0xffff))
878         return CS_BAD_BASE;
879     if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
880         return CS_BAD_SIZE;
881
882     down(&rsrc_sem);
883     switch (adj->Action) {
884     case ADD_MANAGED_RESOURCE:
885         if (add_interval(&io_db, base, num) != 0) {
886             ret = CS_IN_USE;
887             break;
888         }
889 #ifdef CONFIG_PCMCIA_PROBE
890         if (probe_io)
891             do_io_probe(base, num);
892 #endif
893         break;
894     case REMOVE_MANAGED_RESOURCE:
895         sub_interval(&io_db, base, num);
896         break;
897     default:
898         ret = CS_UNSUPPORTED_FUNCTION;
899         break;
900     }
901     up(&rsrc_sem);
902
903     return ret;
904 }
905
906 /*====================================================================*/
907
908 static int adjust_irq(adjust_t *adj)
909 {
910     int ret = CS_SUCCESS;
911 #ifdef CONFIG_PCMCIA_PROBE
912     int irq;
913     irq_info_t *info;
914     
915     irq = adj->resource.irq.IRQ;
916     if ((irq < 0) || (irq > 15))
917         return CS_BAD_IRQ;
918     info = &irq_table[irq];
919
920     down(&rsrc_sem);
921     switch (adj->Action) {
922     case ADD_MANAGED_RESOURCE:
923         if (info->Attributes & RES_REMOVED)
924             info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
925         else
926             if (adj->Attributes & RES_ALLOCATED) {
927                 ret = CS_IN_USE;
928                 break;
929             }
930         if (adj->Attributes & RES_RESERVED)
931             info->Attributes |= RES_RESERVED;
932         else
933             info->Attributes &= ~RES_RESERVED;
934         break;
935     case REMOVE_MANAGED_RESOURCE:
936         if (info->Attributes & RES_REMOVED) {
937             ret = 0;
938             break;
939         }
940         if (info->Attributes & RES_ALLOCATED) {
941             ret = CS_IN_USE;
942             break;
943         }
944         info->Attributes |= RES_ALLOCATED|RES_REMOVED;
945         info->Attributes &= ~RES_RESERVED;
946         break;
947     default:
948         ret = CS_UNSUPPORTED_FUNCTION;
949         break;
950     }
951     up(&rsrc_sem);
952 #endif
953     return ret;
954 }
955
956 /*====================================================================*/
957
958 int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj)
959 {
960     if (CHECK_HANDLE(handle))
961         return CS_BAD_HANDLE;
962     
963     switch (adj->Resource) {
964     case RES_MEMORY_RANGE:
965         return adjust_memory(adj);
966         break;
967     case RES_IO_RANGE:
968         return adjust_io(adj);
969         break;
970     case RES_IRQ:
971         return adjust_irq(adj);
972         break;
973     }
974     return CS_UNSUPPORTED_FUNCTION;
975 }
976
977 /*====================================================================*/
978
979 void release_resource_db(void)
980 {
981     resource_map_t *p, *q;
982     
983     for (p = mem_db.next; p != &mem_db; p = q) {
984         q = p->next;
985         kfree(p);
986     }
987     for (p = io_db.next; p != &io_db; p = q) {
988         q = p->next;
989         kfree(p);
990     }
991 }