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: src/sys/isa/isa_common.c,v 1.16.2.1 2000/09/16 15:49:52 roger Exp $ 27 * $DragonFly: src/sys/bus/isa/isa_common.c,v 1.9 2005/10/30 04:41:09 dillon Exp $ 28 */ 29 /* 30 * Modifications for Intel architecture by Garrett A. Wollman. 31 * Copyright 1998 Massachusetts Institute of Technology 32 * 33 * Permission to use, copy, modify, and distribute this software and 34 * its documentation for any purpose and without fee is hereby 35 * granted, provided that both the above copyright notice and this 36 * permission notice appear in all copies, that both the above 37 * copyright notice and this permission notice appear in all 38 * supporting documentation, and that the name of M.I.T. not be used 39 * in advertising or publicity pertaining to distribution of the 40 * software without specific, written prior permission. M.I.T. makes 41 * no representations about the suitability of this software for any 42 * purpose. It is provided "as is" without express or implied 43 * warranty. 44 * 45 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 46 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 47 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 48 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 49 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 52 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 53 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 54 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 55 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 */ 58 59 /* 60 * Parts of the ISA bus implementation common to all architectures. 61 */ 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/kernel.h> 66 #include <sys/bus.h> 67 #include <sys/malloc.h> 68 #include <sys/module.h> 69 #include <machine/bus.h> 70 #include <sys/rman.h> 71 72 #include <machine/resource.h> 73 74 #include "isavar.h" 75 #include "isa_common.h" 76 77 static int isa_print_child (device_t, device_t); 78 79 MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device"); 80 81 static devclass_t isa_devclass; 82 static int isa_running; 83 84 /* 85 * At 'probe' time, we add all the devices which we know about to the 86 * bus. The generic attach routine will probe and attach them if they 87 * are alive. 88 */ 89 static int 90 isa_probe(device_t dev) 91 { 92 device_set_desc(dev, "ISA bus"); 93 isa_init(); /* Allow machdep code to initialise */ 94 return 0; 95 } 96 97 extern device_t isa_bus_device; 98 99 static int 100 isa_attach(device_t dev) 101 { 102 /* 103 * Arrange for isa_probe_children(dev) to be called later. XXX 104 */ 105 isa_bus_device = dev; 106 return 0; 107 } 108 109 /* 110 * Find a working set of memory regions for a child using the ranges 111 * in *config and return the regions in *result. Returns non-zero if 112 * a set of ranges was found. 113 */ 114 static int 115 isa_find_memory(device_t child, 116 struct isa_config *config, 117 struct isa_config *result) 118 { 119 int success, i; 120 struct resource *res[ISA_NMEM]; 121 122 /* 123 * First clear out any existing resource definitions. 124 */ 125 for (i = 0; i < ISA_NMEM; i++) { 126 bus_delete_resource(child, SYS_RES_MEMORY, i); 127 res[i] = NULL; 128 } 129 130 success = 1; 131 result->ic_nmem = config->ic_nmem; 132 for (i = 0; i < config->ic_nmem; i++) { 133 u_int32_t start, end, size, align; 134 for (start = config->ic_mem[i].ir_start, 135 end = config->ic_mem[i].ir_end, 136 size = config->ic_mem[i].ir_size, 137 align = config->ic_mem[i].ir_align; 138 start + size - 1 <= end; 139 start += align) { 140 bus_set_resource(child, SYS_RES_MEMORY, i, 141 start, size); 142 res[i] = bus_alloc_resource(child, 143 SYS_RES_MEMORY, &i, 144 0, ~0, 1, 0 /* !RF_ACTIVE */); 145 if (res[i]) { 146 result->ic_mem[i].ir_start = start; 147 result->ic_mem[i].ir_end = start + size - 1; 148 result->ic_mem[i].ir_size = size; 149 result->ic_mem[i].ir_align = align; 150 break; 151 } 152 } 153 154 /* 155 * If we didn't find a place for memory range i, then 156 * give up now. 157 */ 158 if (!res[i]) { 159 success = 0; 160 break; 161 } 162 } 163 164 for (i = 0; i < ISA_NMEM; i++) { 165 if (res[i]) 166 bus_release_resource(child, SYS_RES_MEMORY, 167 i, res[i]); 168 } 169 170 return success; 171 } 172 173 /* 174 * Find a working set of port regions for a child using the ranges 175 * in *config and return the regions in *result. Returns non-zero if 176 * a set of ranges was found. 177 */ 178 static int 179 isa_find_port(device_t child, 180 struct isa_config *config, 181 struct isa_config *result) 182 { 183 int success, i; 184 struct resource *res[ISA_NPORT]; 185 186 /* 187 * First clear out any existing resource definitions. 188 */ 189 for (i = 0; i < ISA_NPORT; i++) { 190 bus_delete_resource(child, SYS_RES_IOPORT, i); 191 res[i] = NULL; 192 } 193 194 success = 1; 195 result->ic_nport = config->ic_nport; 196 for (i = 0; i < config->ic_nport; i++) { 197 u_int32_t start, end, size, align; 198 for (start = config->ic_port[i].ir_start, 199 end = config->ic_port[i].ir_end, 200 size = config->ic_port[i].ir_size, 201 align = config->ic_port[i].ir_align; 202 start + size - 1 <= end; 203 start += align) { 204 bus_set_resource(child, SYS_RES_IOPORT, i, 205 start, size); 206 res[i] = bus_alloc_resource(child, 207 SYS_RES_IOPORT, &i, 208 0, ~0, 1, 0 /* !RF_ACTIVE */); 209 if (res[i]) { 210 result->ic_port[i].ir_start = start; 211 result->ic_port[i].ir_end = start + size - 1; 212 result->ic_port[i].ir_size = size; 213 result->ic_port[i].ir_align = align; 214 break; 215 } 216 } 217 218 /* 219 * If we didn't find a place for port range i, then 220 * give up now. 221 */ 222 if (!res[i]) { 223 success = 0; 224 break; 225 } 226 } 227 228 for (i = 0; i < ISA_NPORT; i++) { 229 if (res[i]) 230 bus_release_resource(child, SYS_RES_IOPORT, 231 i, res[i]); 232 } 233 234 return success; 235 } 236 237 /* 238 * Return the index of the first bit in the mask (or -1 if mask is empty. 239 */ 240 static int 241 find_first_bit(u_int32_t mask) 242 { 243 return ffs(mask) - 1; 244 } 245 246 /* 247 * Return the index of the next bit in the mask, or -1 if there are no more. 248 */ 249 static int 250 find_next_bit(u_int32_t mask, int bit) 251 { 252 bit++; 253 while (bit < 32 && !(mask & (1 << bit))) 254 bit++; 255 if (bit != 32) 256 return bit; 257 return -1; 258 } 259 260 /* 261 * Find a working set of irqs for a child using the masks in *config 262 * and return the regions in *result. Returns non-zero if a set of 263 * irqs was found. 264 */ 265 static int 266 isa_find_irq(device_t child, 267 struct isa_config *config, 268 struct isa_config *result) 269 { 270 int success, i; 271 struct resource *res[ISA_NIRQ]; 272 273 /* 274 * First clear out any existing resource definitions. 275 */ 276 for (i = 0; i < ISA_NIRQ; i++) { 277 bus_delete_resource(child, SYS_RES_IRQ, i); 278 res[i] = NULL; 279 } 280 281 success = 1; 282 result->ic_nirq = config->ic_nirq; 283 for (i = 0; i < config->ic_nirq; i++) { 284 u_int32_t mask = config->ic_irqmask[i]; 285 int irq; 286 for (irq = find_first_bit(mask); 287 irq != -1; 288 irq = find_next_bit(mask, irq)) { 289 bus_set_resource(child, SYS_RES_IRQ, i, 290 irq, 1); 291 res[i] = bus_alloc_resource(child, 292 SYS_RES_IRQ, &i, 293 0, ~0, 1, 0 /* !RF_ACTIVE */ ); 294 if (res[i]) { 295 result->ic_irqmask[i] = (1 << irq); 296 break; 297 } 298 } 299 300 /* 301 * If we didn't find a place for irq range i, then 302 * give up now. 303 */ 304 if (!res[i]) { 305 success = 0; 306 break; 307 } 308 } 309 310 for (i = 0; i < ISA_NIRQ; i++) { 311 if (res[i]) 312 bus_release_resource(child, SYS_RES_IRQ, 313 i, res[i]); 314 } 315 316 return success; 317 } 318 319 /* 320 * Find a working set of drqs for a child using the masks in *config 321 * and return the regions in *result. Returns non-zero if a set of 322 * drqs was found. 323 */ 324 static int 325 isa_find_drq(device_t child, 326 struct isa_config *config, 327 struct isa_config *result) 328 { 329 int success, i; 330 struct resource *res[ISA_NDRQ]; 331 332 /* 333 * First clear out any existing resource definitions. 334 */ 335 for (i = 0; i < ISA_NDRQ; i++) { 336 bus_delete_resource(child, SYS_RES_DRQ, i); 337 res[i] = NULL; 338 } 339 340 success = 1; 341 result->ic_ndrq = config->ic_ndrq; 342 for (i = 0; i < config->ic_ndrq; i++) { 343 u_int32_t mask = config->ic_drqmask[i]; 344 int drq; 345 for (drq = find_first_bit(mask); 346 drq != -1; 347 drq = find_next_bit(mask, drq)) { 348 bus_set_resource(child, SYS_RES_DRQ, i, 349 drq, 1); 350 res[i] = bus_alloc_resource(child, 351 SYS_RES_DRQ, &i, 352 0, ~0, 1, 0 /* !RF_ACTIVE */); 353 if (res[i]) { 354 result->ic_drqmask[i] = (1 << drq); 355 break; 356 } 357 } 358 359 /* 360 * If we didn't find a place for drq range i, then 361 * give up now. 362 */ 363 if (!res[i]) { 364 success = 0; 365 break; 366 } 367 } 368 369 for (i = 0; i < ISA_NDRQ; i++) { 370 if (res[i]) 371 bus_release_resource(child, SYS_RES_DRQ, 372 i, res[i]); 373 } 374 375 return success; 376 } 377 378 /* 379 * Attempt to find a working set of resources for a device. Return 380 * non-zero if a working configuration is found. 381 */ 382 static int 383 isa_assign_resources(device_t child) 384 { 385 struct isa_device *idev = DEVTOISA(child); 386 struct isa_config_entry *ice; 387 struct isa_config config; 388 char *reason = "Empty ISA id_configs"; 389 390 bzero(&config, sizeof config); 391 TAILQ_FOREACH(ice, &idev->id_configs, ice_link) { 392 reason = "memory"; 393 if (!isa_find_memory(child, &ice->ice_config, &config)) 394 continue; 395 reason = "port"; 396 if (!isa_find_port(child, &ice->ice_config, &config)) 397 continue; 398 reason = "irq"; 399 if (!isa_find_irq(child, &ice->ice_config, &config)) 400 continue; 401 reason = "drq"; 402 if (!isa_find_drq(child, &ice->ice_config, &config)) 403 continue; 404 405 /* 406 * A working configuration was found enable the device 407 * with this configuration. 408 */ 409 reason = "no callback"; 410 if (idev->id_config_cb) { 411 idev->id_config_cb(idev->id_config_arg, 412 &config, 1); 413 return 1; 414 } 415 } 416 417 /* 418 * Disable the device. 419 */ 420 bus_print_child_header(device_get_parent(child), child); 421 printf(" can't assign resources (%s)\n", reason); 422 if (bootverbose) 423 isa_print_child(device_get_parent(child), child); 424 bzero(&config, sizeof config); 425 if (idev->id_config_cb) 426 idev->id_config_cb(idev->id_config_arg, &config, 0); 427 device_disable(child); 428 429 return 0; 430 } 431 432 /* 433 * Called after other devices have initialised to probe for isa devices. 434 */ 435 void 436 isa_probe_children(device_t dev) 437 { 438 device_t *children; 439 int nchildren, i; 440 441 /* 442 * Create all the children by calling driver's identify methods. 443 * Since this routine is called long after the ISA bus had been 444 * attached, yet never probed, we have to call a hack function that 445 * temporarily sets the bus back to DS_ALIVE to run the probe. 446 */ 447 bus_generic_probe_hack(dev); 448 449 if (device_get_children(dev, &children, &nchildren)) 450 return; 451 452 /* 453 * First disable all pnp devices so that they don't get 454 * matched by legacy probes. 455 */ 456 if (bootverbose) 457 printf("isa_probe_children: disabling PnP devices\n"); 458 for (i = 0; i < nchildren; i++) { 459 device_t child = children[i]; 460 struct isa_device *idev = DEVTOISA(child); 461 struct isa_config config; 462 463 bzero(&config, sizeof config); 464 if (idev->id_config_cb) 465 idev->id_config_cb(idev->id_config_arg, &config, 0); 466 } 467 468 /* 469 * Next probe all non-pnp devices so that they claim their 470 * resources first. 471 */ 472 if (bootverbose) 473 printf("isa_probe_children: probing non-PnP devices\n"); 474 for (i = 0; i < nchildren; i++) { 475 device_t child = children[i]; 476 struct isa_device *idev = DEVTOISA(child); 477 478 if (TAILQ_FIRST(&idev->id_configs)) 479 continue; 480 481 device_probe_and_attach(child); 482 } 483 484 /* 485 * Finally assign resource to pnp devices and probe them. 486 */ 487 if (bootverbose) 488 printf("isa_probe_children: probing PnP devices\n"); 489 for (i = 0; i < nchildren; i++) { 490 device_t child = children[i]; 491 struct isa_device* idev = DEVTOISA(child); 492 493 if (!TAILQ_FIRST(&idev->id_configs)) 494 continue; 495 496 if (isa_assign_resources(child)) { 497 struct resource_list *rl = &idev->id_resources; 498 struct resource_list_entry *rle; 499 500 device_probe_and_attach(child); 501 502 /* 503 * Claim any unallocated resources to keep other 504 * devices from using them. 505 */ 506 SLIST_FOREACH(rle, rl, link) { 507 if (!rle->res) { 508 int rid = rle->rid; 509 resource_list_alloc(rl, dev, child, 510 rle->type, 511 &rid, 512 0, ~0, 1, 513 0 /* !RF_ACTIVE */); 514 } 515 } 516 } 517 } 518 519 free(children, M_TEMP); 520 521 isa_running = 1; 522 } 523 524 /* 525 * Add a new child with default ivars. 526 */ 527 static device_t 528 isa_add_child(device_t bus, device_t parent, int order, const char *name, int unit) 529 { 530 device_t child; 531 struct isa_device *idev; 532 533 idev = malloc(sizeof(struct isa_device), M_ISADEV, M_WAITOK | M_ZERO); 534 535 resource_list_init(&idev->id_resources); 536 TAILQ_INIT(&idev->id_configs); 537 538 child = device_add_child_ordered(parent, order, name, unit); 539 device_set_ivars(child, idev); 540 541 return child; 542 } 543 544 static int 545 isa_print_resources(struct resource_list *rl, const char *name, int type, 546 int count, const char *format) 547 { 548 struct resource_list_entry *rle; 549 int printed; 550 int i, retval = 0;; 551 552 printed = 0; 553 for (i = 0; i < count; i++) { 554 rle = resource_list_find(rl, type, i); 555 if (rle) { 556 if (printed == 0) 557 retval += printf(" %s ", name); 558 else if (printed > 0) 559 retval += printf(","); 560 printed++; 561 retval += printf(format, rle->start); 562 if (rle->count > 1) { 563 retval += printf("-"); 564 retval += printf(format, 565 rle->start + rle->count - 1); 566 } 567 } else if (i > 3) { 568 /* check the first few regardless */ 569 break; 570 } 571 } 572 return retval; 573 } 574 575 static int 576 isa_print_all_resources(device_t dev) 577 { 578 struct isa_device *idev = DEVTOISA(dev); 579 struct resource_list *rl = &idev->id_resources; 580 int retval = 0; 581 582 if (SLIST_FIRST(rl) || device_get_flags(dev)) 583 retval += printf(" at"); 584 585 retval += isa_print_resources(rl, "port", SYS_RES_IOPORT, 586 ISA_NPORT, "%#lx"); 587 retval += isa_print_resources(rl, "iomem", SYS_RES_MEMORY, 588 ISA_NMEM, "%#lx"); 589 retval += isa_print_resources(rl, "irq", SYS_RES_IRQ, 590 ISA_NIRQ, "%ld"); 591 retval += isa_print_resources(rl, "drq", SYS_RES_DRQ, 592 ISA_NDRQ, "%ld"); 593 if (device_get_flags(dev)) 594 retval += printf(" flags %#x", device_get_flags(dev)); 595 596 return retval; 597 } 598 599 static int 600 isa_print_child(device_t bus, device_t dev) 601 { 602 int retval = 0; 603 604 retval += bus_print_child_header(bus, dev); 605 retval += isa_print_all_resources(dev); 606 retval += bus_print_child_footer(bus, dev); 607 608 return (retval); 609 } 610 611 static void 612 isa_probe_nomatch(device_t dev, device_t child) 613 { 614 if (bootverbose) { 615 bus_print_child_header(dev, child); 616 printf(" failed to probe"); 617 isa_print_all_resources(child); 618 bus_print_child_footer(dev, child); 619 } 620 621 return; 622 } 623 624 static int 625 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 626 { 627 struct isa_device* idev = DEVTOISA(dev); 628 struct resource_list *rl = &idev->id_resources; 629 struct resource_list_entry *rle; 630 631 switch (index) { 632 case ISA_IVAR_PORT_0: 633 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 634 if (rle) 635 *result = rle->start; 636 else 637 *result = -1; 638 break; 639 640 case ISA_IVAR_PORT_1: 641 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 642 if (rle) 643 *result = rle->start; 644 else 645 *result = -1; 646 break; 647 648 case ISA_IVAR_PORTSIZE_0: 649 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 650 if (rle) 651 *result = rle->count; 652 else 653 *result = 0; 654 break; 655 656 case ISA_IVAR_PORTSIZE_1: 657 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 658 if (rle) 659 *result = rle->count; 660 else 661 *result = 0; 662 break; 663 664 case ISA_IVAR_MADDR_0: 665 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 666 if (rle) 667 *result = rle->start; 668 else 669 *result = -1; 670 break; 671 672 case ISA_IVAR_MADDR_1: 673 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 674 if (rle) 675 *result = rle->start; 676 else 677 *result = -1; 678 break; 679 680 case ISA_IVAR_MSIZE_0: 681 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 682 if (rle) 683 *result = rle->count; 684 else 685 *result = 0; 686 break; 687 688 case ISA_IVAR_MSIZE_1: 689 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 690 if (rle) 691 *result = rle->count; 692 else 693 *result = 0; 694 break; 695 696 case ISA_IVAR_IRQ_0: 697 rle = resource_list_find(rl, SYS_RES_IRQ, 0); 698 if (rle) 699 *result = rle->start; 700 else 701 *result = -1; 702 break; 703 704 case ISA_IVAR_IRQ_1: 705 rle = resource_list_find(rl, SYS_RES_IRQ, 1); 706 if (rle) 707 *result = rle->start; 708 else 709 *result = -1; 710 break; 711 712 case ISA_IVAR_DRQ_0: 713 rle = resource_list_find(rl, SYS_RES_DRQ, 0); 714 if (rle) 715 *result = rle->start; 716 else 717 *result = -1; 718 break; 719 720 case ISA_IVAR_DRQ_1: 721 rle = resource_list_find(rl, SYS_RES_DRQ, 1); 722 if (rle) 723 *result = rle->start; 724 else 725 *result = -1; 726 break; 727 728 case ISA_IVAR_VENDORID: 729 *result = idev->id_vendorid; 730 break; 731 732 case ISA_IVAR_SERIAL: 733 *result = idev->id_serial; 734 break; 735 736 case ISA_IVAR_LOGICALID: 737 *result = idev->id_logicalid; 738 break; 739 740 case ISA_IVAR_COMPATID: 741 *result = idev->id_compatid; 742 break; 743 744 default: 745 return ENOENT; 746 } 747 748 return 0; 749 } 750 751 static int 752 isa_write_ivar(device_t bus, device_t dev, 753 int index, uintptr_t value) 754 { 755 struct isa_device* idev = DEVTOISA(dev); 756 757 switch (index) { 758 case ISA_IVAR_PORT_0: 759 case ISA_IVAR_PORT_1: 760 case ISA_IVAR_PORTSIZE_0: 761 case ISA_IVAR_PORTSIZE_1: 762 case ISA_IVAR_MADDR_0: 763 case ISA_IVAR_MADDR_1: 764 case ISA_IVAR_MSIZE_0: 765 case ISA_IVAR_MSIZE_1: 766 case ISA_IVAR_IRQ_0: 767 case ISA_IVAR_IRQ_1: 768 case ISA_IVAR_DRQ_0: 769 case ISA_IVAR_DRQ_1: 770 return EINVAL; 771 772 case ISA_IVAR_VENDORID: 773 idev->id_vendorid = value; 774 break; 775 776 case ISA_IVAR_SERIAL: 777 idev->id_serial = value; 778 break; 779 780 case ISA_IVAR_LOGICALID: 781 idev->id_logicalid = value; 782 break; 783 784 case ISA_IVAR_COMPATID: 785 idev->id_compatid = value; 786 break; 787 788 default: 789 return (ENOENT); 790 } 791 792 return (0); 793 } 794 795 /* 796 * Free any resources which the driver missed or which we were holding for 797 * it (see isa_probe_children). 798 */ 799 static void 800 isa_child_detached(device_t dev, device_t child) 801 { 802 struct isa_device* idev = DEVTOISA(child); 803 struct resource_list *rl = &idev->id_resources; 804 struct resource_list_entry *rle; 805 806 if (TAILQ_FIRST(&idev->id_configs)) { 807 /* 808 * Claim any unallocated resources to keep other 809 * devices from using them. 810 */ 811 SLIST_FOREACH(rle, rl, link) { 812 if (!rle->res) { 813 int rid = rle->rid; 814 resource_list_alloc(rl, dev, child, 815 rle->type, 816 &rid, 0, ~0, 1, 0); 817 } 818 } 819 } 820 } 821 822 static void 823 isa_driver_added(device_t dev, driver_t *driver) 824 { 825 device_t *children; 826 int nchildren, i; 827 828 /* 829 * Don't do anything if drivers are dynamically 830 * added during autoconfiguration (cf. ymf724). 831 * since that would end up calling identify 832 * twice. 833 */ 834 if (!isa_running) 835 return; 836 837 DEVICE_IDENTIFY(driver, dev); 838 if (device_get_children(dev, &children, &nchildren)) 839 return; 840 841 for (i = 0; i < nchildren; i++) { 842 device_t child = children[i]; 843 struct isa_device *idev = DEVTOISA(child); 844 struct resource_list *rl = &idev->id_resources; 845 struct resource_list_entry *rle; 846 847 if (device_get_state(child) != DS_NOTPRESENT) 848 continue; 849 if (!device_is_enabled(child)) 850 continue; 851 852 /* 853 * Free resources which we were holding on behalf of 854 * the device. 855 */ 856 SLIST_FOREACH(rle, &idev->id_resources, link) { 857 if (rle->res) 858 resource_list_release(rl, dev, child, 859 rle->type, 860 rle->rid, 861 rle->res); 862 } 863 864 if (TAILQ_FIRST(&idev->id_configs)) 865 if (!isa_assign_resources(child)) 866 continue; 867 868 device_probe_and_attach(child); 869 870 if (TAILQ_FIRST(&idev->id_configs)) { 871 /* 872 * Claim any unallocated resources to keep other 873 * devices from using them. 874 */ 875 SLIST_FOREACH(rle, rl, link) { 876 if (!rle->res) { 877 int rid = rle->rid; 878 resource_list_alloc(rl, dev, child, 879 rle->type, 880 &rid, 881 0, ~0, 1, 882 0 /* !RF_ACTIVE */); 883 } 884 } 885 } 886 } 887 888 free(children, M_TEMP); 889 } 890 891 static int 892 isa_set_resource(device_t dev, device_t child, int type, int rid, 893 u_long start, u_long count) 894 { 895 struct isa_device* idev = DEVTOISA(child); 896 struct resource_list *rl = &idev->id_resources; 897 898 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 899 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 900 return EINVAL; 901 if (rid < 0) 902 return EINVAL; 903 if (type == SYS_RES_IOPORT && rid >= ISA_NPORT) 904 return EINVAL; 905 if (type == SYS_RES_MEMORY && rid >= ISA_NMEM) 906 return EINVAL; 907 if (type == SYS_RES_IRQ && rid >= ISA_NIRQ) 908 return EINVAL; 909 if (type == SYS_RES_DRQ && rid >= ISA_NDRQ) 910 return EINVAL; 911 912 resource_list_add(rl, type, rid, start, start + count - 1, count); 913 914 return 0; 915 } 916 917 static int 918 isa_get_resource(device_t dev, device_t child, int type, int rid, 919 u_long *startp, u_long *countp) 920 { 921 struct isa_device* idev = DEVTOISA(child); 922 struct resource_list *rl = &idev->id_resources; 923 struct resource_list_entry *rle; 924 925 rle = resource_list_find(rl, type, rid); 926 if (!rle) 927 return ENOENT; 928 929 if (startp) 930 *startp = rle->start; 931 if (countp) 932 *countp = rle->count; 933 934 return 0; 935 } 936 937 static void 938 isa_delete_resource(device_t dev, device_t child, int type, int rid) 939 { 940 struct isa_device* idev = DEVTOISA(child); 941 struct resource_list *rl = &idev->id_resources; 942 resource_list_delete(rl, type, rid); 943 } 944 945 static int 946 isa_add_config(device_t dev, device_t child, 947 int priority, struct isa_config *config) 948 { 949 struct isa_device* idev = DEVTOISA(child); 950 struct isa_config_entry *newice, *ice; 951 952 newice = malloc(sizeof *ice, M_DEVBUF, M_WAITOK); 953 newice->ice_priority = priority; 954 newice->ice_config = *config; 955 956 TAILQ_FOREACH(ice, &idev->id_configs, ice_link) { 957 if (ice->ice_priority > priority) 958 break; 959 } 960 if (ice) 961 TAILQ_INSERT_BEFORE(ice, newice, ice_link); 962 else 963 TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link); 964 965 return 0; 966 } 967 968 static void 969 isa_set_config_callback(device_t dev, device_t child, 970 isa_config_cb *fn, void *arg) 971 { 972 struct isa_device* idev = DEVTOISA(child); 973 974 idev->id_config_cb = fn; 975 idev->id_config_arg = arg; 976 } 977 978 static int 979 isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids) 980 { 981 struct isa_device* idev = DEVTOISA(child); 982 983 if (!idev->id_vendorid) 984 return ENOENT; 985 986 while (ids->ip_id) { 987 /* 988 * Really ought to support >1 compat id per device. 989 */ 990 if (idev->id_logicalid == ids->ip_id 991 || idev->id_compatid == ids->ip_id) { 992 if (ids->ip_desc) 993 device_set_desc(child, ids->ip_desc); 994 return 0; 995 } 996 ids++; 997 } 998 999 return ENXIO; 1000 } 1001 1002 static device_method_t isa_methods[] = { 1003 /* Device interface */ 1004 DEVMETHOD(device_probe, isa_probe), 1005 DEVMETHOD(device_attach, isa_attach), 1006 DEVMETHOD(device_detach, bus_generic_detach), 1007 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1008 DEVMETHOD(device_suspend, bus_generic_suspend), 1009 DEVMETHOD(device_resume, bus_generic_resume), 1010 1011 /* Bus interface */ 1012 DEVMETHOD(bus_add_child, isa_add_child), 1013 DEVMETHOD(bus_print_child, isa_print_child), 1014 DEVMETHOD(bus_probe_nomatch, isa_probe_nomatch), 1015 DEVMETHOD(bus_read_ivar, isa_read_ivar), 1016 DEVMETHOD(bus_write_ivar, isa_write_ivar), 1017 DEVMETHOD(bus_child_detached, isa_child_detached), 1018 DEVMETHOD(bus_driver_added, isa_driver_added), 1019 DEVMETHOD(bus_alloc_resource, isa_alloc_resource), 1020 DEVMETHOD(bus_release_resource, isa_release_resource), 1021 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1022 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1023 DEVMETHOD(bus_setup_intr, isa_setup_intr), 1024 DEVMETHOD(bus_teardown_intr, isa_teardown_intr), 1025 DEVMETHOD(bus_set_resource, isa_set_resource), 1026 DEVMETHOD(bus_get_resource, isa_get_resource), 1027 DEVMETHOD(bus_delete_resource, isa_delete_resource), 1028 1029 /* ISA interface */ 1030 DEVMETHOD(isa_add_config, isa_add_config), 1031 DEVMETHOD(isa_set_config_callback, isa_set_config_callback), 1032 DEVMETHOD(isa_pnp_probe, isa_pnp_probe), 1033 1034 { 0, 0 } 1035 }; 1036 1037 static driver_t isa_driver = { 1038 "isa", 1039 isa_methods, 1040 1, /* no softc */ 1041 }; 1042 1043 /* 1044 * ISA can be attached to a PCI-ISA bridge or directly to the nexus. 1045 */ 1046 DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0); 1047 #ifdef __i386__ 1048 DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0); 1049 #endif 1050 1051