1/*
| 1/*
|
2 * Written by Billie Alsup (balsup@tfs.com) 3 * for TRW Financial Systems for use under the MACH(2.5)and OSF/1 operating 4 * systems.
| 2 * EISA bus probe and attach routines
|
5 *
| 3 *
|
6 * TRW Financial Systems, in accordance with their agreement with Carnegie 7 * Mellon University, makes this software available to CMU to distribute 8 * or use in any manner that they see fit as long as this message is kept with 9 * the software. For this reason TFS also grants any other persons or 10 * organisations permission to use or modify this software.
| 4 * Copyright (c) 1995 Justin T. Gibbs. 5 * All rights reserved.
|
11 *
| 6 *
|
12 * TFS supplies this software to be publicly redistributed 13 * on the understanding that TFS is not responsible for the correct 14 * functioning of this software in any circumstances.
| 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.
|
15 *
| 20 *
|
16 * $Id: eisaconf.c,v 1.1 1995/04/23 08:55:41 julian Exp $
| 21 * $Id$
|
17 */
| 22 */
|
18 19/* 20 * Ported to run under FreeBSD by Julian Elischer (julian@tfs.com) Sept 1992 21 */ 22 23
| |
24#include <sys/param.h>
| 23#include <sys/param.h>
|
25#include <sys/systm.h> /* isn't it a joy */ 26#include <sys/kernel.h> /* to have three of these */
| 24#include 25#include
|
27#include <sys/conf.h>
| 26#include <sys/conf.h>
|
| 27#include <sys/malloc.h>
|
28 29#include "sys/types.h"
| 28 29#include "sys/types.h"
|
30#include "i386/isa/icu.h" 31#include "i386/isa/isa_device.h" /*we're a superset, so we need this */
| 30#include "i386/isa/icu.h" /* Hmmm. Interrupt stuff? */ 31#include <sys/devconf.h>
|
32#include "eisaconf.h" 33
| 32#include "eisaconf.h" 33
|
| 34struct eisa_device_node{ 35 struct eisa_device dev; 36 struct eisa_device_node *next; 37};
|
34
| 38
|
35struct isa_device eisaSlot[EISA_SLOTS]; 36struct isa_device isa_devtab_eisa[EISA_SLOTS+1]; 37int nexttab = 0; 38extern struct eisa_dev eisa_dev[];
| 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};
|
39
| 52
|
40#define EISA_MAKEID(p) ((((p)[0]&0x1F)<<10)|(((p)[1]&0x1F)<<5)|(((p)[2]&0x1F))) 41#define EISA_ID0(i) ((((i)>>10)&0x1F)+0x40) 42#define EISA_ID1(i) ((((i)>>5)&0x1F)+0x40) 43#define EISA_ID2(i) (((i)&0x1F)+0x40)
| 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 };
|
44/* 45** probe for EISA devices 46*/ 47void 48eisa_configure() 49{
| 71/* 72** probe for EISA devices 73*/ 74void 75eisa_configure() 76{
|
50 int i,j,slot,found,numports;
| 77 int i,j,slot; 78 char *id_string;
|
51 unsigned int checkthese;
| 79 unsigned int checkthese;
|
52 struct eisa_dev *edev_p;
| 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;
|
53 int eisaBase = 0xC80;
| 84 int eisaBase = 0xC80;
|
54 unsigned short productID, productType; 55 unsigned char productRevision,controlBits; 56 static char hexdigit[] = "0123456789ABCDEF"; 57#define HEXDIGIT(i) hexdigit[(i)&0x0f]
| 85 eisa_id_t eisa_id;
|
58 59 outb(eisaBase,0xFF);
| 86 87 outb(eisaBase,0xFF);
|
60 productID = inb(eisaBase); 61 if (productID & 0x80) { 62 printf("Warning: running EISA kernel on non-EISA system board\n"); 63 return;
| 88 eisa_id = inb(eisaBase); 89 if (eisa_id & 0x80) { 90 /* Not an EISA machine */ 91 return;
|
64 }
| 92 }
|
65 printf("Probing for devices on EISA bus\n"); 66 productID = (productID<<8) | inb(eisaBase+1); 67 productRevision = inb(eisaBase+2);
| |
68
| 93
|
69 printf("EISA0: %c%c%c v%d (System Board)\n" 70 ,EISA_ID0(productID) 71 ,EISA_ID1(productID) 72 ,EISA_ID2(productID) 73 ,(productRevision&7));
| 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 */
|
74
| 103
|
75 for (slot=1; eisaBase += 0x1000, slot < EISA_SLOTS; slot++) { 76 outb(eisaBase,0xFF); 77 productID = inb(eisaBase); 78 if (productID & 0x80) continue; /* no EISA card in slot */
| 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 }
|
79
| 137
|
80 productID = (productID<<8) | inb(eisaBase+1); 81 productType = inb(eisaBase+2); 82 productRevision = inb(eisaBase+3); 83 productType = (productType<<4) | (productRevision>>4); 84 productRevision &= 15; 85 controlBits = inb(eisaBase+4);
| 138 dev_node = eisa_dev_list;
|
86
| 139
|
87 printf("EISA%d: %c%c%c-%c%c%c.%x\n" 88 ,slot,EISA_ID0(productID),EISA_ID1(productID),EISA_ID2(productID) 89 ,HEXDIGIT(productType>>8) 90 ,HEXDIGIT(productType>>4) 91 ,HEXDIGIT(productType) 92 ,productRevision);
| 140 /* 141 * "Attach" the system board 142 */
|
93
| 143
|
94 if (!(controlBits & 1)) { 95 printf("...Card is disabled\n"); 96 /* continue;*/ 97 }
| 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");
|
98
| 147
|
99 /* 100 ** See if we recognize this product 101 */
| 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);
|
102
| 160
|
103 for (edev_p = eisa_dev,found=0; edev_p->productID[0]; edev_p++) { 104 struct isa_device *dev_p; 105 struct isa_driver *drv_p; 106 unsigned short configuredID;
| 161 printf("%s%d: <%s>\n", 162 e_dev->driver->name, 163 e_dev->unit, 164 e_dev->full_name);
|
107
| 165
|
108 configuredID = EISA_MAKEID(edev_p->productID); 109 if (configuredID != productID) continue; 110 if (edev_p->productType != productType) continue; 111 if (edev_p->productRevision > productRevision) continue;
| 166 /* Should set the iosize, but I don't have a spec handy */
|
112
| 167
|
113 /* 114 ** we're assuming: 115 ** if different drivers for the same board exist 116 ** (due to some revision incompatibility), that the 117 ** drivers will be listed in descending revision 118 ** order. The revision in the eisaDevs structure 119 ** should indicate the lowest revision supported 120 ** by the code. 121 ** 122 */ 123 dev_p = &eisaSlot[slot]; 124 memcpy(dev_p,&edev_p->isa_dev,sizeof(edev_p->isa_dev));
| 168 dev_attach(&kdc_eisa0);
|
125
| 169
|
126 drv_p = dev_p->id_driver; 127 dev_p->id_iobase = eisaBase; /* may get ammended by driver */
| 170 printf("Probing for devices on the EISA bus\n");
|
128
| 171
|
129#if defined(DEBUG) 130 printf("eisaProbe: probing %s%d\n" 131 ,drv_p->driver_name, dev_p->id_unit); 132#endif /* defined(DEBUG) */
| 172 /* 173 * See what devices we recognize. 174 */ 175 while(e_drv = *e_drvp++) { 176 (*e_drv->probe)(); 177 }
|
133
| 178
|
134 if (!(numports = drv_p->probe(dev_p))) { 135 continue; /* try another eisa device */ 136 } 137 edev_p->isa_dev.id_unit++; /*dubious*/ 138/** this should all be put in some common routine **/ 139 printf("%s%d", drv_p->name, dev_p->id_unit); 140 if (numports != -1) { 141 printf(" at 0x%x", dev_p->id_iobase); 142 if ((dev_p->id_iobase + numports - 1) != dev_p->id_iobase) { 143 printf("-0x%x", dev_p->id_iobase + numports - 1); 144 }
| 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;
|
145 }
| 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}
|
146
| 213
|
147 if (dev_p->id_irq) 148 printf(" irq %d", ffs(dev_p->id_irq) - 1); 149 if (dev_p->id_drq != -1) 150 printf(" drq %d", dev_p->id_drq); 151 if (dev_p->id_maddr) 152 printf(" maddr 0x%lx", kvtop(dev_p->id_maddr)); 153 if (dev_p->id_msize) 154 printf(" msize %d", dev_p->id_msize); 155 if (dev_p->id_flags) 156 printf(" flags 0x%x", dev_p->id_flags); 157 if (dev_p->id_iobase) { 158 if (dev_p->id_iobase < 0x100) { 159 printf(" on motherboard\n"); 160 } else { 161 if (dev_p->id_iobase >= 0x1000) { 162 printf (" on EISA\n"); 163 } else { 164 printf (" on ISA emulation\n"); 165 }
| 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));
|
166 } 167 }
| 240 } 241 }
|
168 /* 169 ** Now look for any live devices with the same starting I/O port and 170 ** give up if we clash 171 ** 172 ** what i'd really like is to set is how many i/o ports are in use. 173 ** but that isn't in this structure... 174 ** 175 */ 176 checkthese = 0; 177 if(dev_p->id_iobase ) checkthese |= CC_IOADDR; 178 if(dev_p->id_drq != -1 ) checkthese |= CC_DRQ; 179 if(dev_p->id_irq ) checkthese |= CC_IRQ; 180 if(dev_p->id_maddr ) checkthese |= CC_MEMADDR; 181 /* this may be stupid, it's probably too late if we clash here */ 182 if(haveseen_isadev( dev_p,checkthese)) 183 break; /* we can't proceed due to collision. bail */ 184 /* mark ourselves in existence and then put us in the eisa list */ 185 /* so that other things check against US for a clash */ 186 dev_p->id_alive = (numports == -1? 1 : numports); 187 memcpy(&(isa_devtab_eisa[nexttab]),dev_p,sizeof(edev_p->isa_dev)); 188 drv_p->attach(dev_p);
| 242 return NULL; 243}
|
189
| 244
|
190 if (dev_p->id_irq) { 191 if (edev_p->imask) 192 INTRMASK(*(edev_p->imask), dev_p->id_irq); 193 register_intr(ffs(dev_p->id_irq) - 1, dev_p->id_id, 194 dev_p->id_ri_flags, dev_p->id_intr, 195 edev_p->imask, dev_p->id_unit); 196 INTREN(dev_p->id_irq); 197 } 198 found = 1; 199 nexttab++; 200 break; /* go look at next slot*/ 201 }/* end of loop on known devices */ 202 if (!found) { 203 printf("...No driver installed for board\n"); 204 } 205 }/* end of loop on slots */ 206}/* end of routine */
| 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}
|
207
| 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}
|
208
| 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}
|
209
| 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;
|
210
| 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 */
|
211
| 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}
|
| |