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