Bug Summary

File:obj-scan-build/../linux/pcmcia-cs/modules/rsrc_mgr.c
Location:line 732, column 5
Description:Value stored to 'ret' is never read

Annotated Source Code

1/*======================================================================
2
3 Resource management routines
4
5 rsrc_mgr.c 1.94 2003/12/12 17:12:53
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
23 which 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/spinlock.h>
47#include <asm/irq.h>
48#include <asm/io.h>
49
50#include <pcmcia/cs_types.h>
51#include <pcmcia/ss.h>
52#include <pcmcia/cs.h>
53#include <pcmcia/bulkmem.h>
54#include <pcmcia/cistpl.h>
55#include "cs_internal.h"
56
57/*====================================================================*/
58
59/* Parameters that can be set with 'insmod' */
60
61#define INT_MODULE_PARM(n, v)static int n = v; static int n = v; MODULE_PARM(n, "i")
62
63INT_MODULE_PARM(probe_mem, 1)static int probe_mem = 1;; /* memory probe? */
64#ifdef CONFIG_ISA1
65INT_MODULE_PARM(probe_io, 1)static int probe_io = 1;; /* IO port probe? */
66INT_MODULE_PARM(mem_limit, 0x10000)static int mem_limit = 0x10000;;
67#endif
68
69/*======================================================================
70
71 The resource_map_t structures are used to track what resources are
72 available for allocation for PC Card devices.
73
74======================================================================*/
75
76typedef struct resource_map_t {
77 u_long base, num;
78 struct resource_map_t *next;
79} resource_map_t;
80
81/* Memory resource database */
82static resource_map_t mem_db = { 0, 0, &mem_db };
83
84/* IO port resource database */
85static resource_map_t io_db = { 0, 0, &io_db };
86
87#ifdef CONFIG_ISA1
88
89typedef struct irq_info_t {
90 u_int Attributes;
91 int time_share, dyn_share;
92 struct socket_info_t *Socket;
93} irq_info_t;
94
95/* Table of ISA IRQ assignments */
96static irq_info_t irq_table[16] = { { 0, 0, 0 }, /* etc */ };
97
98#endif
99
100/*======================================================================
101
102 Linux resource management extensions
103
104======================================================================*/
105
106#ifndef CONFIG_PNP_BIOS
107#define check_io_region(b,n)(0) (0)
108#endif
109
110#if defined(CONFIG_PNP_BIOS) || !defined(HAVE_MEMRESERVE)
111
112#ifdef __SMP__
113static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED(spinlock_t) { };
114#endif
115
116typedef struct resource_entry_t {
117 u_long base, num;
118 char *name;
119 struct resource_entry_t *next;
120} resource_entry_t;
121
122/* Ordered linked lists of allocated IO and memory blocks */
123#ifdef CONFIG_PNP_BIOS
124static resource_entry_t io_list = { 0, 0, NULL((void *) 0), NULL((void *) 0) };
125#endif
126#ifndef HAVE_MEMRESERVE
127static resource_entry_t mem_list = { 0, 0, NULL((void *) 0), NULL((void *) 0) };
128#endif
129
130static resource_entry_t *find_gap(resource_entry_t *root,
131 resource_entry_t *entry)
132{
133 resource_entry_t *p;
134
135 if (entry->base > entry->base+entry->num-1)
136 return NULL((void *) 0);
137 for (p = root; ; p = p->next) {
138 if ((p != root) && (p->base+p->num-1 >= entry->base)) {
139 p = NULL((void *) 0);
140 break;
141 }
142 if ((p->next == NULL((void *) 0)) ||
143 (p->next->base > entry->base+entry->num-1))
144 break;
145 }
146 return p;
147}
148
149static int register_my_resource(resource_entry_t *list,
150 u_long base, u_long num, char *name)
151{
152 u_long flags;
153 resource_entry_t *p, *entry;
154
155 entry = kmalloclinux_kmalloc(sizeof(resource_entry_t), GFP_ATOMIC0x01);
156 if (!entry) return -ENOMEM12;
157 entry->base = base;
158 entry->num = num;
159 entry->name = name;
160
161 spin_lock_irqsave(&rsrc_lock, flags)do { __asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory"
); __asm__ __volatile__ ("cli": : :"memory"); } while (0)
;
162 p = find_gap(list, entry);
163 if (p == NULL((void *) 0)) {
164 spin_unlock_irqrestore(&rsrc_lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory");
165 kfreelinux_kfree(entry);
166 return -EBUSY16;
167 }
168 entry->next = p->next;
169 p->next = entry;
170 spin_unlock_irqrestore(&rsrc_lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory");
171 return 0;
172}
173
174static void release_my_resource(resource_entry_t *list,
175 u_long base, u_long num)
176{
177 u_long flags;
178 resource_entry_t *p, *q;
179
180 spin_lock_irqsave(&rsrc_lock, flags)do { __asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory"
); __asm__ __volatile__ ("cli": : :"memory"); } while (0)
;
181 for (p = list; ; p = q) {
182 q = p->next;
183 if (q == NULL((void *) 0)) break;
184 if ((q->base == base) && (q->num == num)) {
185 p->next = q->next;
186 kfreelinux_kfree(q);
187 spin_unlock_irqrestore(&rsrc_lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory");
188 return;
189 }
190 }
191 spin_unlock_irqrestore(&rsrc_lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory");
192 return;
193}
194
195static int check_my_resource(resource_entry_t *list,
196 u_long base, u_long num)
197{
198 if (register_my_resource(list, base, num, NULL((void *) 0)) != 0)
199 return -EBUSY16;
200 release_my_resource(list, base, num);
201 return 0;
202}
203
204#ifdef CONFIG_PNP_BIOS
205int check_io_region(u_long base, u_long num)(0)
206{
207 return check_my_resource(&io_list, base, num);
208}
209void request_io_region(u_long base, u_long num, char *name)
210{
211 register_my_resource(&io_list, base, num, name);
212}
213void release_io_region(u_long base, u_long num)
214{
215 release_my_resource(&io_list, base, num);
216}
217#ifdef HAS_PROC_BUS
218int proc_read_io(char *buf, char **start, off_t pos,
219 int count, int *eof, void *data)
220{
221 resource_entry_t *r;
222 u_long flags;
223 char *p = buf;
224
225 spin_lock_irqsave(&rsrc_lock, flags)do { __asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory"
); __asm__ __volatile__ ("cli": : :"memory"); } while (0)
;
226 for (r = io_list.next; r; r = r->next)
227 p += sprintflinux_sprintf(p, "%04lx-%04lx : %s\n", r->base,
228 r->base+r->num-1, r->name);
229 spin_unlock_irqrestore(&rsrc_lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory");
230 return (p - buf);
231}
232#endif
233#endif
234
235#ifndef HAVE_MEMRESERVE
236int check_mem_region(u_long base, u_long num)
237{
238 return check_my_resource(&mem_list, base, num);
239}
240void request_mem_region(u_long base, u_long num, char *name)
241{
242 register_my_resource(&mem_list, base, num, name);
243}
244void release_mem_region(u_long base, u_long num)
245{
246 release_my_resource(&mem_list, base, num);
247}
248#ifdef HAS_PROC_BUS
249int proc_read_mem(char *buf, char **start, off_t pos,
250 int count, int *eof, void *data)
251{
252 resource_entry_t *r;
253 u_long flags;
254 char *p = buf;
255
256 spin_lock_irqsave(&rsrc_lock, flags)do { __asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory"
); __asm__ __volatile__ ("cli": : :"memory"); } while (0)
;
257 for (r = mem_list.next; r; r = r->next)
258 p += sprintflinux_sprintf(p, "%08lx-%08lx : %s\n", r->base,
259 r->base+r->num-1, r->name);
260 spin_unlock_irqrestore(&rsrc_lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory");
261 return (p - buf);
262}
263#endif
264#endif
265
266#endif /* defined(CONFIG_PNP_BIOS) || !defined(HAVE_MEMRESERVE) */
267
268/*======================================================================
269
270 These manage the internal databases of available resources.
271
272======================================================================*/
273
274static int add_interval(resource_map_t *map, u_long base, u_long num)
275{
276 resource_map_t *p, *q;
277
278 for (p = map; ; p = p->next) {
279 if ((p != map) && (p->base+p->num-1 >= base))
280 return -1;
281 if ((p->next == map) || (p->next->base > base+num-1))
282 break;
283 }
284 q = kmalloclinux_kmalloc(sizeof(resource_map_t), GFP_KERNEL0x03);
285 if (!q) return CS_OUT_OF_RESOURCE0x20;
286 q->base = base; q->num = num;
287 q->next = p->next; p->next = q;
288 return CS_SUCCESS0x00;
289}
290
291/*====================================================================*/
292
293static int sub_interval(resource_map_t *map, u_long base, u_long num)
294{
295 resource_map_t *p, *q;
296
297 for (p = map; ; p = q) {
298 q = p->next;
299 if (q == map)
300 break;
301 if ((q->base+q->num > base) && (base+num > q->base)) {
302 if (q->base >= base) {
303 if (q->base+q->num <= base+num) {
304 /* Delete whole block */
305 p->next = q->next;
306 kfreelinux_kfree(q);
307 /* don't advance the pointer yet */
308 q = p;
309 } else {
310 /* Cut off bit from the front */
311 q->num = q->base + q->num - base - num;
312 q->base = base + num;
313 }
314 } else if (q->base+q->num <= base+num) {
315 /* Cut off bit from the end */
316 q->num = base - q->base;
317 } else {
318 /* Split the block into two pieces */
319 p = kmalloclinux_kmalloc(sizeof(resource_map_t), GFP_KERNEL0x03);
320 if (!p) return CS_OUT_OF_RESOURCE0x20;
321 p->base = base+num;
322 p->num = q->base+q->num - p->base;
323 q->num = base - q->base;
324 p->next = q->next ; q->next = p;
325 }
326 }
327 }
328 return CS_SUCCESS0x00;
329}
330
331/*======================================================================
332
333 These routines examine a region of IO or memory addresses to
334 determine what ranges might be genuinely available.
335
336======================================================================*/
337
338#ifdef CONFIG_ISA1
339static void do_io_probe(ioaddr_t base, ioaddr_t num)
340{
341
342 ioaddr_t i, j, bad, any;
343 u_char *b, hole, most;
344
345 printk(KERN_INFO"<6>" "cs: IO port probe 0x%04x-0x%04x:",
346 base, base+num-1);
347
348 /* First, what does a floating port look like? */
349 b = kmalloclinux_kmalloc(256, GFP_KERNEL0x03);
350 if (!b) {
351 printk(KERN_INFO"<6>" " kmalloc failed!\n");
352 return;
353 }
354 memset(b, 0, 256)(__builtin_constant_p(0) ? (__builtin_constant_p((256)) ? __constant_c_and_count_memset
(((b)),((0x01010101UL*(unsigned char)(0))),((256))) : __constant_c_memset
(((b)),((0x01010101UL*(unsigned char)(0))),((256)))) : (__builtin_constant_p
((256)) ? __memset_generic((((b))),(((0))),(((256)))) : __memset_generic
(((b)),((0)),((256)))))
;
355 for (i = base, most = 0; i < base+num; i += 8) {
356 if (check_region(i, 8) || check_io_region(i, 8)(0))
357 continue;
358 hole = inb(i)((__builtin_constant_p((i)) && (i) < 256) ? __inbc
(i) : __inb(i))
;
359 for (j = 1; j < 8; j++)
360 if (inb(i+j)((__builtin_constant_p((i+j)) && (i+j) < 256) ? __inbc
(i+j) : __inb(i+j))
!= hole) break;
361 if ((j == 8) && (++b[hole] > b[most]))
362 most = hole;
363 if (b[most] == 127) break;
364 }
365 kfreelinux_kfree(b);
366
367 bad = any = 0;
368 for (i = base; i < base+num; i += 8) {
369 if (check_region(i, 8) || check_io_region(i, 8)(0))
370 continue;
371 for (j = 0; j < 8; j++)
372 if (inb(i+j)((__builtin_constant_p((i+j)) && (i+j) < 256) ? __inbc
(i+j) : __inb(i+j))
!= most) break;
373 if (j < 8) {
374 if (!any)
375 printk(" excluding");
376 if (!bad)
377 bad = any = i;
378 } else {
379 if (bad) {
380 sub_interval(&io_db, bad, i-bad);
381 printk(" %#04x-%#04x", bad, i-1);
382 bad = 0;
383 }
384 }
385 }
386 if (bad) {
387 if ((num > 16) && (bad == base) && (i == base+num)) {
388 printk(" nothing: probe failed.\n");
389 return;
390 } else {
391 sub_interval(&io_db, bad, i-bad);
392 printk(" %#04x-%#04x", bad, i-1);
393 }
394 }
395
396 printk(any ? "\n" : " clean.\n");
397}
398
399static int io_scan; /* = 0 */
400
401static void invalidate_io(void)
402{
403 io_scan = 0;
404}
405
406static void validate_io(void)
407{
408 resource_map_t *m, *n;
409 if (!probe_io || io_scan++)
410 return;
411 for (m = io_db.next; m != &io_db; m = n) {
412 n = m->next;
413 do_io_probe(m->base, m->num);
414 }
415}
416
417#else /* CONFIG_ISA */
418
419#define validate_io() do { } while (0)
420#define invalidate_io() do { } while (0)
421
422#endif /* CONFIG_ISA */
423
424/*======================================================================
425
426 The memory probe. If the memory list includes a 64K-aligned block
427 below 1MB, we probe in 64K chunks, and as soon as we accumulate at
428 least mem_limit free space, we quit.
429
430======================================================================*/
431
432static int do_mem_probe(u_long base, u_long num,
433 int (*is_valid)(u_long), int (*do_cksum)(u_long))
434{
435 u_long i, j, bad, fail, step;
436
437 printk(KERN_INFO"<6>" "cs: memory probe 0x%06lx-0x%06lx:",
438 base, base+num-1);
439 bad = fail = 0;
440 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
441 for (i = j = base; i < base+num; i = j + step) {
442 if (!fail) {
443 for (j = i; j < base+num; j += step)
444 if ((check_mem_region(j, step) == 0) && is_valid(j))
445 break;
446 fail = ((i == base) && (j == base+num));
447 }
448 if (fail) {
449 for (j = i; j < base+num; j += 2*step)
450 if ((check_mem_region(j, 2*step) == 0) &&
451 do_cksum(j) && do_cksum(j+step))
452 break;
453 }
454 if (i != j) {
455 if (!bad) printk(" excluding");
456 printk(" %#05lx-%#05lx", i, j-1);
457 sub_interval(&mem_db, i, j-i);
458 bad += j-i;
459 }
460 }
461 printk(bad ? "\n" : " clean.\n");
462 return (num - bad);
463}
464
465#ifdef CONFIG_ISA1
466
467static u_long inv_probe(int (*is_valid)(u_long),
468 int (*do_cksum)(u_long),
469 resource_map_t *m)
470{
471 u_long ok;
472 if (m == &mem_db)
473 return 0;
474 ok = inv_probe(is_valid, do_cksum, m->next);
475 if (ok) {
476 if (m->base >= 0x100000)
477 sub_interval(&mem_db, m->base, m->num);
478 return ok;
479 }
480 if (m->base < 0x100000)
481 return 0;
482 return do_mem_probe(m->base, m->num, is_valid, do_cksum);
483}
484
485static int hi_scan, lo_scan; /* = 0 */
486
487static void invalidate_mem(void)
488{
489 hi_scan = lo_scan = 0;
490}
491
492void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
493 int force_low)
494{
495 resource_map_t *m, mm;
496 static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
497 u_long b, i, ok = 0;
498
499 if (!probe_mem) return;
500 /* We do up to four passes through the list */
501 if (!force_low) {
502 if (hi_scan++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
503 return;
504 printk(KERN_NOTICE"<5>" "cs: warning: no high memory space "
505 "available!\n");
506 }
507 if (lo_scan++) return;
508 for (m = mem_db.next; m != &mem_db; m = mm.next) {
509 mm = *m;
510 /* Only probe < 1 MB */
511 if (mm.base >= 0x100000) continue;
512 if ((mm.base | mm.num) & 0xffff) {
513 ok += do_mem_probe(mm.base, mm.num, is_valid, do_cksum);
514 continue;
515 }
516 /* Special probe for 64K-aligned block */
517 for (i = 0; i < 4; i++) {
518 b = order[i] << 12;
519 if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
520 if (ok >= mem_limit)
521 sub_interval(&mem_db, b, 0x10000);
522 else
523 ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
524 }
525 }
526 }
527}
528
529#else /* CONFIG_ISA */
530
531#define invalidate_mem() do { } while (0)
532
533void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
534 int force_low)
535{
536 resource_map_t *m, *n;
537 static int done = 0;
538
539 if (!probe_mem || done++)
540 return;
541 for (m = mem_db.next; m != &mem_db; m = n)
542 n = m->next;
543 if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
544 return;
545}
546
547#endif /* CONFIG_ISA */
548
549/*======================================================================
550
551 These find ranges of I/O ports or memory addresses that are not
552 currently allocated by other devices.
553
554 The 'align' field should reflect the number of bits of address
555 that need to be preserved from the initial value of *base. It
556 should be a power of two, greater than or equal to 'num'. A value
557 of 0 means that all bits of *base are significant. *base should
558 also be strictly less than 'align'.
559
560======================================================================*/
561
562int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
563 char *name)
564{
565 ioaddr_t try;
566 resource_map_t *m;
567
568 validate_io();
569 for (m = io_db.next; m != &io_db; m = m->next) {
570 try = (m->base & ~(align-1)) + *base;
571 for (try = (try >= m->base) ? try : try+align;
572 (try >= m->base) && (try+num <= m->base+m->num);
573 try += align) {
574 if ((check_region(try, num) == 0) &&
575 (check_io_region(try, num)(0) == 0)) {
576 *base = try;
577 if (name) request_region(try, num, name);
578 return 0;
579 }
580 if (!align) break;
581 }
582 }
583 return -1;
584}
585
586int find_mem_region(u_long *base, u_long num, u_long align,
587 int force_low, char *name)
588{
589 u_long try;
590 resource_map_t *m;
591
592 while (1) {
593 for (m = mem_db.next; m != &mem_db; m = m->next) {
594 /* first pass >1MB, second pass <1MB */
595 if ((force_low != 0) ^ (m->base < 0x100000)) continue;
596 try = (m->base & ~(align-1)) + *base;
597 for (try = (try >= m->base) ? try : try+align;
598 (try >= m->base) && (try+num <= m->base+m->num);
599 try += align) {
600 if (check_mem_region(try, num) == 0) {
601 if (name) request_mem_region(try, num, name);
602 *base = try;
603 return 0;
604 }
605 if (!align) break;
606 }
607 }
608 if (force_low) break;
609 force_low++;
610 }
611 return -1;
612}
613
614/*======================================================================
615
616 This checks to see if an interrupt is available, with support
617 for interrupt sharing. We don't support reserving interrupts
618 yet. If the interrupt is available, we allocate it.
619
620======================================================================*/
621
622#ifdef CONFIG_ISA1
623
624static void fake_irq(int i, void *d, struct pt_regs *r) { }
625static inlineinline __attribute__((always_inline)) int check_irq(int irq)
626{
627 if (request_irq(irq, fake_irq, 0, "bogus", NULL((void *) 0)) != 0)
628 return -1;
629 free_irq(irq, NULL((void *) 0));
630 return 0;
631}
632
633int try_irq(u_int Attributes, int irq, int specific)
634{
635 irq_info_t *info = &irq_table[irq];
636 if (info->Attributes & RES_ALLOCATED0x20) {
637 switch (Attributes & IRQ_TYPE0x03) {
638 case IRQ_TYPE_EXCLUSIVE0x00:
639 return CS_IN_USE0x1e;
640 case IRQ_TYPE_TIME0x01:
641 if ((info->Attributes & RES_IRQ_TYPE0x03)
642 != RES_IRQ_TYPE_TIME1)
643 return CS_IN_USE0x1e;
644 if (Attributes & IRQ_FIRST_SHARED0x08)
645 return CS_BAD_ATTRIBUTE0x02;
646 info->Attributes |= RES_IRQ_TYPE_TIME1 | RES_ALLOCATED0x20;
647 info->time_share++;
648 break;
649 case IRQ_TYPE_DYNAMIC_SHARING0x02:
650 if ((info->Attributes & RES_IRQ_TYPE0x03)
651 != RES_IRQ_TYPE_DYNAMIC2)
652 return CS_IN_USE0x1e;
653 if (Attributes & IRQ_FIRST_SHARED0x08)
654 return CS_BAD_ATTRIBUTE0x02;
655 info->Attributes |= RES_IRQ_TYPE_DYNAMIC2 | RES_ALLOCATED0x20;
656 info->dyn_share++;
657 break;
658 }
659 } else {
660 if ((info->Attributes & RES_RESERVED0x10) && !specific)
661 return CS_IN_USE0x1e;
662 if (check_irq(irq) != 0)
663 return CS_IN_USE0x1e;
664 switch (Attributes & IRQ_TYPE0x03) {
665 case IRQ_TYPE_EXCLUSIVE0x00:
666 info->Attributes |= RES_ALLOCATED0x20;
667 break;
668 case IRQ_TYPE_TIME0x01:
669 if (!(Attributes & IRQ_FIRST_SHARED0x08))
670 return CS_BAD_ATTRIBUTE0x02;
671 info->Attributes |= RES_IRQ_TYPE_TIME1 | RES_ALLOCATED0x20;
672 info->time_share = 1;
673 break;
674 case IRQ_TYPE_DYNAMIC_SHARING0x02:
675 if (!(Attributes & IRQ_FIRST_SHARED0x08))
676 return CS_BAD_ATTRIBUTE0x02;
677 info->Attributes |= RES_IRQ_TYPE_DYNAMIC2 | RES_ALLOCATED0x20;
678 info->dyn_share = 1;
679 break;
680 }
681 }
682 return 0;
683}
684
685#endif
686
687/*====================================================================*/
688
689#ifdef CONFIG_ISA1
690
691void undo_irq(u_int Attributes, int irq)
692{
693 irq_info_t *info;
694
695 info = &irq_table[irq];
696 switch (Attributes & IRQ_TYPE0x03) {
697 case IRQ_TYPE_EXCLUSIVE0x00:
698 info->Attributes &= RES_RESERVED0x10;
699 break;
700 case IRQ_TYPE_TIME0x01:
701 info->time_share--;
702 if (info->time_share == 0)
703 info->Attributes &= RES_RESERVED0x10;
704 break;
705 case IRQ_TYPE_DYNAMIC_SHARING0x02:
706 info->dyn_share--;
707 if (info->dyn_share == 0)
708 info->Attributes &= RES_RESERVED0x10;
709 break;
710 }
711}
712
713#endif
714
715/*======================================================================
716
717 The various adjust_* calls form the external interface to the
718 resource database.
719
720======================================================================*/
721
722static int adjust_memory(adjust_t *adj)
723{
724 u_long base, num;
725 int i, ret;
726
727 base = adj->resource.memory.Base;
728 num = adj->resource.memory.Size;
729 if ((num == 0) || (base+num-1 < base))
730 return CS_BAD_SIZE0x0a;
731
732 ret = CS_SUCCESS0x00;
Value stored to 'ret' is never read
733 switch (adj->Action) {
734 case ADD_MANAGED_RESOURCE2:
735 ret = add_interval(&mem_db, base, num);
736 break;
737 case REMOVE_MANAGED_RESOURCE1:
738 ret = sub_interval(&mem_db, base, num);
739 if (ret == CS_SUCCESS0x00) {
740 invalidate_mem();
741 for (i = 0; i < sockets; i++) {
742 release_cis_mem(socket_table[i]);
743#ifdef CONFIG_CARDBUS
744 cb_release_cis_mem(socket_table[i]);
745#endif
746 }
747 }
748 break;
749 default:
750 ret = CS_UNSUPPORTED_FUNCTION0x15;
751 }
752
753 return ret;
754}
755
756/*====================================================================*/
757
758static int adjust_io(adjust_t *adj)
759{
760 int base, num;
761
762 base = adj->resource.io.BasePort;
763 num = adj->resource.io.NumPorts;
764 if ((base < 0) || (base > 0xffff))
765 return CS_BAD_BASE0x03;
766 if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
767 return CS_BAD_SIZE0x0a;
768
769 switch (adj->Action) {
770 case ADD_MANAGED_RESOURCE2:
771 if (add_interval(&io_db, base, num) != 0)
772 return CS_IN_USE0x1e;
773 break;
774 case REMOVE_MANAGED_RESOURCE1:
775 sub_interval(&io_db, base, num);
776 invalidate_io();
777 break;
778 default:
779 return CS_UNSUPPORTED_FUNCTION0x15;
780 break;
781 }
782
783 return CS_SUCCESS0x00;
784}
785
786/*====================================================================*/
787
788static int adjust_irq(adjust_t *adj)
789{
790#ifdef CONFIG_ISA1
791 int irq;
792 irq_info_t *info;
793
794 irq = adj->resource.irq.IRQ;
795 if ((irq < 0) || (irq > 15))
796 return CS_BAD_IRQ0x06;
797 info = &irq_table[irq];
798
799 switch (adj->Action) {
800 case ADD_MANAGED_RESOURCE2:
801 if (info->Attributes & RES_REMOVED0x40)
802 info->Attributes &= ~(RES_REMOVED0x40|RES_ALLOCATED0x20);
803 else
804 if (adj->Attributes & RES_ALLOCATED0x20)
805 return CS_IN_USE0x1e;
806 if (adj->Attributes & RES_RESERVED0x10)
807 info->Attributes |= RES_RESERVED0x10;
808 else
809 info->Attributes &= ~RES_RESERVED0x10;
810 break;
811 case REMOVE_MANAGED_RESOURCE1:
812 if (info->Attributes & RES_REMOVED0x40)
813 return 0;
814 if (info->Attributes & RES_ALLOCATED0x20)
815 return CS_IN_USE0x1e;
816 info->Attributes |= RES_ALLOCATED0x20|RES_REMOVED0x40;
817 info->Attributes &= ~RES_RESERVED0x10;
818 break;
819 default:
820 return CS_UNSUPPORTED_FUNCTION0x15;
821 break;
822 }
823#endif
824 return CS_SUCCESS0x00;
825}
826
827/*====================================================================*/
828
829int adjust_resource_info(client_handle_t handle, adjust_t *adj)
830{
831 if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6
))
)
832 return CS_BAD_HANDLE0x21;
833
834 switch (adj->Resource) {
835 case RES_MEMORY_RANGE1:
836 return adjust_memory(adj);
837 break;
838 case RES_IO_RANGE2:
839 return adjust_io(adj);
840 break;
841 case RES_IRQ3:
842 return adjust_irq(adj);
843 break;
844 }
845 return CS_UNSUPPORTED_FUNCTION0x15;
846}
847
848/*====================================================================*/
849
850void release_resource_db(void)
851{
852 resource_map_t *p, *q;
853#if defined(CONFIG_PNP_BIOS) || !defined(HAVE_MEMRESERVE)
854 resource_entry_t *u, *v;
855#endif
856
857 for (p = mem_db.next; p != &mem_db; p = q) {
858 q = p->next;
859 kfreelinux_kfree(p);
860 }
861 for (p = io_db.next; p != &io_db; p = q) {
862 q = p->next;
863 kfreelinux_kfree(p);
864 }
865#ifdef CONFIG_PNP_BIOS
866 for (u = io_list.next; u; u = v) {
867 v = u->next;
868 kfreelinux_kfree(u);
869 }
870#endif
871#ifndef HAVE_MEMRESERVE
872 for (u = mem_list.next; u; u = v) {
873 v = u->next;
874 kfreelinux_kfree(u);
875 }
876#endif
877}