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