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