eisaconf.c revision 45791
1/* 2 * EISA bus probe and attach routines 3 * 4 * Copyright (c) 1995, 1996 Justin T. Gibbs. 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 immediately at the beginning of the file, without modification, 12 * this list of conditions, and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $Id: eisaconf.c,v 1.37 1999/01/14 06:22:03 jdp Exp $ 32 */ 33 34#include "opt_eisa.h" 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/queue.h> 39#include <sys/malloc.h> 40#include <sys/kernel.h> 41#include <sys/module.h> 42#include <sys/bus.h> 43 44#include <machine/limits.h> 45#include <machine/bus.h> 46#include <machine/resource.h> 47#include <sys/rman.h> 48 49#include <i386/eisa/eisaconf.h> 50 51#include <sys/interrupt.h> 52 53typedef struct resvaddr { 54 u_long addr; /* start address */ 55 u_long size; /* size of reserved area */ 56 int flags; 57 struct resource *res; /* resource manager handle */ 58 LIST_ENTRY(resvaddr) links; /* List links */ 59} resvaddr_t; 60 61LIST_HEAD(resvlist, resvaddr); 62 63struct irq_node { 64 int irq_no; 65 void *idesc; 66 TAILQ_ENTRY(irq_node) links; 67}; 68 69TAILQ_HEAD(irqlist, irq_node); 70 71struct eisa_ioconf { 72 int slot; 73 struct resvlist ioaddrs; /* list of reserved I/O ranges */ 74 struct resvlist maddrs; /* list of reserved memory ranges */ 75 struct irqlist irqs; /* list of reserved irqs */ 76}; 77 78/* To be replaced by the "super device" generic device structure... */ 79struct eisa_device { 80 eisa_id_t id; 81 struct eisa_ioconf ioconf; 82}; 83 84 85/* 86 * Local function declarations and static variables 87 */ 88#if 0 89static void eisa_reg_print __P((struct eisa_device *e_dev, 90 char *string, char *separator)); 91static int eisa_add_resvaddr __P((struct eisa_device *e_dev, 92 struct resvlist *head, u_long base, 93 u_long size, int flags)); 94static int eisa_reg_resvaddr __P((struct eisa_device *e_dev, 95 struct resvlist *head, resvaddr_t *resvaddr, 96 int *reg_count)); 97#endif 98 99#if 0 100/* 101 * Keep some state about what we've printed so far 102 * to make probe output pretty. 103 */ 104static struct { 105 int in_registration;/* reg_start has been called */ 106 int num_interrupts; 107 int num_ioaddrs; 108 int num_maddrs; 109 int column; /* How much we have output so far. */ 110#define MAX_COL 80 111} reg_state; 112#endif 113 114/* Global variable, so UserConfig can change it. */ 115#ifndef EISA_SLOTS 116#define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */ 117#endif 118int num_eisa_slots = EISA_SLOTS; 119 120static devclass_t eisa_devclass; 121 122static int 123mainboard_probe(device_t dev) 124{ 125 char *idstring; 126 eisa_id_t id = eisa_get_id(dev); 127 128 if (eisa_get_slot(dev) != 0) 129 return (ENXIO); 130 131 idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1, 132 M_DEVBUF, M_NOWAIT); 133 if (idstring == NULL) { 134 panic("Eisa probe unable to malloc"); 135 } 136 sprintf(idstring, "%c%c%c%x%x (System Board)", 137 EISA_MFCTR_CHAR0(id), 138 EISA_MFCTR_CHAR1(id), 139 EISA_MFCTR_CHAR2(id), 140 EISA_PRODUCT_ID(id), 141 EISA_REVISION_ID(id)); 142 device_set_desc(dev, idstring); 143 144 return (0); 145} 146 147static int 148mainboard_attach(device_t dev) 149{ 150 return (0); 151} 152 153static device_method_t mainboard_methods[] = { 154 /* Device interface */ 155 DEVMETHOD(device_probe, mainboard_probe), 156 DEVMETHOD(device_attach, mainboard_attach), 157 158 { 0, 0 } 159}; 160 161static driver_t mainboard_driver = { 162 "mainboard", 163 mainboard_methods, 164 DRIVER_TYPE_MISC, 165 1, 166}; 167 168static devclass_t mainboard_devclass; 169 170DRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0); 171 172/* 173** probe for EISA devices 174*/ 175static int 176eisa_probe(device_t dev) 177{ 178 int i,slot; 179 struct eisa_device *e_dev; 180 int eisaBase = 0xc80; 181 eisa_id_t eisa_id; 182 183 for (slot = 0; slot < num_eisa_slots; eisaBase+=0x1000, slot++) { 184 int id_size = sizeof(eisa_id); 185 eisa_id = 0; 186 for( i = 0; i < id_size; i++ ) { 187 outb(eisaBase,0x80 + i); /*Some cards require priming*/ 188 eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT); 189 } 190 if (eisa_id & 0x80000000) 191 continue; /* no EISA card in slot */ 192 193 /* Prepare an eisa_device_node for this slot */ 194 e_dev = (struct eisa_device *)malloc(sizeof(*e_dev), 195 M_DEVBUF, M_NOWAIT); 196 if (!e_dev) { 197 printf("eisa0: cannot malloc eisa_device"); 198 break; /* Try to attach what we have already */ 199 } 200 bzero(e_dev, sizeof(*e_dev)); 201 202 e_dev->id = eisa_id; 203 204 e_dev->ioconf.slot = slot; 205 206 /* Initialize our lists of reserved addresses */ 207 LIST_INIT(&(e_dev->ioconf.ioaddrs)); 208 LIST_INIT(&(e_dev->ioconf.maddrs)); 209 TAILQ_INIT(&(e_dev->ioconf.irqs)); 210 211 device_add_child(dev, NULL, -1, e_dev); 212 } 213 214 return 0; 215} 216 217static void 218eisa_print_child(device_t dev, device_t child) 219{ 220 /* XXX print resource descriptions? */ 221 printf(" at slot %d", eisa_get_slot(child)); 222 printf(" on %s", device_get_nameunit(dev)); 223} 224 225static int 226eisa_find_irq(struct eisa_device *e_dev, int rid) 227{ 228 int i; 229 struct irq_node *irq; 230 231 for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs); 232 i < rid && irq; 233 i++, irq = TAILQ_NEXT(irq, links)) 234 ; 235 236 if (irq) 237 return irq->irq_no; 238 else 239 return -1; 240} 241 242static struct resvaddr * 243eisa_find_maddr(struct eisa_device *e_dev, int rid) 244{ 245 int i; 246 struct resvaddr *resv; 247 248 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs); 249 i < rid && resv; 250 i++, resv = LIST_NEXT(resv, links)) 251 ; 252 253 return resv; 254} 255 256static struct resvaddr * 257eisa_find_ioaddr(struct eisa_device *e_dev, int rid) 258{ 259 int i; 260 struct resvaddr *resv; 261 262 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs); 263 i < rid && resv; 264 i++, resv = LIST_NEXT(resv, links)) 265 ; 266 267 return resv; 268} 269 270static int 271eisa_read_ivar(device_t dev, device_t child, int which, u_long *result) 272{ 273 struct eisa_device *e_dev = device_get_ivars(child); 274 275 switch (which) { 276 case EISA_IVAR_SLOT: 277 *result = e_dev->ioconf.slot; 278 break; 279 280 case EISA_IVAR_ID: 281 *result = e_dev->id; 282 break; 283 284 case EISA_IVAR_IRQ: 285 /* XXX only first irq */ 286 *result = eisa_find_irq(e_dev, 0); 287 break; 288 289 default: 290 return (ENOENT); 291 } 292 293 return (0); 294} 295 296static int 297eisa_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 298{ 299 return (EINVAL); 300} 301 302static struct resource * 303eisa_alloc_resource(device_t dev, device_t child, int type, int *rid, 304 u_long start, u_long end, u_long count, u_int flags) 305{ 306 int isdefault; 307 struct eisa_device *e_dev = device_get_ivars(child); 308 struct resource *rv, **rvp = 0; 309 310 isdefault = (device_get_parent(child) == dev 311 && start == 0UL && end == ~0UL && count == 1); 312 313 switch (type) { 314 case SYS_RES_IRQ: 315 if (isdefault) { 316 int irq = eisa_find_irq(e_dev, *rid); 317 if (irq == -1) 318 return 0; 319 start = end = irq; 320 count = 1; 321 } 322 break; 323 324 case SYS_RES_MEMORY: 325 if (isdefault) { 326 struct resvaddr *resv; 327 328 resv = eisa_find_maddr(e_dev, *rid); 329 if (!resv) 330 return 0; 331 332 start = resv->addr; 333 end = resv->size - 1; 334 count = resv->size; 335 rvp = &resv->res; 336 } 337 break; 338 339 case SYS_RES_IOPORT: 340 if (isdefault) { 341 struct resvaddr *resv; 342 343 resv = eisa_find_ioaddr(e_dev, *rid); 344 if (!resv) 345 return 0; 346 347 start = resv->addr; 348 end = resv->size - 1; 349 count = resv->size; 350 rvp = &resv->res; 351 } 352 break; 353 354 default: 355 return 0; 356 } 357 358 rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 359 type, rid, start, end, count, flags); 360 if (rvp) 361 *rvp = rv; 362 363 return rv; 364} 365 366static int 367eisa_release_resource(device_t dev, device_t child, int type, int rid, 368 struct resource *r) 369{ 370 int rv; 371 struct eisa_device *e_dev = device_get_ivars(child); 372 struct resvaddr *resv = 0; 373 374 switch (type) { 375 case SYS_RES_IRQ: 376 if (eisa_find_irq(e_dev, rid) == -1) 377 return EINVAL; 378 break; 379 380 case SYS_RES_MEMORY: 381 if (device_get_parent(child) == dev) 382 resv = eisa_find_maddr(e_dev, rid); 383 break; 384 385 386 case SYS_RES_IOPORT: 387 if (device_get_parent(child) == dev) 388 resv = eisa_find_ioaddr(e_dev, rid); 389 break; 390 391 default: 392 return (ENOENT); 393 } 394 395 rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r); 396 397 if (rv == 0) { 398 if (resv) 399 resv->res = 0; 400 } 401 402 return rv; 403} 404 405#if 0 406 407/* Interrupt and I/O space registration facitlities */ 408void 409eisa_reg_start(e_dev) 410 struct eisa_device *e_dev; 411{ 412 /* 413 * Announce the device. 414 */ 415 char *string; 416 417 reg_state.in_registration = 1; 418 reg_state.num_interrupts = 0; 419 reg_state.num_ioaddrs = 0; 420 reg_state.num_maddrs = 0; 421 reg_state.column = 0; 422 423 string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1, 424 M_TEMP, M_NOWAIT); 425 if(!string) { 426 printf("eisa0: cannot malloc device description string\n"); 427 return; 428 } 429 sprintf(string, " <%s>", e_dev->full_name); 430 eisa_reg_print(e_dev, string, /*separator=*/NULL); 431 free(string, M_TEMP); 432} 433 434/* 435 * Output registration information mindfull of screen wrap. 436 * Output an optional character separator before the string 437 * if the line does not wrap. 438 */ 439static void 440eisa_reg_print(e_dev, string, separator) 441 struct eisa_device *e_dev; 442 char *string; 443 char *separator; 444{ 445 int len = strlen(string); 446 447 if(separator) 448 len++; 449 450 if(reg_state.column + len > MAX_COL) { 451 printf("\n"); 452 reg_state.column = 0; 453 } 454 else if(separator) { 455 printf("%c", *separator); 456 reg_state.column++; 457 } 458 459 if(reg_state.column == 0) 460 reg_state.column += printf("%s%ld:%s", 461 e_dev->driver->name, 462 e_dev->unit, 463 string); 464 else 465 reg_state.column += printf("%s", string); 466} 467 468/* Interrupt and I/O space registration facitlities */ 469void 470eisa_reg_end(e_dev) 471 struct eisa_device *e_dev; 472{ 473 if( reg_state.in_registration ) 474 { 475 char string[25]; 476 477 snprintf(string, sizeof(string), " on %s0 slot %d", 478 mainboard_drv.name, 479 e_dev->ioconf.slot); 480 eisa_reg_print(e_dev, string, NULL); 481 printf("\n"); 482 reg_state.in_registration = 0; 483 } 484 else 485 printf("eisa_reg_end called outside of a " 486 "registration session\n"); 487} 488 489#endif /* 0 */ 490 491int 492eisa_add_intr(dev, irq) 493 device_t dev; 494 int irq; 495{ 496 struct eisa_device *e_dev = device_get_ivars(dev); 497 struct irq_node *irq_info; 498 499 irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF, 500 M_NOWAIT); 501 if (irq_info == NULL) 502 return (1); 503 504 irq_info->irq_no = irq; 505 irq_info->idesc = NULL; 506 TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links); 507 return 0; 508} 509 510#if 0 511 512int 513eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) 514 struct eisa_device *e_dev; 515 int irq; 516 void (*func)(void *); 517 void *arg; 518 u_int *maskptr; 519 int shared; 520{ 521 char string[25]; 522 char separator = ','; 523 524#if NOT_YET 525 /* 526 * Punt on conflict detection for the moment. 527 * I want to develop a generic routine to do 528 * this for all device types. 529 */ 530 int checkthese = CC_IRQ; 531 if (haveseen_dev(dev, checkthese)) 532 return 1; 533#endif 534 if (reg_state.in_registration) { 535 /* 536 * Find the first instance of this irq that has a 537 * NULL idesc. 538 */ 539 struct irq_node *cur_irq; 540 541 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs); 542 while (cur_irq != NULL) { 543 if (cur_irq->irq_no == irq 544 && cur_irq->idesc == NULL) { 545 /* XXX use cfg->devdata */ 546 void *dev_instance = (void *)-1; 547 548 cur_irq->idesc = intr_create(dev_instance, 549 irq, 550 func, 551 arg, 552 maskptr, 0); 553 break; 554 } 555 cur_irq = TAILQ_NEXT(cur_irq, links); 556 } 557 558 if (cur_irq == NULL || cur_irq->idesc == NULL) 559 return (-1); 560 } else { 561 return EPERM; 562 } 563 564 snprintf(string, sizeof(string), " irq %d", irq); 565 eisa_reg_print(e_dev, string, reg_state.num_interrupts ? 566 &separator : NULL); 567 reg_state.num_interrupts++; 568 return (0); 569} 570 571int 572eisa_release_intr(e_dev, irq, func) 573 struct eisa_device *e_dev; 574 int irq; 575 void (*func)(void *); 576{ 577 int result; 578 struct irq_node *cur_irq; 579 580 result = -1; 581 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs); 582 while (cur_irq != NULL) { 583 if (cur_irq->irq_no == irq) { 584 struct irq_node *next_irq; 585 586 next_irq = TAILQ_NEXT(cur_irq, links); 587 if (cur_irq->idesc != NULL) 588 intr_destroy(cur_irq->idesc); 589 TAILQ_REMOVE(&e_dev->ioconf.irqs, cur_irq, links); 590 free(cur_irq, M_DEVBUF); 591 cur_irq = next_irq; 592 result = 0; 593 } else { 594 cur_irq = TAILQ_NEXT(cur_irq, links); 595 } 596 } 597 if (result != 0) { 598 printf("%s%ld: Attempted to release an interrupt (%d) " 599 "it doesn't own\n", e_dev->driver->name, 600 e_dev->unit, irq); 601 } 602 603 return (result); 604} 605 606int 607eisa_enable_intr(e_dev, irq) 608 struct eisa_device *e_dev; 609 int irq; 610{ 611 struct irq_node *cur_irq; 612 int result; 613 614 result = -1; 615 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs); 616 while (cur_irq != NULL) { 617 if (cur_irq->irq_no == irq 618 && cur_irq->idesc != NULL) { 619 result = intr_connect(cur_irq->idesc); 620 } 621 cur_irq = TAILQ_NEXT(cur_irq, links); 622 } 623 return (result); 624} 625 626#endif /* 0 */ 627 628static int 629eisa_add_resvaddr(e_dev, head, base, size, flags) 630 struct eisa_device *e_dev; 631 struct resvlist *head; 632 u_long base; 633 u_long size; 634 int flags; 635{ 636 resvaddr_t *reservation; 637 638 reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t), 639 M_DEVBUF, M_NOWAIT); 640 if(!reservation) 641 return (ENOMEM); 642 643 reservation->addr = base; 644 reservation->size = size; 645 reservation->flags = flags; 646 647 if (!head->lh_first) { 648 LIST_INSERT_HEAD(head, reservation, links); 649 } 650 else { 651 resvaddr_t *node; 652 for(node = head->lh_first; node; node = node->links.le_next) { 653 if (node->addr > reservation->addr) { 654 /* 655 * List is sorted in increasing 656 * address order. 657 */ 658 LIST_INSERT_BEFORE(node, reservation, links); 659 break; 660 } 661 662 if (node->addr == reservation->addr) { 663 /* 664 * If the entry we want to add 665 * matches any already in here, 666 * fail. 667 */ 668 free(reservation, M_DEVBUF); 669 return (EEXIST); 670 } 671 672 if (!node->links.le_next) { 673 LIST_INSERT_AFTER(node, reservation, links); 674 break; 675 } 676 } 677 } 678 return (0); 679} 680 681int 682eisa_add_mspace(dev, mbase, msize, flags) 683 device_t dev; 684 u_long mbase; 685 u_long msize; 686 int flags; 687{ 688 struct eisa_device *e_dev = device_get_ivars(dev); 689 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize, 690 flags); 691} 692 693int 694eisa_add_iospace(dev, iobase, iosize, flags) 695 device_t dev; 696 u_long iobase; 697 u_long iosize; 698 int flags; 699{ 700 struct eisa_device *e_dev = device_get_ivars(dev); 701 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase, 702 iosize, flags); 703} 704 705#if 0 706 707static int 708eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count) 709 struct eisa_device *e_dev; 710 struct resvlist *head; 711 resvaddr_t *resvaddr; 712 int *reg_count; 713{ 714 if (reg_state.in_registration) { 715 resvaddr_t *node; 716 /* 717 * Ensure that this resvaddr is actually in the devices' 718 * reservation list. 719 */ 720 for(node = head->lh_first; node; 721 node = node->links.le_next) { 722 if (node == resvaddr) { 723 char buf[35]; 724 char separator = ','; 725 char *string = buf; 726 727 if (*reg_count == 0) { 728 /* First time */ 729 string += sprintf(string, " at"); 730 } 731 732 if (node->size == 1 733 || (node->flags & RESVADDR_BITMASK)) 734 sprintf(string, " 0x%lx", node->addr); 735 else 736 sprintf(string, " 0x%lx-0x%lx", 737 node->addr, 738 node->addr + node->size - 1); 739 eisa_reg_print(e_dev, buf, 740 *reg_count ? &separator : NULL); 741 (*reg_count)++; 742 return (0); 743 } 744 } 745 return (ENOENT); 746 } 747 return EPERM; 748} 749 750int 751eisa_reg_mspace(e_dev, resvaddr) 752 struct eisa_device *e_dev; 753 resvaddr_t *resvaddr; 754{ 755#ifdef NOT_YET 756 /* 757 * Punt on conflict detection for the moment. 758 * I want to develop a generic routine to do 759 * this for all device types. 760 */ 761 int checkthese = CC_MADDR; 762 if (haveseen_dev(dev, checkthese)) 763 return -1; 764#endif 765 return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr, 766 &(reg_state.num_maddrs))); 767} 768 769int 770eisa_reg_iospace(e_dev, resvaddr) 771 struct eisa_device *e_dev; 772 resvaddr_t *resvaddr; 773{ 774#ifdef NOT_YET 775 /* 776 * Punt on conflict detection for the moment. 777 * I want to develop a generic routine to do 778 * this for all device types. 779 */ 780 int checkthese = CC_IOADDR; 781 if (haveseen_dev(dev, checkthese)) 782 return -1; 783#endif 784 return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr, 785 &(reg_state.num_ioaddrs))); 786} 787 788#endif 789 790static device_method_t eisa_methods[] = { 791 /* Device interface */ 792 DEVMETHOD(device_probe, eisa_probe), 793 DEVMETHOD(device_attach, bus_generic_attach), 794 DEVMETHOD(device_shutdown, bus_generic_shutdown), 795 796 /* Bus interface */ 797 DEVMETHOD(bus_print_child, eisa_print_child), 798 DEVMETHOD(bus_read_ivar, eisa_read_ivar), 799 DEVMETHOD(bus_write_ivar, eisa_write_ivar), 800 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 801 DEVMETHOD(bus_alloc_resource, eisa_alloc_resource), 802 DEVMETHOD(bus_release_resource, eisa_release_resource), 803 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 804 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 805 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 806 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 807 808 { 0, 0 } 809}; 810 811static driver_t eisa_driver = { 812 "eisa", 813 eisa_methods, 814 DRIVER_TYPE_MISC, 815 1, /* no softc */ 816}; 817 818DRIVER_MODULE(eisa, isab, eisa_driver, eisa_devclass, 0, 0); 819 820