manager.c revision 9dd78466c956ac4b4f38e12032dc4249ccf57ad1
1/* 2 * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices 3 * 4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz> 5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com> 6 * 7 */ 8 9#include <linux/errno.h> 10#include <linux/module.h> 11#include <linux/init.h> 12#include <linux/kernel.h> 13#include <linux/pnp.h> 14#include <linux/slab.h> 15#include <linux/bitmap.h> 16#include "base.h" 17 18DECLARE_MUTEX(pnp_res_mutex); 19 20static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) 21{ 22 resource_size_t *start, *end; 23 unsigned long *flags; 24 25 if (!dev || !rule) 26 return -EINVAL; 27 28 if (idx >= PNP_MAX_PORT) { 29 pnp_err 30 ("More than 4 ports is incompatible with pnp specifications."); 31 /* pretend we were successful so at least the manager won't try again */ 32 return 1; 33 } 34 35 /* check if this resource has been manually set, if so skip */ 36 if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO)) 37 return 1; 38 39 start = &dev->res.port_resource[idx].start; 40 end = &dev->res.port_resource[idx].end; 41 flags = &dev->res.port_resource[idx].flags; 42 43 /* set the initial values */ 44 *flags |= rule->flags | IORESOURCE_IO; 45 *flags &= ~IORESOURCE_UNSET; 46 47 if (!rule->size) { 48 *flags |= IORESOURCE_DISABLED; 49 return 1; /* skip disabled resource requests */ 50 } 51 52 *start = rule->min; 53 *end = *start + rule->size - 1; 54 55 /* run through until pnp_check_port is happy */ 56 while (!pnp_check_port(dev, idx)) { 57 *start += rule->align; 58 *end = *start + rule->size - 1; 59 if (*start > rule->max || !rule->align) 60 return 0; 61 } 62 return 1; 63} 64 65static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) 66{ 67 resource_size_t *start, *end; 68 unsigned long *flags; 69 70 if (!dev || !rule) 71 return -EINVAL; 72 73 if (idx >= PNP_MAX_MEM) { 74 pnp_err 75 ("More than 8 mems is incompatible with pnp specifications."); 76 /* pretend we were successful so at least the manager won't try again */ 77 return 1; 78 } 79 80 /* check if this resource has been manually set, if so skip */ 81 if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO)) 82 return 1; 83 84 start = &dev->res.mem_resource[idx].start; 85 end = &dev->res.mem_resource[idx].end; 86 flags = &dev->res.mem_resource[idx].flags; 87 88 /* set the initial values */ 89 *flags |= rule->flags | IORESOURCE_MEM; 90 *flags &= ~IORESOURCE_UNSET; 91 92 /* convert pnp flags to standard Linux flags */ 93 if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) 94 *flags |= IORESOURCE_READONLY; 95 if (rule->flags & IORESOURCE_MEM_CACHEABLE) 96 *flags |= IORESOURCE_CACHEABLE; 97 if (rule->flags & IORESOURCE_MEM_RANGELENGTH) 98 *flags |= IORESOURCE_RANGELENGTH; 99 if (rule->flags & IORESOURCE_MEM_SHADOWABLE) 100 *flags |= IORESOURCE_SHADOWABLE; 101 102 if (!rule->size) { 103 *flags |= IORESOURCE_DISABLED; 104 return 1; /* skip disabled resource requests */ 105 } 106 107 *start = rule->min; 108 *end = *start + rule->size - 1; 109 110 /* run through until pnp_check_mem is happy */ 111 while (!pnp_check_mem(dev, idx)) { 112 *start += rule->align; 113 *end = *start + rule->size - 1; 114 if (*start > rule->max || !rule->align) 115 return 0; 116 } 117 return 1; 118} 119 120static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) 121{ 122 resource_size_t *start, *end; 123 unsigned long *flags; 124 int i; 125 126 /* IRQ priority: this table is good for i386 */ 127 static unsigned short xtab[16] = { 128 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 129 }; 130 131 if (!dev || !rule) 132 return -EINVAL; 133 134 if (idx >= PNP_MAX_IRQ) { 135 pnp_err 136 ("More than 2 irqs is incompatible with pnp specifications."); 137 /* pretend we were successful so at least the manager won't try again */ 138 return 1; 139 } 140 141 /* check if this resource has been manually set, if so skip */ 142 if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO)) 143 return 1; 144 145 start = &dev->res.irq_resource[idx].start; 146 end = &dev->res.irq_resource[idx].end; 147 flags = &dev->res.irq_resource[idx].flags; 148 149 /* set the initial values */ 150 *flags |= rule->flags | IORESOURCE_IRQ; 151 *flags &= ~IORESOURCE_UNSET; 152 153 if (bitmap_empty(rule->map, PNP_IRQ_NR)) { 154 *flags |= IORESOURCE_DISABLED; 155 return 1; /* skip disabled resource requests */ 156 } 157 158 /* TBD: need check for >16 IRQ */ 159 *start = find_next_bit(rule->map, PNP_IRQ_NR, 16); 160 if (*start < PNP_IRQ_NR) { 161 *end = *start; 162 return 1; 163 } 164 for (i = 0; i < 16; i++) { 165 if (test_bit(xtab[i], rule->map)) { 166 *start = *end = xtab[i]; 167 if (pnp_check_irq(dev, idx)) 168 return 1; 169 } 170 } 171 return 0; 172} 173 174static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) 175{ 176 resource_size_t *start, *end; 177 unsigned long *flags; 178 int i; 179 180 /* DMA priority: this table is good for i386 */ 181 static unsigned short xtab[8] = { 182 1, 3, 5, 6, 7, 0, 2, 4 183 }; 184 185 if (!dev || !rule) 186 return -EINVAL; 187 188 if (idx >= PNP_MAX_DMA) { 189 pnp_err 190 ("More than 2 dmas is incompatible with pnp specifications."); 191 /* pretend we were successful so at least the manager won't try again */ 192 return 1; 193 } 194 195 /* check if this resource has been manually set, if so skip */ 196 if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO)) 197 return 1; 198 199 start = &dev->res.dma_resource[idx].start; 200 end = &dev->res.dma_resource[idx].end; 201 flags = &dev->res.dma_resource[idx].flags; 202 203 /* set the initial values */ 204 *flags |= rule->flags | IORESOURCE_DMA; 205 *flags &= ~IORESOURCE_UNSET; 206 207 if (!rule->map) { 208 *flags |= IORESOURCE_DISABLED; 209 return 1; /* skip disabled resource requests */ 210 } 211 212 for (i = 0; i < 8; i++) { 213 if (rule->map & (1 << xtab[i])) { 214 *start = *end = xtab[i]; 215 if (pnp_check_dma(dev, idx)) 216 return 1; 217 } 218 } 219 return 0; 220} 221 222/** 223 * pnp_init_resources - Resets a resource table to default values. 224 * @table: pointer to the desired resource table 225 * 226 */ 227void pnp_init_resource_table(struct pnp_resource_table *table) 228{ 229 int idx; 230 for (idx = 0; idx < PNP_MAX_IRQ; idx++) { 231 table->irq_resource[idx].name = NULL; 232 table->irq_resource[idx].start = -1; 233 table->irq_resource[idx].end = -1; 234 table->irq_resource[idx].flags = 235 IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET; 236 } 237 for (idx = 0; idx < PNP_MAX_DMA; idx++) { 238 table->dma_resource[idx].name = NULL; 239 table->dma_resource[idx].start = -1; 240 table->dma_resource[idx].end = -1; 241 table->dma_resource[idx].flags = 242 IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET; 243 } 244 for (idx = 0; idx < PNP_MAX_PORT; idx++) { 245 table->port_resource[idx].name = NULL; 246 table->port_resource[idx].start = 0; 247 table->port_resource[idx].end = 0; 248 table->port_resource[idx].flags = 249 IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET; 250 } 251 for (idx = 0; idx < PNP_MAX_MEM; idx++) { 252 table->mem_resource[idx].name = NULL; 253 table->mem_resource[idx].start = 0; 254 table->mem_resource[idx].end = 0; 255 table->mem_resource[idx].flags = 256 IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET; 257 } 258} 259 260/** 261 * pnp_clean_resources - clears resources that were not manually set 262 * @res: the resources to clean 263 * 264 */ 265static void pnp_clean_resource_table(struct pnp_resource_table *res) 266{ 267 int idx; 268 for (idx = 0; idx < PNP_MAX_IRQ; idx++) { 269 if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO)) 270 continue; 271 res->irq_resource[idx].start = -1; 272 res->irq_resource[idx].end = -1; 273 res->irq_resource[idx].flags = 274 IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET; 275 } 276 for (idx = 0; idx < PNP_MAX_DMA; idx++) { 277 if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO)) 278 continue; 279 res->dma_resource[idx].start = -1; 280 res->dma_resource[idx].end = -1; 281 res->dma_resource[idx].flags = 282 IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET; 283 } 284 for (idx = 0; idx < PNP_MAX_PORT; idx++) { 285 if (!(res->port_resource[idx].flags & IORESOURCE_AUTO)) 286 continue; 287 res->port_resource[idx].start = 0; 288 res->port_resource[idx].end = 0; 289 res->port_resource[idx].flags = 290 IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET; 291 } 292 for (idx = 0; idx < PNP_MAX_MEM; idx++) { 293 if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO)) 294 continue; 295 res->mem_resource[idx].start = 0; 296 res->mem_resource[idx].end = 0; 297 res->mem_resource[idx].flags = 298 IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET; 299 } 300} 301 302/** 303 * pnp_assign_resources - assigns resources to the device based on the specified dependent number 304 * @dev: pointer to the desired device 305 * @depnum: the dependent function number 306 * 307 * Only set depnum to 0 if the device does not have dependent options. 308 */ 309static int pnp_assign_resources(struct pnp_dev *dev, int depnum) 310{ 311 struct pnp_port *port; 312 struct pnp_mem *mem; 313 struct pnp_irq *irq; 314 struct pnp_dma *dma; 315 int nport = 0, nmem = 0, nirq = 0, ndma = 0; 316 317 if (!pnp_can_configure(dev)) 318 return -ENODEV; 319 320 down(&pnp_res_mutex); 321 pnp_clean_resource_table(&dev->res); /* start with a fresh slate */ 322 if (dev->independent) { 323 port = dev->independent->port; 324 mem = dev->independent->mem; 325 irq = dev->independent->irq; 326 dma = dev->independent->dma; 327 while (port) { 328 if (!pnp_assign_port(dev, port, nport)) 329 goto fail; 330 nport++; 331 port = port->next; 332 } 333 while (mem) { 334 if (!pnp_assign_mem(dev, mem, nmem)) 335 goto fail; 336 nmem++; 337 mem = mem->next; 338 } 339 while (irq) { 340 if (!pnp_assign_irq(dev, irq, nirq)) 341 goto fail; 342 nirq++; 343 irq = irq->next; 344 } 345 while (dma) { 346 if (!pnp_assign_dma(dev, dma, ndma)) 347 goto fail; 348 ndma++; 349 dma = dma->next; 350 } 351 } 352 353 if (depnum) { 354 struct pnp_option *dep; 355 int i; 356 for (i = 1, dep = dev->dependent; i < depnum; 357 i++, dep = dep->next) 358 if (!dep) 359 goto fail; 360 port = dep->port; 361 mem = dep->mem; 362 irq = dep->irq; 363 dma = dep->dma; 364 while (port) { 365 if (!pnp_assign_port(dev, port, nport)) 366 goto fail; 367 nport++; 368 port = port->next; 369 } 370 while (mem) { 371 if (!pnp_assign_mem(dev, mem, nmem)) 372 goto fail; 373 nmem++; 374 mem = mem->next; 375 } 376 while (irq) { 377 if (!pnp_assign_irq(dev, irq, nirq)) 378 goto fail; 379 nirq++; 380 irq = irq->next; 381 } 382 while (dma) { 383 if (!pnp_assign_dma(dev, dma, ndma)) 384 goto fail; 385 ndma++; 386 dma = dma->next; 387 } 388 } else if (dev->dependent) 389 goto fail; 390 391 up(&pnp_res_mutex); 392 return 1; 393 394 fail: 395 pnp_clean_resource_table(&dev->res); 396 up(&pnp_res_mutex); 397 return 0; 398} 399 400/** 401 * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table 402 * @dev: pointer to the desired device 403 * @res: pointer to the new resource config 404 * @mode: 0 or PNP_CONFIG_FORCE 405 * 406 * This function can be used by drivers that want to manually set thier resources. 407 */ 408int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, 409 int mode) 410{ 411 int i; 412 struct pnp_resource_table *bak; 413 if (!dev || !res) 414 return -EINVAL; 415 if (!pnp_can_configure(dev)) 416 return -ENODEV; 417 bak = pnp_alloc(sizeof(struct pnp_resource_table)); 418 if (!bak) 419 return -ENOMEM; 420 *bak = dev->res; 421 422 down(&pnp_res_mutex); 423 dev->res = *res; 424 if (!(mode & PNP_CONFIG_FORCE)) { 425 for (i = 0; i < PNP_MAX_PORT; i++) { 426 if (!pnp_check_port(dev, i)) 427 goto fail; 428 } 429 for (i = 0; i < PNP_MAX_MEM; i++) { 430 if (!pnp_check_mem(dev, i)) 431 goto fail; 432 } 433 for (i = 0; i < PNP_MAX_IRQ; i++) { 434 if (!pnp_check_irq(dev, i)) 435 goto fail; 436 } 437 for (i = 0; i < PNP_MAX_DMA; i++) { 438 if (!pnp_check_dma(dev, i)) 439 goto fail; 440 } 441 } 442 up(&pnp_res_mutex); 443 444 kfree(bak); 445 return 0; 446 447 fail: 448 dev->res = *bak; 449 up(&pnp_res_mutex); 450 kfree(bak); 451 return -EINVAL; 452} 453 454/** 455 * pnp_auto_config_dev - automatically assigns resources to a device 456 * @dev: pointer to the desired device 457 * 458 */ 459int pnp_auto_config_dev(struct pnp_dev *dev) 460{ 461 struct pnp_option *dep; 462 int i = 1; 463 464 if (!dev) 465 return -EINVAL; 466 467 if (!pnp_can_configure(dev)) { 468 pnp_dbg("Device %s does not support resource configuration.", 469 dev->dev.bus_id); 470 return -ENODEV; 471 } 472 473 if (!dev->dependent) { 474 if (pnp_assign_resources(dev, 0)) 475 return 0; 476 } else { 477 dep = dev->dependent; 478 do { 479 if (pnp_assign_resources(dev, i)) 480 return 0; 481 dep = dep->next; 482 i++; 483 } while (dep); 484 } 485 486 pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id); 487 return -EBUSY; 488} 489 490/** 491 * pnp_start_dev - low-level start of the PnP device 492 * @dev: pointer to the desired device 493 * 494 * assumes that resources have alread been allocated 495 */ 496 497int pnp_start_dev(struct pnp_dev *dev) 498{ 499 if (!pnp_can_write(dev)) { 500 pnp_dbg("Device %s does not support activation.", 501 dev->dev.bus_id); 502 return -EINVAL; 503 } 504 505 if (dev->protocol->set(dev, &dev->res) < 0) { 506 pnp_err("Failed to activate device %s.", dev->dev.bus_id); 507 return -EIO; 508 } 509 510 pnp_info("Device %s activated.", dev->dev.bus_id); 511 512 return 0; 513} 514 515/** 516 * pnp_stop_dev - low-level disable of the PnP device 517 * @dev: pointer to the desired device 518 * 519 * does not free resources 520 */ 521 522int pnp_stop_dev(struct pnp_dev *dev) 523{ 524 if (!pnp_can_disable(dev)) { 525 pnp_dbg("Device %s does not support disabling.", 526 dev->dev.bus_id); 527 return -EINVAL; 528 } 529 if (dev->protocol->disable(dev) < 0) { 530 pnp_err("Failed to disable device %s.", dev->dev.bus_id); 531 return -EIO; 532 } 533 534 pnp_info("Device %s disabled.", dev->dev.bus_id); 535 536 return 0; 537} 538 539/** 540 * pnp_activate_dev - activates a PnP device for use 541 * @dev: pointer to the desired device 542 * 543 * does not validate or set resources so be careful. 544 */ 545int pnp_activate_dev(struct pnp_dev *dev) 546{ 547 int error; 548 549 if (!dev) 550 return -EINVAL; 551 if (dev->active) { 552 return 0; /* the device is already active */ 553 } 554 555 /* ensure resources are allocated */ 556 if (pnp_auto_config_dev(dev)) 557 return -EBUSY; 558 559 error = pnp_start_dev(dev); 560 if (error) 561 return error; 562 563 dev->active = 1; 564 565 return 1; 566} 567 568/** 569 * pnp_disable_dev - disables device 570 * @dev: pointer to the desired device 571 * 572 * inform the correct pnp protocol so that resources can be used by other devices 573 */ 574int pnp_disable_dev(struct pnp_dev *dev) 575{ 576 int error; 577 578 if (!dev) 579 return -EINVAL; 580 if (!dev->active) { 581 return 0; /* the device is already disabled */ 582 } 583 584 error = pnp_stop_dev(dev); 585 if (error) 586 return error; 587 588 dev->active = 0; 589 590 /* release the resources so that other devices can use them */ 591 down(&pnp_res_mutex); 592 pnp_clean_resource_table(&dev->res); 593 up(&pnp_res_mutex); 594 595 return 1; 596} 597 598/** 599 * pnp_resource_change - change one resource 600 * @resource: pointer to resource to be changed 601 * @start: start of region 602 * @size: size of region 603 * 604 */ 605void pnp_resource_change(struct resource *resource, resource_size_t start, 606 resource_size_t size) 607{ 608 if (resource == NULL) 609 return; 610 resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET); 611 resource->start = start; 612 resource->end = start + size - 1; 613} 614 615EXPORT_SYMBOL(pnp_manual_config_dev); 616#if 0 617EXPORT_SYMBOL(pnp_auto_config_dev); 618#endif 619EXPORT_SYMBOL(pnp_start_dev); 620EXPORT_SYMBOL(pnp_stop_dev); 621EXPORT_SYMBOL(pnp_activate_dev); 622EXPORT_SYMBOL(pnp_disable_dev); 623EXPORT_SYMBOL(pnp_resource_change); 624EXPORT_SYMBOL(pnp_init_resource_table); 625