manager.c revision 6e906f0e1c8633ed357a64e9861f1822789bee3d
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 <linux/mutex.h> 16#include "base.h" 17 18DEFINE_MUTEX(pnp_res_mutex); 19 20static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) 21{ 22 struct resource *res, local_res; 23 24 res = pnp_get_resource(dev, IORESOURCE_IO, idx); 25 if (res) { 26 dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx " 27 "flags %#lx\n", idx, (unsigned long long) res->start, 28 (unsigned long long) res->end, res->flags); 29 return 0; 30 } 31 32 res = &local_res; 33 res->flags = rule->flags | IORESOURCE_AUTO; 34 res->start = 0; 35 res->end = 0; 36 37 if (!rule->size) { 38 res->flags |= IORESOURCE_DISABLED; 39 dev_dbg(&dev->dev, " io %d disabled\n", idx); 40 goto __add; 41 } 42 43 res->start = rule->min; 44 res->end = res->start + rule->size - 1; 45 46 while (!pnp_check_port(dev, res)) { 47 res->start += rule->align; 48 res->end = res->start + rule->size - 1; 49 if (res->start > rule->max || !rule->align) { 50 dev_dbg(&dev->dev, " couldn't assign io %d " 51 "(min %#llx max %#llx)\n", idx, 52 (unsigned long long) rule->min, 53 (unsigned long long) rule->max); 54 return -EBUSY; 55 } 56 } 57 58__add: 59 pnp_add_io_resource(dev, res->start, res->end, res->flags); 60 return 0; 61} 62 63static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) 64{ 65 struct resource *res, local_res; 66 67 res = pnp_get_resource(dev, IORESOURCE_MEM, idx); 68 if (res) { 69 dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx " 70 "flags %#lx\n", idx, (unsigned long long) res->start, 71 (unsigned long long) res->end, res->flags); 72 return 0; 73 } 74 75 res = &local_res; 76 res->flags = rule->flags | IORESOURCE_AUTO; 77 res->start = 0; 78 res->end = 0; 79 80 if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) 81 res->flags |= IORESOURCE_READONLY; 82 if (rule->flags & IORESOURCE_MEM_CACHEABLE) 83 res->flags |= IORESOURCE_CACHEABLE; 84 if (rule->flags & IORESOURCE_MEM_RANGELENGTH) 85 res->flags |= IORESOURCE_RANGELENGTH; 86 if (rule->flags & IORESOURCE_MEM_SHADOWABLE) 87 res->flags |= IORESOURCE_SHADOWABLE; 88 89 if (!rule->size) { 90 res->flags |= IORESOURCE_DISABLED; 91 dev_dbg(&dev->dev, " mem %d disabled\n", idx); 92 goto __add; 93 } 94 95 res->start = rule->min; 96 res->end = res->start + rule->size - 1; 97 98 while (!pnp_check_mem(dev, res)) { 99 res->start += rule->align; 100 res->end = res->start + rule->size - 1; 101 if (res->start > rule->max || !rule->align) { 102 dev_dbg(&dev->dev, " couldn't assign mem %d " 103 "(min %#llx max %#llx)\n", idx, 104 (unsigned long long) rule->min, 105 (unsigned long long) rule->max); 106 return -EBUSY; 107 } 108 } 109 110__add: 111 pnp_add_mem_resource(dev, res->start, res->end, res->flags); 112 return 0; 113} 114 115static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) 116{ 117 struct resource *res, local_res; 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 res = pnp_get_resource(dev, IORESOURCE_IRQ, idx); 126 if (res) { 127 dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n", 128 idx, (int) res->start, res->flags); 129 return 0; 130 } 131 132 res = &local_res; 133 res->flags = rule->flags | IORESOURCE_AUTO; 134 res->start = -1; 135 res->end = -1; 136 137 if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) { 138 res->flags |= IORESOURCE_DISABLED; 139 dev_dbg(&dev->dev, " irq %d disabled\n", idx); 140 goto __add; 141 } 142 143 /* TBD: need check for >16 IRQ */ 144 res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16); 145 if (res->start < PNP_IRQ_NR) { 146 res->end = res->start; 147 goto __add; 148 } 149 for (i = 0; i < 16; i++) { 150 if (test_bit(xtab[i], rule->map.bits)) { 151 res->start = res->end = xtab[i]; 152 if (pnp_check_irq(dev, res)) 153 goto __add; 154 } 155 } 156 dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx); 157 return -EBUSY; 158 159__add: 160 pnp_add_irq_resource(dev, res->start, res->flags); 161 return 0; 162} 163 164static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) 165{ 166 struct resource *res, local_res; 167 int i; 168 169 /* DMA priority: this table is good for i386 */ 170 static unsigned short xtab[8] = { 171 1, 3, 5, 6, 7, 0, 2, 4 172 }; 173 174 res = pnp_get_resource(dev, IORESOURCE_DMA, idx); 175 if (res) { 176 dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n", 177 idx, (int) res->start, res->flags); 178 return 0; 179 } 180 181 res = &local_res; 182 res->flags = rule->flags | IORESOURCE_AUTO; 183 res->start = -1; 184 res->end = -1; 185 186 for (i = 0; i < 8; i++) { 187 if (rule->map & (1 << xtab[i])) { 188 res->start = res->end = xtab[i]; 189 if (pnp_check_dma(dev, res)) 190 goto __add; 191 } 192 } 193#ifdef MAX_DMA_CHANNELS 194 res->start = res->end = MAX_DMA_CHANNELS; 195#endif 196 res->flags |= IORESOURCE_DISABLED; 197 dev_dbg(&dev->dev, " disable dma %d\n", idx); 198 199__add: 200 pnp_add_dma_resource(dev, res->start, res->flags); 201 return 0; 202} 203 204void pnp_init_resources(struct pnp_dev *dev) 205{ 206 pnp_free_resources(dev); 207} 208 209static void pnp_clean_resource_table(struct pnp_dev *dev) 210{ 211 struct pnp_resource *pnp_res, *tmp; 212 213 list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) { 214 if (pnp_res->res.flags & IORESOURCE_AUTO) 215 pnp_free_resource(pnp_res); 216 } 217} 218 219/** 220 * pnp_assign_resources - assigns resources to the device based on the specified dependent number 221 * @dev: pointer to the desired device 222 * @depnum: the dependent function number 223 * 224 * Only set depnum to 0 if the device does not have dependent options. 225 */ 226static int pnp_assign_resources(struct pnp_dev *dev, int depnum) 227{ 228 struct pnp_port *port; 229 struct pnp_mem *mem; 230 struct pnp_irq *irq; 231 struct pnp_dma *dma; 232 int nport = 0, nmem = 0, nirq = 0, ndma = 0; 233 234 if (!pnp_can_configure(dev)) 235 return -ENODEV; 236 237 dbg_pnp_show_resources(dev, "before pnp_assign_resources"); 238 mutex_lock(&pnp_res_mutex); 239 pnp_clean_resource_table(dev); 240 if (dev->independent) { 241 dev_dbg(&dev->dev, "assigning independent options\n"); 242 port = dev->independent->port; 243 mem = dev->independent->mem; 244 irq = dev->independent->irq; 245 dma = dev->independent->dma; 246 while (port) { 247 if (pnp_assign_port(dev, port, nport) < 0) 248 goto fail; 249 nport++; 250 port = port->next; 251 } 252 while (mem) { 253 if (pnp_assign_mem(dev, mem, nmem) < 0) 254 goto fail; 255 nmem++; 256 mem = mem->next; 257 } 258 while (irq) { 259 if (pnp_assign_irq(dev, irq, nirq) < 0) 260 goto fail; 261 nirq++; 262 irq = irq->next; 263 } 264 while (dma) { 265 if (pnp_assign_dma(dev, dma, ndma) < 0) 266 goto fail; 267 ndma++; 268 dma = dma->next; 269 } 270 } 271 272 if (depnum) { 273 struct pnp_option *dep; 274 int i; 275 276 dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum); 277 for (i = 1, dep = dev->dependent; i < depnum; 278 i++, dep = dep->next) 279 if (!dep) 280 goto fail; 281 port = dep->port; 282 mem = dep->mem; 283 irq = dep->irq; 284 dma = dep->dma; 285 while (port) { 286 if (pnp_assign_port(dev, port, nport) < 0) 287 goto fail; 288 nport++; 289 port = port->next; 290 } 291 while (mem) { 292 if (pnp_assign_mem(dev, mem, nmem) < 0) 293 goto fail; 294 nmem++; 295 mem = mem->next; 296 } 297 while (irq) { 298 if (pnp_assign_irq(dev, irq, nirq) < 0) 299 goto fail; 300 nirq++; 301 irq = irq->next; 302 } 303 while (dma) { 304 if (pnp_assign_dma(dev, dma, ndma) < 0) 305 goto fail; 306 ndma++; 307 dma = dma->next; 308 } 309 } else if (dev->dependent) 310 goto fail; 311 312 mutex_unlock(&pnp_res_mutex); 313 dbg_pnp_show_resources(dev, "after pnp_assign_resources"); 314 return 1; 315 316fail: 317 pnp_clean_resource_table(dev); 318 mutex_unlock(&pnp_res_mutex); 319 dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)"); 320 return 0; 321} 322 323/** 324 * pnp_auto_config_dev - automatically assigns resources to a device 325 * @dev: pointer to the desired device 326 */ 327int pnp_auto_config_dev(struct pnp_dev *dev) 328{ 329 struct pnp_option *dep; 330 int i = 1; 331 332 if (!pnp_can_configure(dev)) { 333 dev_dbg(&dev->dev, "configuration not supported\n"); 334 return -ENODEV; 335 } 336 337 if (!dev->dependent) { 338 if (pnp_assign_resources(dev, 0)) 339 return 0; 340 } else { 341 dep = dev->dependent; 342 do { 343 if (pnp_assign_resources(dev, i)) 344 return 0; 345 dep = dep->next; 346 i++; 347 } while (dep); 348 } 349 350 dev_err(&dev->dev, "unable to assign resources\n"); 351 return -EBUSY; 352} 353 354/** 355 * pnp_start_dev - low-level start of the PnP device 356 * @dev: pointer to the desired device 357 * 358 * assumes that resources have already been allocated 359 */ 360int pnp_start_dev(struct pnp_dev *dev) 361{ 362 if (!pnp_can_write(dev)) { 363 dev_dbg(&dev->dev, "activation not supported\n"); 364 return -EINVAL; 365 } 366 367 dbg_pnp_show_resources(dev, "pnp_start_dev"); 368 if (dev->protocol->set(dev) < 0) { 369 dev_err(&dev->dev, "activation failed\n"); 370 return -EIO; 371 } 372 373 dev_info(&dev->dev, "activated\n"); 374 return 0; 375} 376 377/** 378 * pnp_stop_dev - low-level disable of the PnP device 379 * @dev: pointer to the desired device 380 * 381 * does not free resources 382 */ 383int pnp_stop_dev(struct pnp_dev *dev) 384{ 385 if (!pnp_can_disable(dev)) { 386 dev_dbg(&dev->dev, "disabling not supported\n"); 387 return -EINVAL; 388 } 389 if (dev->protocol->disable(dev) < 0) { 390 dev_err(&dev->dev, "disable failed\n"); 391 return -EIO; 392 } 393 394 dev_info(&dev->dev, "disabled\n"); 395 return 0; 396} 397 398/** 399 * pnp_activate_dev - activates a PnP device for use 400 * @dev: pointer to the desired device 401 * 402 * does not validate or set resources so be careful. 403 */ 404int pnp_activate_dev(struct pnp_dev *dev) 405{ 406 int error; 407 408 if (dev->active) 409 return 0; 410 411 /* ensure resources are allocated */ 412 if (pnp_auto_config_dev(dev)) 413 return -EBUSY; 414 415 error = pnp_start_dev(dev); 416 if (error) 417 return error; 418 419 dev->active = 1; 420 return 0; 421} 422 423/** 424 * pnp_disable_dev - disables device 425 * @dev: pointer to the desired device 426 * 427 * inform the correct pnp protocol so that resources can be used by other devices 428 */ 429int pnp_disable_dev(struct pnp_dev *dev) 430{ 431 int error; 432 433 if (!dev->active) 434 return 0; 435 436 error = pnp_stop_dev(dev); 437 if (error) 438 return error; 439 440 dev->active = 0; 441 442 /* release the resources so that other devices can use them */ 443 mutex_lock(&pnp_res_mutex); 444 pnp_clean_resource_table(dev); 445 mutex_unlock(&pnp_res_mutex); 446 447 return 0; 448} 449 450EXPORT_SYMBOL(pnp_start_dev); 451EXPORT_SYMBOL(pnp_stop_dev); 452EXPORT_SYMBOL(pnp_activate_dev); 453EXPORT_SYMBOL(pnp_disable_dev); 454