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