eisaconf.c revision 13179
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.11 1995/12/10 13:33:49 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,0x80 + 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
464int
465eisa_generic_externalize(struct kern_devconf *kdc, struct sysctl_req *req)
466{
467    return (SYSCTL_OUT(req, kdc->kdc_eisa, sizeof(struct eisa_device)));
468}
469