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 child = device_add_child_ordered(dev, order, name, unit); 631 if (child == NULL) 632 return (child); 633 634 idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT | M_ZERO); 635 if (!idev) 636 return 0; 637 638 resource_list_init(&idev->id_resources); 639 TAILQ_INIT(&idev->id_configs); 640 641 device_set_ivars(child, idev); 642 643 return (child); 644 } 645 646 static int 647 isa_print_all_resources(device_t dev) 648 { 649 struct isa_device *idev = DEVTOISA(dev); 650 struct resource_list *rl = &idev->id_resources; 651 int retval = 0; 652 653 if (SLIST_FIRST(rl) || device_get_flags(dev)) 654 retval += printf(" at"); 655 656 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 657 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 658 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 659 retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld"); 660 if (device_get_flags(dev)) 661 retval += printf(" flags %#x", device_get_flags(dev)); 662 663 return retval; 664 } 665 666 static int 667 isa_print_child(device_t bus, device_t dev) 668 { 669 int retval = 0; 670 671 retval += bus_print_child_header(bus, dev); 672 retval += isa_print_all_resources(dev); 673 retval += bus_print_child_footer(bus, dev); 674 675 return (retval); 676 } 677 678 static void 679 isa_probe_nomatch(device_t dev, device_t child) 680 { 681 if (bootverbose) { 682 bus_print_child_header(dev, child); 683 printf(" failed to probe"); 684 isa_print_all_resources(child); 685 bus_print_child_footer(dev, child); 686 } 687 688 return; 689 } 690 691 static int 692 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 693 { 694 struct isa_device* idev = DEVTOISA(dev); 695 struct resource_list *rl = &idev->id_resources; 696 struct resource_list_entry *rle; 697 698 switch (index) { 699 case ISA_IVAR_PORT_0: 700 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 701 if (rle) 702 *result = rle->start; 703 else 704 *result = -1; 705 break; 706 707 case ISA_IVAR_PORT_1: 708 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 709 if (rle) 710 *result = rle->start; 711 else 712 *result = -1; 713 break; 714 715 case ISA_IVAR_PORTSIZE_0: 716 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 717 if (rle) 718 *result = rle->count; 719 else 720 *result = 0; 721 break; 722 723 case ISA_IVAR_PORTSIZE_1: 724 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 725 if (rle) 726 *result = rle->count; 727 else 728 *result = 0; 729 break; 730 731 case ISA_IVAR_MADDR_0: 732 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 733 if (rle) 734 *result = rle->start; 735 else 736 *result = -1; 737 break; 738 739 case ISA_IVAR_MADDR_1: 740 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 741 if (rle) 742 *result = rle->start; 743 else 744 *result = -1; 745 break; 746 747 case ISA_IVAR_MEMSIZE_0: 748 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 749 if (rle) 750 *result = rle->count; 751 else 752 *result = 0; 753 break; 754 755 case ISA_IVAR_MEMSIZE_1: 756 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 757 if (rle) 758 *result = rle->count; 759 else 760 *result = 0; 761 break; 762 763 case ISA_IVAR_IRQ_0: 764 rle = resource_list_find(rl, SYS_RES_IRQ, 0); 765 if (rle) 766 *result = rle->start; 767 else 768 *result = -1; 769 break; 770 771 case ISA_IVAR_IRQ_1: 772 rle = resource_list_find(rl, SYS_RES_IRQ, 1); 773 if (rle) 774 *result = rle->start; 775 else 776 *result = -1; 777 break; 778 779 case ISA_IVAR_DRQ_0: 780 rle = resource_list_find(rl, SYS_RES_DRQ, 0); 781 if (rle) 782 *result = rle->start; 783 else 784 *result = -1; 785 break; 786 787 case ISA_IVAR_DRQ_1: 788 rle = resource_list_find(rl, SYS_RES_DRQ, 1); 789 if (rle) 790 *result = rle->start; 791 else 792 *result = -1; 793 break; 794 795 case ISA_IVAR_VENDORID: 796 *result = idev->id_vendorid; 797 break; 798 799 case ISA_IVAR_SERIAL: 800 *result = idev->id_serial; 801 break; 802 803 case ISA_IVAR_LOGICALID: 804 *result = idev->id_logicalid; 805 break; 806 807 case ISA_IVAR_COMPATID: 808 *result = idev->id_compatid; 809 break; 810 811 case ISA_IVAR_CONFIGATTR: 812 *result = idev->id_config_attr; 813 break; 814 815 default: 816 return ENOENT; 817 } 818 819 return 0; 820 } 821 822 static int 823 isa_write_ivar(device_t bus, device_t dev, 824 int index, uintptr_t value) 825 { 826 struct isa_device* idev = DEVTOISA(dev); 827 828 switch (index) { 829 case ISA_IVAR_PORT_0: 830 case ISA_IVAR_PORT_1: 831 case ISA_IVAR_PORTSIZE_0: 832 case ISA_IVAR_PORTSIZE_1: 833 case ISA_IVAR_MADDR_0: 834 case ISA_IVAR_MADDR_1: 835 case ISA_IVAR_MEMSIZE_0: 836 case ISA_IVAR_MEMSIZE_1: 837 case ISA_IVAR_IRQ_0: 838 case ISA_IVAR_IRQ_1: 839 case ISA_IVAR_DRQ_0: 840 case ISA_IVAR_DRQ_1: 841 return EINVAL; 842 843 case ISA_IVAR_VENDORID: 844 idev->id_vendorid = value; 845 break; 846 847 case ISA_IVAR_SERIAL: 848 idev->id_serial = value; 849 break; 850 851 case ISA_IVAR_LOGICALID: 852 idev->id_logicalid = value; 853 break; 854 855 case ISA_IVAR_COMPATID: 856 idev->id_compatid = value; 857 break; 858 859 case ISA_IVAR_CONFIGATTR: 860 idev->id_config_attr = value; 861 break; 862 863 default: 864 return (ENOENT); 865 } 866 867 return (0); 868 } 869 870 /* 871 * Free any resources which the driver missed or which we were holding for 872 * it (see isa_probe_children). 873 */ 874 static void 875 isa_child_detached(device_t dev, device_t child) 876 { 877 struct isa_device* idev = DEVTOISA(child); 878 struct resource_list *rl = &idev->id_resources; 879 struct resource_list_entry *rle; 880 881 if (TAILQ_FIRST(&idev->id_configs)) { 882 /* 883 * Claim any unallocated resources to keep other 884 * devices from using them. 885 */ 886 SLIST_FOREACH(rle, rl, link) { 887 if (!rle->res) { 888 int rid = rle->rid; 889 resource_list_alloc(rl, dev, child, 890 rle->type, 891 &rid, 0, ~0, 1, 0); 892 } 893 } 894 } 895 } 896 897 static void 898 isa_driver_added(device_t dev, driver_t *driver) 899 { 900 device_t *children; 901 int nchildren, i; 902 903 /* 904 * Don't do anything if drivers are dynamically 905 * added during autoconfiguration (cf. ymf724). 906 * since that would end up calling identify 907 * twice. 908 */ 909 if (!isa_running) 910 return; 911 912 DEVICE_IDENTIFY(driver, dev); 913 if (device_get_children(dev, &children, &nchildren)) 914 return; 915 916 for (i = 0; i < nchildren; i++) { 917 device_t child = children[i]; 918 struct isa_device *idev = DEVTOISA(child); 919 struct resource_list *rl = &idev->id_resources; 920 struct resource_list_entry *rle; 921 922 if (device_get_state(child) != DS_NOTPRESENT) 923 continue; 924 if (!device_is_enabled(child)) 925 continue; 926 927 /* 928 * Free resources which we were holding on behalf of 929 * the device. 930 */ 931 SLIST_FOREACH(rle, &idev->id_resources, link) { 932 if (rle->res) 933 resource_list_release(rl, dev, child, 934 rle->type, 935 rle->rid, 936 rle->res); 937 } 938 939 if (TAILQ_FIRST(&idev->id_configs)) 940 if (!isa_assign_resources(child)) 941 continue; 942 943 device_probe_and_attach(child); 944 945 if (TAILQ_FIRST(&idev->id_configs)) { 946 /* 947 * Claim any unallocated resources to keep other 948 * devices from using them. 949 */ 950 SLIST_FOREACH(rle, rl, link) { 951 if (!rle->res) { 952 int rid = rle->rid; 953 resource_list_alloc(rl, dev, child, 954 rle->type, 955 &rid, 0, ~0, 1, 0); 956 } 957 } 958 } 959 } 960 961 free(children, M_TEMP); 962 } 963 964 static int 965 isa_set_resource(device_t dev, device_t child, int type, int rid, 966 u_long start, u_long count) 967 { 968 struct isa_device* idev = DEVTOISA(child); 969 struct resource_list *rl = &idev->id_resources; 970 971 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 972 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 973 return EINVAL; 974 if (rid < 0) 975 return EINVAL; 976 if (type == SYS_RES_IOPORT && rid >= ISA_NPORT) 977 return EINVAL; 978 if (type == SYS_RES_MEMORY && rid >= ISA_NMEM) 979 return EINVAL; 980 if (type == SYS_RES_IRQ && rid >= ISA_NIRQ) 981 return EINVAL; 982 if (type == SYS_RES_DRQ && rid >= ISA_NDRQ) 983 return EINVAL; 984 985 resource_list_add(rl, type, rid, start, start + count - 1, count); 986 987 return 0; 988 } 989 990 static struct resource_list * 991 isa_get_resource_list (device_t dev, device_t child) 992 { 993 struct isa_device* idev = DEVTOISA(child); 994 struct resource_list *rl = &idev->id_resources; 995 996 if (!rl) 997 return (NULL); 998 999 return (rl); 1000 } 1001 1002 static int 1003 isa_add_config(device_t dev, device_t child, 1004 int priority, struct isa_config *config) 1005 { 1006 struct isa_device* idev = DEVTOISA(child); 1007 struct isa_config_entry *newice, *ice; 1008 1009 newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT); 1010 if (!newice) 1011 return ENOMEM; 1012 1013 newice->ice_priority = priority; 1014 newice->ice_config = *config; 1015 1016 TAILQ_FOREACH(ice, &idev->id_configs, ice_link) { 1017 if (ice->ice_priority > priority) 1018 break; 1019 } 1020 if (ice) 1021 TAILQ_INSERT_BEFORE(ice, newice, ice_link); 1022 else 1023 TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link); 1024 1025 if (isa_has_single_config(child)) 1026 idev->id_config_attr &= ~ISACFGATTR_MULTI; 1027 else 1028 idev->id_config_attr |= ISACFGATTR_MULTI; 1029 1030 return 0; 1031 } 1032 1033 static void 1034 isa_set_config_callback(device_t dev, device_t child, 1035 isa_config_cb *fn, void *arg) 1036 { 1037 struct isa_device* idev = DEVTOISA(child); 1038 1039 idev->id_config_cb = fn; 1040 idev->id_config_arg = arg; 1041 } 1042 1043 static int 1044 isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids) 1045 { 1046 struct isa_device* idev = DEVTOISA(child); 1047 1048 if (!idev->id_vendorid) 1049 return ENOENT; 1050 1051 while (ids && ids->ip_id) { 1052 /* 1053 * Really ought to support >1 compat id per device. 1054 */ 1055 if (idev->id_logicalid == ids->ip_id 1056 || idev->id_compatid == ids->ip_id) { 1057 if (ids->ip_desc) 1058 device_set_desc(child, ids->ip_desc); 1059 return 0; 1060 } 1061 ids++; 1062 } 1063 1064 return ENXIO; 1065 } 1066 1067 static device_method_t isa_methods[] = { 1068 /* Device interface */ 1069 DEVMETHOD(device_probe, isa_probe), 1070 DEVMETHOD(device_attach, isa_attach), 1071 DEVMETHOD(device_detach, bus_generic_detach), 1072 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1073 DEVMETHOD(device_suspend, bus_generic_suspend), 1074 DEVMETHOD(device_resume, bus_generic_resume), 1075 1076 /* Bus interface */ 1077 DEVMETHOD(bus_add_child, isa_add_child), 1078 DEVMETHOD(bus_print_child, isa_print_child), 1079 DEVMETHOD(bus_probe_nomatch, isa_probe_nomatch), 1080 DEVMETHOD(bus_read_ivar, isa_read_ivar), 1081 DEVMETHOD(bus_write_ivar, isa_write_ivar), 1082 DEVMETHOD(bus_child_detached, isa_child_detached), 1083 DEVMETHOD(bus_driver_added, isa_driver_added), 1084 DEVMETHOD(bus_setup_intr, isa_setup_intr), 1085 DEVMETHOD(bus_teardown_intr, isa_teardown_intr), 1086 1087 DEVMETHOD(bus_get_resource_list,isa_get_resource_list), 1088 DEVMETHOD(bus_alloc_resource, isa_alloc_resource), 1089 DEVMETHOD(bus_release_resource, isa_release_resource), 1090 DEVMETHOD(bus_set_resource, isa_set_resource), 1091 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 1092 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 1093 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1094 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1095 1096 /* ISA interface */ 1097 DEVMETHOD(isa_add_config, isa_add_config), 1098 DEVMETHOD(isa_set_config_callback, isa_set_config_callback), 1099 DEVMETHOD(isa_pnp_probe, isa_pnp_probe), 1100 1101 { 0, 0 } 1102 }; 1103 1104 static driver_t isa_driver = { 1105 "isa", 1106 isa_methods, 1107 1, /* no softc */ 1108 }; 1109 1110 /* 1111 * ISA can be attached to a PCI-ISA bridge or directly to the legacy device. 1112 */ 1113 DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0); 1114 DRIVER_MODULE(isa, eisab, isa_driver, isa_devclass, 0, 0); 1115 #ifdef __i386__ 1116 DRIVER_MODULE(isa, legacy, isa_driver, isa_devclass, 0, 0); 1117 #endif 1118