eisaconf.c revision 18084
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.21 1996/08/31 14:47:30 bde Exp $ 32 */ 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/kernel.h> 36#include <sys/sysctl.h> 37#include <sys/conf.h> 38#include <sys/malloc.h> 39 40#include <i386/eisa/eisaconf.h> 41 42#include <i386/isa/icu.h> /* Hmmm. Interrupt stuff? */ 43 44struct eisa_device_node{ 45 struct eisa_device dev; 46 struct eisa_device_node *next; 47}; 48 49/* 50 * This should probably be a list of "struct device" once it exists. 51 * A struct device will incorperate ioconf and driver entry point data 52 * regardless of how its attached to the system (via unions) as well 53 * as more generic information that all device types should support (unit 54 * number, if its installed, etc). 55 */ 56static struct eisa_device_node *eisa_dev_list; 57static struct eisa_device_node **eisa_dev_list_tail = &eisa_dev_list; 58static u_long eisa_unit; 59 60static struct eisa_driver mainboard_drv = { 61 "eisa", 62 NULL, 63 NULL, 64 NULL, 65 &eisa_unit 66 }; 67 68/* 69 * Add the mainboard_drv to the eisa driver linkerset so that it is 70 * defined even if no EISA drivers are linked into the kernel. 71 */ 72DATA_SET (eisadriver_set, mainboard_drv); 73 74/* 75 * Local function declarations and static variables 76 */ 77void eisa_reg_print __P((struct eisa_device *e_dev, char *string, 78 char *separator)); 79static int eisa_add_resvaddr __P((struct eisa_device *e_dev, 80 struct resvlist *head, u_long base, 81 u_long size, int flags)); 82static int eisa_reg_resvaddr __P((struct eisa_device *e_dev, 83 struct resvlist *head, resvaddr_t *resvaddr, 84 int *reg_count)); 85 86/* 87 * Keep some state about what we've printed so far 88 * to make probe output pretty. 89 */ 90static struct { 91 int in_registration;/* reg_start has been called */ 92 int num_interrupts; 93 int num_ioaddrs; 94 int num_maddrs; 95 int column; /* How much we have output so far. */ 96#define MAX_COL 80 97} reg_state; 98 99/* 100** probe for EISA devices 101*/ 102void 103eisa_configure() 104{ 105 int i,slot; 106 char *id_string; 107 struct eisa_device_node *dev_node; 108 struct eisa_driver **e_drvp; 109 struct eisa_driver *e_drv; 110 struct eisa_device *e_dev; 111 int eisaBase = 0xc80; 112 eisa_id_t eisa_id; 113 114 e_drvp = (struct eisa_driver**)eisadriver_set.ls_items; 115 116 for (slot = 0; slot < EISA_SLOTS; eisaBase+=0x1000, slot++) { 117 int id_size = sizeof(eisa_id); 118 eisa_id = 0; 119 for( i = 0; i < id_size; i++ ) { 120 outb(eisaBase,0x80 + i); /*Some cards require priming*/ 121 eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT); 122 } 123 if (eisa_id & 0x80000000) 124 continue; /* no EISA card in slot */ 125 126 /* Prepare an eisa_device_node for this slot */ 127 dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node), 128 M_DEVBUF, M_NOWAIT); 129 if (!dev_node) { 130 printf("eisa0: cannot malloc eisa_device_node"); 131 break; /* Try to attach what we have already */ 132 } 133 bzero(dev_node, sizeof(*dev_node)); 134 e_dev = &(dev_node->dev); 135 136 e_dev->id = eisa_id; 137 /* 138 * Add an EISA ID based descriptive name incase we don't 139 * have a driver for it. We do this now instead of after all 140 * probes because in the future, the eisa module will only 141 * be responsible for creating the list of devices in the system 142 * for the configuration manager to use. 143 */ 144 e_dev->full_name = (char *)malloc(8*sizeof(char), 145 M_DEVBUF, M_NOWAIT); 146 if (!e_dev->full_name) { 147 panic("Eisa probe unable to malloc"); 148 } 149 sprintf(e_dev->full_name, "%c%c%c%x%x", 150 EISA_MFCTR_CHAR0(e_dev->id), 151 EISA_MFCTR_CHAR1(e_dev->id), 152 EISA_MFCTR_CHAR2(e_dev->id), 153 EISA_PRODUCT_ID(e_dev->id), 154 EISA_REVISION_ID(e_dev->id)); 155 156 e_dev->ioconf.slot = slot; 157 158 /* Initialize our lists of reserved addresses */ 159 LIST_INIT(&(e_dev->ioconf.ioaddrs)); 160 LIST_INIT(&(e_dev->ioconf.maddrs)); 161 162 *eisa_dev_list_tail = dev_node; 163 eisa_dev_list_tail = &dev_node->next; 164 } 165 166 dev_node = eisa_dev_list; 167 168 /* 169 * "Attach" the system board 170 */ 171 172 /* The first will be the motherboard in a true EISA system */ 173 if (dev_node && (dev_node->dev.ioconf.slot == 0)) { 174 e_dev = &dev_node->dev; 175 e_dev->driver = &mainboard_drv; 176 e_dev->unit = (*e_dev->driver->unit)++; 177 id_string = e_dev->full_name; 178 e_dev->full_name = (char *)malloc(strlen(e_dev->full_name) 179 + sizeof(" (System Board)") 180 + 1, M_DEVBUF, M_NOWAIT); 181 if (!e_dev->full_name) { 182 panic("Eisa probe unable to malloc"); 183 } 184 sprintf(e_dev->full_name, "%s (System Board)", id_string); 185 free(id_string, M_DEVBUF); 186 187 printf("%s%ld: <%s>\n", 188 e_dev->driver->name, 189 e_dev->unit, 190 e_dev->full_name); 191 192 /* Should set the iosize, but I don't have a spec handy */ 193 printf("Probing for devices on the EISA bus\n"); 194 dev_node = dev_node->next; 195 } 196 197 if (!eisa_dev_list) { 198 /* 199 * No devices. 200 */ 201 return; 202 } 203 /* 204 * See what devices we recognize. 205 */ 206 while((e_drv = *e_drvp++)) { 207 if (e_drv->probe) 208 (*e_drv->probe)(); 209 } 210 211 /* 212 * Attach the devices we found in slot order 213 */ 214 for (; dev_node; dev_node=dev_node->next) { 215 e_dev = &dev_node->dev; 216 e_drv = e_dev->driver; 217 218 if (e_drv) { 219 /* 220 * Determine the proper unit number for this device. 221 * Here we should look in the device table generated 222 * by config to see if this type of device is enabled 223 * either generically or for this particular address 224 * as well as determine if a reserved unit number 225 * should be used. We should also ensure that the 226 * "next availible unit number" skips over "wired" unit 227 * numbers. This will be done after config is fixed or 228 * some other configuration method is chosen. 229 */ 230 e_dev->unit = (*e_drv->unit)++; 231 if ((*e_drv->attach)(e_dev) < 0) { 232 /* Ensure registration has ended */ 233 reg_state.in_registration = 0; 234 printf("\n%s0:%d <%s> attach failed\n", 235 mainboard_drv.name, 236 e_dev->ioconf.slot, 237 e_dev->full_name); 238 continue; 239 } 240 /* Ensure registration has ended */ 241 reg_state.in_registration = 0; 242 } 243 else { 244 /* Announce unattached device */ 245 printf("%s0:%d <%s=0x%x> unknown device\n", 246 mainboard_drv.name, 247 e_dev->ioconf.slot, 248 e_dev->full_name, 249 e_dev->id); 250 } 251 } 252} 253 254struct eisa_device * 255eisa_match_dev(e_dev, match_func) 256 struct eisa_device *e_dev; 257 char* (*match_func)(eisa_id_t); 258{ 259 struct eisa_device_node *e_node = eisa_dev_list; 260 261 if (e_dev) { 262 /* Start our search from the last successful match */ 263 e_node = ((struct eisa_device_node *)e_dev)->next; 264 } 265 266 for(; e_node; e_node = e_node->next) { 267 char *result; 268 if (e_node->dev.driver) { 269 /* Already claimed */ 270 continue; 271 } 272 result = (*match_func)(e_node->dev.id); 273 if (result) { 274 free(e_node->dev.full_name, M_DEVBUF); 275 e_node->dev.full_name = result; 276 return (&(e_node->dev)); 277 } 278 } 279 return NULL; 280} 281 282/* Interrupt and I/O space registration facitlities */ 283void 284eisa_reg_start(e_dev) 285 struct eisa_device *e_dev; 286{ 287 /* 288 * Announce the device. 289 */ 290 char *string; 291 292 reg_state.in_registration = 1; 293 reg_state.num_interrupts = 0; 294 reg_state.num_ioaddrs = 0; 295 reg_state.num_maddrs = 0; 296 reg_state.column = 0; 297 298 string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1, 299 M_TEMP, M_NOWAIT); 300 if(!string) { 301 printf("eisa0: cannot malloc device description string\n"); 302 return; 303 } 304 sprintf(string, " <%s>", e_dev->full_name); 305 eisa_reg_print(e_dev, string, /*separator=*/NULL); 306 free(string, M_TEMP); 307} 308 309/* 310 * Output registration information mindfull of screen wrap. 311 * Output an optional character separator before the string 312 * if the line does not wrap. 313 */ 314void 315eisa_reg_print(e_dev, string, separator) 316 struct eisa_device *e_dev; 317 char *string; 318 char *separator; 319{ 320 int len = strlen(string); 321 322 if(separator) 323 len++; 324 325 if(reg_state.column + len > MAX_COL) { 326 printf("\n"); 327 reg_state.column = 0; 328 } 329 else if(separator) { 330 printf("%c", *separator); 331 reg_state.column++; 332 } 333 334 if(reg_state.column == 0) 335 reg_state.column += printf("%s%ld:%s", 336 e_dev->driver->name, 337 e_dev->unit, 338 string); 339 else 340 reg_state.column += printf("%s", string); 341} 342 343/* Interrupt and I/O space registration facitlities */ 344void 345eisa_reg_end(e_dev) 346 struct eisa_device *e_dev; 347{ 348 if( reg_state.in_registration ) 349 { 350 /* 351 * The device should have called eisa_registerdev() 352 * during its probe. So hopefully we can use the kdc 353 * to weed out ISA/VL devices that use EISA id registers. 354 */ 355 char string[25]; 356 357 sprintf(string, " on %s0 slot %d", 358 mainboard_drv.name, 359 e_dev->ioconf.slot); 360 eisa_reg_print(e_dev, string, NULL); 361 printf("\n"); 362 reg_state.in_registration = 0; 363 } 364 else 365 printf("eisa_reg_end called outside of a " 366 "registration session\n"); 367} 368 369int 370eisa_add_intr(e_dev, irq) 371 struct eisa_device *e_dev; 372 int irq; 373{ 374 e_dev->ioconf.irq |= 1ul << irq; 375 return 0; 376} 377 378int 379eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) 380 struct eisa_device *e_dev; 381 int irq; 382 void (*func)(void *); 383 void *arg; 384 u_int *maskptr; 385 int shared; 386{ 387 int result; 388 int s; 389 char string[25]; 390 char separator = ','; 391 392#if NOT_YET 393 /* 394 * Punt on conflict detection for the moment. 395 * I want to develop a generic routine to do 396 * this for all device types. 397 */ 398 int checkthese = CC_IRQ; 399 if (haveseen_dev(dev, checkthese)) 400 return 1; 401#endif 402 if (reg_state.in_registration) { 403 s = splhigh(); 404 /* 405 * This should really go to a routine that can optionally 406 * handle shared interrupts. 407 */ 408 result = register_intr(irq, /* isa irq */ 409 0, /* deviced?? */ 410 0, /* flags? */ 411 (inthand2_t*) func, /* handler */ 412 maskptr, /* mask pointer */ 413 (int)arg); /* handler arg */ 414 415 if (result) { 416 printf ("\neisa_reg_int: result=%d\n", result); 417 splx(s); 418 return (result); 419 }; 420 update_intr_masks(); 421 splx(s); 422 } 423 else 424 return EPERM; 425 426 e_dev->ioconf.irq |= 1ul << irq; 427 sprintf(string, " irq %d", irq); 428 eisa_reg_print(e_dev, string, reg_state.num_interrupts ? 429 &separator : NULL); 430 reg_state.num_interrupts++; 431 return (0); 432} 433 434int 435eisa_release_intr(e_dev, irq, func) 436 struct eisa_device *e_dev; 437 int irq; 438 void (*func)(void *); 439{ 440 int result; 441 int s; 442 443 if (!(e_dev->ioconf.irq & (1ul << irq))) { 444 printf("%s%ld: Attempted to release an interrupt (%d) " 445 "it doesn't own\n", e_dev->driver->name, 446 e_dev->unit, irq); 447 return (-1); 448 } 449 450 s = splhigh(); 451 INTRDIS ((1ul<<irq)); 452 453 result = unregister_intr (irq, (inthand2_t*)func); 454 455 if (result) 456 printf ("eisa_release_intr: result=%d\n", result); 457 458 update_intr_masks(); 459 460 splx(s); 461 return (result); 462} 463 464int 465eisa_enable_intr(e_dev, irq) 466 struct eisa_device *e_dev; 467 int irq; 468{ 469 int s; 470 471 if (!(e_dev->ioconf.irq & (1ul << irq))) { 472 printf("%s%ld: Attempted to enable an interrupt (%d) " 473 "it doesn't own\n", e_dev->driver->name, 474 e_dev->unit, irq); 475 return (-1); 476 } 477 s = splhigh(); 478 INTREN((1ul << irq)); 479 splx(s); 480 return 0; 481} 482 483static int 484eisa_add_resvaddr(e_dev, head, base, size, flags) 485 struct eisa_device *e_dev; 486 struct resvlist *head; 487 u_long base; 488 u_long size; 489 int flags; 490{ 491 resvaddr_t *reservation; 492 493 reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t), 494 M_DEVBUF, M_NOWAIT); 495 if(!reservation) 496 return (ENOMEM); 497 498 reservation->addr = base; 499 reservation->size = size; 500 reservation->flags = flags; 501 502 if (!head->lh_first) { 503 LIST_INSERT_HEAD(head, reservation, links); 504 } 505 else { 506 resvaddr_t *node; 507 for(node = head->lh_first; node; node = node->links.le_next) { 508 if (node->addr > reservation->addr) { 509 /* 510 * List is sorted in increasing 511 * address order. 512 */ 513 LIST_INSERT_BEFORE(node, reservation, links); 514 break; 515 } 516 517 if (node->addr == reservation->addr) { 518 /* 519 * If the entry we want to add 520 * matches any already in here, 521 * fail. 522 */ 523 free(reservation, M_DEVBUF); 524 return (EEXIST); 525 } 526 527 if (!node->links.le_next) { 528 LIST_INSERT_AFTER(node, reservation, links); 529 break; 530 } 531 } 532 } 533 return (0); 534} 535 536int 537eisa_add_mspace(e_dev, mbase, msize, flags) 538 struct eisa_device *e_dev; 539 u_long mbase; 540 u_long msize; 541 int flags; 542{ 543 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize, 544 flags); 545} 546 547int 548eisa_add_iospace(e_dev, iobase, iosize, flags) 549 struct eisa_device *e_dev; 550 u_long iobase; 551 u_long iosize; 552 int flags; 553{ 554 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase, 555 iosize, flags); 556} 557 558static int 559eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count) 560 struct eisa_device *e_dev; 561 struct resvlist *head; 562 resvaddr_t *resvaddr; 563 int *reg_count; 564{ 565 if (reg_state.in_registration) { 566 resvaddr_t *node; 567 /* 568 * Ensure that this resvaddr is actually in the devices' 569 * reservation list. 570 */ 571 for(node = head->lh_first; node; 572 node = node->links.le_next) { 573 if (node == resvaddr) { 574 char buf[35]; 575 char separator = ','; 576 char *string = buf; 577 578 if (*reg_count == 0) { 579 /* First time */ 580 string += sprintf(string, " at"); 581 } 582 583 if (node->size == 1 584 || (node->flags & RESVADDR_BITMASK)) 585 sprintf(string, " 0x%lx", node->addr); 586 else 587 sprintf(string, " 0x%lx-0x%lx", 588 node->addr, 589 node->addr + node->size - 1); 590 eisa_reg_print(e_dev, buf, 591 *reg_count ? &separator : NULL); 592 (*reg_count)++; 593 return (0); 594 } 595 } 596 return (ENOENT); 597 } 598 return EPERM; 599} 600 601int 602eisa_reg_mspace(e_dev, resvaddr) 603 struct eisa_device *e_dev; 604 resvaddr_t *resvaddr; 605{ 606#ifdef NOT_YET 607 /* 608 * Punt on conflict detection for the moment. 609 * I want to develop a generic routine to do 610 * this for all device types. 611 */ 612 int checkthese = CC_MADDR; 613 if (haveseen_dev(dev, checkthese)) 614 return -1; 615#endif 616 return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr, 617 &(reg_state.num_maddrs))); 618} 619 620int 621eisa_reg_iospace(e_dev, resvaddr) 622 struct eisa_device *e_dev; 623 resvaddr_t *resvaddr; 624{ 625#ifdef NOT_YET 626 /* 627 * Punt on conflict detection for the moment. 628 * I want to develop a generic routine to do 629 * this for all device types. 630 */ 631 int checkthese = CC_IOADDR; 632 if (haveseen_dev(dev, checkthese)) 633 return -1; 634#endif 635 return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr, 636 &(reg_state.num_ioaddrs))); 637} 638 639int 640eisa_registerdev(e_dev, driver) 641 struct eisa_device *e_dev; 642 struct eisa_driver *driver; 643{ 644 e_dev->driver = driver; /* Driver now owns this device */ 645 return (0); 646} 647 648