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