linux/drivers/pnp/resource.c
<<
>>
Prefs
   1/*
   2 * resource.c - Contains functions for registering and analyzing resource information
   3 *
   4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
   5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
   6 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
   7 *      Bjorn Helgaas <bjorn.helgaas@hp.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/slab.h>
  12#include <linux/errno.h>
  13#include <linux/interrupt.h>
  14#include <linux/kernel.h>
  15#include <asm/io.h>
  16#include <asm/dma.h>
  17#include <asm/irq.h>
  18#include <linux/pci.h>
  19#include <linux/ioport.h>
  20#include <linux/init.h>
  21
  22#include <linux/pnp.h>
  23#include "base.h"
  24
  25static int pnp_reserve_irq[16] = {[0 ... 15] = -1 };    /* reserve (don't use) some IRQ */
  26static int pnp_reserve_dma[8] = {[0 ... 7] = -1 };      /* reserve (don't use) some DMA */
  27static int pnp_reserve_io[16] = {[0 ... 15] = -1 };     /* reserve (don't use) some I/O region */
  28static int pnp_reserve_mem[16] = {[0 ... 15] = -1 };    /* reserve (don't use) some memory region */
  29
  30/*
  31 * option registration
  32 */
  33
  34static struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type,
  35                                    unsigned int option_flags)
  36{
  37        struct pnp_option *option;
  38
  39        option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL);
  40        if (!option)
  41                return NULL;
  42
  43        option->flags = option_flags;
  44        option->type = type;
  45
  46        list_add_tail(&option->list, &dev->options);
  47        return option;
  48}
  49
  50int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
  51                              pnp_irq_mask_t *map, unsigned char flags)
  52{
  53        struct pnp_option *option;
  54        struct pnp_irq *irq;
  55
  56        option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags);
  57        if (!option)
  58                return -ENOMEM;
  59
  60        irq = &option->u.irq;
  61        irq->map = *map;
  62        irq->flags = flags;
  63
  64#ifdef CONFIG_PCI
  65        {
  66                int i;
  67
  68                for (i = 0; i < 16; i++)
  69                        if (test_bit(i, irq->map.bits))
  70                                pcibios_penalize_isa_irq(i, 0);
  71        }
  72#endif
  73
  74        dbg_pnp_show_option(dev, option);
  75        return 0;
  76}
  77
  78int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
  79                              unsigned char map, unsigned char flags)
  80{
  81        struct pnp_option *option;
  82        struct pnp_dma *dma;
  83
  84        option = pnp_build_option(dev, IORESOURCE_DMA, option_flags);
  85        if (!option)
  86                return -ENOMEM;
  87
  88        dma = &option->u.dma;
  89        dma->map = map;
  90        dma->flags = flags;
  91
  92        dbg_pnp_show_option(dev, option);
  93        return 0;
  94}
  95
  96int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
  97                               resource_size_t min, resource_size_t max,
  98                               resource_size_t align, resource_size_t size,
  99                               unsigned char flags)
 100{
 101        struct pnp_option *option;
 102        struct pnp_port *port;
 103
 104        option = pnp_build_option(dev, IORESOURCE_IO, option_flags);
 105        if (!option)
 106                return -ENOMEM;
 107
 108        port = &option->u.port;
 109        port->min = min;
 110        port->max = max;
 111        port->align = align;
 112        port->size = size;
 113        port->flags = flags;
 114
 115        dbg_pnp_show_option(dev, option);
 116        return 0;
 117}
 118
 119int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
 120                              resource_size_t min, resource_size_t max,
 121                              resource_size_t align, resource_size_t size,
 122                              unsigned char flags)
 123{
 124        struct pnp_option *option;
 125        struct pnp_mem *mem;
 126
 127        option = pnp_build_option(dev, IORESOURCE_MEM, option_flags);
 128        if (!option)
 129                return -ENOMEM;
 130
 131        mem = &option->u.mem;
 132        mem->min = min;
 133        mem->max = max;
 134        mem->align = align;
 135        mem->size = size;
 136        mem->flags = flags;
 137
 138        dbg_pnp_show_option(dev, option);
 139        return 0;
 140}
 141
 142void pnp_free_options(struct pnp_dev *dev)
 143{
 144        struct pnp_option *option, *tmp;
 145
 146        list_for_each_entry_safe(option, tmp, &dev->options, list) {
 147                list_del(&option->list);
 148                kfree(option);
 149        }
 150}
 151
 152/*
 153 * resource validity checking
 154 */
 155
 156#define length(start, end) (*(end) - *(start) + 1)
 157
 158/* Two ranges conflict if one doesn't end before the other starts */
 159#define ranged_conflict(starta, enda, startb, endb) \
 160        !((*(enda) < *(startb)) || (*(endb) < *(starta)))
 161
 162#define cannot_compare(flags) \
 163((flags) & IORESOURCE_DISABLED)
 164
 165int pnp_check_port(struct pnp_dev *dev, struct resource *res)
 166{
 167        int i;
 168        struct pnp_dev *tdev;
 169        struct resource *tres;
 170        resource_size_t *port, *end, *tport, *tend;
 171
 172        port = &res->start;
 173        end = &res->end;
 174
 175        /* if the resource doesn't exist, don't complain about it */
 176        if (cannot_compare(res->flags))
 177                return 1;
 178
 179        /* check if the resource is already in use, skip if the
 180         * device is active because it itself may be in use */
 181        if (!dev->active) {
 182                if (!request_region(*port, length(port, end), "pnp"))
 183                        return 0;
 184                release_region(*port, length(port, end));
 185        }
 186
 187        /* check if the resource is reserved */
 188        for (i = 0; i < 8; i++) {
 189                int rport = pnp_reserve_io[i << 1];
 190                int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1;
 191                if (ranged_conflict(port, end, &rport, &rend))
 192                        return 0;
 193        }
 194
 195        /* check for internal conflicts */
 196        for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
 197                if (tres != res && tres->flags & IORESOURCE_IO) {
 198                        tport = &tres->start;
 199                        tend = &tres->end;
 200                        if (ranged_conflict(port, end, tport, tend))
 201                                return 0;
 202                }
 203        }
 204
 205        /* check for conflicts with other pnp devices */
 206        pnp_for_each_dev(tdev) {
 207                if (tdev == dev)
 208                        continue;
 209                for (i = 0;
 210                     (tres = pnp_get_resource(tdev, IORESOURCE_IO, i));
 211                     i++) {
 212                        if (tres->flags & IORESOURCE_IO) {
 213                                if (cannot_compare(tres->flags))
 214                                        continue;
 215                                if (tres->flags & IORESOURCE_WINDOW)
 216                                        continue;
 217                                tport = &tres->start;
 218                                tend = &tres->end;
 219                                if (ranged_conflict(port, end, tport, tend))
 220                                        return 0;
 221                        }
 222                }
 223        }
 224
 225        return 1;
 226}
 227
 228int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
 229{
 230        int i;
 231        struct pnp_dev *tdev;
 232        struct resource *tres;
 233        resource_size_t *addr, *end, *taddr, *tend;
 234
 235        addr = &res->start;
 236        end = &res->end;
 237
 238        /* if the resource doesn't exist, don't complain about it */
 239        if (cannot_compare(res->flags))
 240                return 1;
 241
 242        /* check if the resource is already in use, skip if the
 243         * device is active because it itself may be in use */
 244        if (!dev->active) {
 245                if (!request_mem_region(*addr, length(addr, end), "pnp"))
 246                        return 0;
 247                release_mem_region(*addr, length(addr, end));
 248        }
 249
 250        /* check if the resource is reserved */
 251        for (i = 0; i < 8; i++) {
 252                int raddr = pnp_reserve_mem[i << 1];
 253                int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1;
 254                if (ranged_conflict(addr, end, &raddr, &rend))
 255                        return 0;
 256        }
 257
 258        /* check for internal conflicts */
 259        for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
 260                if (tres != res && tres->flags & IORESOURCE_MEM) {
 261                        taddr = &tres->start;
 262                        tend = &tres->end;
 263                        if (ranged_conflict(addr, end, taddr, tend))
 264                                return 0;
 265                }
 266        }
 267
 268        /* check for conflicts with other pnp devices */
 269        pnp_for_each_dev(tdev) {
 270                if (tdev == dev)
 271                        continue;
 272                for (i = 0;
 273                     (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i));
 274                     i++) {
 275                        if (tres->flags & IORESOURCE_MEM) {
 276                                if (cannot_compare(tres->flags))
 277                                        continue;
 278                                if (tres->flags & IORESOURCE_WINDOW)
 279                                        continue;
 280                                taddr = &tres->start;
 281                                tend = &tres->end;
 282                                if (ranged_conflict(addr, end, taddr, tend))
 283                                        return 0;
 284                        }
 285                }
 286        }
 287
 288        return 1;
 289}
 290
 291static irqreturn_t pnp_test_handler(int irq, void *dev_id)
 292{
 293        return IRQ_HANDLED;
 294}
 295
 296#ifdef CONFIG_PCI
 297static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci,
 298                            unsigned int irq)
 299{
 300        u32 class;
 301        u8 progif;
 302
 303        if (pci->irq == irq) {
 304                pnp_dbg(&pnp->dev, "  device %s using irq %d\n",
 305                        pci_name(pci), irq);
 306                return 1;
 307        }
 308
 309        /*
 310         * See pci_setup_device() and ata_pci_sff_activate_host() for
 311         * similar IDE legacy detection.
 312         */
 313        pci_read_config_dword(pci, PCI_CLASS_REVISION, &class);
 314        class >>= 8;            /* discard revision ID */
 315        progif = class & 0xff;
 316        class >>= 8;
 317
 318        if (class == PCI_CLASS_STORAGE_IDE) {
 319                /*
 320                 * Unless both channels are native-PCI mode only,
 321                 * treat the compatibility IRQs as busy.
 322                 */
 323                if ((progif & 0x5) != 0x5)
 324                        if (pci_get_legacy_ide_irq(pci, 0) == irq ||
 325                            pci_get_legacy_ide_irq(pci, 1) == irq) {
 326                                pnp_dbg(&pnp->dev, "  legacy IDE device %s "
 327                                        "using irq %d\n", pci_name(pci), irq);
 328                                return 1;
 329                        }
 330        }
 331
 332        return 0;
 333}
 334#endif
 335
 336static int pci_uses_irq(struct pnp_dev *pnp, unsigned int irq)
 337{
 338#ifdef CONFIG_PCI
 339        struct pci_dev *pci = NULL;
 340
 341        for_each_pci_dev(pci) {
 342                if (pci_dev_uses_irq(pnp, pci, irq)) {
 343                        pci_dev_put(pci);
 344                        return 1;
 345                }
 346        }
 347#endif
 348        return 0;
 349}
 350
 351int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
 352{
 353        int i;
 354        struct pnp_dev *tdev;
 355        struct resource *tres;
 356        resource_size_t *irq;
 357
 358        irq = &res->start;
 359
 360        /* if the resource doesn't exist, don't complain about it */
 361        if (cannot_compare(res->flags))
 362                return 1;
 363
 364        /* check if the resource is valid */
 365        if (*irq > 15)
 366                return 0;
 367
 368        /* check if the resource is reserved */
 369        for (i = 0; i < 16; i++) {
 370                if (pnp_reserve_irq[i] == *irq)
 371                        return 0;
 372        }
 373
 374        /* check for internal conflicts */
 375        for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
 376                if (tres != res && tres->flags & IORESOURCE_IRQ) {
 377                        if (tres->start == *irq)
 378                                return 0;
 379                }
 380        }
 381
 382        /* check if the resource is being used by a pci device */
 383        if (pci_uses_irq(dev, *irq))
 384                return 0;
 385
 386        /* check if the resource is already in use, skip if the
 387         * device is active because it itself may be in use */
 388        if (!dev->active) {
 389                if (request_irq(*irq, pnp_test_handler,
 390                                IRQF_PROBE_SHARED, "pnp", NULL))
 391                        return 0;
 392                free_irq(*irq, NULL);
 393        }
 394
 395        /* check for conflicts with other pnp devices */
 396        pnp_for_each_dev(tdev) {
 397                if (tdev == dev)
 398                        continue;
 399                for (i = 0;
 400                     (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i));
 401                     i++) {
 402                        if (tres->flags & IORESOURCE_IRQ) {
 403                                if (cannot_compare(tres->flags))
 404                                        continue;
 405                                if (tres->start == *irq)
 406                                        return 0;
 407                        }
 408                }
 409        }
 410
 411        return 1;
 412}
 413
 414#ifdef CONFIG_ISA_DMA_API
 415int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
 416{
 417        int i;
 418        struct pnp_dev *tdev;
 419        struct resource *tres;
 420        resource_size_t *dma;
 421
 422        dma = &res->start;
 423
 424        /* if the resource doesn't exist, don't complain about it */
 425        if (cannot_compare(res->flags))
 426                return 1;
 427
 428        /* check if the resource is valid */
 429        if (*dma == 4 || *dma > 7)
 430                return 0;
 431
 432        /* check if the resource is reserved */
 433        for (i = 0; i < 8; i++) {
 434                if (pnp_reserve_dma[i] == *dma)
 435                        return 0;
 436        }
 437
 438        /* check for internal conflicts */
 439        for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
 440                if (tres != res && tres->flags & IORESOURCE_DMA) {
 441                        if (tres->start == *dma)
 442                                return 0;
 443                }
 444        }
 445
 446        /* check if the resource is already in use, skip if the
 447         * device is active because it itself may be in use */
 448        if (!dev->active) {
 449                if (request_dma(*dma, "pnp"))
 450                        return 0;
 451                free_dma(*dma);
 452        }
 453
 454        /* check for conflicts with other pnp devices */
 455        pnp_for_each_dev(tdev) {
 456                if (tdev == dev)
 457                        continue;
 458                for (i = 0;
 459                     (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i));
 460                     i++) {
 461                        if (tres->flags & IORESOURCE_DMA) {
 462                                if (cannot_compare(tres->flags))
 463                                        continue;
 464                                if (tres->start == *dma)
 465                                        return 0;
 466                        }
 467                }
 468        }
 469
 470        return 1;
 471}
 472#endif /* CONFIG_ISA_DMA_API */
 473
 474unsigned long pnp_resource_type(struct resource *res)
 475{
 476        return res->flags & (IORESOURCE_IO  | IORESOURCE_MEM |
 477                             IORESOURCE_IRQ | IORESOURCE_DMA |
 478                             IORESOURCE_BUS);
 479}
 480
 481struct resource *pnp_get_resource(struct pnp_dev *dev,
 482                                  unsigned long type, unsigned int num)
 483{
 484        struct pnp_resource *pnp_res;
 485        struct resource *res;
 486
 487        list_for_each_entry(pnp_res, &dev->resources, list) {
 488                res = &pnp_res->res;
 489                if (pnp_resource_type(res) == type && num-- == 0)
 490                        return res;
 491        }
 492        return NULL;
 493}
 494EXPORT_SYMBOL(pnp_get_resource);
 495
 496static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
 497{
 498        struct pnp_resource *pnp_res;
 499
 500        pnp_res = kzalloc(sizeof(struct pnp_resource), GFP_KERNEL);
 501        if (!pnp_res)
 502                return NULL;
 503
 504        list_add_tail(&pnp_res->list, &dev->resources);
 505        return pnp_res;
 506}
 507
 508struct pnp_resource *pnp_add_resource(struct pnp_dev *dev,
 509                                      struct resource *res)
 510{
 511        struct pnp_resource *pnp_res;
 512
 513        pnp_res = pnp_new_resource(dev);
 514        if (!pnp_res) {
 515                dev_err(&dev->dev, "can't add resource %pR\n", res);
 516                return NULL;
 517        }
 518
 519        pnp_res->res = *res;
 520        pnp_res->res.name = dev->name;
 521        dev_dbg(&dev->dev, "%pR\n", res);
 522        return pnp_res;
 523}
 524
 525struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
 526                                          int flags)
 527{
 528        struct pnp_resource *pnp_res;
 529        struct resource *res;
 530
 531        pnp_res = pnp_new_resource(dev);
 532        if (!pnp_res) {
 533                dev_err(&dev->dev, "can't add resource for IRQ %d\n", irq);
 534                return NULL;
 535        }
 536
 537        res = &pnp_res->res;
 538        res->flags = IORESOURCE_IRQ | flags;
 539        res->start = irq;
 540        res->end = irq;
 541
 542        dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
 543        return pnp_res;
 544}
 545
 546struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
 547                                          int flags)
 548{
 549        struct pnp_resource *pnp_res;
 550        struct resource *res;
 551
 552        pnp_res = pnp_new_resource(dev);
 553        if (!pnp_res) {
 554                dev_err(&dev->dev, "can't add resource for DMA %d\n", dma);
 555                return NULL;
 556        }
 557
 558        res = &pnp_res->res;
 559        res->flags = IORESOURCE_DMA | flags;
 560        res->start = dma;
 561        res->end = dma;
 562
 563        dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
 564        return pnp_res;
 565}
 566
 567struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
 568                                         resource_size_t start,
 569                                         resource_size_t end, int flags)
 570{
 571        struct pnp_resource *pnp_res;
 572        struct resource *res;
 573
 574        pnp_res = pnp_new_resource(dev);
 575        if (!pnp_res) {
 576                dev_err(&dev->dev, "can't add resource for IO %#llx-%#llx\n",
 577                        (unsigned long long) start,
 578                        (unsigned long long) end);
 579                return NULL;
 580        }
 581
 582        res = &pnp_res->res;
 583        res->flags = IORESOURCE_IO | flags;
 584        res->start = start;
 585        res->end = end;
 586
 587        dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
 588        return pnp_res;
 589}
 590
 591struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
 592                                          resource_size_t start,
 593                                          resource_size_t end, int flags)
 594{
 595        struct pnp_resource *pnp_res;
 596        struct resource *res;
 597
 598        pnp_res = pnp_new_resource(dev);
 599        if (!pnp_res) {
 600                dev_err(&dev->dev, "can't add resource for MEM %#llx-%#llx\n",
 601                        (unsigned long long) start,
 602                        (unsigned long long) end);
 603                return NULL;
 604        }
 605
 606        res = &pnp_res->res;
 607        res->flags = IORESOURCE_MEM | flags;
 608        res->start = start;
 609        res->end = end;
 610
 611        dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
 612        return pnp_res;
 613}
 614
 615struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev,
 616                                          resource_size_t start,
 617                                          resource_size_t end)
 618{
 619        struct pnp_resource *pnp_res;
 620        struct resource *res;
 621
 622        pnp_res = pnp_new_resource(dev);
 623        if (!pnp_res) {
 624                dev_err(&dev->dev, "can't add resource for BUS %#llx-%#llx\n",
 625                        (unsigned long long) start,
 626                        (unsigned long long) end);
 627                return NULL;
 628        }
 629
 630        res = &pnp_res->res;
 631        res->flags = IORESOURCE_BUS;
 632        res->start = start;
 633        res->end = end;
 634
 635        dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
 636        return pnp_res;
 637}
 638
 639/*
 640 * Determine whether the specified resource is a possible configuration
 641 * for this device.
 642 */
 643int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
 644                        resource_size_t size)
 645{
 646        struct pnp_option *option;
 647        struct pnp_port *port;
 648        struct pnp_mem *mem;
 649        struct pnp_irq *irq;
 650        struct pnp_dma *dma;
 651
 652        list_for_each_entry(option, &dev->options, list) {
 653                if (option->type != type)
 654                        continue;
 655
 656                switch (option->type) {
 657                case IORESOURCE_IO:
 658                        port = &option->u.port;
 659                        if (port->min == start && port->size == size)
 660                                return 1;
 661                        break;
 662                case IORESOURCE_MEM:
 663                        mem = &option->u.mem;
 664                        if (mem->min == start && mem->size == size)
 665                                return 1;
 666                        break;
 667                case IORESOURCE_IRQ:
 668                        irq = &option->u.irq;
 669                        if (start < PNP_IRQ_NR &&
 670                            test_bit(start, irq->map.bits))
 671                                return 1;
 672                        break;
 673                case IORESOURCE_DMA:
 674                        dma = &option->u.dma;
 675                        if (dma->map & (1 << start))
 676                                return 1;
 677                        break;
 678                }
 679        }
 680
 681        return 0;
 682}
 683EXPORT_SYMBOL(pnp_possible_config);
 684
 685int pnp_range_reserved(resource_size_t start, resource_size_t end)
 686{
 687        struct pnp_dev *dev;
 688        struct pnp_resource *pnp_res;
 689        resource_size_t *dev_start, *dev_end;
 690
 691        pnp_for_each_dev(dev) {
 692                list_for_each_entry(pnp_res, &dev->resources, list) {
 693                        dev_start = &pnp_res->res.start;
 694                        dev_end   = &pnp_res->res.end;
 695                        if (ranged_conflict(&start, &end, dev_start, dev_end))
 696                                return 1;
 697                }
 698        }
 699        return 0;
 700}
 701EXPORT_SYMBOL(pnp_range_reserved);
 702
 703/* format is: pnp_reserve_irq=irq1[,irq2] .... */
 704static int __init pnp_setup_reserve_irq(char *str)
 705{
 706        int i;
 707
 708        for (i = 0; i < 16; i++)
 709                if (get_option(&str, &pnp_reserve_irq[i]) != 2)
 710                        break;
 711        return 1;
 712}
 713
 714__setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
 715
 716/* format is: pnp_reserve_dma=dma1[,dma2] .... */
 717static int __init pnp_setup_reserve_dma(char *str)
 718{
 719        int i;
 720
 721        for (i = 0; i < 8; i++)
 722                if (get_option(&str, &pnp_reserve_dma[i]) != 2)
 723                        break;
 724        return 1;
 725}
 726
 727__setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
 728
 729/* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
 730static int __init pnp_setup_reserve_io(char *str)
 731{
 732        int i;
 733
 734        for (i = 0; i < 16; i++)
 735                if (get_option(&str, &pnp_reserve_io[i]) != 2)
 736                        break;
 737        return 1;
 738}
 739
 740__setup("pnp_reserve_io=", pnp_setup_reserve_io);
 741
 742/* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
 743static int __init pnp_setup_reserve_mem(char *str)
 744{
 745        int i;
 746
 747        for (i = 0; i < 16; i++)
 748                if (get_option(&str, &pnp_reserve_mem[i]) != 2)
 749                        break;
 750        return 1;
 751}
 752
 753__setup("pnp_reserve_mem=", pnp_setup_reserve_mem);
 754