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