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