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