1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause AND MIT 3 * 4 * Copyright (c) 1999 Doug Rabson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 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/cdefs.h> 63 __FBSDID("$FreeBSD$"); 64 65 #include "opt_isa.h" 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/kernel.h> 70 #include <sys/bus.h> 71 #include <sys/endian.h> 72 #include <sys/malloc.h> 73 #include <sys/module.h> 74 #include <machine/bus.h> 75 #include <sys/rman.h> 76 #include <sys/sbuf.h> 77 #include <sys/sysctl.h> 78 79 #include <machine/resource.h> 80 81 #include <isa/isavar.h> 82 #include <isa/isa_common.h> 83 84 static int isa_print_child(device_t bus, device_t dev); 85 86 static MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device"); 87 88 static int isa_running; 89 90 /* 91 * At 'probe' time, we add all the devices which we know about to the 92 * bus. The generic attach routine will probe and attach them if they 93 * are alive. 94 */ 95 static int 96 isa_probe(device_t dev) 97 { 98 device_set_desc(dev, "ISA bus"); 99 isa_init(dev); /* Allow machdep code to initialise */ 100 return (0); 101 } 102 103 extern device_t isa_bus_device; 104 105 static int 106 isa_attach(device_t dev) 107 { 108 /* 109 * Arrange for isa_probe_children(dev) to be called later. XXX 110 */ 111 isa_bus_device = dev; 112 return (0); 113 } 114 115 /* 116 * Find a working set of memory regions for a child using the ranges 117 * in *config and return the regions in *result. Returns non-zero if 118 * a set of ranges was found. 119 */ 120 static int 121 isa_find_memory(device_t child, struct isa_config *config, 122 struct isa_config *result) 123 { 124 int success, i; 125 struct resource *res[ISA_NMEM]; 126 127 /* 128 * First clear out any existing resource definitions. 129 */ 130 for (i = 0; i < ISA_NMEM; i++) { 131 bus_delete_resource(child, SYS_RES_MEMORY, i); 132 res[i] = NULL; 133 } 134 135 success = 1; 136 result->ic_nmem = config->ic_nmem; 137 for (i = 0; i < config->ic_nmem; i++) { 138 uint32_t start, end, size, align; 139 140 size = config->ic_mem[i].ir_size; 141 142 /* the PnP device may have a null resource as filler */ 143 if (size == 0) { 144 result->ic_mem[i].ir_start = 0; 145 result->ic_mem[i].ir_end = 0; 146 result->ic_mem[i].ir_size = 0; 147 result->ic_mem[i].ir_align = 0; 148 continue; 149 } 150 151 for (start = config->ic_mem[i].ir_start, 152 end = config->ic_mem[i].ir_end, 153 align = config->ic_mem[i].ir_align; 154 start + size - 1 <= end && start + size > start; 155 start += MAX(align, 1)) { 156 bus_set_resource(child, SYS_RES_MEMORY, i, 157 start, size); 158 res[i] = bus_alloc_resource_any(child, 159 SYS_RES_MEMORY, &i, 160 rman_make_alignment_flags(align) /* !RF_ACTIVE */); 161 if (res[i]) { 162 result->ic_mem[i].ir_start = start; 163 result->ic_mem[i].ir_end = start + size - 1; 164 result->ic_mem[i].ir_size = size; 165 result->ic_mem[i].ir_align = align; 166 break; 167 } 168 } 169 170 /* 171 * If we didn't find a place for memory range i, then 172 * give up now. 173 */ 174 if (!res[i]) { 175 success = 0; 176 break; 177 } 178 } 179 180 for (i = 0; i < ISA_NMEM; i++) { 181 if (res[i]) 182 bus_release_resource(child, SYS_RES_MEMORY, 183 i, res[i]); 184 } 185 186 return (success); 187 } 188 189 /* 190 * Find a working set of port regions for a child using the ranges 191 * in *config and return the regions in *result. Returns non-zero if 192 * a set of ranges was found. 193 */ 194 static int 195 isa_find_port(device_t child, struct isa_config *config, 196 struct isa_config *result) 197 { 198 int success, i; 199 struct resource *res[ISA_NPORT]; 200 201 /* 202 * First clear out any existing resource definitions. 203 */ 204 for (i = 0; i < ISA_NPORT; i++) { 205 bus_delete_resource(child, SYS_RES_IOPORT, i); 206 res[i] = NULL; 207 } 208 209 success = 1; 210 result->ic_nport = config->ic_nport; 211 for (i = 0; i < config->ic_nport; i++) { 212 uint32_t start, end, size, align; 213 214 size = config->ic_port[i].ir_size; 215 216 /* the PnP device may have a null resource as filler */ 217 if (size == 0) { 218 result->ic_port[i].ir_start = 0; 219 result->ic_port[i].ir_end = 0; 220 result->ic_port[i].ir_size = 0; 221 result->ic_port[i].ir_align = 0; 222 continue; 223 } 224 225 for (start = config->ic_port[i].ir_start, 226 end = config->ic_port[i].ir_end, 227 align = config->ic_port[i].ir_align; 228 start + size - 1 <= end; 229 start += align) { 230 bus_set_resource(child, SYS_RES_IOPORT, i, 231 start, size); 232 res[i] = bus_alloc_resource_any(child, 233 SYS_RES_IOPORT, &i, 234 rman_make_alignment_flags(align) /* !RF_ACTIVE */); 235 if (res[i]) { 236 result->ic_port[i].ir_start = start; 237 result->ic_port[i].ir_end = start + size - 1; 238 result->ic_port[i].ir_size = size; 239 result->ic_port[i].ir_align = align; 240 break; 241 } 242 } 243 244 /* 245 * If we didn't find a place for port range i, then 246 * give up now. 247 */ 248 if (!res[i]) { 249 success = 0; 250 break; 251 } 252 } 253 254 for (i = 0; i < ISA_NPORT; i++) { 255 if (res[i]) 256 bus_release_resource(child, SYS_RES_IOPORT, 257 i, res[i]); 258 } 259 260 return success; 261 } 262 263 /* 264 * Return the index of the first bit in the mask (or -1 if mask is empty. 265 */ 266 static int 267 find_first_bit(uint32_t mask) 268 { 269 return (ffs(mask) - 1); 270 } 271 272 /* 273 * Return the index of the next bit in the mask, or -1 if there are no more. 274 */ 275 static int 276 find_next_bit(uint32_t mask, int bit) 277 { 278 bit++; 279 while (bit < 32 && !(mask & (1 << bit))) 280 bit++; 281 if (bit != 32) 282 return (bit); 283 return (-1); 284 } 285 286 /* 287 * Find a working set of irqs for a child using the masks in *config 288 * and return the regions in *result. Returns non-zero if a set of 289 * irqs was found. 290 */ 291 static int 292 isa_find_irq(device_t child, 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 uint32_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, 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 uint32_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_any(child, 389 SYS_RES_DRQ, &i, 390 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 * Claim any unallocated resources to keep other devices from using 477 * them. 478 */ 479 static void 480 isa_claim_resources(device_t dev, device_t child) 481 { 482 struct isa_device *idev = DEVTOISA(child); 483 struct resource_list *rl = &idev->id_resources; 484 struct resource_list_entry *rle; 485 int rid; 486 487 STAILQ_FOREACH(rle, rl, link) { 488 if (!rle->res) { 489 rid = rle->rid; 490 resource_list_alloc(rl, dev, child, rle->type, &rid, 491 0, ~0, 1, 0); 492 } 493 } 494 } 495 496 /* 497 * Called after other devices have initialised to probe for isa devices. 498 */ 499 void 500 isa_probe_children(device_t dev) 501 { 502 struct isa_device *idev; 503 device_t *children, child; 504 struct isa_config *cfg; 505 int nchildren, i, err; 506 507 /* 508 * Create all the non-hinted children by calling drivers' 509 * identify methods. 510 */ 511 bus_generic_probe(dev); 512 513 if (device_get_children(dev, &children, &nchildren)) 514 return; 515 516 /* 517 * First disable all pnp devices so that they don't get 518 * matched by legacy probes. 519 */ 520 if (bootverbose) 521 printf("isa_probe_children: disabling PnP devices\n"); 522 523 cfg = malloc(sizeof(*cfg), M_TEMP, M_NOWAIT|M_ZERO); 524 if (cfg == NULL) { 525 free(children, M_TEMP); 526 return; 527 } 528 529 for (i = 0; i < nchildren; i++) { 530 idev = DEVTOISA(children[i]); 531 532 bzero(cfg, sizeof(*cfg)); 533 if (idev->id_config_cb) 534 idev->id_config_cb(idev->id_config_arg, cfg, 0); 535 } 536 537 free(cfg, M_TEMP); 538 539 /* 540 * Next, probe all the PnP BIOS devices so they can subsume any 541 * hints. 542 */ 543 for (i = 0; i < nchildren; i++) { 544 child = children[i]; 545 idev = DEVTOISA(child); 546 547 if (idev->id_order > ISA_ORDER_PNPBIOS) 548 continue; 549 if (!TAILQ_EMPTY(&idev->id_configs) && 550 !isa_assign_resources(child)) 551 continue; 552 553 if (device_probe_and_attach(child) == 0) 554 isa_claim_resources(dev, child); 555 } 556 free(children, M_TEMP); 557 558 /* 559 * Next, enumerate hinted devices and probe all non-pnp devices so 560 * that they claim their resources first. 561 */ 562 bus_enumerate_hinted_children(dev); 563 if (device_get_children(dev, &children, &nchildren)) 564 return; 565 if (bootverbose) 566 printf("isa_probe_children: probing non-PnP devices\n"); 567 for (i = 0; i < nchildren; i++) { 568 child = children[i]; 569 idev = DEVTOISA(child); 570 571 if (device_is_attached(child) || 572 !TAILQ_EMPTY(&idev->id_configs)) 573 continue; 574 575 err = device_probe_and_attach(child); 576 if (err == 0 && idev->id_vendorid == 0 && 577 strcmp(kern_ident, "GENERIC") == 0 && 578 device_is_attached(child)) 579 device_printf(child, 580 "non-PNP ISA device will be removed from GENERIC in FreeBSD 14.\n"); 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 child = children[i]; 590 idev = DEVTOISA(child); 591 592 if (device_is_attached(child) || TAILQ_EMPTY(&idev->id_configs)) 593 continue; 594 595 if (isa_assign_resources(child)) { 596 device_probe_and_attach(child); 597 isa_claim_resources(dev, child); 598 } 599 } 600 601 free(children, M_TEMP); 602 603 isa_running = 1; 604 } 605 606 /* 607 * Add a new child with default ivars. 608 */ 609 static device_t 610 isa_add_child(device_t dev, u_int order, const char *name, int unit) 611 { 612 device_t child; 613 struct isa_device *idev; 614 615 child = device_add_child_ordered(dev, order, name, unit); 616 if (child == NULL) 617 return (child); 618 619 idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT | M_ZERO); 620 if (!idev) 621 return (0); 622 623 resource_list_init(&idev->id_resources); 624 TAILQ_INIT(&idev->id_configs); 625 idev->id_order = order; 626 627 device_set_ivars(child, idev); 628 629 return (child); 630 } 631 632 static int 633 isa_print_all_resources(device_t dev) 634 { 635 struct isa_device *idev = DEVTOISA(dev); 636 struct resource_list *rl = &idev->id_resources; 637 int retval = 0; 638 639 if (STAILQ_FIRST(rl) || device_get_flags(dev)) 640 retval += printf(" at"); 641 642 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx"); 643 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx"); 644 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 645 retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%jd"); 646 if (device_get_flags(dev)) 647 retval += printf(" flags %#x", device_get_flags(dev)); 648 if (idev->id_vendorid) 649 retval += printf(" pnpid %s", pnp_eisaformat(idev->id_vendorid)); 650 651 return (retval); 652 } 653 654 static int 655 isa_print_child(device_t bus, device_t dev) 656 { 657 int retval = 0; 658 659 retval += bus_print_child_header(bus, dev); 660 retval += isa_print_all_resources(dev); 661 retval += bus_print_child_footer(bus, dev); 662 663 return (retval); 664 } 665 666 static void 667 isa_probe_nomatch(device_t dev, device_t child) 668 { 669 if (bootverbose) { 670 bus_print_child_header(dev, child); 671 printf(" failed to probe"); 672 isa_print_all_resources(child); 673 bus_print_child_footer(dev, child); 674 } 675 676 return; 677 } 678 679 static int 680 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 681 { 682 struct isa_device* idev = DEVTOISA(dev); 683 struct resource_list *rl = &idev->id_resources; 684 struct resource_list_entry *rle; 685 686 switch (index) { 687 case ISA_IVAR_PORT_0: 688 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 689 if (rle) 690 *result = rle->start; 691 else 692 *result = -1; 693 break; 694 695 case ISA_IVAR_PORT_1: 696 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 697 if (rle) 698 *result = rle->start; 699 else 700 *result = -1; 701 break; 702 703 case ISA_IVAR_PORTSIZE_0: 704 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 705 if (rle) 706 *result = rle->count; 707 else 708 *result = 0; 709 break; 710 711 case ISA_IVAR_PORTSIZE_1: 712 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 713 if (rle) 714 *result = rle->count; 715 else 716 *result = 0; 717 break; 718 719 case ISA_IVAR_MADDR_0: 720 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 721 if (rle) 722 *result = rle->start; 723 else 724 *result = -1; 725 break; 726 727 case ISA_IVAR_MADDR_1: 728 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 729 if (rle) 730 *result = rle->start; 731 else 732 *result = -1; 733 break; 734 735 case ISA_IVAR_MEMSIZE_0: 736 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 737 if (rle) 738 *result = rle->count; 739 else 740 *result = 0; 741 break; 742 743 case ISA_IVAR_MEMSIZE_1: 744 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 745 if (rle) 746 *result = rle->count; 747 else 748 *result = 0; 749 break; 750 751 case ISA_IVAR_IRQ_0: 752 rle = resource_list_find(rl, SYS_RES_IRQ, 0); 753 if (rle) 754 *result = rle->start; 755 else 756 *result = -1; 757 break; 758 759 case ISA_IVAR_IRQ_1: 760 rle = resource_list_find(rl, SYS_RES_IRQ, 1); 761 if (rle) 762 *result = rle->start; 763 else 764 *result = -1; 765 break; 766 767 case ISA_IVAR_DRQ_0: 768 rle = resource_list_find(rl, SYS_RES_DRQ, 0); 769 if (rle) 770 *result = rle->start; 771 else 772 *result = -1; 773 break; 774 775 case ISA_IVAR_DRQ_1: 776 rle = resource_list_find(rl, SYS_RES_DRQ, 1); 777 if (rle) 778 *result = rle->start; 779 else 780 *result = -1; 781 break; 782 783 case ISA_IVAR_VENDORID: 784 *result = idev->id_vendorid; 785 break; 786 787 case ISA_IVAR_SERIAL: 788 *result = idev->id_serial; 789 break; 790 791 case ISA_IVAR_LOGICALID: 792 *result = idev->id_logicalid; 793 break; 794 795 case ISA_IVAR_COMPATID: 796 *result = idev->id_compatid; 797 break; 798 799 case ISA_IVAR_CONFIGATTR: 800 *result = idev->id_config_attr; 801 break; 802 803 case ISA_IVAR_PNP_CSN: 804 *result = idev->id_pnp_csn; 805 break; 806 807 case ISA_IVAR_PNP_LDN: 808 *result = idev->id_pnp_ldn; 809 break; 810 811 case ISA_IVAR_PNPBIOS_HANDLE: 812 *result = idev->id_pnpbios_handle; 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, int index, uintptr_t value) 824 { 825 struct isa_device* idev = DEVTOISA(dev); 826 827 switch (index) { 828 case ISA_IVAR_PORT_0: 829 case ISA_IVAR_PORT_1: 830 case ISA_IVAR_PORTSIZE_0: 831 case ISA_IVAR_PORTSIZE_1: 832 case ISA_IVAR_MADDR_0: 833 case ISA_IVAR_MADDR_1: 834 case ISA_IVAR_MEMSIZE_0: 835 case ISA_IVAR_MEMSIZE_1: 836 case ISA_IVAR_IRQ_0: 837 case ISA_IVAR_IRQ_1: 838 case ISA_IVAR_DRQ_0: 839 case ISA_IVAR_DRQ_1: 840 return (EINVAL); 841 842 case ISA_IVAR_VENDORID: 843 idev->id_vendorid = value; 844 break; 845 846 case ISA_IVAR_SERIAL: 847 idev->id_serial = value; 848 break; 849 850 case ISA_IVAR_LOGICALID: 851 idev->id_logicalid = value; 852 break; 853 854 case ISA_IVAR_COMPATID: 855 idev->id_compatid = value; 856 break; 857 858 case ISA_IVAR_CONFIGATTR: 859 idev->id_config_attr = value; 860 break; 861 862 default: 863 return (ENOENT); 864 } 865 866 return (0); 867 } 868 869 /* 870 * Free any resources which the driver missed or which we were holding for 871 * it (see isa_probe_children). 872 */ 873 static void 874 isa_child_detached(device_t dev, device_t child) 875 { 876 struct isa_device* idev = DEVTOISA(child); 877 878 if (TAILQ_FIRST(&idev->id_configs)) 879 isa_claim_resources(dev, child); 880 } 881 882 static void 883 isa_driver_added(device_t dev, driver_t *driver) 884 { 885 device_t *children; 886 int nchildren, i; 887 888 /* 889 * Don't do anything if drivers are dynamically 890 * added during autoconfiguration (cf. ymf724). 891 * since that would end up calling identify 892 * twice. 893 */ 894 if (!isa_running) 895 return; 896 897 DEVICE_IDENTIFY(driver, dev); 898 if (device_get_children(dev, &children, &nchildren)) 899 return; 900 901 for (i = 0; i < nchildren; i++) { 902 device_t child = children[i]; 903 struct isa_device *idev = DEVTOISA(child); 904 struct resource_list *rl = &idev->id_resources; 905 struct resource_list_entry *rle; 906 907 if (device_get_state(child) != DS_NOTPRESENT) 908 continue; 909 if (!device_is_enabled(child)) 910 continue; 911 912 /* 913 * Free resources which we were holding on behalf of 914 * the device. 915 */ 916 STAILQ_FOREACH(rle, &idev->id_resources, link) { 917 if (rle->res) 918 resource_list_release(rl, dev, child, 919 rle->type, 920 rle->rid, 921 rle->res); 922 } 923 924 if (TAILQ_FIRST(&idev->id_configs)) 925 if (!isa_assign_resources(child)) 926 continue; 927 928 device_probe_and_attach(child); 929 930 if (TAILQ_FIRST(&idev->id_configs)) 931 isa_claim_resources(dev, child); 932 } 933 934 free(children, M_TEMP); 935 } 936 937 static int 938 isa_set_resource(device_t dev, device_t child, int type, int rid, 939 rman_res_t start, rman_res_t count) 940 { 941 struct isa_device* idev = DEVTOISA(child); 942 struct resource_list *rl = &idev->id_resources; 943 944 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 945 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 946 return (EINVAL); 947 if (rid < 0) 948 return (EINVAL); 949 if (type == SYS_RES_IOPORT && rid >= ISA_NPORT) 950 return (EINVAL); 951 if (type == SYS_RES_MEMORY && rid >= ISA_NMEM) 952 return (EINVAL); 953 if (type == SYS_RES_IRQ && rid >= ISA_NIRQ) 954 return (EINVAL); 955 if (type == SYS_RES_DRQ && rid >= ISA_NDRQ) 956 return (EINVAL); 957 958 resource_list_add(rl, type, rid, start, start + count - 1, count); 959 960 return (0); 961 } 962 963 static struct resource_list * 964 isa_get_resource_list (device_t dev, device_t child) 965 { 966 struct isa_device* idev = DEVTOISA(child); 967 struct resource_list *rl = &idev->id_resources; 968 969 if (!rl) 970 return (NULL); 971 972 return (rl); 973 } 974 975 static int 976 isa_add_config(device_t dev, device_t child, int priority, 977 struct isa_config *config) 978 { 979 struct isa_device* idev = DEVTOISA(child); 980 struct isa_config_entry *newice, *ice; 981 982 newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT); 983 if (!newice) 984 return (ENOMEM); 985 986 newice->ice_priority = priority; 987 newice->ice_config = *config; 988 989 TAILQ_FOREACH(ice, &idev->id_configs, ice_link) { 990 if (ice->ice_priority > priority) 991 break; 992 } 993 if (ice) 994 TAILQ_INSERT_BEFORE(ice, newice, ice_link); 995 else 996 TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link); 997 998 return (0); 999 } 1000 1001 static void 1002 isa_set_config_callback(device_t dev, device_t child, isa_config_cb *fn, 1003 void *arg) 1004 { 1005 struct isa_device* idev = DEVTOISA(child); 1006 1007 idev->id_config_cb = fn; 1008 idev->id_config_arg = arg; 1009 } 1010 1011 static int 1012 isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids) 1013 { 1014 struct isa_device* idev = DEVTOISA(child); 1015 1016 if (!idev->id_vendorid) 1017 return (ENOENT); 1018 1019 while (ids && ids->ip_id) { 1020 /* 1021 * Really ought to support >1 compat id per device. 1022 */ 1023 if (idev->id_logicalid == ids->ip_id 1024 || idev->id_compatid == ids->ip_id) { 1025 if (ids->ip_desc) 1026 device_set_desc(child, ids->ip_desc); 1027 return (0); 1028 } 1029 ids++; 1030 } 1031 1032 return (ENXIO); 1033 } 1034 1035 static int 1036 isa_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb) 1037 { 1038 struct isa_device *idev = DEVTOISA(child); 1039 1040 if (idev->id_vendorid) 1041 sbuf_printf(sb, "pnpid=%s", 1042 pnp_eisaformat(idev->id_vendorid)); 1043 return (0); 1044 } 1045 1046 static int 1047 isa_child_location(device_t bus, device_t child, struct sbuf *sb) 1048 { 1049 #if 0 1050 /* id_pnphandle isn't there yet */ 1051 struct isa_device *idev = DEVTOISA(child); 1052 1053 if (idev->id_vendorid) 1054 sbuf_printf(sbuf, "pnphandle=%d", idev->id_pnphandle); 1055 #endif 1056 return (0); 1057 } 1058 1059 static device_method_t isa_methods[] = { 1060 /* Device interface */ 1061 DEVMETHOD(device_probe, isa_probe), 1062 DEVMETHOD(device_attach, isa_attach), 1063 DEVMETHOD(device_detach, bus_generic_detach), 1064 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1065 DEVMETHOD(device_suspend, bus_generic_suspend), 1066 DEVMETHOD(device_resume, bus_generic_resume), 1067 1068 /* Bus interface */ 1069 DEVMETHOD(bus_add_child, isa_add_child), 1070 DEVMETHOD(bus_print_child, isa_print_child), 1071 DEVMETHOD(bus_probe_nomatch, isa_probe_nomatch), 1072 DEVMETHOD(bus_read_ivar, isa_read_ivar), 1073 DEVMETHOD(bus_write_ivar, isa_write_ivar), 1074 DEVMETHOD(bus_child_detached, isa_child_detached), 1075 DEVMETHOD(bus_driver_added, isa_driver_added), 1076 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 1077 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 1078 1079 DEVMETHOD(bus_get_resource_list,isa_get_resource_list), 1080 DEVMETHOD(bus_alloc_resource, isa_alloc_resource), 1081 DEVMETHOD(bus_release_resource, isa_release_resource), 1082 DEVMETHOD(bus_set_resource, isa_set_resource), 1083 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 1084 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 1085 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1086 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1087 DEVMETHOD(bus_child_pnpinfo, isa_child_pnpinfo), 1088 DEVMETHOD(bus_child_location, isa_child_location), 1089 DEVMETHOD(bus_hinted_child, isa_hinted_child), 1090 DEVMETHOD(bus_hint_device_unit, isa_hint_device_unit), 1091 1092 /* ISA interface */ 1093 DEVMETHOD(isa_add_config, isa_add_config), 1094 DEVMETHOD(isa_set_config_callback, isa_set_config_callback), 1095 DEVMETHOD(isa_pnp_probe, isa_pnp_probe), 1096 1097 { 0, 0 } 1098 }; 1099 1100 DEFINE_CLASS_0(isa, isa_driver, isa_methods, 0); 1101 1102 /* 1103 * ISA can be attached to a PCI-ISA bridge, or other locations on some 1104 * platforms. 1105 */ 1106 DRIVER_MODULE(isa, isab, isa_driver, 0, 0); 1107 DRIVER_MODULE(isa, eisab, isa_driver, 0, 0); 1108 MODULE_VERSION(isa, 1); 1109 1110 /* 1111 * Code common to ISA bridges. 1112 */ 1113 1114 int 1115 isab_attach(device_t dev) 1116 { 1117 device_t child; 1118 1119 child = device_add_child(dev, "isa", 0); 1120 if (child != NULL) 1121 return (bus_generic_attach(dev)); 1122 return (ENXIO); 1123 } 1124 1125 char * 1126 pnp_eisaformat(uint32_t id) 1127 { 1128 uint8_t *data; 1129 static char idbuf[8]; 1130 const char hextoascii[] = "0123456789abcdef"; 1131 1132 id = htole32(id); 1133 data = (uint8_t *)&id; 1134 idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); 1135 idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); 1136 idbuf[2] = '@' + (data[1] & 0x1f); 1137 idbuf[3] = hextoascii[(data[2] >> 4)]; 1138 idbuf[4] = hextoascii[(data[2] & 0xf)]; 1139 idbuf[5] = hextoascii[(data[3] >> 4)]; 1140 idbuf[6] = hextoascii[(data[3] & 0xf)]; 1141 idbuf[7] = 0; 1142 return(idbuf); 1143 } 1144