eisaconf.c revision 12513
1/* 2 * EISA bus probe and attach routines 3 * 4 * Copyright (c) 1995 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.8 1995/11/20 12:41:11 phk Exp $ 22 */ 23#include <sys/param.h> 24#include <sys/systm.h> 25#include <sys/kernel.h> 26#include <sys/sysctl.h> 27#include <sys/conf.h> 28#include <sys/malloc.h> 29#include <sys/devconf.h> 30 31#include "i386/isa/icu.h" /* Hmmm. Interrupt stuff? */ 32#include "eisaconf.h" 33 34struct eisa_device_node{ 35 struct eisa_device dev; 36 struct eisa_device_node *next; 37}; 38 39extern struct kern_devconf kdc_cpu0; 40extern int bootverbose; 41 42struct kern_devconf kdc_eisa0 = { 43 0, 0, 0, /* filled in by dev_attach */ 44 "eisa", 0, { MDDT_BUS, 0 }, 45 0, 0, 0, BUS_EXTERNALLEN, 46 &kdc_cpu0, /* parent is the CPU */ 47 0, /* no parentdata */ 48 DC_BUSY, /* busses are always busy */ 49 NULL, 50 DC_CLS_BUS /* class */ 51}; 52 53/* 54 * This should probably be a list of "struct device" once it exists. 55 * A struct device will incorperate ioconf and driver entry point data 56 * regardless of how its attached to the system (via unions) as well 57 * as more generic information that all device types should support (unit 58 * number, if its installed, etc). 59 */ 60static struct eisa_device_node *eisa_dev_list; 61static struct eisa_device_node **eisa_dev_list_tail = &eisa_dev_list; 62static u_long eisa_unit; 63 64static static struct eisa_driver mainboard_drv = { 65 "eisa", 66 NULL, 67 NULL, 68 NULL, 69 &eisa_unit 70 }; 71 72/* 73 * Add the mainboard_drv to the eisa driver linkerset so that it is 74 * defined even if no EISA drivers are linked into the kernel. 75 */ 76DATA_SET (eisadriver_set, mainboard_drv); 77 78/* 79** probe for EISA devices 80*/ 81void 82eisa_configure() 83{ 84 int i,slot; 85 char *id_string; 86 struct eisa_device_node *dev_node; 87 struct eisa_driver **e_drvp; 88 struct eisa_driver *e_drv; 89 struct eisa_device *e_dev; 90 int eisaBase = 0xc80; 91 eisa_id_t eisa_id; 92 93 e_drvp = (struct eisa_driver**)eisadriver_set.ls_items; 94 95 for (slot = 0; slot < EISA_SLOTS; eisaBase+=0x1000, slot++) { 96 int id_size = sizeof(eisa_id); 97 eisa_id = 0; 98 for( i = 0; i < id_size; i++ ) { 99 outb(eisaBase,0xc80 + i); /*Some cards require priming*/ 100 eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT); 101 } 102 if (eisa_id & 0x80000000) 103 continue; /* no EISA card in slot */ 104 105 /* Prepare an eisa_device_node for this slot */ 106 dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node), 107 M_DEVBUF, M_NOWAIT); 108 if (!dev_node) { 109 printf("eisa0: cannot malloc eisa_device_node"); 110 break; /* Try to attach what we have already */ 111 } 112 bzero(dev_node, sizeof(*dev_node)); 113 e_dev = &(dev_node->dev); 114 e_dev->id = eisa_id; 115 /* 116 * Add an EISA ID based descriptive name incase we don't 117 * have a driver for it. We do this now instead of after all 118 * probes because in the future, the eisa module will only 119 * be responsible for creating the list of devices in the system 120 * for the configuration manager to use. 121 */ 122 e_dev->full_name = (char *)malloc(10*sizeof(char), 123 M_DEVBUF, M_NOWAIT); 124 if (!e_dev->full_name) { 125 panic("Eisa probe unable to malloc"); 126 } 127 sprintf(e_dev->full_name, "%c%c%c%x%x", 128 EISA_MFCTR_CHAR0(e_dev->id), 129 EISA_MFCTR_CHAR1(e_dev->id), 130 EISA_MFCTR_CHAR2(e_dev->id), 131 EISA_PRODUCT_ID(e_dev->id), 132 EISA_REVISION_ID(e_dev->id)); 133 e_dev->ioconf.slot = slot; 134 /* Is iobase defined in any EISA specs? */ 135 e_dev->ioconf.iobase = eisaBase & 0xff00; 136 *eisa_dev_list_tail = dev_node; 137 eisa_dev_list_tail = &dev_node->next; 138 } 139 140 dev_node = eisa_dev_list; 141 142 /* 143 * "Attach" the system board 144 */ 145 146 /* The first will be the motherboard in a true EISA system */ 147 if (dev_node && (dev_node->dev.ioconf.slot == 0)) { 148 e_dev = &dev_node->dev; 149 e_dev->driver = &mainboard_drv; 150 e_dev->unit = (*e_dev->driver->unit)++; 151 id_string = e_dev->full_name; 152 e_dev->full_name = (char *)malloc(strlen(e_dev->full_name) 153 + sizeof(" (System Board)") 154 + 1, M_DEVBUF, M_NOWAIT); 155 if (!e_dev->full_name) { 156 panic("Eisa probe unable to malloc"); 157 } 158 sprintf(e_dev->full_name, "%s (System Board)", id_string); 159 free(id_string, M_DEVBUF); 160 161 printf("%s%ld: <%s>\n", 162 e_dev->driver->name, 163 e_dev->unit, 164 e_dev->full_name); 165 166 /* Should set the iosize, but I don't have a spec handy */ 167 kdc_eisa0.kdc_description = 168 (char *)malloc(strlen(e_dev->full_name) 169 + sizeof("EISA bus <>") 170 + 1, M_DEVBUF, M_NOWAIT); 171 if (!kdc_eisa0.kdc_description) { 172 panic("Eisa probe unable to malloc"); 173 } 174 sprintf((char *)kdc_eisa0.kdc_description, "EISA bus <%s>", 175 e_dev->full_name); 176 dev_attach(&kdc_eisa0); 177 printf("Probing for devices on the EISA bus\n"); 178 dev_node = dev_node->next; 179 } 180 181 if (!eisa_dev_list) { 182 /* 183 * No devices. 184 */ 185 return; 186 } 187 /* 188 * See what devices we recognize. 189 */ 190 while((e_drv = *e_drvp++)) { 191 if (e_drv->probe) 192 (*e_drv->probe)(); 193 } 194 195 /* 196 * Attach the devices we found in slot order 197 */ 198 for (; dev_node; dev_node=dev_node->next) { 199 e_dev = &dev_node->dev; 200 e_drv = e_dev->driver; 201 if (e_drv) { 202 /* 203 * Determine the proper unit number for this device. 204 * Here we should look in the device table generated 205 * by config to see if this type of device is enabled 206 * either generically or for this particular address 207 * as well as determine if a reserved unit number 208 * should be used. We should also ensure that the 209 * "next availible unit number" skips over "wired" unit 210 * numbers. This will be done after config is fixed or 211 * some other configuration method is chosen. 212 */ 213 e_dev->unit = (*e_drv->unit)++; 214 if ((*e_drv->attach)(e_dev) < 0) { 215 printf("%s0:%d <%s> attach failed\n", 216 mainboard_drv.name, 217 e_dev->ioconf.slot, 218 e_dev->full_name); 219 continue; 220 } 221 e_dev->kdc->kdc_unit = e_dev->unit; 222 } 223 else { 224 /* Announce unattached device */ 225 printf("%s0:%d <%s> unknown device\n", 226 mainboard_drv.name, 227 e_dev->ioconf.slot, 228 e_dev->full_name); 229 } 230 } 231} 232 233struct eisa_device * 234eisa_match_dev(e_dev, match_func) 235 struct eisa_device *e_dev; 236 char* (*match_func)(eisa_id_t); 237{ 238 struct eisa_device_node *e_node = eisa_dev_list; 239 240 if (e_dev) { 241 /* Start our search from the last successful match */ 242 e_node = ((struct eisa_device_node *)e_dev)->next; 243 } 244 245 for(; e_node; e_node = e_node->next) { 246 char *result; 247 if (e_node->dev.driver) { 248 /* Already claimed */ 249 continue; 250 } 251 result = (*match_func)(e_node->dev.id); 252 if (result) { 253 free(e_node->dev.full_name, M_DEVBUF); 254 e_node->dev.full_name = result; 255 return (&(e_node->dev)); 256 } 257 } 258 return NULL; 259} 260 261/* Interrupt and I/O space registration facitlities */ 262void 263eisa_reg_start(e_dev) 264 struct eisa_device *e_dev; 265{ 266 /* 267 * Announce the device. 268 */ 269 printf("%s%ld: <%s>", 270 e_dev->driver->name, 271 e_dev->unit, 272 e_dev->full_name); 273} 274 275/* Interrupt and I/O space registration facitlities */ 276void 277eisa_reg_end(e_dev) 278 struct eisa_device *e_dev; 279{ 280 /* 281 * The device should have called eisa_registerdev() 282 * during its probe. So hopefully we can use the kdc 283 * to weed out ISA/VL devices that use EISA id registers. 284 */ 285 if (e_dev->kdc && (e_dev->kdc->kdc_parent == &kdc_isa0)) { 286 printf(" on isa\n"); 287 } 288 else { 289 printf(" on %s0 slot %d\n", 290 mainboard_drv.name, 291 e_dev->ioconf.slot); 292 } 293} 294 295int 296eisa_add_intr(e_dev, irq) 297 struct eisa_device *e_dev; 298 int irq; 299{ 300 e_dev->ioconf.irq |= 1ul << irq; 301 return 0; 302} 303 304int 305eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) 306 struct eisa_device *e_dev; 307 int irq; 308 void (*func)(void *); 309 void *arg; 310 u_int *maskptr; 311 int shared; 312{ 313 int result; 314 int s; 315 316#if NOT_YET 317 /* 318 * Punt on conflict detection for the moment. 319 * I want to develop a generic routine to do 320 * this for all device types. 321 */ 322 int checkthese = CC_IRQ; 323 if (haveseen_dev(dev, checkthese)) 324 return 1; 325#endif 326 s = splhigh(); 327 /* 328 * This should really go to a routine that can optionally 329 * handle shared interrupts. 330 */ 331 result = register_intr(irq, /* isa irq */ 332 0, /* deviced?? */ 333 0, /* flags? */ 334 (inthand2_t*) func, /* handler */ 335 maskptr, /* mask pointer */ 336 (int)arg); /* handler arg */ 337 338 if (result) { 339 printf ("eisa_reg_int: result=%d\n", result); 340 splx(s); 341 return (result); 342 }; 343 update_intr_masks(); 344 splx(s); 345 346 e_dev->ioconf.irq |= 1ul << irq; 347 printf(" irq %d", irq); 348 return (0); 349} 350 351int 352eisa_release_intr(e_dev, irq, func) 353 struct eisa_device *e_dev; 354 int irq; 355 void (*func)(void *); 356{ 357 int result; 358 int s; 359 360 if (!(e_dev->ioconf.irq & (1ul << irq))) { 361 printf("%s%ld: Attempted to release an interrupt (%d) " 362 "it doesn't own\n", e_dev->driver->name, 363 e_dev->unit, irq); 364 return (-1); 365 } 366 367 s = splhigh(); 368 INTRDIS ((1ul<<irq)); 369 370 result = unregister_intr (irq, (inthand2_t*)func); 371 372 if (result) 373 printf ("eisa_release_intr: result=%d\n", result); 374 375 update_intr_masks(); 376 377 splx(s); 378 return (result); 379} 380 381int 382eisa_enable_intr(e_dev, irq) 383 struct eisa_device *e_dev; 384 int irq; 385{ 386 int s; 387 388 if (!(e_dev->ioconf.irq & (1ul << irq))) { 389 printf("%s%ld: Attempted to enable an interrupt (%d) " 390 "it doesn't own\n", e_dev->driver->name, 391 e_dev->unit, irq); 392 return (-1); 393 } 394 s = splhigh(); 395 INTREN((1ul << irq)); 396 splx(s); 397 return 0; 398} 399 400int 401eisa_add_iospace(e_dev, iobase, iosize) 402 struct eisa_device *e_dev; 403 u_long iobase; 404 int iosize; 405{ 406 /* 407 * We should develop a scheme for storing the results of 408 * multiple calls to this function. 409 */ 410 e_dev->ioconf.iobase = iobase; 411 e_dev->ioconf.iosize = iosize; 412 return 0; 413} 414 415int 416eisa_reg_iospace(e_dev, iobase, iosize) 417 struct eisa_device *e_dev; 418 u_long iobase; 419 int iosize; 420{ 421 /* 422 * We should develop a scheme for storing the results of 423 * multiple calls to this function. 424 */ 425#ifdef NOT_YET 426 /* 427 * Punt on conflict detection for the moment. 428 * I want to develop a generic routine to do 429 * this for all device types. 430 */ 431 int checkthese = CC_IOADDR; 432 if (haveseen_dev(dev, checkthese)) 433 return -1; 434#endif 435 e_dev->ioconf.iobase = iobase; 436 e_dev->ioconf.iosize = iosize; 437 438 printf(" at 0x%lx-0x%lx", iobase, iobase + iosize - 1); 439 return (0); 440} 441 442int 443eisa_registerdev(e_dev, driver, kdc_template) 444 struct eisa_device *e_dev; 445 struct eisa_driver *driver; 446 struct kern_devconf *kdc_template; 447{ 448 e_dev->driver = driver; /* Driver now owns this device */ 449 e_dev->kdc = (struct kern_devconf *)malloc(sizeof(struct kern_devconf), 450 M_DEVBUF, M_NOWAIT); 451 if (!e_dev->kdc) { 452 printf("WARNING: eisa_registerdev unable to malloc! " 453 "Device kdc will not be registerd\n"); 454 return 1; 455 } 456 bcopy(kdc_template, e_dev->kdc, sizeof(*kdc_template)); 457 e_dev->kdc->kdc_description = e_dev->full_name; 458 e_dev->kdc->kdc_parentdata = e_dev; 459 dev_attach(e_dev->kdc); 460 return (0); 461} 462 463/* 464 * Provide EISA-specific device information to user programs using the 465 * hw.devconf interface. 466 */ 467int 468eisa_externalize(struct eisa_device *e_dev, struct sysctl_req *req) 469{ 470 return (SYSCTL_OUT(req, e_dev, sizeof *e_dev)); 471} 472 473 474int 475eisa_generic_externalize(struct kern_devconf *kdc, struct sysctl_req *req) 476{ 477 return eisa_externalize(kdc->kdc_eisa, req); 478} 479