eisaconf.c revision 143758
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 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/sys/dev/eisa/eisaconf.c 143758 2005-03-17 17:33:52Z imp $"); 35 36#include "opt_eisa.h" 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/queue.h> 41#include <sys/limits.h> 42#include <sys/malloc.h> 43#include <sys/kernel.h> 44#include <sys/module.h> 45#include <sys/bus.h> 46 47#include <machine/bus.h> 48#include <machine/resource.h> 49#include <sys/rman.h> 50 51#include <dev/eisa/eisaconf.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 int irq_trigger; 66 void *idesc; 67 TAILQ_ENTRY(irq_node) links; 68}; 69 70TAILQ_HEAD(irqlist, irq_node); 71 72struct eisa_ioconf { 73 int slot; 74 struct resvlist ioaddrs; /* list of reserved I/O ranges */ 75 struct resvlist maddrs; /* list of reserved memory ranges */ 76 struct irqlist irqs; /* list of reserved irqs */ 77}; 78 79/* To be replaced by the "super device" generic device structure... */ 80struct eisa_device { 81 eisa_id_t id; 82 struct eisa_ioconf ioconf; 83}; 84 85 86#define MAX_COL 79 87#ifndef EISA_SLOTS 88#define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */ 89#endif 90int num_eisa_slots = EISA_SLOTS; 91TUNABLE_INT("hw.eisa_slots", &num_eisa_slots); 92 93static devclass_t eisa_devclass; 94 95static int eisa_probe_slot(int slot, eisa_id_t *eisa_id); 96static void eisa_reg_print (device_t, char *, char *, int *); 97static struct irq_node * eisa_find_irq(struct eisa_device *e_dev, int rid); 98static struct resvaddr * eisa_find_maddr(struct eisa_device *e_dev, int rid); 99static struct resvaddr * eisa_find_ioaddr(struct eisa_device *e_dev, int rid); 100 101static int 102mainboard_probe(device_t dev) 103{ 104 char *idstring; 105 eisa_id_t id = eisa_get_id(dev); 106 107 if (eisa_get_slot(dev) != 0) 108 return (ENXIO); 109 110 idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1, 111 M_DEVBUF, M_NOWAIT); 112 if (idstring == NULL) 113 panic("Eisa probe unable to malloc"); 114 sprintf(idstring, "%c%c%c%03x%01x (System Board)", 115 EISA_MFCTR_CHAR0(id), EISA_MFCTR_CHAR1(id), EISA_MFCTR_CHAR2(id), 116 EISA_PRODUCT_ID(id), EISA_REVISION_ID(id)); 117 device_set_desc(dev, idstring); 118 119 return (0); 120} 121 122static int 123mainboard_attach(device_t dev) 124{ 125 return (0); 126} 127 128static device_method_t mainboard_methods[] = { 129 /* Device interface */ 130 DEVMETHOD(device_probe, mainboard_probe), 131 DEVMETHOD(device_attach, mainboard_attach), 132 133 { 0, 0 } 134}; 135 136static driver_t mainboard_driver = { 137 "mainboard", 138 mainboard_methods, 139 1, 140}; 141 142static devclass_t mainboard_devclass; 143 144DRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0); 145 146/* 147** probe for EISA devices 148*/ 149static int 150eisa_probe(device_t dev) 151{ 152 int devices_found, slot; 153 struct eisa_device *e_dev; 154 device_t child; 155 eisa_id_t eisa_id; 156 157 device_set_desc(dev, "EISA bus"); 158 159 devices_found = 0; 160 for (slot = 0; slot < num_eisa_slots; slot++) { 161 eisa_id = 0; 162 if (eisa_probe_slot(slot, &eisa_id)) { 163 /* 164 * If there's no card in the first slot (the 165 * mainboard), then the system doesn't have EISA. 166 * We abort the probe early in this case since 167 * continuing on causes a hang on some systems. 168 * Interestingly enough, the inb has been seen to 169 * cause the hang. However, aborting here causes 170 * the Adaptec 2842 probe to fail so that driver 171 * needs to be fixed separately. 172 */ 173 if (slot == 0) 174 break; 175 continue; 176 } 177 178 devices_found++; 179 180 /* Prepare an eisa_device_node for this slot */ 181 e_dev = (struct eisa_device *)malloc(sizeof(*e_dev), 182 M_DEVBUF, M_NOWAIT|M_ZERO); 183 if (!e_dev) { 184 device_printf(dev, "cannot malloc eisa_device"); 185 break; /* Try to attach what we have already */ 186 } 187 188 e_dev->id = eisa_id; 189 e_dev->ioconf.slot = slot; 190 191 /* Initialize our lists of reserved addresses */ 192 LIST_INIT(&(e_dev->ioconf.ioaddrs)); 193 LIST_INIT(&(e_dev->ioconf.maddrs)); 194 TAILQ_INIT(&(e_dev->ioconf.irqs)); 195 196 child = device_add_child(dev, NULL, -1); 197 device_set_ivars(child, e_dev); 198 } 199 200 /* 201 * EISA busses themselves are not easily detectable, the easiest way 202 * to tell if there is an eisa bus is if we found something - there 203 * should be a motherboard "card" there somewhere. 204 */ 205 return (devices_found ? 0 : ENXIO); 206} 207 208static int 209eisa_probe_slot(int slot, eisa_id_t *eisa_id) 210{ 211 eisa_id_t probe_id; 212 int base, i, id_size; 213 214 probe_id = 0; 215 id_size = sizeof(probe_id); 216 base = 0x0c80 + (slot * 0x1000); 217 218 for (i = 0; i < id_size; i++) 219 probe_id |= inb(base + i) << ((id_size - i - 1) * CHAR_BIT); 220 221 /* If we found a card, return its EISA id. */ 222 if ((probe_id & 0x80000000) == 0) { 223 *eisa_id = probe_id; 224 return (0); 225 } 226 227 return (ENXIO); 228} 229 230static void 231eisa_probe_nomatch(device_t dev, device_t child) 232{ 233 u_int32_t eisa_id = eisa_get_id(child); 234 u_int8_t slot = eisa_get_slot(child); 235 236 device_printf(dev, "unknown card %c%c%c%03x%01x (0x%08x) at slot %d\n", 237 EISA_MFCTR_CHAR0(eisa_id), EISA_MFCTR_CHAR1(eisa_id), 238 EISA_MFCTR_CHAR2(eisa_id), EISA_PRODUCT_ID(eisa_id), 239 EISA_REVISION_ID(eisa_id), eisa_id, slot); 240 return; 241} 242 243static void 244eisa_reg_print (device_t dev, char *string, char *separator, int *column) 245{ 246 int length = strlen(string); 247 248 length += (separator ? 2 : 1); 249 250 if (((*column) + length) >= MAX_COL) { 251 printf("\n"); 252 (*column) = 0; 253 } else if ((*column) != 0) { 254 if (separator) { 255 printf("%c", *separator); 256 (*column)++; 257 } 258 printf(" "); 259 (*column)++; 260 } 261 262 if ((*column) == 0) 263 (*column) += device_printf(dev, "%s", string); 264 else 265 (*column) += printf("%s", string); 266 267 return; 268} 269 270static int 271eisa_print_child(device_t dev, device_t child) 272{ 273 char buf[81]; 274 struct eisa_device * e_dev = device_get_ivars(child); 275 int rid; 276 struct irq_node * irq; 277 struct resvaddr * resv; 278 char separator = ','; 279 int column = 0; 280 int retval = 0; 281 282 if (device_get_desc(child)) { 283 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child)); 284 eisa_reg_print(child, buf, NULL, &column); 285 } 286 287 rid = 0; 288 while ((resv = eisa_find_ioaddr(e_dev, rid++))) { 289 if (resv->size == 1 || (resv->flags & RESVADDR_BITMASK)) 290 snprintf(buf, sizeof(buf), "%s%lx", 291 rid == 1 ? "at 0x" : "0x", resv->addr); 292 else 293 snprintf(buf, sizeof(buf), "%s%lx-0x%lx", 294 rid == 1 ? "at 0x" : "0x", resv->addr, 295 resv->addr + resv->size - 1); 296 eisa_reg_print(child, buf, rid == 2 ? &separator : NULL, 297 &column); 298 } 299 300 rid = 0; 301 while ((resv = eisa_find_maddr(e_dev, rid++))) { 302 if (resv->size == 1 || (resv->flags & RESVADDR_BITMASK)) 303 snprintf(buf, sizeof(buf), "%s%lx", 304 rid == 1 ? "at 0x" : "0x", resv->addr); 305 else 306 snprintf(buf, sizeof(buf), "%s%lx-0x%lx", 307 rid == 1 ? "at 0x" : "0x", 308 resv->addr, resv->addr + resv->size - 1); 309 eisa_reg_print(child, buf, rid == 2 ? &separator : NULL, 310 &column); 311 } 312 313 rid = 0; 314 while ((irq = eisa_find_irq(e_dev, rid++)) != NULL) { 315 snprintf(buf, sizeof(buf), "irq %d (%s)", irq->irq_no, 316 irq->irq_trigger ? "level" : "edge"); 317 eisa_reg_print(child, buf, rid == 1 ? &separator : NULL, 318 &column); 319 } 320 321 snprintf(buf, sizeof(buf), "on %s slot %d\n", 322 device_get_nameunit(dev), eisa_get_slot(child)); 323 eisa_reg_print(child, buf, NULL, &column); 324 325 return (retval); 326} 327 328static struct irq_node * 329eisa_find_irq(struct eisa_device *e_dev, int rid) 330{ 331 int i; 332 struct irq_node *irq; 333 334 for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs); 335 i < rid && irq != NULL; i++, irq = TAILQ_NEXT(irq, links)) 336 continue; 337 338 return (irq); 339} 340 341static struct resvaddr * 342eisa_find_maddr(struct eisa_device *e_dev, int rid) 343{ 344 int i; 345 struct resvaddr *resv; 346 347 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs); 348 i < rid && resv != NULL; i++, resv = LIST_NEXT(resv, links)) 349 continue; 350 351 return (resv); 352} 353 354static struct resvaddr * 355eisa_find_ioaddr(struct eisa_device *e_dev, int rid) 356{ 357 int i; 358 struct resvaddr *resv; 359 360 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs); 361 i < rid && resv != NULL; i++, resv = LIST_NEXT(resv, links)) 362 continue; 363 364 return (resv); 365} 366 367static int 368eisa_read_ivar(device_t dev, device_t child, int which, u_long *result) 369{ 370 struct eisa_device *e_dev = device_get_ivars(child); 371 struct irq_node *irq; 372 373 switch (which) { 374 case EISA_IVAR_SLOT: 375 *result = e_dev->ioconf.slot; 376 break; 377 378 case EISA_IVAR_ID: 379 *result = e_dev->id; 380 break; 381 382 case EISA_IVAR_IRQ: 383 /* XXX only first irq */ 384 if ((irq = eisa_find_irq(e_dev, 0)) != NULL) 385 *result = irq->irq_no; 386 else 387 *result = -1; 388 break; 389 390 default: 391 return (ENOENT); 392 } 393 394 return (0); 395} 396 397static int 398eisa_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 399{ 400 return (EINVAL); 401} 402 403static struct resource * 404eisa_alloc_resource(device_t dev, device_t child, int type, int *rid, 405 u_long start, u_long end, u_long count, u_int flags) 406{ 407 int isdefault; 408 struct eisa_device *e_dev = device_get_ivars(child); 409 struct resource *rv, **rvp = 0; 410 411 isdefault = (device_get_parent(child) == dev && 412 start == 0UL && end == ~0UL && count == 1); 413 414 switch (type) { 415 case SYS_RES_IRQ: 416 if (isdefault) { 417 struct irq_node * irq = eisa_find_irq(e_dev, *rid); 418 if (irq == NULL) 419 return (NULL); 420 start = end = irq->irq_no; 421 count = 1; 422 if (irq->irq_trigger == EISA_TRIGGER_LEVEL) 423 flags |= RF_SHAREABLE; 424 else 425 flags &= ~RF_SHAREABLE; 426 } 427 break; 428 429 case SYS_RES_MEMORY: 430 if (isdefault) { 431 struct resvaddr *resv; 432 433 resv = eisa_find_maddr(e_dev, *rid); 434 if (resv == NULL) 435 return (NULL); 436 437 start = resv->addr; 438 end = resv->addr + (resv->size - 1); 439 count = resv->size; 440 rvp = &resv->res; 441 } 442 break; 443 444 case SYS_RES_IOPORT: 445 if (isdefault) { 446 struct resvaddr *resv; 447 448 resv = eisa_find_ioaddr(e_dev, *rid); 449 if (resv == NULL) 450 return (NULL); 451 452 start = resv->addr; 453 end = resv->addr + (resv->size - 1); 454 count = resv->size; 455 rvp = &resv->res; 456 } 457 break; 458 459 default: 460 return 0; 461 } 462 463 rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 464 type, rid, start, end, count, flags); 465 if (rvp) 466 *rvp = rv; 467 468 return (rv); 469} 470 471static int 472eisa_release_resource(device_t dev, device_t child, int type, int rid, 473 struct resource *r) 474{ 475 int rv; 476 struct eisa_device *e_dev = device_get_ivars(child); 477 struct resvaddr *resv = 0; 478 479 switch (type) { 480 case SYS_RES_IRQ: 481 if (eisa_find_irq(e_dev, rid) == NULL) 482 return (EINVAL); 483 break; 484 485 case SYS_RES_MEMORY: 486 if (device_get_parent(child) == dev) 487 resv = eisa_find_maddr(e_dev, rid); 488 break; 489 490 491 case SYS_RES_IOPORT: 492 if (device_get_parent(child) == dev) 493 resv = eisa_find_ioaddr(e_dev, rid); 494 break; 495 496 default: 497 return (ENOENT); 498 } 499 500 rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r); 501 502 if (rv == 0) { 503 if (resv != NULL) 504 resv->res = 0; 505 } 506 507 return (rv); 508} 509 510static int 511eisa_add_intr_m(device_t eisa, device_t dev, int irq, int trigger) 512{ 513 struct eisa_device *e_dev = device_get_ivars(dev); 514 struct irq_node *irq_info; 515 516 irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF, 517 M_NOWAIT); 518 if (irq_info == NULL) 519 return (1); 520 521 irq_info->irq_no = irq; 522 irq_info->irq_trigger = trigger; 523 irq_info->idesc = NULL; 524 TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links); 525 return (0); 526} 527 528static int 529eisa_add_resvaddr(struct eisa_device *e_dev, struct resvlist *head, u_long base, 530 u_long size, int flags) 531{ 532 resvaddr_t *reservation; 533 534 reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t), 535 M_DEVBUF, M_NOWAIT); 536 if(!reservation) 537 return (ENOMEM); 538 539 reservation->addr = base; 540 reservation->size = size; 541 reservation->flags = flags; 542 543 if (!LIST_FIRST(head)) { 544 LIST_INSERT_HEAD(head, reservation, links); 545 } 546 else { 547 resvaddr_t *node; 548 LIST_FOREACH(node, head, links) { 549 if (node->addr > reservation->addr) { 550 /* 551 * List is sorted in increasing 552 * address order. 553 */ 554 LIST_INSERT_BEFORE(node, reservation, links); 555 break; 556 } 557 558 if (node->addr == reservation->addr) { 559 /* 560 * If the entry we want to add 561 * matches any already in here, 562 * fail. 563 */ 564 free(reservation, M_DEVBUF); 565 return (EEXIST); 566 } 567 568 if (!LIST_NEXT(node, links)) { 569 LIST_INSERT_AFTER(node, reservation, links); 570 break; 571 } 572 } 573 } 574 return (0); 575} 576 577static int 578eisa_add_mspace_m(device_t eisa, device_t dev, u_long mbase, u_long msize, 579 int flags) 580{ 581 struct eisa_device *e_dev = device_get_ivars(dev); 582 583 return (eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize, 584 flags)); 585} 586 587static int 588eisa_add_iospace_m(device_t eisa, device_t dev, u_long iobase, u_long iosize, 589 int flags) 590{ 591 struct eisa_device *e_dev = device_get_ivars(dev); 592 593 return (eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase, 594 iosize, flags)); 595} 596 597static device_method_t eisa_methods[] = { 598 /* Device interface */ 599 DEVMETHOD(device_probe, eisa_probe), 600 DEVMETHOD(device_attach, bus_generic_attach), 601 DEVMETHOD(device_shutdown, bus_generic_shutdown), 602 DEVMETHOD(device_suspend, bus_generic_suspend), 603 DEVMETHOD(device_resume, bus_generic_resume), 604 605 /* Bus interface */ 606 DEVMETHOD(bus_print_child, eisa_print_child), 607 DEVMETHOD(bus_probe_nomatch, eisa_probe_nomatch), 608 DEVMETHOD(bus_read_ivar, eisa_read_ivar), 609 DEVMETHOD(bus_write_ivar, eisa_write_ivar), 610 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 611 DEVMETHOD(bus_alloc_resource, eisa_alloc_resource), 612 DEVMETHOD(bus_release_resource, eisa_release_resource), 613 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 614 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 615 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 616 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 617 618 /* EISA interface */ 619 DEVMETHOD(eisa_add_intr, eisa_add_intr_m), 620 DEVMETHOD(eisa_add_iospace, eisa_add_iospace_m), 621 DEVMETHOD(eisa_add_mspace, eisa_add_mspace_m), 622 623 { 0, 0 } 624}; 625 626static driver_t eisa_driver = { 627 "eisa", 628 eisa_methods, 629 1, /* no softc */ 630}; 631 632DRIVER_MODULE(eisa, eisab, eisa_driver, eisa_devclass, 0, 0); 633DRIVER_MODULE(eisa, legacy, eisa_driver, eisa_devclass, 0, 0); 634