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