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