isa.c revision 45720
171SN/A/*- 2551SN/A * Copyright (c) 1998 Doug Rabson 371SN/A * All rights reserved. 471SN/A * 571SN/A * Redistribution and use in source and binary forms, with or without 671SN/A * modification, are permitted provided that the following conditions 7157SN/A * are met: 871SN/A * 1. Redistributions of source code must retain the above copyright 9157SN/A * notice, this list of conditions and the following disclaimer. 1071SN/A * 2. Redistributions in binary form must reproduce the above copyright 1171SN/A * notice, this list of conditions and the following disclaimer in the 1271SN/A * documentation and/or other materials provided with the distribution. 1371SN/A * 1471SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1571SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1671SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1771SN/A * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1871SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1971SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2071SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21157SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22157SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23157SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2471SN/A * SUCH DAMAGE. 2571SN/A * 260SN/A * $Id: isa.c,v 1.4 1998/09/16 08:23:51 dfr Exp $ 270SN/A */ 280SN/A 290SN/A/* 300SN/A * Modifications for Intel architecture by Garrett A. Wollman. 310SN/A * Copyright 1998 Massachusetts Institute of Technology 320SN/A * 330SN/A * Permission to use, copy, modify, and distribute this software and 340SN/A * its documentation for any purpose and without fee is hereby 350SN/A * granted, provided that both the above copyright notice and this 360SN/A * permission notice appear in all copies, that both the above 370SN/A * copyright notice and this permission notice appear in all 380SN/A * supporting documentation, and that the name of M.I.T. not be used 390SN/A * in advertising or publicity pertaining to distribution of the 400SN/A * software without specific, written prior permission. M.I.T. makes 410SN/A * no representations about the suitability of this software for any 420SN/A * purpose. It is provided "as is" without express or implied 430SN/A * warranty. 440SN/A * 450SN/A * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 460SN/A * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 470SN/A * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 480SN/A * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 490SN/A * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 500SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 510SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 520SN/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 530SN/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 540SN/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 550SN/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 560SN/A * SUCH DAMAGE. 570SN/A */ 580SN/A 590SN/A#include <sys/param.h> 600SN/A#include <sys/systm.h> 610SN/A#include <sys/kernel.h> 620SN/A#include <sys/bus.h> 630SN/A#include <sys/malloc.h> 640SN/A#include <sys/module.h> 650SN/A#include <machine/bus.h> 660SN/A#include <sys/rman.h> 67263SN/A 68263SN/A#include <machine/resource.h> 69263SN/A 70263SN/A#include <isa/isavar.h> 71452SN/A 72263SN/AMALLOC_DEFINE(M_ISADEV, "isadev", "ISA device"); 73263SN/A 74263SN/A/* 75263SN/A * The structure used to attach devices to the isa bus. 76263SN/A */ 77263SN/Astruct isa_device { 78263SN/A short id_port[ISA_NPORT_IVARS]; 79263SN/A u_short id_portsize[ISA_NPORT_IVARS]; 80263SN/A vm_offset_t id_maddr[ISA_NMEM_IVARS]; 81263SN/A vm_size_t id_msize[ISA_NMEM_IVARS]; 82263SN/A int id_irq[ISA_NIRQ_IVARS]; 83263SN/A int id_drq[ISA_NDRQ_IVARS]; 84263SN/A int id_flags; 85263SN/A struct resource *id_portres[ISA_NPORT_IVARS]; 86263SN/A struct resource *id_memres[ISA_NMEM_IVARS]; 87263SN/A struct resource *id_irqres[ISA_NIRQ_IVARS]; 88263SN/A struct resource *id_drqres[ISA_NDRQ_IVARS]; 89263SN/A}; 90263SN/A 91263SN/A#define DEVTOISA(dev) ((struct isa_device *) device_get_ivars(dev)) 92263SN/A 93263SN/Astatic devclass_t isa_devclass; 94263SN/A 95263SN/Astatic void 96263SN/Aisa_add_device(device_t dev, const char *name, int unit) 97263SN/A{ 98263SN/A struct isa_device *idev; 99263SN/A device_t child; 100263SN/A int sensitive, t; 101263SN/A static device_t last_sensitive; 102263SN/A 103263SN/A if (resource_int_value(name, unit, "sensitive", &sensitive) != 0) 104263SN/A sensitive = 0; 105263SN/A 106263SN/A idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT); 107263SN/A if (!idev) 108263SN/A return; 109263SN/A bzero(idev, sizeof *idev); 110263SN/A 111263SN/A if (resource_int_value(name, unit, "port", &t) == 0) 112263SN/A idev->id_port[0] = t; 113561SN/A else 114263SN/A idev->id_port[0] = -1; 115263SN/A idev->id_port[1] = 0; 116263SN/A 117452SN/A if (resource_int_value(name, unit, "portsize", &t) == 0) 118263SN/A idev->id_portsize[0] = t; 119263SN/A else 120263SN/A idev->id_portsize[0] = 0; 121263SN/A idev->id_portsize[1] = 0; 122263SN/A 123263SN/A if (resource_int_value(name, unit, "maddr", &t) == 0) 124263SN/A idev->id_maddr[0] = t; 125263SN/A else 126263SN/A idev->id_maddr[0] = 0; 127263SN/A idev->id_maddr[1] = 0; 128263SN/A 129263SN/A if (resource_int_value(name, unit, "msize", &t) == 0) 130263SN/A idev->id_msize[0] = t; 131263SN/A else 132263SN/A idev->id_msize[0] = 0; 133263SN/A idev->id_msize[1] = 0; 134263SN/A 135263SN/A if (resource_int_value(name, unit, "flags", &t) == 0) 136263SN/A idev->id_flags = t; 137263SN/A else 138263SN/A idev->id_flags = 0; 139263SN/A 140263SN/A if (resource_int_value(name, unit, "irq", &t) == 0) 141263SN/A idev->id_irq[0] = t; 142263SN/A else 143263SN/A idev->id_irq[0] = -1; 144263SN/A idev->id_irq[1] = -1; 145263SN/A 146263SN/A if (resource_int_value(name, unit, "drq", &t) == 0) 147263SN/A idev->id_drq[0] = t; 148263SN/A else 149452SN/A idev->id_drq[0] = -1; 150263SN/A idev->id_drq[1] = -1; 151263SN/A 152263SN/A if (sensitive) 153263SN/A child = device_add_child_after(dev, last_sensitive, name, 154263SN/A unit, idev); 155263SN/A else 156263SN/A child = device_add_child(dev, name, unit, idev); 157263SN/A if (child == 0) 1580SN/A return; 1590SN/A else if (sensitive) 1600SN/A last_sensitive = child; 1610SN/A 1620SN/A if (resource_int_value(name, unit, "disabled", &t) == 0 && t != 0) 1630SN/A device_disable(child); 1640SN/A} 1650SN/A 1660SN/A/* 167263SN/A * At 'probe' time, we add all the devices which we know about to the 168263SN/A * bus. The generic attach routine will probe and attach them if they 169263SN/A * are alive. 170263SN/A */ 1710SN/Astatic int 1720SN/Aisa_probe(device_t dev) 1730SN/A{ 1740SN/A int i; 1750SN/A static char buf[] = "isaXXX"; 176452SN/A 1770SN/A device_set_desc(dev, "ISA bus"); 178 179 /* 180 * Add all devices configured to be attached to isa0. 181 */ 182 sprintf(buf, "isa%d", device_get_unit(dev)); 183 for (i = resource_query_string(-1, "at", buf); 184 i != -1; 185 i = resource_query_string(i, "at", buf)) { 186 isa_add_device(dev, resource_query_name(i), 187 resource_query_unit(i)); 188 } 189 190 /* 191 * and isa? 192 */ 193 for (i = resource_query_string(-1, "at", "isa"); 194 i != -1; 195 i = resource_query_string(i, "at", "isa")) { 196 isa_add_device(dev, resource_query_name(i), 197 resource_query_unit(i)); 198 } 199 200 isa_wrap_old_drivers(); 201 202 return 0; 203} 204 205extern device_t isa_bus_device; 206 207static int 208isa_attach(device_t dev) 209{ 210 /* 211 * Arrange for bus_generic_attach(dev) to be called later. 212 */ 213 isa_bus_device = dev; 214 return 0; 215} 216 217static void 218isa_print_child(device_t bus, device_t dev) 219{ 220 struct isa_device *id = DEVTOISA(dev); 221 222 if (id->id_port[0] > 0 || id->id_port[1] > 0 223 || id->id_maddr[0] > 0 || id->id_maddr[1] > 0 224 || id->id_irq[0] >= 0 || id->id_irq[1] >= 0 225 || id->id_drq[0] >= 0 || id->id_drq[1] >= 0) 226 printf(" at"); 227 if (id->id_port[0] > 0 && id->id_port[1] > 0) { 228 printf(" ports %#x", (u_int)id->id_port[0]); 229 if (id->id_portsize[0] > 1) 230 printf("-%#x", (u_int)(id->id_port[0] 231 + id->id_portsize[0] - 1)); 232 printf(" and %#x", (u_int)id->id_port[1]); 233 if (id->id_portsize[1] > 1) 234 printf("-%#x", (u_int)(id->id_port[1] 235 + id->id_portsize[1] - 1)); 236 } else if (id->id_port[0] > 0) { 237 printf(" port %#x", (u_int)id->id_port[0]); 238 if (id->id_portsize[0] > 1) 239 printf("-%#x", (u_int)(id->id_port[0] 240 + id->id_portsize[0] - 1)); 241 } else if (id->id_port[1] > 0) { 242 printf(" port %#x", (u_int)id->id_port[1]); 243 if (id->id_portsize[1] > 1) 244 printf("-%#x", (u_int)(id->id_port[1] 245 + id->id_portsize[1] - 1)); 246 } 247 if (id->id_maddr[0] && id->id_maddr[1]) { 248 printf(" iomem %#x", (u_int)id->id_maddr[0]); 249 if (id->id_msize[0]) 250 printf("-%#x", (u_int)(id->id_maddr[0] 251 + id->id_msize[0] - 1)); 252 printf(" and %#x", (u_int)id->id_maddr[1]); 253 if (id->id_msize[1]) 254 printf("-%#x", (u_int)(id->id_maddr[1] 255 + id->id_msize[1] - 1)); 256 } else if (id->id_maddr[0]) { 257 printf(" iomem %#x", (u_int)id->id_maddr[0]); 258 if (id->id_msize[0]) 259 printf("-%#x", (u_int)(id->id_maddr[0] 260 + id->id_msize[0] - 1)); 261 } else if (id->id_maddr[1]) { 262 printf(" iomem %#x", (u_int)id->id_maddr[1]); 263 if (id->id_msize[1]) 264 printf("-%#x", (u_int)(id->id_maddr[1] 265 + id->id_msize[1] - 1)); 266 } 267 if (id->id_irq[0] >= 0 && id->id_irq[1] >= 0) 268 printf(" irqs %d and %d", id->id_irq[0], id->id_irq[1]); 269 else if (id->id_irq[0] >= 0) 270 printf(" irq %d", id->id_irq[0]); 271 else if (id->id_irq[1] >= 0) 272 printf(" irq %d", id->id_irq[1]); 273 if (id->id_drq[0] >= 0 && id->id_drq[1] >= 0) 274 printf(" drqs %d and %d", id->id_drq[0], id->id_drq[1]); 275 else if (id->id_drq[0] >= 0) 276 printf(" drq %d", id->id_drq[0]); 277 else if (id->id_drq[1] >= 0) 278 printf(" drq %d", id->id_drq[1]); 279 280 if (id->id_flags) 281 printf(" flags %#x", id->id_flags); 282 283 printf(" on %s%d", 284 device_get_name(bus), device_get_unit(bus)); 285} 286 287static int 288isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 289{ 290 struct isa_device* idev = DEVTOISA(dev); 291 292 switch (index) { 293 case ISA_IVAR_PORT_0: 294 *result = idev->id_port[0]; 295 break; 296 case ISA_IVAR_PORT_1: 297 *result = idev->id_port[1]; 298 break; 299 case ISA_IVAR_PORTSIZE_0: 300 *result = idev->id_portsize[0]; 301 break; 302 case ISA_IVAR_PORTSIZE_1: 303 *result = idev->id_portsize[1]; 304 break; 305 case ISA_IVAR_MADDR_0: 306 *result = idev->id_maddr[0]; 307 break; 308 case ISA_IVAR_MADDR_1: 309 *result = idev->id_maddr[1]; 310 break; 311 case ISA_IVAR_MSIZE_0: 312 *result = idev->id_msize[0]; 313 break; 314 case ISA_IVAR_MSIZE_1: 315 *result = idev->id_msize[1]; 316 break; 317 case ISA_IVAR_IRQ_0: 318 *result = idev->id_irq[0]; 319 break; 320 case ISA_IVAR_IRQ_1: 321 *result = idev->id_irq[1]; 322 break; 323 case ISA_IVAR_DRQ_0: 324 *result = idev->id_drq[0]; 325 break; 326 case ISA_IVAR_DRQ_1: 327 *result = idev->id_drq[1]; 328 break; 329 case ISA_IVAR_FLAGS: 330 *result = idev->id_flags; 331 break; 332 } 333 return ENOENT; 334} 335 336/* 337 * XXX -- this interface is pretty much irrelevant in the presence of 338 * BUS_ALLOC_RESOURCE / BUS_RELEASE_RESOURCE (at least for the ivars which 339 * are defined at this point). 340 */ 341static int 342isa_write_ivar(device_t bus, device_t dev, 343 int index, uintptr_t value) 344{ 345 struct isa_device* idev = DEVTOISA(dev); 346 347 switch (index) { 348 case ISA_IVAR_PORT_0: 349 idev->id_port[0] = value; 350 break; 351 case ISA_IVAR_PORT_1: 352 idev->id_port[1] = value; 353 break; 354 case ISA_IVAR_PORTSIZE_0: 355 idev->id_portsize[0] = value; 356 break; 357 case ISA_IVAR_PORTSIZE_1: 358 idev->id_portsize[1] = value; 359 break; 360 case ISA_IVAR_MADDR_0: 361 idev->id_maddr[0] = value; 362 break; 363 case ISA_IVAR_MADDR_1: 364 idev->id_maddr[1] = value; 365 break; 366 case ISA_IVAR_MSIZE_0: 367 idev->id_msize[0] = value; 368 break; 369 case ISA_IVAR_MSIZE_1: 370 idev->id_msize[1] = value; 371 break; 372 case ISA_IVAR_IRQ_0: 373 idev->id_irq[0] = value; 374 break; 375 case ISA_IVAR_IRQ_1: 376 idev->id_irq[1] = value; 377 break; 378 case ISA_IVAR_DRQ_0: 379 idev->id_drq[0] = value; 380 break; 381 case ISA_IVAR_DRQ_1: 382 idev->id_drq[1] = value; 383 break; 384 case ISA_IVAR_FLAGS: 385 idev->id_flags = value; 386 break; 387 default: 388 return (ENOENT); 389 } 390 return (0); 391} 392 393/* 394 * This implementation simply passes the request up to the parent 395 * bus, which in our case is the special i386 nexus, substituting any 396 * configured values if the caller defaulted. We can get away with 397 * this because there is no special mapping for ISA resources on an Intel 398 * platform. When porting this code to another architecture, it may be 399 * necessary to interpose a mapping layer here. 400 */ 401static struct resource * 402isa_alloc_resource(device_t bus, device_t child, int type, int *rid, 403 u_long start, u_long end, u_long count, u_int flags) 404{ 405 int isdefault; 406 struct resource *rv, **rvp = 0; 407 struct isa_device *id = DEVTOISA(child); 408 409 if (child) { 410 /* 411 * If this is our child, then use the isa_device to find 412 * defaults and to record results. 413 */ 414 if (device_get_devclass(device_get_parent(child)) == isa_devclass) 415 id = DEVTOISA(child); 416 else 417 id = NULL; 418 } else 419 id = NULL; 420 isdefault = (id != NULL && start == 0UL && end == ~0UL && *rid == 0); 421 if (*rid > 1) 422 return 0; 423 424 switch (type) { 425 case SYS_RES_IRQ: 426 if (isdefault && id->id_irq[0] >= 0) { 427 start = id->id_irq[0]; 428 end = id->id_irq[0]; 429 count = 1; 430 } 431 if (id) 432 rvp = &id->id_irqres[*rid]; 433 break; 434 435 case SYS_RES_DRQ: 436 if (isdefault && id->id_drq[0] >= 0) { 437 start = id->id_drq[0]; 438 end = id->id_drq[0]; 439 count = 1; 440 } 441 if (id) 442 rvp = &id->id_drqres[*rid]; 443 break; 444 445 case SYS_RES_MEMORY: 446 if (isdefault && id->id_maddr[0]) { 447 start = id->id_maddr[0]; 448 count = max(count, (u_long)id->id_msize[0]); 449 end = id->id_maddr[0] + count; 450 } 451 if (id) 452 rvp = &id->id_memres[*rid]; 453 break; 454 455 case SYS_RES_IOPORT: 456 if (isdefault && id->id_port[0]) { 457 start = id->id_port[0]; 458 count = max(count, (u_long)id->id_portsize[0]); 459 end = id->id_port[0] + count; 460 } 461 if (id) 462 rvp = &id->id_portres[*rid]; 463 break; 464 465 default: 466 return 0; 467 } 468 469 /* 470 * If the client attempts to reallocate a resource without 471 * releasing what was there previously, die horribly so that 472 * he knows how he !@#$ed up. 473 */ 474 if (rvp && *rvp != 0) 475 panic("%s%d: (%d, %d) not free for %s%d\n", 476 device_get_name(bus), device_get_unit(bus), 477 type, *rid, 478 device_get_name(child), device_get_unit(child)); 479 480 /* 481 * nexus_alloc_resource had better not change *rid... 482 */ 483 rv = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, 484 start, end, count, flags); 485 if (rvp && (*rvp = rv) != 0) { 486 switch (type) { 487 case SYS_RES_MEMORY: 488 id->id_maddr[*rid] = rv->r_start; 489 id->id_msize[*rid] = count; 490 break; 491 case SYS_RES_IOPORT: 492 id->id_port[*rid] = rv->r_start; 493 id->id_portsize[*rid] = count; 494 break; 495 case SYS_RES_IRQ: 496 id->id_irq[*rid] = rv->r_start; 497 break; 498 case SYS_RES_DRQ: 499 id->id_drq[*rid] = rv->r_start; 500 break; 501 } 502 } 503 return rv; 504} 505 506static int 507isa_release_resource(device_t bus, device_t child, int type, int rid, 508 struct resource *r) 509{ 510 int rv; 511 struct isa_device *id = DEVTOISA(child); 512 513 if (rid > 1) 514 return EINVAL; 515 516 switch (type) { 517 case SYS_RES_IRQ: 518 case SYS_RES_DRQ: 519 case SYS_RES_IOPORT: 520 case SYS_RES_MEMORY: 521 break; 522 default: 523 return (ENOENT); 524 } 525 526 rv = BUS_RELEASE_RESOURCE(device_get_parent(bus), child, type, rid, r); 527 528#if 0 529 if (rv) { 530 /* Kludge, isa as a child of pci doesn't have mapping regs */ 531 printf("WARNING: isa_release_resource: BUS_RELEASE_RESOURCE() failed: %d\n", rv); 532 rv = 0; 533 } 534#endif 535 536 if (rv == 0) { 537 switch (type) { 538 case SYS_RES_IRQ: 539 id->id_irqres[rid] = 0; 540 id->id_irq[rid] = -1; 541 break; 542 543 case SYS_RES_DRQ: 544 id->id_drqres[rid] = 0; 545 id->id_drq[rid] = -1; 546 break; 547 548 case SYS_RES_MEMORY: 549 id->id_memres[rid] = 0; 550 id->id_maddr[rid] = 0; 551 id->id_msize[rid] = 0; 552 break; 553 554 case SYS_RES_IOPORT: 555 id->id_portres[rid] = 0; 556 id->id_port[rid] = 0; 557 id->id_portsize[rid] = 0; 558 break; 559 560 default: 561 return ENOENT; 562 } 563 } 564 565 return rv; 566} 567 568/* 569 * We can't use the bus_generic_* versions of these methods because those 570 * methods always pass the bus param as the requesting device, and we need 571 * to pass the child (the i386 nexus knows about this and is prepared to 572 * deal). 573 */ 574static int 575isa_setup_intr(device_t bus, device_t child, struct resource *r, 576 void (*ihand)(void *), void *arg, void **cookiep) 577{ 578 return (BUS_SETUP_INTR(device_get_parent(bus), child, r, ihand, arg, 579 cookiep)); 580} 581 582static int 583isa_teardown_intr(device_t bus, device_t child, struct resource *r, 584 void *cookie) 585{ 586 return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, cookie)); 587} 588 589static device_method_t isa_methods[] = { 590 /* Device interface */ 591 DEVMETHOD(device_probe, isa_probe), 592 DEVMETHOD(device_attach, isa_attach), 593 DEVMETHOD(device_detach, bus_generic_detach), 594 DEVMETHOD(device_shutdown, bus_generic_shutdown), 595 DEVMETHOD(device_suspend, bus_generic_suspend), 596 DEVMETHOD(device_resume, bus_generic_resume), 597 598 /* Bus interface */ 599 DEVMETHOD(bus_print_child, isa_print_child), 600 DEVMETHOD(bus_read_ivar, isa_read_ivar), 601 DEVMETHOD(bus_write_ivar, isa_write_ivar), 602 DEVMETHOD(bus_alloc_resource, isa_alloc_resource), 603 DEVMETHOD(bus_release_resource, isa_release_resource), 604 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 605 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 606 DEVMETHOD(bus_setup_intr, isa_setup_intr), 607 DEVMETHOD(bus_teardown_intr, isa_teardown_intr), 608 609 { 0, 0 } 610}; 611 612static driver_t isa_driver = { 613 "isa", 614 isa_methods, 615 DRIVER_TYPE_MISC, 616 1, /* no softc */ 617}; 618 619/* 620 * ISA can be attached to a PCI-ISA bridge or directly to the nexus. 621 */ 622DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0); 623DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0); 624