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