|
|
1.1 ! root 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: <[email protected]>. 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; MODULE_PARM(n, "i") ! 62: ! 63: INT_MODULE_PARM(probe_mem, 1); /* memory probe? */ ! 64: #ifdef CONFIG_ISA ! 65: INT_MODULE_PARM(probe_io, 1); /* IO port probe? */ ! 66: INT_MODULE_PARM(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: ! 76: typedef struct resource_map_t { ! 77: u_long base, num; ! 78: struct resource_map_t *next; ! 79: } resource_map_t; ! 80: ! 81: /* Memory resource database */ ! 82: static resource_map_t mem_db = { 0, 0, &mem_db }; ! 83: ! 84: /* IO port resource database */ ! 85: static resource_map_t io_db = { 0, 0, &io_db }; ! 86: ! 87: #ifdef CONFIG_ISA ! 88: ! 89: typedef 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 */ ! 96: static 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) ! 108: #endif ! 109: ! 110: #if defined(CONFIG_PNP_BIOS) || !defined(HAVE_MEMRESERVE) ! 111: ! 112: #ifdef __SMP__ ! 113: static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED; ! 114: #endif ! 115: ! 116: typedef 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 ! 124: static resource_entry_t io_list = { 0, 0, NULL, NULL }; ! 125: #endif ! 126: #ifndef HAVE_MEMRESERVE ! 127: static resource_entry_t mem_list = { 0, 0, NULL, NULL }; ! 128: #endif ! 129: ! 130: static 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; ! 137: for (p = root; ; p = p->next) { ! 138: if ((p != root) && (p->base+p->num-1 >= entry->base)) { ! 139: p = NULL; ! 140: break; ! 141: } ! 142: if ((p->next == NULL) || ! 143: (p->next->base > entry->base+entry->num-1)) ! 144: break; ! 145: } ! 146: return p; ! 147: } ! 148: ! 149: static 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 = kmalloc(sizeof(resource_entry_t), GFP_ATOMIC); ! 156: if (!entry) return -ENOMEM; ! 157: entry->base = base; ! 158: entry->num = num; ! 159: entry->name = name; ! 160: ! 161: spin_lock_irqsave(&rsrc_lock, flags); ! 162: p = find_gap(list, entry); ! 163: if (p == NULL) { ! 164: spin_unlock_irqrestore(&rsrc_lock, flags); ! 165: kfree(entry); ! 166: return -EBUSY; ! 167: } ! 168: entry->next = p->next; ! 169: p->next = entry; ! 170: spin_unlock_irqrestore(&rsrc_lock, flags); ! 171: return 0; ! 172: } ! 173: ! 174: static 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); ! 181: for (p = list; ; p = q) { ! 182: q = p->next; ! 183: if (q == NULL) break; ! 184: if ((q->base == base) && (q->num == num)) { ! 185: p->next = q->next; ! 186: kfree(q); ! 187: spin_unlock_irqrestore(&rsrc_lock, flags); ! 188: return; ! 189: } ! 190: } ! 191: spin_unlock_irqrestore(&rsrc_lock, flags); ! 192: return; ! 193: } ! 194: ! 195: static 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) != 0) ! 199: return -EBUSY; ! 200: release_my_resource(list, base, num); ! 201: return 0; ! 202: } ! 203: ! 204: #ifdef CONFIG_PNP_BIOS ! 205: int check_io_region(u_long base, u_long num) ! 206: { ! 207: return check_my_resource(&io_list, base, num); ! 208: } ! 209: void request_io_region(u_long base, u_long num, char *name) ! 210: { ! 211: register_my_resource(&io_list, base, num, name); ! 212: } ! 213: void release_io_region(u_long base, u_long num) ! 214: { ! 215: release_my_resource(&io_list, base, num); ! 216: } ! 217: #ifdef HAS_PROC_BUS ! 218: int 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); ! 226: for (r = io_list.next; r; r = r->next) ! 227: p += sprintf(p, "%04lx-%04lx : %s\n", r->base, ! 228: r->base+r->num-1, r->name); ! 229: spin_unlock_irqrestore(&rsrc_lock, flags); ! 230: return (p - buf); ! 231: } ! 232: #endif ! 233: #endif ! 234: ! 235: #ifndef HAVE_MEMRESERVE ! 236: int check_mem_region(u_long base, u_long num) ! 237: { ! 238: return check_my_resource(&mem_list, base, num); ! 239: } ! 240: void request_mem_region(u_long base, u_long num, char *name) ! 241: { ! 242: register_my_resource(&mem_list, base, num, name); ! 243: } ! 244: void release_mem_region(u_long base, u_long num) ! 245: { ! 246: release_my_resource(&mem_list, base, num); ! 247: } ! 248: #ifdef HAS_PROC_BUS ! 249: int 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); ! 257: for (r = mem_list.next; r; r = r->next) ! 258: p += sprintf(p, "%08lx-%08lx : %s\n", r->base, ! 259: r->base+r->num-1, r->name); ! 260: spin_unlock_irqrestore(&rsrc_lock, flags); ! 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: ! 274: static 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 = kmalloc(sizeof(resource_map_t), GFP_KERNEL); ! 285: if (!q) return CS_OUT_OF_RESOURCE; ! 286: q->base = base; q->num = num; ! 287: q->next = p->next; p->next = q; ! 288: return CS_SUCCESS; ! 289: } ! 290: ! 291: /*====================================================================*/ ! 292: ! 293: static 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: 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 = kmalloc(sizeof(resource_map_t), GFP_KERNEL); ! 320: if (!p) return CS_OUT_OF_RESOURCE; ! 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_SUCCESS; ! 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_ISA ! 339: static 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 "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 = kmalloc(256, GFP_KERNEL); ! 350: if (!b) { ! 351: printk(KERN_INFO " kmalloc failed!\n"); ! 352: return; ! 353: } ! 354: memset(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)) ! 357: continue; ! 358: hole = inb(i); ! 359: for (j = 1; j < 8; j++) ! 360: if (inb(i+j) != hole) break; ! 361: if ((j == 8) && (++b[hole] > b[most])) ! 362: most = hole; ! 363: if (b[most] == 127) break; ! 364: } ! 365: 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)) ! 370: continue; ! 371: for (j = 0; j < 8; j++) ! 372: if (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: ! 399: static int io_scan; /* = 0 */ ! 400: ! 401: static void invalidate_io(void) ! 402: { ! 403: io_scan = 0; ! 404: } ! 405: ! 406: static 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: ! 432: static 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 "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_ISA ! 466: ! 467: static 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: ! 485: static int hi_scan, lo_scan; /* = 0 */ ! 486: ! 487: static void invalidate_mem(void) ! 488: { ! 489: hi_scan = lo_scan = 0; ! 490: } ! 491: ! 492: void 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 "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: ! 533: void 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: ! 562: int 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)) { ! 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: ! 586: int 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_ISA ! 623: ! 624: static void fake_irq(int i, void *d, struct pt_regs *r) { } ! 625: static inline int check_irq(int irq) ! 626: { ! 627: if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0) ! 628: return -1; ! 629: free_irq(irq, NULL); ! 630: return 0; ! 631: } ! 632: ! 633: int try_irq(u_int Attributes, int irq, int specific) ! 634: { ! 635: irq_info_t *info = &irq_table[irq]; ! 636: if (info->Attributes & RES_ALLOCATED) { ! 637: switch (Attributes & IRQ_TYPE) { ! 638: case IRQ_TYPE_EXCLUSIVE: ! 639: return CS_IN_USE; ! 640: case IRQ_TYPE_TIME: ! 641: if ((info->Attributes & RES_IRQ_TYPE) ! 642: != RES_IRQ_TYPE_TIME) ! 643: return CS_IN_USE; ! 644: if (Attributes & IRQ_FIRST_SHARED) ! 645: return CS_BAD_ATTRIBUTE; ! 646: info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED; ! 647: info->time_share++; ! 648: break; ! 649: case IRQ_TYPE_DYNAMIC_SHARING: ! 650: if ((info->Attributes & RES_IRQ_TYPE) ! 651: != RES_IRQ_TYPE_DYNAMIC) ! 652: return CS_IN_USE; ! 653: if (Attributes & IRQ_FIRST_SHARED) ! 654: return CS_BAD_ATTRIBUTE; ! 655: info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED; ! 656: info->dyn_share++; ! 657: break; ! 658: } ! 659: } else { ! 660: if ((info->Attributes & RES_RESERVED) && !specific) ! 661: return CS_IN_USE; ! 662: if (check_irq(irq) != 0) ! 663: return CS_IN_USE; ! 664: switch (Attributes & IRQ_TYPE) { ! 665: case IRQ_TYPE_EXCLUSIVE: ! 666: info->Attributes |= RES_ALLOCATED; ! 667: break; ! 668: case IRQ_TYPE_TIME: ! 669: if (!(Attributes & IRQ_FIRST_SHARED)) ! 670: return CS_BAD_ATTRIBUTE; ! 671: info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED; ! 672: info->time_share = 1; ! 673: break; ! 674: case IRQ_TYPE_DYNAMIC_SHARING: ! 675: if (!(Attributes & IRQ_FIRST_SHARED)) ! 676: return CS_BAD_ATTRIBUTE; ! 677: info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED; ! 678: info->dyn_share = 1; ! 679: break; ! 680: } ! 681: } ! 682: return 0; ! 683: } ! 684: ! 685: #endif ! 686: ! 687: /*====================================================================*/ ! 688: ! 689: #ifdef CONFIG_ISA ! 690: ! 691: void undo_irq(u_int Attributes, int irq) ! 692: { ! 693: irq_info_t *info; ! 694: ! 695: info = &irq_table[irq]; ! 696: switch (Attributes & IRQ_TYPE) { ! 697: case IRQ_TYPE_EXCLUSIVE: ! 698: info->Attributes &= RES_RESERVED; ! 699: break; ! 700: case IRQ_TYPE_TIME: ! 701: info->time_share--; ! 702: if (info->time_share == 0) ! 703: info->Attributes &= RES_RESERVED; ! 704: break; ! 705: case IRQ_TYPE_DYNAMIC_SHARING: ! 706: info->dyn_share--; ! 707: if (info->dyn_share == 0) ! 708: info->Attributes &= RES_RESERVED; ! 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: ! 722: static 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_SIZE; ! 731: ! 732: ret = CS_SUCCESS; ! 733: switch (adj->Action) { ! 734: case ADD_MANAGED_RESOURCE: ! 735: ret = add_interval(&mem_db, base, num); ! 736: break; ! 737: case REMOVE_MANAGED_RESOURCE: ! 738: ret = sub_interval(&mem_db, base, num); ! 739: if (ret == CS_SUCCESS) { ! 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_FUNCTION; ! 751: } ! 752: ! 753: return ret; ! 754: } ! 755: ! 756: /*====================================================================*/ ! 757: ! 758: static 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_BASE; ! 766: if ((num <= 0) || (base+num > 0x10000) || (base+num <= base)) ! 767: return CS_BAD_SIZE; ! 768: ! 769: switch (adj->Action) { ! 770: case ADD_MANAGED_RESOURCE: ! 771: if (add_interval(&io_db, base, num) != 0) ! 772: return CS_IN_USE; ! 773: break; ! 774: case REMOVE_MANAGED_RESOURCE: ! 775: sub_interval(&io_db, base, num); ! 776: invalidate_io(); ! 777: break; ! 778: default: ! 779: return CS_UNSUPPORTED_FUNCTION; ! 780: break; ! 781: } ! 782: ! 783: return CS_SUCCESS; ! 784: } ! 785: ! 786: /*====================================================================*/ ! 787: ! 788: static int adjust_irq(adjust_t *adj) ! 789: { ! 790: #ifdef CONFIG_ISA ! 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_IRQ; ! 797: info = &irq_table[irq]; ! 798: ! 799: switch (adj->Action) { ! 800: case ADD_MANAGED_RESOURCE: ! 801: if (info->Attributes & RES_REMOVED) ! 802: info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED); ! 803: else ! 804: if (adj->Attributes & RES_ALLOCATED) ! 805: return CS_IN_USE; ! 806: if (adj->Attributes & RES_RESERVED) ! 807: info->Attributes |= RES_RESERVED; ! 808: else ! 809: info->Attributes &= ~RES_RESERVED; ! 810: break; ! 811: case REMOVE_MANAGED_RESOURCE: ! 812: if (info->Attributes & RES_REMOVED) ! 813: return 0; ! 814: if (info->Attributes & RES_ALLOCATED) ! 815: return CS_IN_USE; ! 816: info->Attributes |= RES_ALLOCATED|RES_REMOVED; ! 817: info->Attributes &= ~RES_RESERVED; ! 818: break; ! 819: default: ! 820: return CS_UNSUPPORTED_FUNCTION; ! 821: break; ! 822: } ! 823: #endif ! 824: return CS_SUCCESS; ! 825: } ! 826: ! 827: /*====================================================================*/ ! 828: ! 829: int adjust_resource_info(client_handle_t handle, adjust_t *adj) ! 830: { ! 831: if (CHECK_HANDLE(handle)) ! 832: return CS_BAD_HANDLE; ! 833: ! 834: switch (adj->Resource) { ! 835: case RES_MEMORY_RANGE: ! 836: return adjust_memory(adj); ! 837: break; ! 838: case RES_IO_RANGE: ! 839: return adjust_io(adj); ! 840: break; ! 841: case RES_IRQ: ! 842: return adjust_irq(adj); ! 843: break; ! 844: } ! 845: return CS_UNSUPPORTED_FUNCTION; ! 846: } ! 847: ! 848: /*====================================================================*/ ! 849: ! 850: void 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: kfree(p); ! 860: } ! 861: for (p = io_db.next; p != &io_db; p = q) { ! 862: q = p->next; ! 863: kfree(p); ! 864: } ! 865: #ifdef CONFIG_PNP_BIOS ! 866: for (u = io_list.next; u; u = v) { ! 867: v = u->next; ! 868: kfree(u); ! 869: } ! 870: #endif ! 871: #ifndef HAVE_MEMRESERVE ! 872: for (u = mem_list.next; u; u = v) { ! 873: v = u->next; ! 874: kfree(u); ! 875: } ! 876: #endif ! 877: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.