resource.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  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. */
  7. #include <linux/module.h>
  8. #include <linux/errno.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/kernel.h>
  11. #include <asm/io.h>
  12. #include <asm/dma.h>
  13. #include <asm/irq.h>
  14. #include <linux/pci.h>
  15. #include <linux/ioport.h>
  16. #include <linux/init.h>
  17. #include <linux/pnp.h>
  18. #include "base.h"
  19. static int pnp_reserve_irq[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some IRQ */
  20. static int pnp_reserve_dma[8] = {[0 ... 7] = -1 }; /* reserve (don't use) some DMA */
  21. static int pnp_reserve_io[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some I/O region */
  22. static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some memory region */
  23. /*
  24. * option registration
  25. */
  26. struct pnp_option *pnp_build_option(int priority)
  27. {
  28. struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
  29. if (!option)
  30. return NULL;
  31. option->priority = priority & 0xff;
  32. /* make sure the priority is valid */
  33. if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
  34. option->priority = PNP_RES_PRIORITY_INVALID;
  35. return option;
  36. }
  37. struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
  38. {
  39. struct pnp_option *option;
  40. option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
  41. /* this should never happen but if it does we'll try to continue */
  42. if (dev->independent)
  43. dev_err(&dev->dev, "independent resource already registered\n");
  44. dev->independent = option;
  45. dev_dbg(&dev->dev, "new independent option\n");
  46. return option;
  47. }
  48. struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
  49. int priority)
  50. {
  51. struct pnp_option *option;
  52. option = pnp_build_option(priority);
  53. if (dev->dependent) {
  54. struct pnp_option *parent = dev->dependent;
  55. while (parent->next)
  56. parent = parent->next;
  57. parent->next = option;
  58. } else
  59. dev->dependent = option;
  60. dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority);
  61. return option;
  62. }
  63. int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
  64. struct pnp_irq *data)
  65. {
  66. struct pnp_irq *ptr;
  67. #ifdef DEBUG
  68. char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */
  69. #endif
  70. ptr = option->irq;
  71. while (ptr && ptr->next)
  72. ptr = ptr->next;
  73. if (ptr)
  74. ptr->next = data;
  75. else
  76. option->irq = data;
  77. #ifdef CONFIG_PCI
  78. {
  79. int i;
  80. for (i = 0; i < 16; i++)
  81. if (test_bit(i, data->map.bits))
  82. pcibios_penalize_isa_irq(i, 0);
  83. }
  84. #endif
  85. #ifdef DEBUG
  86. bitmap_scnprintf(buf, sizeof(buf), data->map.bits, PNP_IRQ_NR);
  87. dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf,
  88. data->flags);
  89. #endif
  90. return 0;
  91. }
  92. int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
  93. struct pnp_dma *data)
  94. {
  95. struct pnp_dma *ptr;
  96. ptr = option->dma;
  97. while (ptr && ptr->next)
  98. ptr = ptr->next;
  99. if (ptr)
  100. ptr->next = data;
  101. else
  102. option->dma = data;
  103. dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", data->map,
  104. data->flags);
  105. return 0;
  106. }
  107. int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
  108. struct pnp_port *data)
  109. {
  110. struct pnp_port *ptr;
  111. ptr = option->port;
  112. while (ptr && ptr->next)
  113. ptr = ptr->next;
  114. if (ptr)
  115. ptr->next = data;
  116. else
  117. option->port = data;
  118. dev_dbg(&dev->dev, " io "
  119. "min %#llx max %#llx align %lld size %lld flags %#x\n",
  120. (unsigned long long) data->min,
  121. (unsigned long long) data->max,
  122. (unsigned long long) data->align,
  123. (unsigned long long) data->size, data->flags);
  124. return 0;
  125. }
  126. int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
  127. struct pnp_mem *data)
  128. {
  129. struct pnp_mem *ptr;
  130. ptr = option->mem;
  131. while (ptr && ptr->next)
  132. ptr = ptr->next;
  133. if (ptr)
  134. ptr->next = data;
  135. else
  136. option->mem = data;
  137. dev_dbg(&dev->dev, " mem "
  138. "min %#llx max %#llx align %lld size %lld flags %#x\n",
  139. (unsigned long long) data->min,
  140. (unsigned long long) data->max,
  141. (unsigned long long) data->align,
  142. (unsigned long long) data->size, data->flags);
  143. return 0;
  144. }
  145. static void pnp_free_port(struct pnp_port *port)
  146. {
  147. struct pnp_port *next;
  148. while (port) {
  149. next = port->next;
  150. kfree(port);
  151. port = next;
  152. }
  153. }
  154. static void pnp_free_irq(struct pnp_irq *irq)
  155. {
  156. struct pnp_irq *next;
  157. while (irq) {
  158. next = irq->next;
  159. kfree(irq);
  160. irq = next;
  161. }
  162. }
  163. static void pnp_free_dma(struct pnp_dma *dma)
  164. {
  165. struct pnp_dma *next;
  166. while (dma) {
  167. next = dma->next;
  168. kfree(dma);
  169. dma = next;
  170. }
  171. }
  172. static void pnp_free_mem(struct pnp_mem *mem)
  173. {
  174. struct pnp_mem *next;
  175. while (mem) {
  176. next = mem->next;
  177. kfree(mem);
  178. mem = next;
  179. }
  180. }
  181. void pnp_free_option(struct pnp_option *option)
  182. {
  183. struct pnp_option *next;
  184. while (option) {
  185. next = option->next;
  186. pnp_free_port(option->port);
  187. pnp_free_irq(option->irq);
  188. pnp_free_dma(option->dma);
  189. pnp_free_mem(option->mem);
  190. kfree(option);
  191. option = next;
  192. }
  193. }
  194. /*
  195. * resource validity checking
  196. */
  197. #define length(start, end) (*(end) - *(start) + 1)
  198. /* Two ranges conflict if one doesn't end before the other starts */
  199. #define ranged_conflict(starta, enda, startb, endb) \
  200. !((*(enda) < *(startb)) || (*(endb) < *(starta)))
  201. #define cannot_compare(flags) \
  202. ((flags) & IORESOURCE_DISABLED)
  203. int pnp_check_port(struct pnp_dev *dev, struct resource *res)
  204. {
  205. int i;
  206. struct pnp_dev *tdev;
  207. struct resource *tres;
  208. resource_size_t *port, *end, *tport, *tend;
  209. port = &res->start;
  210. end = &res->end;
  211. /* if the resource doesn't exist, don't complain about it */
  212. if (cannot_compare(res->flags))
  213. return 1;
  214. /* check if the resource is already in use, skip if the
  215. * device is active because it itself may be in use */
  216. if (!dev->active) {
  217. if (__check_region(&ioport_resource, *port, length(port, end)))
  218. return 0;
  219. }
  220. /* check if the resource is reserved */
  221. for (i = 0; i < 8; i++) {
  222. int rport = pnp_reserve_io[i << 1];
  223. int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1;
  224. if (ranged_conflict(port, end, &rport, &rend))
  225. return 0;
  226. }
  227. /* check for internal conflicts */
  228. for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
  229. if (tres != res && tres->flags & IORESOURCE_IO) {
  230. tport = &tres->start;
  231. tend = &tres->end;
  232. if (ranged_conflict(port, end, tport, tend))
  233. return 0;
  234. }
  235. }
  236. /* check for conflicts with other pnp devices */
  237. pnp_for_each_dev(tdev) {
  238. if (tdev == dev)
  239. continue;
  240. for (i = 0;
  241. (tres = pnp_get_resource(tdev, IORESOURCE_IO, i));
  242. i++) {
  243. if (tres->flags & IORESOURCE_IO) {
  244. if (cannot_compare(tres->flags))
  245. continue;
  246. tport = &tres->start;
  247. tend = &tres->end;
  248. if (ranged_conflict(port, end, tport, tend))
  249. return 0;
  250. }
  251. }
  252. }
  253. return 1;
  254. }
  255. int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
  256. {
  257. int i;
  258. struct pnp_dev *tdev;
  259. struct resource *tres;
  260. resource_size_t *addr, *end, *taddr, *tend;
  261. addr = &res->start;
  262. end = &res->end;
  263. /* if the resource doesn't exist, don't complain about it */
  264. if (cannot_compare(res->flags))
  265. return 1;
  266. /* check if the resource is already in use, skip if the
  267. * device is active because it itself may be in use */
  268. if (!dev->active) {
  269. if (check_mem_region(*addr, length(addr, end)))
  270. return 0;
  271. }
  272. /* check if the resource is reserved */
  273. for (i = 0; i < 8; i++) {
  274. int raddr = pnp_reserve_mem[i << 1];
  275. int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1;
  276. if (ranged_conflict(addr, end, &raddr, &rend))
  277. return 0;
  278. }
  279. /* check for internal conflicts */
  280. for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
  281. if (tres != res && tres->flags & IORESOURCE_MEM) {
  282. taddr = &tres->start;
  283. tend = &tres->end;
  284. if (ranged_conflict(addr, end, taddr, tend))
  285. return 0;
  286. }
  287. }
  288. /* check for conflicts with other pnp devices */
  289. pnp_for_each_dev(tdev) {
  290. if (tdev == dev)
  291. continue;
  292. for (i = 0;
  293. (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i));
  294. i++) {
  295. if (tres->flags & IORESOURCE_MEM) {
  296. if (cannot_compare(tres->flags))
  297. continue;
  298. taddr = &tres->start;
  299. tend = &tres->end;
  300. if (ranged_conflict(addr, end, taddr, tend))
  301. return 0;
  302. }
  303. }
  304. }
  305. return 1;
  306. }
  307. static irqreturn_t pnp_test_handler(int irq, void *dev_id)
  308. {
  309. return IRQ_HANDLED;
  310. }
  311. int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
  312. {
  313. int i;
  314. struct pnp_dev *tdev;
  315. struct resource *tres;
  316. resource_size_t *irq;
  317. irq = &res->start;
  318. /* if the resource doesn't exist, don't complain about it */
  319. if (cannot_compare(res->flags))
  320. return 1;
  321. /* check if the resource is valid */
  322. if (*irq < 0 || *irq > 15)
  323. return 0;
  324. /* check if the resource is reserved */
  325. for (i = 0; i < 16; i++) {
  326. if (pnp_reserve_irq[i] == *irq)
  327. return 0;
  328. }
  329. /* check for internal conflicts */
  330. for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
  331. if (tres != res && tres->flags & IORESOURCE_IRQ) {
  332. if (tres->start == *irq)
  333. return 0;
  334. }
  335. }
  336. #ifdef CONFIG_PCI
  337. /* check if the resource is being used by a pci device */
  338. {
  339. struct pci_dev *pci = NULL;
  340. for_each_pci_dev(pci) {
  341. if (pci->irq == *irq) {
  342. pci_dev_put(pci);
  343. return 0;
  344. }
  345. }
  346. }
  347. #endif
  348. /* check if the resource is already in use, skip if the
  349. * device is active because it itself may be in use */
  350. if (!dev->active) {
  351. if (request_irq(*irq, pnp_test_handler,
  352. IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
  353. return 0;
  354. free_irq(*irq, NULL);
  355. }
  356. /* check for conflicts with other pnp devices */
  357. pnp_for_each_dev(tdev) {
  358. if (tdev == dev)
  359. continue;
  360. for (i = 0;
  361. (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i));
  362. i++) {
  363. if (tres->flags & IORESOURCE_IRQ) {
  364. if (cannot_compare(tres->flags))
  365. continue;
  366. if (tres->start == *irq)
  367. return 0;
  368. }
  369. }
  370. }
  371. return 1;
  372. }
  373. int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
  374. {
  375. #ifndef CONFIG_IA64
  376. int i;
  377. struct pnp_dev *tdev;
  378. struct resource *tres;
  379. resource_size_t *dma;
  380. dma = &res->start;
  381. /* if the resource doesn't exist, don't complain about it */
  382. if (cannot_compare(res->flags))
  383. return 1;
  384. /* check if the resource is valid */
  385. if (*dma < 0 || *dma == 4 || *dma > 7)
  386. return 0;
  387. /* check if the resource is reserved */
  388. for (i = 0; i < 8; i++) {
  389. if (pnp_reserve_dma[i] == *dma)
  390. return 0;
  391. }
  392. /* check for internal conflicts */
  393. for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
  394. if (tres != res && tres->flags & IORESOURCE_DMA) {
  395. if (tres->start == *dma)
  396. return 0;
  397. }
  398. }
  399. /* check if the resource is already in use, skip if the
  400. * device is active because it itself may be in use */
  401. if (!dev->active) {
  402. if (request_dma(*dma, "pnp"))
  403. return 0;
  404. free_dma(*dma);
  405. }
  406. /* check for conflicts with other pnp devices */
  407. pnp_for_each_dev(tdev) {
  408. if (tdev == dev)
  409. continue;
  410. for (i = 0;
  411. (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i));
  412. i++) {
  413. if (tres->flags & IORESOURCE_DMA) {
  414. if (cannot_compare(tres->flags))
  415. continue;
  416. if (tres->start == *dma)
  417. return 0;
  418. }
  419. }
  420. }
  421. return 1;
  422. #else
  423. /* IA64 does not have legacy DMA */
  424. return 0;
  425. #endif
  426. }
  427. int pnp_resource_type(struct resource *res)
  428. {
  429. return res->flags & (IORESOURCE_IO | IORESOURCE_MEM |
  430. IORESOURCE_IRQ | IORESOURCE_DMA);
  431. }
  432. struct resource *pnp_get_resource(struct pnp_dev *dev,
  433. unsigned int type, unsigned int num)
  434. {
  435. struct pnp_resource *pnp_res;
  436. struct resource *res;
  437. list_for_each_entry(pnp_res, &dev->resources, list) {
  438. res = &pnp_res->res;
  439. if (pnp_resource_type(res) == type && num-- == 0)
  440. return res;
  441. }
  442. return NULL;
  443. }
  444. EXPORT_SYMBOL(pnp_get_resource);
  445. static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
  446. {
  447. struct pnp_resource *pnp_res;
  448. pnp_res = kzalloc(sizeof(struct pnp_resource), GFP_KERNEL);
  449. if (!pnp_res)
  450. return NULL;
  451. list_add_tail(&pnp_res->list, &dev->resources);
  452. return pnp_res;
  453. }
  454. struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
  455. int flags)
  456. {
  457. struct pnp_resource *pnp_res;
  458. struct resource *res;
  459. pnp_res = pnp_new_resource(dev);
  460. if (!pnp_res) {
  461. dev_err(&dev->dev, "can't add resource for IRQ %d\n", irq);
  462. return NULL;
  463. }
  464. res = &pnp_res->res;
  465. res->flags = IORESOURCE_IRQ | flags;
  466. res->start = irq;
  467. res->end = irq;
  468. dev_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags);
  469. return pnp_res;
  470. }
  471. struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
  472. int flags)
  473. {
  474. struct pnp_resource *pnp_res;
  475. struct resource *res;
  476. pnp_res = pnp_new_resource(dev);
  477. if (!pnp_res) {
  478. dev_err(&dev->dev, "can't add resource for DMA %d\n", dma);
  479. return NULL;
  480. }
  481. res = &pnp_res->res;
  482. res->flags = IORESOURCE_DMA | flags;
  483. res->start = dma;
  484. res->end = dma;
  485. dev_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags);
  486. return pnp_res;
  487. }
  488. struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
  489. resource_size_t start,
  490. resource_size_t end, int flags)
  491. {
  492. struct pnp_resource *pnp_res;
  493. struct resource *res;
  494. pnp_res = pnp_new_resource(dev);
  495. if (!pnp_res) {
  496. dev_err(&dev->dev, "can't add resource for IO %#llx-%#llx\n",
  497. (unsigned long long) start,
  498. (unsigned long long) end);
  499. return NULL;
  500. }
  501. res = &pnp_res->res;
  502. res->flags = IORESOURCE_IO | flags;
  503. res->start = start;
  504. res->end = end;
  505. dev_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n",
  506. (unsigned long long) start, (unsigned long long) end, flags);
  507. return pnp_res;
  508. }
  509. struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
  510. resource_size_t start,
  511. resource_size_t end, int flags)
  512. {
  513. struct pnp_resource *pnp_res;
  514. struct resource *res;
  515. pnp_res = pnp_new_resource(dev);
  516. if (!pnp_res) {
  517. dev_err(&dev->dev, "can't add resource for MEM %#llx-%#llx\n",
  518. (unsigned long long) start,
  519. (unsigned long long) end);
  520. return NULL;
  521. }
  522. res = &pnp_res->res;
  523. res->flags = IORESOURCE_MEM | flags;
  524. res->start = start;
  525. res->end = end;
  526. dev_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n",
  527. (unsigned long long) start, (unsigned long long) end, flags);
  528. return pnp_res;
  529. }
  530. static int pnp_possible_option(struct pnp_option *option, int type,
  531. resource_size_t start, resource_size_t size)
  532. {
  533. struct pnp_option *tmp;
  534. struct pnp_port *port;
  535. struct pnp_mem *mem;
  536. struct pnp_irq *irq;
  537. struct pnp_dma *dma;
  538. if (!option)
  539. return 0;
  540. for (tmp = option; tmp; tmp = tmp->next) {
  541. switch (type) {
  542. case IORESOURCE_IO:
  543. for (port = tmp->port; port; port = port->next) {
  544. if (port->min == start && port->size == size)
  545. return 1;
  546. }
  547. break;
  548. case IORESOURCE_MEM:
  549. for (mem = tmp->mem; mem; mem = mem->next) {
  550. if (mem->min == start && mem->size == size)
  551. return 1;
  552. }
  553. break;
  554. case IORESOURCE_IRQ:
  555. for (irq = tmp->irq; irq; irq = irq->next) {
  556. if (start < PNP_IRQ_NR &&
  557. test_bit(start, irq->map.bits))
  558. return 1;
  559. }
  560. break;
  561. case IORESOURCE_DMA:
  562. for (dma = tmp->dma; dma; dma = dma->next) {
  563. if (dma->map & (1 << start))
  564. return 1;
  565. }
  566. break;
  567. }
  568. }
  569. return 0;
  570. }
  571. /*
  572. * Determine whether the specified resource is a possible configuration
  573. * for this device.
  574. */
  575. int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
  576. resource_size_t size)
  577. {
  578. if (pnp_possible_option(dev->independent, type, start, size))
  579. return 1;
  580. if (pnp_possible_option(dev->dependent, type, start, size))
  581. return 1;
  582. return 0;
  583. }
  584. EXPORT_SYMBOL(pnp_possible_config);
  585. /* format is: pnp_reserve_irq=irq1[,irq2] .... */
  586. static int __init pnp_setup_reserve_irq(char *str)
  587. {
  588. int i;
  589. for (i = 0; i < 16; i++)
  590. if (get_option(&str, &pnp_reserve_irq[i]) != 2)
  591. break;
  592. return 1;
  593. }
  594. __setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
  595. /* format is: pnp_reserve_dma=dma1[,dma2] .... */
  596. static int __init pnp_setup_reserve_dma(char *str)
  597. {
  598. int i;
  599. for (i = 0; i < 8; i++)
  600. if (get_option(&str, &pnp_reserve_dma[i]) != 2)
  601. break;
  602. return 1;
  603. }
  604. __setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
  605. /* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
  606. static int __init pnp_setup_reserve_io(char *str)
  607. {
  608. int i;
  609. for (i = 0; i < 16; i++)
  610. if (get_option(&str, &pnp_reserve_io[i]) != 2)
  611. break;
  612. return 1;
  613. }
  614. __setup("pnp_reserve_io=", pnp_setup_reserve_io);
  615. /* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
  616. static int __init pnp_setup_reserve_mem(char *str)
  617. {
  618. int i;
  619. for (i = 0; i < 16; i++)
  620. if (get_option(&str, &pnp_reserve_mem[i]) != 2)
  621. break;
  622. return 1;
  623. }
  624. __setup("pnp_reserve_mem=", pnp_setup_reserve_mem);