Deleted Added
full compact
eisaconf.c (8876) eisaconf.c (12090)
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}