1 /*- 2 * Copyright (c) 1999 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /* 27 * Modifications for Intel architecture by Garrett A. Wollman. 28 * Copyright 1998 Massachusetts Institute of Technology 29 * 30 * Permission to use, copy, modify, and distribute this software and 31 * its documentation for any purpose and without fee is hereby 32 * granted, provided that both the above copyright notice and this 33 * permission notice appear in all copies, that both the above 34 * copyright notice and this permission notice appear in all 35 * supporting documentation, and that the name of M.I.T. not be used 36 * in advertising or publicity pertaining to distribution of the 37 * software without specific, written prior permission. M.I.T. makes 38 * no representations about the suitability of this software for any 39 * purpose. It is provided "as is" without express or implied 40 * warranty. 41 * 42 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 43 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 44 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 45 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 46 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 49 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 50 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 51 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 52 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 */ 55 56 /* 57 * Parts of the ISA bus implementation common to all architectures. 58 */ 59 60 #include <sys/cdefs.h> 61 __FBSDID("$FreeBSD$"); 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/kernel.h> 66 #include <sys/bus.h> 67 #include <sys/malloc.h> 68 #include <sys/module.h> 69 #include <machine/bus.h> 70 #include <sys/rman.h> 71 72 #include <machine/resource.h> 73 74 #include <isa/isavar.h> 75 #include <isa/isa_common.h> 76 #ifdef __alpha__ /* XXX workaround a stupid warning */ 77 #include <alpha/isa/isavar.h> 78 #endif 79 80 static int isa_print_child(device_t bus, device_t dev); 81 82 static MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device"); 83 84 static int isa_running; 85 86 /* 87 * At 'probe' time, we add all the devices which we know about to the 88 * bus. The generic attach routine will probe and attach them if they 89 * are alive. 90 */ 91 static int 92 isa_probe(device_t dev) 93 { 94 device_set_desc(dev, "ISA bus"); 95 isa_init(dev); /* Allow machdep code to initialise */ 96 return (0); 97 } 98 99 extern device_t isa_bus_device; 100 101 static int 102 isa_attach(device_t dev) 103 { 104 /* 105 * Arrange for isa_probe_children(dev) to be called later. XXX 106 */ 107 isa_bus_device = dev; 108 return (0); 109 } 110 111 /* 112 * Find a working set of memory regions for a child using the ranges 113 * in *config and return the regions in *result. Returns non-zero if 114 * a set of ranges was found. 115 */ 116 static int 117 isa_find_memory(device_t child, struct isa_config *config, 118 struct isa_config *result) 119 { 120 int success, i; 121 struct resource *res[ISA_NMEM]; 122 123 /* 124 * First clear out any existing resource definitions. 125 */ 126 for (i = 0; i < ISA_NMEM; i++) { 127 bus_delete_resource(child, SYS_RES_MEMORY, i); 128 res[i] = NULL; 129 } 130 131 success = 1; 132 result->ic_nmem = config->ic_nmem; 133 for (i = 0; i < config->ic_nmem; i++) { 134 uint32_t start, end, size, align; 135 136 size = config->ic_mem[i].ir_size; 137 138 /* the PnP device may have a null resource as filler */ 139 if (size == 0) { 140 result->ic_mem[i].ir_start = 0; 141 result->ic_mem[i].ir_end = 0; 142 result->ic_mem[i].ir_size = 0; 143 result->ic_mem[i].ir_align = 0; 144 continue; 145 } 146 147 for (start = config->ic_mem[i].ir_start, 148 end = config->ic_mem[i].ir_end, 149 align = config->ic_mem[i].ir_align; 150 start + size - 1 <= end && start + size > start; 151 start += align) { 152 bus_set_resource(child, SYS_RES_MEMORY, i, 153 start, size); 154 res[i] = bus_alloc_resource(child, 155 SYS_RES_MEMORY, &i, 0, ~0, 1, 156 rman_make_alignment_flags(align) /* !RF_ACTIVE */); 157 if (res[i]) { 158 result->ic_mem[i].ir_start = start; 159 result->ic_mem[i].ir_end = start + size - 1; 160 result->ic_mem[i].ir_size = size; 161 result->ic_mem[i].ir_align = align; 162 break; 163 } 164 } 165 166 /* 167 * If we didn't find a place for memory range i, then 168 * give up now. 169 */ 170 if (!res[i]) { 171 success = 0; 172 break; 173 } 174 } 175 176 for (i = 0; i < ISA_NMEM; i++) { 177 if (res[i]) 178 bus_release_resource(child, SYS_RES_MEMORY, 179 i, res[i]); 180 } 181 182 return (success); 183 } 184 185 /* 186 * Find a working set of port regions for a child using the ranges 187 * in *config and return the regions in *result. Returns non-zero if 188 * a set of ranges was found. 189 */ 190 static int 191 isa_find_port(device_t child, struct isa_config *config, 192 struct isa_config *result) 193 { 194 int success, i; 195 struct resource *res[ISA_NPORT]; 196 197 /* 198 * First clear out any existing resource definitions. 199 */ 200 for (i = 0; i < ISA_NPORT; i++) { 201 bus_delete_resource(child, SYS_RES_IOPORT, i); 202 res[i] = NULL; 203 } 204 205 success = 1; 206 result->ic_nport = config->ic_nport; 207 for (i = 0; i < config->ic_nport; i++) { 208 uint32_t start, end, size, align; 209 210 size = config->ic_port[i].ir_size; 211 212 /* the PnP device may have a null resource as filler */ 213 if (size == 0) { 214 result->ic_port[i].ir_start = 0; 215 result->ic_port[i].ir_end = 0; 216 result->ic_port[i].ir_size = 0; 217 result->ic_port[i].ir_align = 0; 218 continue; 219 } 220 221 for (start = config->ic_port[i].ir_start, 222 end = config->ic_port[i].ir_end, 223 align = config->ic_port[i].ir_align; 224 start + size - 1 <= end; 225 start += align) { 226 bus_set_resource(child, SYS_RES_IOPORT, i, 227 start, size); 228 res[i] = bus_alloc_resource(child, 229 SYS_RES_IOPORT, &i, 0, ~0, 1, 230 rman_make_alignment_flags(align) /* !RF_ACTIVE */); 231 if (res[i]) { 232 result->ic_port[i].ir_start = start; 233 result->ic_port[i].ir_end = start + size - 1; 234 result->ic_port[i].ir_size = size; 235 result->ic_port[i].ir_align = align; 236 break; 237 } 238 } 239 240 /* 241 * If we didn't find a place for port range i, then 242 * give up now. 243 */ 244 if (!res[i]) { 245 success = 0; 246 break; 247 } 248 } 249 250 for (i = 0; i < ISA_NPORT; i++) { 251 if (res[i]) 252 bus_release_resource(child, SYS_RES_IOPORT, 253 i, res[i]); 254 } 255 256 return success; 257 } 258 259 /* 260 * Return the index of the first bit in the mask (or -1 if mask is empty. 261 */ 262 static int 263 find_first_bit(uint32_t mask) 264 { 265 return (ffs(mask) - 1); 266 } 267 268 /* 269 * Return the index of the next bit in the mask, or -1 if there are no more. 270 */ 271 static int 272 find_next_bit(uint32_t mask, int bit) 273 { 274 bit++; 275 while (bit < 32 && !(mask & (1 << bit))) 276 bit++; 277 if (bit != 32) 278 return (bit); 279 return (-1); 280 } 281 282 /* 283 * Find a working set of irqs for a child using the masks in *config 284 * and return the regions in *result. Returns non-zero if a set of 285 * irqs was found. 286 */ 287 static int 288 isa_find_irq(device_t child, struct isa_config *config, 289 struct isa_config *result) 290 { 291 int success, i; 292 struct resource *res[ISA_NIRQ]; 293 294 /* 295 * First clear out any existing resource definitions. 296 */ 297 for (i = 0; i < ISA_NIRQ; i++) { 298 bus_delete_resource(child, SYS_RES_IRQ, i); 299 res[i] = NULL; 300 } 301 302 success = 1; 303 result->ic_nirq = config->ic_nirq; 304 for (i = 0; i < config->ic_nirq; i++) { 305 uint32_t mask = config->ic_irqmask[i]; 306 int irq; 307 308 /* the PnP device may have a null resource as filler */ 309 if (mask == 0) { 310 result->ic_irqmask[i] = 0; 311 continue; 312 } 313 314 for (irq = find_first_bit(mask); 315 irq != -1; 316 irq = find_next_bit(mask, irq)) { 317 bus_set_resource(child, SYS_RES_IRQ, i, 318 irq, 1); 319 res[i] = bus_alloc_resource_any(child, 320 SYS_RES_IRQ, &i, 321 0 /* !RF_ACTIVE */ ); 322 if (res[i]) { 323 result->ic_irqmask[i] = (1 << irq); 324 break; 325 } 326 } 327 328 /* 329 * If we didn't find a place for irq range i, then 330 * give up now. 331 */ 332 if (!res[i]) { 333 success = 0; 334 break; 335 } 336 } 337 338 for (i = 0; i < ISA_NIRQ; i++) { 339 if (res[i]) 340 bus_release_resource(child, SYS_RES_IRQ, 341 i, res[i]); 342 } 343 344 return (success); 345 } 346 347 /* 348 * Find a working set of drqs for a child using the masks in *config 349 * and return the regions in *result. Returns non-zero if a set of 350 * drqs was found. 351 */ 352 static int 353 isa_find_drq(device_t child, struct isa_config *config, 354 struct isa_config *result) 355 { 356 int success, i; 357 struct resource *res[ISA_NDRQ]; 358 359 /* 360 * First clear out any existing resource definitions. 361 */ 362 for (i = 0; i < ISA_NDRQ; i++) { 363 bus_delete_resource(child, SYS_RES_DRQ, i); 364 res[i] = NULL; 365 } 366 367 success = 1; 368 result->ic_ndrq = config->ic_ndrq; 369 for (i = 0; i < config->ic_ndrq; i++) { 370 uint32_t mask = config->ic_drqmask[i]; 371 int drq; 372 373 /* the PnP device may have a null resource as filler */ 374 if (mask == 0) { 375 result->ic_drqmask[i] = 0; 376 continue; 377 } 378 379 for (drq = find_first_bit(mask); 380 drq != -1; 381 drq = find_next_bit(mask, drq)) { 382 bus_set_resource(child, SYS_RES_DRQ, i, 383 drq, 1); 384 res[i] = bus_alloc_resource_any(child, 385 SYS_RES_DRQ, &i, 386 0 /* !RF_ACTIVE */); 387 if (res[i]) { 388 result->ic_drqmask[i] = (1 << drq); 389 break; 390 } 391 } 392 393 /* 394 * If we didn't find a place for drq range i, then 395 * give up now. 396 */ 397 if (!res[i]) { 398 success = 0; 399 break; 400 } 401 } 402 403 for (i = 0; i < ISA_NDRQ; i++) { 404 if (res[i]) 405 bus_release_resource(child, SYS_RES_DRQ, 406 i, res[i]); 407 } 408 409 return (success); 410 } 411 412 /* 413 * Attempt to find a working set of resources for a device. Return 414 * non-zero if a working configuration is found. 415 */ 416 static int 417 isa_assign_resources(device_t child) 418 { 419 struct isa_device *idev = DEVTOISA(child); 420 struct isa_config_entry *ice; 421 struct isa_config *cfg; 422 const char *reason; 423 424 reason = "Empty ISA id_configs"; 425 cfg = malloc(sizeof(struct isa_config), M_TEMP, M_NOWAIT|M_ZERO); 426 if (cfg == NULL) 427 return(0); 428 TAILQ_FOREACH(ice, &idev->id_configs, ice_link) { 429 reason = "memory"; 430 if (!isa_find_memory(child, &ice->ice_config, cfg)) 431 continue; 432 reason = "port"; 433 if (!isa_find_port(child, &ice->ice_config, cfg)) 434 continue; 435 reason = "irq"; 436 if (!isa_find_irq(child, &ice->ice_config, cfg)) 437 continue; 438 reason = "drq"; 439 if (!isa_find_drq(child, &ice->ice_config, cfg)) 440 continue; 441 442 /* 443 * A working configuration was found enable the device 444 * with this configuration. 445 */ 446 reason = "no callback"; 447 if (idev->id_config_cb) { 448 idev->id_config_cb(idev->id_config_arg, 449 cfg, 1); 450 free(cfg, M_TEMP); 451 return (1); 452 } 453 } 454 455 /* 456 * Disable the device. 457 */ 458 bus_print_child_header(device_get_parent(child), child); 459 printf(" can't assign resources (%s)\n", reason); 460 if (bootverbose) 461 isa_print_child(device_get_parent(child), child); 462 bzero(cfg, sizeof (*cfg)); 463 if (idev->id_config_cb) 464 idev->id_config_cb(idev->id_config_arg, cfg, 0); 465 device_disable(child); 466 467 free(cfg, M_TEMP); 468 return (0); 469 } 470 471 /* 472 * Return non-zero if the device has a single configuration, that is, 473 * a fixed set of resoruces. 474 */ 475 static int 476 isa_has_single_config(device_t dev) 477 { 478 struct isa_device *idev = DEVTOISA(dev); 479 struct isa_config_entry *ice; 480 uint32_t mask; 481 int i; 482 483 ice = TAILQ_FIRST(&idev->id_configs); 484 if (TAILQ_NEXT(ice, ice_link)) 485 return (0); 486 487 for (i = 0; i < ice->ice_config.ic_nmem; ++i) { 488 if (ice->ice_config.ic_mem[i].ir_size == 0) 489 continue; 490 if (ice->ice_config.ic_mem[i].ir_end != 491 ice->ice_config.ic_mem[i].ir_start + 492 ice->ice_config.ic_mem[i].ir_size - 1) 493 return (0); 494 } 495 for (i = 0; i < ice->ice_config.ic_nport; ++i) { 496 if (ice->ice_config.ic_port[i].ir_size == 0) 497 continue; 498 if (ice->ice_config.ic_port[i].ir_end != 499 ice->ice_config.ic_port[i].ir_start + 500 ice->ice_config.ic_port[i].ir_size - 1) 501 return (0); 502 } 503 for (i = 0; i < ice->ice_config.ic_nirq; ++i) { 504 mask = ice->ice_config.ic_irqmask[i]; 505 if (mask == 0) 506 continue; 507 if (find_next_bit(mask, find_first_bit(mask)) != -1) 508 return (0); 509 } 510 for (i = 0; i < ice->ice_config.ic_ndrq; ++i) { 511 mask = ice->ice_config.ic_drqmask[i]; 512 if (mask == 0) 513 continue; 514 if (find_next_bit(mask, find_first_bit(mask)) != -1) 515 return (0); 516 } 517 return (1); 518 } 519 520 /* 521 * Called after other devices have initialised to probe for isa devices. 522 */ 523 void 524 isa_probe_children(device_t dev) 525 { 526 device_t *children; 527 struct isa_config *cfg; 528 int nchildren, i; 529 530 /* 531 * Create all the children by calling driver's identify methods. 532 */ 533 bus_generic_probe(dev); 534 535 if (device_get_children(dev, &children, &nchildren)) 536 return; 537 538 /* 539 * First disable all pnp devices so that they don't get 540 * matched by legacy probes. 541 */ 542 if (bootverbose) 543 printf("isa_probe_children: disabling PnP devices\n"); 544 545 cfg = malloc(sizeof(*cfg), M_TEMP, M_NOWAIT|M_ZERO); 546 if (cfg == NULL) { 547 free(children, M_TEMP); 548 return; 549 } 550 551 for (i = 0; i < nchildren; i++) { 552 device_t child = children[i]; 553 struct isa_device *idev = DEVTOISA(child); 554 555 bzero(cfg, sizeof(*cfg)); 556 if (idev->id_config_cb) 557 idev->id_config_cb(idev->id_config_arg, cfg, 0); 558 } 559 560 free(cfg, M_TEMP); 561 562 /* 563 * Next probe all non-pnp devices so that they claim their 564 * resources first. 565 */ 566 if (bootverbose) 567 printf("isa_probe_children: probing non-PnP devices\n"); 568 for (i = 0; i < nchildren; i++) { 569 device_t child = children[i]; 570 struct isa_device *idev = DEVTOISA(child); 571 572 if (TAILQ_FIRST(&idev->id_configs)) 573 continue; 574 575 device_probe_and_attach(child); 576 } 577 578 /* 579 * Finally assign resource to pnp devices and probe them. 580 */ 581 if (bootverbose) 582 printf("isa_probe_children: probing PnP devices\n"); 583 for (i = 0; i < nchildren; i++) { 584 device_t child = children[i]; 585 struct isa_device* idev = DEVTOISA(child); 586 587 if (!TAILQ_FIRST(&idev->id_configs)) 588 continue; 589 590 if (isa_assign_resources(child)) { 591 struct resource_list *rl = &idev->id_resources; 592 struct resource_list_entry *rle; 593 594 device_probe_and_attach(child); 595 596 /* 597 * Claim any unallocated resources to keep other 598 * devices from using them. 599 */ 600 STAILQ_FOREACH(rle, rl, link) { 601 if (!rle->res) { 602 int rid = rle->rid; 603 resource_list_alloc(rl, dev, child, 604 rle->type, 605 &rid, 606 0, ~0, 1, 0); 607 } 608 } 609 } 610 } 611 612 free(children, M_TEMP); 613 614 isa_running = 1; 615 } 616 617 /* 618 * Add a new child with default ivars. 619 */ 620 static device_t 621 isa_add_child(device_t dev, int order, const char *name, int unit) 622 { 623 device_t child; 624 struct isa_device *idev; 625 626 child = device_add_child_ordered(dev, order, name, unit); 627 if (child == NULL) 628 return (child); 629 630 idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT | M_ZERO); 631 if (!idev) 632 return (0); 633 634 resource_list_init(&idev->id_resources); 635 TAILQ_INIT(&idev->id_configs); 636 637 device_set_ivars(child, idev); 638 639 return (child); 640 } 641 642 static int 643 isa_print_all_resources(device_t dev) 644 { 645 struct isa_device *idev = DEVTOISA(dev); 646 struct resource_list *rl = &idev->id_resources; 647 int retval = 0; 648 649 if (STAILQ_FIRST(rl) || device_get_flags(dev)) 650 retval += printf(" at"); 651 652 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 653 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 654 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 655 retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld"); 656 if (device_get_flags(dev)) 657 retval += printf(" flags %#x", device_get_flags(dev)); 658 if (idev->id_vendorid) 659 retval += printf(" pnpid %s", pnp_eisaformat(idev->id_vendorid)); 660 661 return (retval); 662 } 663 664 static int 665 isa_print_child(device_t bus, device_t dev) 666 { 667 int retval = 0; 668 669 retval += bus_print_child_header(bus, dev); 670 retval += isa_print_all_resources(dev); 671 retval += bus_print_child_footer(bus, dev); 672 673 return (retval); 674 } 675 676 static void 677 isa_probe_nomatch(device_t dev, device_t child) 678 { 679 if (bootverbose) { 680 bus_print_child_header(dev, child); 681 printf(" failed to probe"); 682 isa_print_all_resources(child); 683 bus_print_child_footer(dev, child); 684 } 685 686 return; 687 } 688 689 static int 690 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 691 { 692 struct isa_device* idev = DEVTOISA(dev); 693 struct resource_list *rl = &idev->id_resources; 694 struct resource_list_entry *rle; 695 696 switch (index) { 697 case ISA_IVAR_PORT_0: 698 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 699 if (rle) 700 *result = rle->start; 701 else 702 *result = -1; 703 break; 704 705 case ISA_IVAR_PORT_1: 706 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 707 if (rle) 708 *result = rle->start; 709 else 710 *result = -1; 711 break; 712 713 case ISA_IVAR_PORTSIZE_0: 714 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 715 if (rle) 716 *result = rle->count; 717 else 718 *result = 0; 719 break; 720 721 case ISA_IVAR_PORTSIZE_1: 722 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 723 if (rle) 724 *result = rle->count; 725 else 726 *result = 0; 727 break; 728 729 case ISA_IVAR_MADDR_0: 730 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 731 if (rle) 732 *result = rle->start; 733 else 734 *result = -1; 735 break; 736 737 case ISA_IVAR_MADDR_1: 738 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 739 if (rle) 740 *result = rle->start; 741 else 742 *result = -1; 743 break; 744 745 case ISA_IVAR_MEMSIZE_0: 746 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 747 if (rle) 748 *result = rle->count; 749 else 750 *result = 0; 751 break; 752 753 case ISA_IVAR_MEMSIZE_1: 754 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 755 if (rle) 756 *result = rle->count; 757 else 758 *result = 0; 759 break; 760 761 case ISA_IVAR_IRQ_0: 762 rle = resource_list_find(rl, SYS_RES_IRQ, 0); 763 if (rle) 764 *result = rle->start; 765 else 766 *result = -1; 767 break; 768 769 case ISA_IVAR_IRQ_1: 770 rle = resource_list_find(rl, SYS_RES_IRQ, 1); 771 if (rle) 772 *result = rle->start; 773 else 774 *result = -1; 775 break; 776 777 case ISA_IVAR_DRQ_0: 778 rle = resource_list_find(rl, SYS_RES_DRQ, 0); 779 if (rle) 780 *result = rle->start; 781 else 782 *result = -1; 783 break; 784 785 case ISA_IVAR_DRQ_1: 786 rle = resource_list_find(rl, SYS_RES_DRQ, 1); 787 if (rle) 788 *result = rle->start; 789 else 790 *result = -1; 791 break; 792 793 case ISA_IVAR_VENDORID: 794 *result = idev->id_vendorid; 795 break; 796 797 case ISA_IVAR_SERIAL: 798 *result = idev->id_serial; 799 break; 800 801 case ISA_IVAR_LOGICALID: 802 *result = idev->id_logicalid; 803 break; 804 805 case ISA_IVAR_COMPATID: 806 *result = idev->id_compatid; 807 break; 808 809 case ISA_IVAR_CONFIGATTR: 810 *result = idev->id_config_attr; 811 break; 812 813 default: 814 return (ENOENT); 815 } 816 817 return (0); 818 } 819 820 static int 821 isa_write_ivar(device_t bus, device_t dev, int index, uintptr_t value) 822 { 823 struct isa_device* idev = DEVTOISA(dev); 824 825 switch (index) { 826 case ISA_IVAR_PORT_0: 827 case ISA_IVAR_PORT_1: 828 case ISA_IVAR_PORTSIZE_0: 829 case ISA_IVAR_PORTSIZE_1: 830 case ISA_IVAR_MADDR_0: 831 case ISA_IVAR_MADDR_1: 832 case ISA_IVAR_MEMSIZE_0: 833 case ISA_IVAR_MEMSIZE_1: 834 case ISA_IVAR_IRQ_0: 835 case ISA_IVAR_IRQ_1: 836 case ISA_IVAR_DRQ_0: 837 case ISA_IVAR_DRQ_1: 838 return (EINVAL); 839 840 case ISA_IVAR_VENDORID: 841 idev->id_vendorid = value; 842 break; 843 844 case ISA_IVAR_SERIAL: 845 idev->id_serial = value; 846 break; 847 848 case ISA_IVAR_LOGICALID: 849 idev->id_logicalid = value; 850 break; 851 852 case ISA_IVAR_COMPATID: 853 idev->id_compatid = value; 854 break; 855 856 case ISA_IVAR_CONFIGATTR: 857 idev->id_config_attr = value; 858 break; 859 860 default: 861 return (ENOENT); 862 } 863 864 return (0); 865 } 866 867 /* 868 * Free any resources which the driver missed or which we were holding for 869 * it (see isa_probe_children). 870 */ 871 static void 872 isa_child_detached(device_t dev, device_t child) 873 { 874 struct isa_device* idev = DEVTOISA(child); 875 struct resource_list *rl = &idev->id_resources; 876 struct resource_list_entry *rle; 877 878 if (TAILQ_FIRST(&idev->id_configs)) { 879 /* 880 * Claim any unallocated resources to keep other 881 * devices from using them. 882 */ 883 STAILQ_FOREACH(rle, rl, link) { 884 if (!rle->res) { 885 int rid = rle->rid; 886 resource_list_alloc(rl, dev, child, 887 rle->type, 888 &rid, 0, ~0, 1, 0); 889 } 890 } 891 } 892 } 893 894 static void 895 isa_driver_added(device_t dev, driver_t *driver) 896 { 897 device_t *children; 898 int nchildren, i; 899 900 /* 901 * Don't do anything if drivers are dynamically 902 * added during autoconfiguration (cf. ymf724). 903 * since that would end up calling identify 904 * twice. 905 */ 906 if (!isa_running) 907 return; 908 909 DEVICE_IDENTIFY(driver, dev); 910 if (device_get_children(dev, &children, &nchildren)) 911 return; 912 913 for (i = 0; i < nchildren; i++) { 914 device_t child = children[i]; 915 struct isa_device *idev = DEVTOISA(child); 916 struct resource_list *rl = &idev->id_resources; 917 struct resource_list_entry *rle; 918 919 if (device_get_state(child) != DS_NOTPRESENT) 920 continue; 921 if (!device_is_enabled(child)) 922 continue; 923 924 /* 925 * Free resources which we were holding on behalf of 926 * the device. 927 */ 928 STAILQ_FOREACH(rle, &idev->id_resources, link) { 929 if (rle->res) 930 resource_list_release(rl, dev, child, 931 rle->type, 932 rle->rid, 933 rle->res); 934 } 935 936 if (TAILQ_FIRST(&idev->id_configs)) 937 if (!isa_assign_resources(child)) 938 continue; 939 940 device_probe_and_attach(child); 941 942 if (TAILQ_FIRST(&idev->id_configs)) { 943 /* 944 * Claim any unallocated resources to keep other 945 * devices from using them. 946 */ 947 STAILQ_FOREACH(rle, rl, link) { 948 if (!rle->res) { 949 int rid = rle->rid; 950 resource_list_alloc(rl, dev, child, 951 rle->type, 952 &rid, 0, ~0, 1, 0); 953 } 954 } 955 } 956 } 957 958 free(children, M_TEMP); 959 } 960 961 static int 962 isa_set_resource(device_t dev, device_t child, int type, int rid, 963 u_long start, u_long count) 964 { 965 struct isa_device* idev = DEVTOISA(child); 966 struct resource_list *rl = &idev->id_resources; 967 968 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 969 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 970 return (EINVAL); 971 if (rid < 0) 972 return (EINVAL); 973 if (type == SYS_RES_IOPORT && rid >= ISA_NPORT) 974 return (EINVAL); 975 if (type == SYS_RES_MEMORY && rid >= ISA_NMEM) 976 return (EINVAL); 977 if (type == SYS_RES_IRQ && rid >= ISA_NIRQ) 978 return (EINVAL); 979 if (type == SYS_RES_DRQ && rid >= ISA_NDRQ) 980 return (EINVAL); 981 982 resource_list_add(rl, type, rid, start, start + count - 1, count); 983 984 return (0); 985 } 986 987 static struct resource_list * 988 isa_get_resource_list (device_t dev, device_t child) 989 { 990 struct isa_device* idev = DEVTOISA(child); 991 struct resource_list *rl = &idev->id_resources; 992 993 if (!rl) 994 return (NULL); 995 996 return (rl); 997 } 998 999 static int 1000 isa_add_config(device_t dev, device_t child, int priority, 1001 struct isa_config *config) 1002 { 1003 struct isa_device* idev = DEVTOISA(child); 1004 struct isa_config_entry *newice, *ice; 1005 1006 newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT); 1007 if (!newice) 1008 return (ENOMEM); 1009 1010 newice->ice_priority = priority; 1011 newice->ice_config = *config; 1012 1013 TAILQ_FOREACH(ice, &idev->id_configs, ice_link) { 1014 if (ice->ice_priority > priority) 1015 break; 1016 } 1017 if (ice) 1018 TAILQ_INSERT_BEFORE(ice, newice, ice_link); 1019 else 1020 TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link); 1021 1022 if (isa_has_single_config(child)) 1023 idev->id_config_attr &= ~ISACFGATTR_MULTI; 1024 else 1025 idev->id_config_attr |= ISACFGATTR_MULTI; 1026 1027 return (0); 1028 } 1029 1030 static void 1031 isa_set_config_callback(device_t dev, device_t child, isa_config_cb *fn, 1032 void *arg) 1033 { 1034 struct isa_device* idev = DEVTOISA(child); 1035 1036 idev->id_config_cb = fn; 1037 idev->id_config_arg = arg; 1038 } 1039 1040 static int 1041 isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids) 1042 { 1043 struct isa_device* idev = DEVTOISA(child); 1044 1045 if (!idev->id_vendorid) 1046 return (ENOENT); 1047 1048 while (ids && ids->ip_id) { 1049 /* 1050 * Really ought to support >1 compat id per device. 1051 */ 1052 if (idev->id_logicalid == ids->ip_id 1053 || idev->id_compatid == ids->ip_id) { 1054 if (ids->ip_desc) 1055 device_set_desc(child, ids->ip_desc); 1056 return (0); 1057 } 1058 ids++; 1059 } 1060 1061 return (ENXIO); 1062 } 1063 1064 static int 1065 isa_child_pnpinfo_str(device_t bus, device_t child, char *buf, 1066 size_t buflen) 1067 { 1068 struct isa_device *idev = DEVTOISA(child); 1069 1070 if (idev->id_vendorid) 1071 snprintf(buf, buflen, "pnpid=%s", 1072 pnp_eisaformat(idev->id_vendorid)); 1073 return (0); 1074 } 1075 1076 static int 1077 isa_child_location_str(device_t bus, device_t child, char *buf, 1078 size_t buflen) 1079 { 1080 /* Nothing here yet */ 1081 *buf = '\0'; 1082 return (0); 1083 } 1084 1085 static device_method_t isa_methods[] = { 1086 /* Device interface */ 1087 DEVMETHOD(device_probe, isa_probe), 1088 DEVMETHOD(device_attach, isa_attach), 1089 DEVMETHOD(device_detach, bus_generic_detach), 1090 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1091 DEVMETHOD(device_suspend, bus_generic_suspend), 1092 DEVMETHOD(device_resume, bus_generic_resume), 1093 1094 /* Bus interface */ 1095 DEVMETHOD(bus_add_child, isa_add_child), 1096 DEVMETHOD(bus_print_child, isa_print_child), 1097 DEVMETHOD(bus_probe_nomatch, isa_probe_nomatch), 1098 DEVMETHOD(bus_read_ivar, isa_read_ivar), 1099 DEVMETHOD(bus_write_ivar, isa_write_ivar), 1100 DEVMETHOD(bus_child_detached, isa_child_detached), 1101 DEVMETHOD(bus_driver_added, isa_driver_added), 1102 DEVMETHOD(bus_setup_intr, isa_setup_intr), 1103 DEVMETHOD(bus_teardown_intr, isa_teardown_intr), 1104 1105 DEVMETHOD(bus_get_resource_list,isa_get_resource_list), 1106 DEVMETHOD(bus_alloc_resource, isa_alloc_resource), 1107 DEVMETHOD(bus_release_resource, isa_release_resource), 1108 DEVMETHOD(bus_set_resource, isa_set_resource), 1109 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 1110 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 1111 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1112 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1113 DEVMETHOD(bus_child_pnpinfo_str, isa_child_pnpinfo_str), 1114 DEVMETHOD(bus_child_location_str, isa_child_location_str), 1115 1116 /* ISA interface */ 1117 DEVMETHOD(isa_add_config, isa_add_config), 1118 DEVMETHOD(isa_set_config_callback, isa_set_config_callback), 1119 DEVMETHOD(isa_pnp_probe, isa_pnp_probe), 1120 1121 { 0, 0 } 1122 }; 1123 1124 driver_t isa_driver = { 1125 "isa", 1126 isa_methods, 1127 1, /* no softc */ 1128 }; 1129 1130 devclass_t isa_devclass; 1131 1132 /* 1133 * ISA can be attached to a PCI-ISA bridge, or other locations on some 1134 * platforms. 1135 */ 1136 DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0); 1137 DRIVER_MODULE(isa, eisab, isa_driver, isa_devclass, 0, 0); 1138 MODULE_VERSION(isa, 1); 1139 1140 /* 1141 * Code common to ISA bridges. 1142 */ 1143 1144 devclass_t isab_devclass; 1145 1146 int 1147 isab_attach(device_t dev) 1148 { 1149 device_t child; 1150 1151 child = device_add_child(dev, "isa", 0); 1152 if (child != NULL) 1153 return (bus_generic_attach(dev)); 1154 return (ENXIO); 1155 } 1156