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 * $FreeBSD$ 27 */ 28 /* 29 * Modifications for Intel architecture by Garrett A. Wollman. 30 * Copyright 1998 Massachusetts Institute of Technology 31 * 32 * Permission to use, copy, modify, and distribute this software and 33 * its documentation for any purpose and without fee is hereby 34 * granted, provided that both the above copyright notice and this 35 * permission notice appear in all copies, that both the above 36 * copyright notice and this permission notice appear in all 37 * supporting documentation, and that the name of M.I.T. not be used 38 * in advertising or publicity pertaining to distribution of the 39 * software without specific, written prior permission. M.I.T. makes 40 * no representations about the suitability of this software for any 41 * purpose. It is provided "as is" without express or implied 42 * warranty. 43 * 44 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 45 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 46 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 47 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 48 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 49 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 50 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 51 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 52 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 53 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 54 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58 /* 59 * Parts of the ISA bus implementation common to all architectures. 60 */ 61 62 #include <sys/param.h> 63 #include <sys/systm.h> 64 #include <sys/kernel.h> 65 #include <sys/bus.h> 66 #include <sys/malloc.h> 67 #include <sys/module.h> 68 #include <machine/bus.h> 69 #include <sys/rman.h> 70 71 #include <machine/resource.h> 72 73 #include <isa/isavar.h> 74 #include <isa/isa_common.h> 75 #ifdef __alpha__ /* XXX workaround a stupid warning */ 76 #include <alpha/isa/isavar.h> 77 #endif 78 79 static int isa_print_child(device_t bus, device_t dev); 80 81 static MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device"); 82 83 static devclass_t isa_devclass; 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, 118 struct isa_config *config, 119 struct isa_config *result) 120 { 121 int success, i; 122 struct resource *res[ISA_NMEM]; 123 124 /* 125 * First clear out any existing resource definitions. 126 */ 127 for (i = 0; i < ISA_NMEM; i++) { 128 bus_delete_resource(child, SYS_RES_MEMORY, i); 129 res[i] = NULL; 130 } 131 132 success = 1; 133 result->ic_nmem = config->ic_nmem; 134 for (i = 0; i < config->ic_nmem; i++) { 135 u_int32_t start, end, size, align; 136 137 size = config->ic_mem[i].ir_size; 138 139 /* the PnP device may have a null resource as filler */ 140 if (size == 0) { 141 result->ic_mem[i].ir_start = 0; 142 result->ic_mem[i].ir_end = 0; 143 result->ic_mem[i].ir_size = 0; 144 result->ic_mem[i].ir_align = 0; 145 continue; 146 } 147 148 for (start = config->ic_mem[i].ir_start, 149 end = config->ic_mem[i].ir_end, 150 align = config->ic_mem[i].ir_align; 151 start + size - 1 <= end; 152 start += align) { 153 bus_set_resource(child, SYS_RES_MEMORY, i, 154 start, size); 155 res[i] = bus_alloc_resource(child, 156 SYS_RES_MEMORY, &i, 157 0, ~0, 1, 0 /* !RF_ACTIVE */); 158 if (res[i]) { 159 result->ic_mem[i].ir_start = start; 160 result->ic_mem[i].ir_end = start + size - 1; 161 result->ic_mem[i].ir_size = size; 162 result->ic_mem[i].ir_align = align; 163 break; 164 } 165 } 166 167 /* 168 * If we didn't find a place for memory range i, then 169 * give up now. 170 */ 171 if (!res[i]) { 172 success = 0; 173 break; 174 } 175 } 176 177 for (i = 0; i < ISA_NMEM; i++) { 178 if (res[i]) 179 bus_release_resource(child, SYS_RES_MEMORY, 180 i, res[i]); 181 } 182 183 return success; 184 } 185 186 /* 187 * Find a working set of port regions for a child using the ranges 188 * in *config and return the regions in *result. Returns non-zero if 189 * a set of ranges was found. 190 */ 191 static int 192 isa_find_port(device_t child, 193 struct isa_config *config, 194 struct isa_config *result) 195 { 196 int success, i; 197 struct resource *res[ISA_NPORT]; 198 199 /* 200 * First clear out any existing resource definitions. 201 */ 202 for (i = 0; i < ISA_NPORT; i++) { 203 bus_delete_resource(child, SYS_RES_IOPORT, i); 204 res[i] = NULL; 205 } 206 207 success = 1; 208 result->ic_nport = config->ic_nport; 209 for (i = 0; i < config->ic_nport; i++) { 210 u_int32_t start, end, size, align; 211 212 size = config->ic_port[i].ir_size; 213 214 /* the PnP device may have a null resource as filler */ 215 if (size == 0) { 216 result->ic_port[i].ir_start = 0; 217 result->ic_port[i].ir_end = 0; 218 result->ic_port[i].ir_size = 0; 219 result->ic_port[i].ir_align = 0; 220 continue; 221 } 222 223 for (start = config->ic_port[i].ir_start, 224 end = config->ic_port[i].ir_end, 225 align = config->ic_port[i].ir_align; 226 start + size - 1 <= end; 227 start += align) { 228 bus_set_resource(child, SYS_RES_IOPORT, i, 229 start, size); 230 res[i] = bus_alloc_resource(child, 231 SYS_RES_IOPORT, &i, 232 0, ~0, 1, 0 /* !RF_ACTIVE */); 233 if (res[i]) { 234 result->ic_port[i].ir_start = start; 235 result->ic_port[i].ir_end = start + size - 1; 236 result->ic_port[i].ir_size = size; 237 result->ic_port[i].ir_align = align; 238 break; 239 } 240 } 241 242 /* 243 * If we didn't find a place for port range i, then 244 * give up now. 245 */ 246 if (!res[i]) { 247 success = 0; 248 break; 249 } 250 } 251 252 for (i = 0; i < ISA_NPORT; i++) { 253 if (res[i]) 254 bus_release_resource(child, SYS_RES_IOPORT, 255 i, res[i]); 256 } 257 258 return success; 259 } 260 261 /* 262 * Return the index of the first bit in the mask (or -1 if mask is empty. 263 */ 264 static int 265 find_first_bit(u_int32_t mask) 266 { 267 return ffs(mask) - 1; 268 } 269 270 /* 271 * Return the index of the next bit in the mask, or -1 if there are no more. 272 */ 273 static int 274 find_next_bit(u_int32_t mask, int bit) 275 { 276 bit++; 277 while (bit < 32 && !(mask & (1 << bit))) 278 bit++; 279 if (bit != 32) 280 return bit; 281 return -1; 282 } 283 284 /* 285 * Find a working set of irqs for a child using the masks in *config 286 * and return the regions in *result. Returns non-zero if a set of 287 * irqs was found. 288 */ 289 static int 290 isa_find_irq(device_t child, 291 struct isa_config *config, 292 struct isa_config *result) 293 { 294 int success, i; 295 struct resource *res[ISA_NIRQ]; 296 297 /* 298 * First clear out any existing resource definitions. 299 */ 300 for (i = 0; i < ISA_NIRQ; i++) { 301 bus_delete_resource(child, SYS_RES_IRQ, i); 302 res[i] = NULL; 303 } 304 305 success = 1; 306 result->ic_nirq = config->ic_nirq; 307 for (i = 0; i < config->ic_nirq; i++) { 308 u_int32_t mask = config->ic_irqmask[i]; 309 int irq; 310 311 /* the PnP device may have a null resource as filler */ 312 if (mask == 0) { 313 result->ic_irqmask[i] = 0; 314 continue; 315 } 316 317 for (irq = find_first_bit(mask); 318 irq != -1; 319 irq = find_next_bit(mask, irq)) { 320 bus_set_resource(child, SYS_RES_IRQ, i, 321 irq, 1); 322 res[i] = bus_alloc_resource(child, 323 SYS_RES_IRQ, &i, 324 0, ~0, 1, 0 /* !RF_ACTIVE */ ); 325 if (res[i]) { 326 result->ic_irqmask[i] = (1 << irq); 327 break; 328 } 329 } 330 331 /* 332 * If we didn't find a place for irq range i, then 333 * give up now. 334 */ 335 if (!res[i]) { 336 success = 0; 337 break; 338 } 339 } 340 341 for (i = 0; i < ISA_NIRQ; i++) { 342 if (res[i]) 343 bus_release_resource(child, SYS_RES_IRQ, 344 i, res[i]); 345 } 346 347 return success; 348 } 349 350 /* 351 * Find a working set of drqs for a child using the masks in *config 352 * and return the regions in *result. Returns non-zero if a set of 353 * drqs was found. 354 */ 355 static int 356 isa_find_drq(device_t child, 357 struct isa_config *config, 358 struct isa_config *result) 359 { 360 int success, i; 361 struct resource *res[ISA_NDRQ]; 362 363 /* 364 * First clear out any existing resource definitions. 365 */ 366 for (i = 0; i < ISA_NDRQ; i++) { 367 bus_delete_resource(child, SYS_RES_DRQ, i); 368 res[i] = NULL; 369 } 370 371 success = 1; 372 result->ic_ndrq = config->ic_ndrq; 373 for (i = 0; i < config->ic_ndrq; i++) { 374 u_int32_t mask = config->ic_drqmask[i]; 375 int drq; 376 377 /* the PnP device may have a null resource as filler */ 378 if (mask == 0) { 379 result->ic_drqmask[i] = 0; 380 continue; 381 } 382 383 for (drq = find_first_bit(mask); 384 drq != -1; 385 drq = find_next_bit(mask, drq)) { 386 bus_set_resource(child, SYS_RES_DRQ, i, 387 drq, 1); 388 res[i] = bus_alloc_resource(child, 389 SYS_RES_DRQ, &i, 390 0, ~0, 1, 0 /* !RF_ACTIVE */); 391 if (res[i]) { 392 result->ic_drqmask[i] = (1 << drq); 393 break; 394 } 395 } 396 397 /* 398 * If we didn't find a place for drq range i, then 399 * give up now. 400 */ 401 if (!res[i]) { 402 success = 0; 403 break; 404 } 405 } 406 407 for (i = 0; i < ISA_NDRQ; i++) { 408 if (res[i]) 409 bus_release_resource(child, SYS_RES_DRQ, 410 i, res[i]); 411 } 412 413 return success; 414 } 415 416 /* 417 * Attempt to find a working set of resources for a device. Return 418 * non-zero if a working configuration is found. 419 */ 420 static int 421 isa_assign_resources(device_t child) 422 { 423 struct isa_device *idev = DEVTOISA(child); 424 struct isa_config_entry *ice; 425 struct isa_config *cfg; 426 const char *reason; 427 428 reason = "Empty ISA id_configs"; 429 cfg = malloc(sizeof(struct isa_config), M_TEMP, M_NOWAIT|M_ZERO); 430 if (cfg == NULL) 431 return(0); 432 TAILQ_FOREACH(ice, &idev->id_configs, ice_link) { 433 reason = "memory"; 434 if (!isa_find_memory(child, &ice->ice_config, cfg)) 435 continue; 436 reason = "port"; 437 if (!isa_find_port(child, &ice->ice_config, cfg)) 438 continue; 439 reason = "irq"; 440 if (!isa_find_irq(child, &ice->ice_config, cfg)) 441 continue; 442 reason = "drq"; 443 if (!isa_find_drq(child, &ice->ice_config, cfg)) 444 continue; 445 446 /* 447 * A working configuration was found enable the device 448 * with this configuration. 449 */ 450 reason = "no callback"; 451 if (idev->id_config_cb) { 452 idev->id_config_cb(idev->id_config_arg, 453 cfg, 1); 454 free(cfg, M_TEMP); 455 return 1; 456 } 457 } 458 459 /* 460 * Disable the device. 461 */ 462 bus_print_child_header(device_get_parent(child), child); 463 printf(" can't assign resources (%s)\n", reason); 464 if (bootverbose) 465 isa_print_child(device_get_parent(child), child); 466 bzero(cfg, sizeof (*cfg)); 467 if (idev->id_config_cb) 468 idev->id_config_cb(idev->id_config_arg, cfg, 0); 469 device_disable(child); 470 471 free(cfg, M_TEMP); 472 return 0; 473 } 474 475 /* 476 * Return non-zero if the device has a single configuration, that is, 477 * a fixed set of resoruces. 478 */ 479 static int 480 isa_has_single_config(device_t dev) 481 { 482 struct isa_device *idev = DEVTOISA(dev); 483 struct isa_config_entry *ice; 484 u_int32_t mask; 485 int i; 486 487 ice = TAILQ_FIRST(&idev->id_configs); 488 if (TAILQ_NEXT(ice, ice_link)) 489 return 0; 490 491 for (i = 0; i < ice->ice_config.ic_nmem; ++i) { 492 if (ice->ice_config.ic_mem[i].ir_size == 0) 493 continue; 494 if (ice->ice_config.ic_mem[i].ir_end != 495 ice->ice_config.ic_mem[i].ir_start + 496 ice->ice_config.ic_mem[i].ir_size - 1) 497 return 0; 498 } 499 for (i = 0; i < ice->ice_config.ic_nport; ++i) { 500 if (ice->ice_config.ic_port[i].ir_size == 0) 501 continue; 502 if (ice->ice_config.ic_port[i].ir_end != 503 ice->ice_config.ic_port[i].ir_start + 504 ice->ice_config.ic_port[i].ir_size - 1) 505 return 0; 506 } 507 for (i = 0; i < ice->ice_config.ic_nirq; ++i) { 508 mask = ice->ice_config.ic_irqmask[i]; 509 if (mask == 0) 510 continue; 511 if (find_next_bit(mask, find_first_bit(mask)) != -1) 512 return 0; 513 } 514 for (i = 0; i < ice->ice_config.ic_ndrq; ++i) { 515 mask = ice->ice_config.ic_drqmask[i]; 516 if (mask == 0) 517 continue; 518 if (find_next_bit(mask, find_first_bit(mask)) != -1) 519 return 0; 520 } 521 return 1; 522 } 523 524 /* 525 * Called after other devices have initialised to probe for isa devices. 526 */ 527 void 528 isa_probe_children(device_t dev) 529 { 530 device_t *children; 531 struct isa_config *cfg; 532 int nchildren, i; 533 534 /* 535 * Create all the children by calling driver's identify methods. 536 */ 537 bus_generic_probe(dev); 538 539 if (device_get_children(dev, &children, &nchildren)) 540 return; 541 542 /* 543 * First disable all pnp devices so that they don't get 544 * matched by legacy probes. 545 */ 546 if (bootverbose) 547 printf("isa_probe_children: disabling PnP devices\n"); 548 549 cfg = malloc(sizeof(*cfg), M_TEMP, M_NOWAIT|M_ZERO); 550 if (cfg == NULL) { 551 free(children, M_TEMP); 552 return; 553 } 554 555 for (i = 0; i < nchildren; i++) { 556 device_t child = children[i]; 557 struct isa_device *idev = DEVTOISA(child); 558 559 bzero(cfg, sizeof(*cfg)); 560 if (idev->id_config_cb) 561 idev->id_config_cb(idev->id_config_arg, cfg, 0); 562 } 563 564 free(cfg, M_TEMP); 565 566 /* 567 * Next probe all non-pnp devices so that they claim their 568 * resources first. 569 */ 570 if (bootverbose) 571 printf("isa_probe_children: probing non-PnP devices\n"); 572 for (i = 0; i < nchildren; i++) { 573 device_t child = children[i]; 574 struct isa_device *idev = DEVTOISA(child); 575 576 if (TAILQ_FIRST(&idev->id_configs)) 577 continue; 578 579 device_probe_and_attach(child); 580 } 581 582 /* 583 * Finally assign resource to pnp devices and probe them. 584 */ 585 if (bootverbose) 586 printf("isa_probe_children: probing PnP devices\n"); 587 for (i = 0; i < nchildren; i++) { 588 device_t child = children[i]; 589 struct isa_device* idev = DEVTOISA(child); 590 591 if (!TAILQ_FIRST(&idev->id_configs)) 592 continue; 593 594 if (isa_assign_resources(child)) { 595 struct resource_list *rl = &idev->id_resources; 596 struct resource_list_entry *rle; 597 598 device_probe_and_attach(child); 599 600 /* 601 * Claim any unallocated resources to keep other 602 * devices from using them. 603 */ 604 SLIST_FOREACH(rle, rl, link) { 605 if (!rle->res) { 606 int rid = rle->rid; 607 resource_list_alloc(rl, dev, child, 608 rle->type, 609 &rid, 610 0, ~0, 1, 0); 611 } 612 } 613 } 614 } 615 616 free(children, M_TEMP); 617 618 isa_running = 1; 619 } 620 621 /* 622 * Add a new child with default ivars. 623 */ 624 static device_t 625 isa_add_child(device_t dev, int order, const char *name, int unit) 626 { 627 device_t child; 628 struct isa_device *idev; 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 child = device_add_child_ordered(dev, order, name, unit); 638 device_set_ivars(child, idev); 639 640 return child; 641 } 642 643 static int 644 isa_print_all_resources(device_t dev) 645 { 646 struct isa_device *idev = DEVTOISA(dev); 647 struct resource_list *rl = &idev->id_resources; 648 int retval = 0; 649 650 if (SLIST_FIRST(rl) || device_get_flags(dev)) 651 retval += printf(" at"); 652 653 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 654 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 655 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 656 retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld"); 657 if (device_get_flags(dev)) 658 retval += printf(" flags %#x", device_get_flags(dev)); 659 660 return retval; 661 } 662 663 static int 664 isa_print_child(device_t bus, device_t dev) 665 { 666 int retval = 0; 667 668 retval += bus_print_child_header(bus, dev); 669 retval += isa_print_all_resources(dev); 670 retval += bus_print_child_footer(bus, dev); 671 672 return (retval); 673 } 674 675 static void 676 isa_probe_nomatch(device_t dev, device_t child) 677 { 678 if (bootverbose) { 679 bus_print_child_header(dev, child); 680 printf(" failed to probe"); 681 isa_print_all_resources(child); 682 bus_print_child_footer(dev, child); 683 } 684 685 return; 686 } 687 688 static int 689 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 690 { 691 struct isa_device* idev = DEVTOISA(dev); 692 struct resource_list *rl = &idev->id_resources; 693 struct resource_list_entry *rle; 694 695 switch (index) { 696 case ISA_IVAR_PORT_0: 697 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 698 if (rle) 699 *result = rle->start; 700 else 701 *result = -1; 702 break; 703 704 case ISA_IVAR_PORT_1: 705 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 706 if (rle) 707 *result = rle->start; 708 else 709 *result = -1; 710 break; 711 712 case ISA_IVAR_PORTSIZE_0: 713 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 714 if (rle) 715 *result = rle->count; 716 else 717 *result = 0; 718 break; 719 720 case ISA_IVAR_PORTSIZE_1: 721 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 722 if (rle) 723 *result = rle->count; 724 else 725 *result = 0; 726 break; 727 728 case ISA_IVAR_MADDR_0: 729 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 730 if (rle) 731 *result = rle->start; 732 else 733 *result = -1; 734 break; 735 736 case ISA_IVAR_MADDR_1: 737 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 738 if (rle) 739 *result = rle->start; 740 else 741 *result = -1; 742 break; 743 744 case ISA_IVAR_MSIZE_0: 745 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 746 if (rle) 747 *result = rle->count; 748 else 749 *result = 0; 750 break; 751 752 case ISA_IVAR_MSIZE_1: 753 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 754 if (rle) 755 *result = rle->count; 756 else 757 *result = 0; 758 break; 759 760 case ISA_IVAR_IRQ_0: 761 rle = resource_list_find(rl, SYS_RES_IRQ, 0); 762 if (rle) 763 *result = rle->start; 764 else 765 *result = -1; 766 break; 767 768 case ISA_IVAR_IRQ_1: 769 rle = resource_list_find(rl, SYS_RES_IRQ, 1); 770 if (rle) 771 *result = rle->start; 772 else 773 *result = -1; 774 break; 775 776 case ISA_IVAR_DRQ_0: 777 rle = resource_list_find(rl, SYS_RES_DRQ, 0); 778 if (rle) 779 *result = rle->start; 780 else 781 *result = -1; 782 break; 783 784 case ISA_IVAR_DRQ_1: 785 rle = resource_list_find(rl, SYS_RES_DRQ, 1); 786 if (rle) 787 *result = rle->start; 788 else 789 *result = -1; 790 break; 791 792 case ISA_IVAR_VENDORID: 793 *result = idev->id_vendorid; 794 break; 795 796 case ISA_IVAR_SERIAL: 797 *result = idev->id_serial; 798 break; 799 800 case ISA_IVAR_LOGICALID: 801 *result = idev->id_logicalid; 802 break; 803 804 case ISA_IVAR_COMPATID: 805 *result = idev->id_compatid; 806 break; 807 808 case ISA_IVAR_CONFIGATTR: 809 *result = idev->id_config_attr; 810 break; 811 812 default: 813 return ENOENT; 814 } 815 816 return 0; 817 } 818 819 static int 820 isa_write_ivar(device_t bus, device_t dev, 821 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_MSIZE_0: 833 case ISA_IVAR_MSIZE_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 SLIST_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 SLIST_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 SLIST_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, 1001 int priority, 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, 1032 isa_config_cb *fn, 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 device_method_t isa_methods[] = { 1065 /* Device interface */ 1066 DEVMETHOD(device_probe, isa_probe), 1067 DEVMETHOD(device_attach, isa_attach), 1068 DEVMETHOD(device_detach, bus_generic_detach), 1069 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1070 DEVMETHOD(device_suspend, bus_generic_suspend), 1071 DEVMETHOD(device_resume, bus_generic_resume), 1072 1073 /* Bus interface */ 1074 DEVMETHOD(bus_add_child, isa_add_child), 1075 DEVMETHOD(bus_print_child, isa_print_child), 1076 DEVMETHOD(bus_probe_nomatch, isa_probe_nomatch), 1077 DEVMETHOD(bus_read_ivar, isa_read_ivar), 1078 DEVMETHOD(bus_write_ivar, isa_write_ivar), 1079 DEVMETHOD(bus_child_detached, isa_child_detached), 1080 DEVMETHOD(bus_driver_added, isa_driver_added), 1081 DEVMETHOD(bus_setup_intr, isa_setup_intr), 1082 DEVMETHOD(bus_teardown_intr, isa_teardown_intr), 1083 1084 DEVMETHOD(bus_get_resource_list,isa_get_resource_list), 1085 DEVMETHOD(bus_alloc_resource, isa_alloc_resource), 1086 DEVMETHOD(bus_release_resource, isa_release_resource), 1087 DEVMETHOD(bus_set_resource, isa_set_resource), 1088 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 1089 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 1090 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1091 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1092 1093 /* ISA interface */ 1094 DEVMETHOD(isa_add_config, isa_add_config), 1095 DEVMETHOD(isa_set_config_callback, isa_set_config_callback), 1096 DEVMETHOD(isa_pnp_probe, isa_pnp_probe), 1097 1098 { 0, 0 } 1099 }; 1100 1101 static driver_t isa_driver = { 1102 "isa", 1103 isa_methods, 1104 1, /* no softc */ 1105 }; 1106 1107 /* 1108 * ISA can be attached to a PCI-ISA bridge or directly to the nexus. 1109 */ 1110 DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0); 1111 DRIVER_MODULE(isa, eisab, isa_driver, isa_devclass, 0, 0); 1112 #ifdef __i386__ 1113 DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0); 1114 #endif 1115