eisaconf.c revision 50477
1193323Sed/*
2193323Sed * EISA bus probe and attach routines
3193323Sed *
4193323Sed * Copyright (c) 1995, 1996 Justin T. Gibbs.
5193323Sed * All rights reserved.
6193323Sed *
7193323Sed * Redistribution and use in source and binary forms, with or without
8193323Sed * modification, are permitted provided that the following conditions
9193323Sed * are met:
10193323Sed * 1. Redistributions of source code must retain the above copyright
11193323Sed *    notice immediately at the beginning of the file, without modification,
12193323Sed *    this list of conditions, and the following disclaimer.
13204961Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
14198090Srdivacky *    notice, this list of conditions and the following disclaimer in the
15193323Sed *    documentation and/or other materials provided with the distribution.
16206274Srdivacky * 3. The name of the author may not be used to endorse or promote products
17234353Sdim *    derived from this software without specific prior written permission.
18221345Sdim *
19206274Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21218893Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22234353Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23198090Srdivacky * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25204961Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26198090Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27198090Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28204961Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29198090Srdivacky * SUCH DAMAGE.
30218893Sdim *
31198090Srdivacky * $FreeBSD: head/sys/dev/eisa/eisaconf.c 50477 1999-08-28 01:08:13Z peter $
32206274Srdivacky */
33198090Srdivacky
34207618Srdivacky#include "opt_eisa.h"
35206274Srdivacky
36219077Sdim#include <sys/param.h>
37218893Sdim#include <sys/systm.h>
38205218Srdivacky#include <sys/queue.h>
39198090Srdivacky#include <sys/malloc.h>
40207618Srdivacky#include <sys/kernel.h>
41198090Srdivacky#include <sys/module.h>
42198090Srdivacky#include <sys/bus.h>
43203954Srdivacky
44202878Srdivacky#include <machine/limits.h>
45193323Sed#include <machine/bus.h>
46218893Sdim#include <machine/resource.h>
47193323Sed#include <sys/rman.h>
48193323Sed
49212904Sdim#include <i386/eisa/eisaconf.h>
50210299Sed
51207618Srdivacky#include <sys/interrupt.h>
52207618Srdivacky
53208599Srdivackytypedef struct resvaddr {
54221345Sdim        u_long	addr;				/* start address */
55208599Srdivacky        u_long	size;				/* size of reserved area */
56208599Srdivacky	int	flags;
57234353Sdim	struct resource *res;			/* resource manager handle */
58234353Sdim	LIST_ENTRY(resvaddr) links;		/* List links */
59234353Sdim} resvaddr_t;
60234353Sdim
61207618SrdivackyLIST_HEAD(resvlist, resvaddr);
62207618Srdivacky
63207618Srdivackystruct irq_node {
64207618Srdivacky	int	irq_no;
65207618Srdivacky	int	irq_trigger;
66193323Sed	void	*idesc;
67193323Sed	TAILQ_ENTRY(irq_node) links;
68193323Sed};
69193323Sed
70193323SedTAILQ_HEAD(irqlist, irq_node);
71193323Sed
72193323Sedstruct eisa_ioconf {
73193323Sed	int		slot;
74226633Sdim	struct resvlist	ioaddrs;	/* list of reserved I/O ranges */
75221345Sdim	struct resvlist maddrs;		/* list of reserved memory ranges */
76221345Sdim	struct irqlist	irqs;		/* list of reserved irqs */
77221345Sdim};
78221345Sdim
79221345Sdim/* To be replaced by the "super device" generic device structure... */
80221345Sdimstruct eisa_device {
81221345Sdim	eisa_id_t		id;
82221345Sdim	struct eisa_ioconf	ioconf;
83221345Sdim};
84221345Sdim
85221345Sdim
86221345Sdim/* Global variable, so UserConfig can change it. */
87221345Sdim#define MAX_COL		79
88221345Sdim#ifndef EISA_SLOTS
89221345Sdim#define EISA_SLOTS 10   /* PCI clashes with higher ones.. fix later */
90221345Sdim#endif
91221345Sdimint num_eisa_slots = EISA_SLOTS;
92221345Sdim
93221345Sdimstatic devclass_t eisa_devclass;
94221345Sdim
95221345Sdimstatic void eisa_reg_print (device_t, char *, char *, int *);
96221345Sdimstatic struct irq_node * eisa_find_irq(struct eisa_device *e_dev, int rid);
97221345Sdimstatic struct resvaddr * eisa_find_maddr(struct eisa_device *e_dev, int rid);
98221345Sdimstatic struct resvaddr * eisa_find_ioaddr(struct eisa_device *e_dev, int rid);
99221345Sdim
100221345Sdimstatic int
101221345Sdimmainboard_probe(device_t dev)
102221345Sdim{
103221345Sdim	char *idstring;
104221345Sdim	eisa_id_t id = eisa_get_id(dev);
105221345Sdim
106221345Sdim	if (eisa_get_slot(dev) != 0)
107221345Sdim		return (ENXIO);
108221345Sdim
109212904Sdim	idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1,
110221345Sdim				  M_DEVBUF, M_NOWAIT);
111221345Sdim	if (idstring == NULL) {
112221345Sdim		panic("Eisa probe unable to malloc");
113221345Sdim	}
114221345Sdim	sprintf(idstring, "%c%c%c%03x%01x (System Board)",
115221345Sdim		EISA_MFCTR_CHAR0(id),
116221345Sdim		EISA_MFCTR_CHAR1(id),
117221345Sdim		EISA_MFCTR_CHAR2(id),
118221345Sdim		EISA_PRODUCT_ID(id),
119221345Sdim		EISA_REVISION_ID(id));
120212904Sdim	device_set_desc(dev, idstring);
121212904Sdim
122221345Sdim	return (0);
123221345Sdim}
124193323Sed
125206274Srdivackystatic int
126193323Sedmainboard_attach(device_t dev)
127206274Srdivacky{
128208599Srdivacky	return (0);
129212904Sdim}
130226633Sdim
131205218Srdivackystatic device_method_t mainboard_methods[] = {
132212904Sdim	/* Device interface */
133223017Sdim	DEVMETHOD(device_probe,		mainboard_probe),
134206274Srdivacky	DEVMETHOD(device_attach,	mainboard_attach),
135212904Sdim
136208599Srdivacky	{ 0, 0 }
137234353Sdim};
138234353Sdim
139234353Sdimstatic driver_t mainboard_driver = {
140234353Sdim	"mainboard",
141234353Sdim	mainboard_methods,
142210299Sed	1,
143210299Sed};
144210299Sed
145207618Srdivackystatic devclass_t mainboard_devclass;
146193323Sed
147193323SedDRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0);
148193323Sed
149193323Sed/*
150234353Sdim** probe for EISA devices
151234353Sdim*/
152234353Sdimstatic int
153234353Sdimeisa_probe(device_t dev)
154234353Sdim{
155234353Sdim	int i,slot;
156234353Sdim	struct eisa_device *e_dev;
157234353Sdim	int eisaBase = 0xc80;
158234353Sdim	eisa_id_t eisa_id;
159234353Sdim	int devices_found = 0;
160234353Sdim
161234353Sdim	device_set_desc(dev, "EISA bus");
162234353Sdim
163234353Sdim	for (slot = 0; slot < num_eisa_slots; eisaBase+=0x1000, slot++) {
164234353Sdim		int id_size = sizeof(eisa_id);
165234353Sdim		eisa_id = 0;
166205218Srdivacky    		for( i = 0; i < id_size; i++ ) {
167205218Srdivacky			outb(eisaBase,0x80 + i); /*Some cards require priming*/
168205218Srdivacky			eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT);
169205218Srdivacky		}
170205218Srdivacky		if (eisa_id & 0x80000000)
171206274Srdivacky			continue;  /* no EISA card in slot */
172205218Srdivacky
173205218Srdivacky		devices_found++;
174199989Srdivacky
175193323Sed		/* Prepare an eisa_device_node for this slot */
176199989Srdivacky		e_dev = (struct eisa_device *)malloc(sizeof(*e_dev),
177193323Sed						     M_DEVBUF, M_NOWAIT);
178193323Sed		if (!e_dev) {
179193323Sed			device_printf(dev, "cannot malloc eisa_device");
180193323Sed			break; /* Try to attach what we have already */
181193323Sed		}
182193323Sed		bzero(e_dev, sizeof(*e_dev));
183193323Sed
184193323Sed		e_dev->id = eisa_id;
185193323Sed
186193323Sed		e_dev->ioconf.slot = slot;
187193323Sed
188193323Sed		/* Initialize our lists of reserved addresses */
189193323Sed		LIST_INIT(&(e_dev->ioconf.ioaddrs));
190193323Sed		LIST_INIT(&(e_dev->ioconf.maddrs));
191193323Sed		TAILQ_INIT(&(e_dev->ioconf.irqs));
192193323Sed
193193323Sed		device_add_child(dev, NULL, -1, e_dev);
194193323Sed	}
195193323Sed
196193323Sed	/*
197212904Sdim	 * EISA busses themselves are not easily detectable, the easiest way
198202375Srdivacky	 * to tell if there is an eisa bus is if we found something - there
199202375Srdivacky	 * should be a motherboard "card" there somewhere.
200202375Srdivacky	 */
201202375Srdivacky	return devices_found ? 0 : ENXIO;
202202375Srdivacky}
203202375Srdivacky
204202375Srdivackystatic void
205202375Srdivackyeisa_probe_nomatch(device_t dev, device_t child)
206202375Srdivacky{
207234353Sdim	u_int32_t	eisa_id = eisa_get_id(child);
208234353Sdim	u_int8_t	slot = eisa_get_slot(child);
209234353Sdim
210234353Sdim	device_printf(dev, "unknown card %c%c%c%03x%01x (0x%08x) at slot %d\n",
211234353Sdim		EISA_MFCTR_CHAR0(eisa_id),
212234353Sdim		EISA_MFCTR_CHAR1(eisa_id),
213234353Sdim		EISA_MFCTR_CHAR2(eisa_id),
214234353Sdim		EISA_PRODUCT_ID(eisa_id),
215234353Sdim		EISA_REVISION_ID(eisa_id),
216234353Sdim		eisa_id,
217234353Sdim		slot);
218234353Sdim
219234353Sdim	return;
220234353Sdim}
221234353Sdim
222234353Sdimstatic void
223234353Sdimeisa_reg_print (dev, string, separator, column)
224234353Sdim	device_t	dev;
225234353Sdim	char *		string;
226234353Sdim	char *		separator;
227234353Sdim	int *		column;
228234353Sdim{
229234353Sdim	int length = strlen(string);
230234353Sdim
231234353Sdim	length += (separator ? 2 : 1);
232234353Sdim
233234353Sdim	if (((*column) + length) >= MAX_COL) {
234234353Sdim		printf("\n");
235234353Sdim		(*column) = 0;
236234353Sdim	} else if ((*column) != 0) {
237234353Sdim		if (separator) {
238234353Sdim			printf("%c", *separator);
239234353Sdim			(*column)++;
240234353Sdim		}
241234353Sdim		printf(" ");
242234353Sdim		(*column)++;
243234353Sdim	}
244234353Sdim
245234353Sdim	if ((*column) == 0) {
246234353Sdim		(*column) += device_printf(dev, "%s", string);
247234353Sdim	} else {
248234353Sdim		(*column) += printf("%s", string);
249234353Sdim	}
250234353Sdim
251234353Sdim	return;
252234353Sdim}
253234353Sdim
254234353Sdimstatic int
255234353Sdimeisa_print_child(device_t dev, device_t child)
256234353Sdim{
257234353Sdim	char			buf[81];
258234353Sdim	struct eisa_device *	e_dev = device_get_ivars(child);
259234353Sdim	int			rid;
260234353Sdim	struct irq_node *	irq;
261234353Sdim	struct resvaddr *	resv;
262234353Sdim	char			separator = ',';
263234353Sdim	int			column = 0;
264199989Srdivacky	int			retval = 0;
265199989Srdivacky
266199989Srdivacky	if (device_get_desc(child)) {
267199989Srdivacky		snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
268226633Sdim		eisa_reg_print(child, buf, NULL, &column);
269226633Sdim	}
270208599Srdivacky
271210299Sed	rid = 0;
272206274Srdivacky	while ((resv = eisa_find_ioaddr(e_dev, rid++))) {
273206274Srdivacky		if ((resv->size == 1) ||
274212904Sdim		    (resv->flags & RESVADDR_BITMASK)) {
275221345Sdim			snprintf(buf, sizeof(buf), "%s%lx",
276234353Sdim				((rid == 1) ? "at 0x" : "0x"),
277221345Sdim				resv->addr);
278221345Sdim		} else {
279221345Sdim			snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
280221345Sdim				((rid == 1) ? "at 0x" : "0x"),
281221345Sdim				resv->addr,
282221345Sdim				(resv->addr + (resv->size - 1)));
283221345Sdim		}
284221345Sdim		eisa_reg_print(child, buf,
285234353Sdim			((rid == 2) ? &separator : NULL), &column);
286221345Sdim	}
287221345Sdim
288221345Sdim	rid = 0;
289221345Sdim	while ((resv = eisa_find_maddr(e_dev, rid++))) {
290221345Sdim		if ((resv->size == 1) ||
291221345Sdim		    (resv->flags & RESVADDR_BITMASK)) {
292221345Sdim			snprintf(buf, sizeof(buf), "%s%lx",
293221345Sdim				((rid == 1) ? "at 0x" : "0x"),
294221345Sdim				resv->addr);
295221345Sdim		} else {
296221345Sdim			snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
297221345Sdim				((rid == 1) ? "at 0x" : "0x"),
298221345Sdim				resv->addr,
299221345Sdim				(resv->addr + (resv->size - 1)));
300221345Sdim		}
301221345Sdim		eisa_reg_print(child, buf,
302221345Sdim			((rid == 2) ? &separator : NULL), &column);
303221345Sdim	}
304221345Sdim
305221345Sdim	rid = 0;
306206274Srdivacky	while ((irq = eisa_find_irq(e_dev, rid++)) != NULL) {
307210299Sed		snprintf(buf, sizeof(buf), "irq %d (%s)", irq->irq_no,
308210299Sed			 (irq->irq_trigger ? "level" : "edge"));
309210299Sed		eisa_reg_print(child, buf,
310221345Sdim			((rid == 1) ? &separator : NULL), &column);
311221345Sdim	}
312210299Sed
313210299Sed	snprintf(buf, sizeof(buf), "on %s slot %d\n",
314210299Sed		device_get_nameunit(dev), eisa_get_slot(child));
315221345Sdim	eisa_reg_print(child, buf, NULL, &column);
316221345Sdim
317221345Sdim	return (retval);
318221345Sdim}
319206274Srdivacky
320206274Srdivackystatic struct irq_node *
321221345Sdimeisa_find_irq(struct eisa_device *e_dev, int rid)
322203954Srdivacky{
323234353Sdim	int i;
324234353Sdim	struct irq_node *irq;
325234353Sdim
326234353Sdim	for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
327206274Srdivacky	     i < rid && irq;
328199481Srdivacky	     i++, irq = TAILQ_NEXT(irq, links))
329193323Sed		;
330199989Srdivacky
331199989Srdivacky	if (irq)
332226633Sdim		return (irq);
333226633Sdim	else
334207618Srdivacky		return (NULL);
335207618Srdivacky}
336207618Srdivacky
337207618Srdivackystatic struct resvaddr *
338226633Sdimeisa_find_maddr(struct eisa_device *e_dev, int rid)
339207618Srdivacky{
340207618Srdivacky	int i;
341207618Srdivacky	struct resvaddr *resv;
342226633Sdim
343207618Srdivacky	for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs);
344207618Srdivacky	     i < rid && resv;
345212904Sdim	     i++, resv = LIST_NEXT(resv, links))
346207618Srdivacky		;
347221345Sdim
348226633Sdim	return resv;
349226633Sdim}
350226633Sdim
351207618Srdivackystatic struct resvaddr *
352208599Srdivackyeisa_find_ioaddr(struct eisa_device *e_dev, int rid)
353208599Srdivacky{
354207618Srdivacky	int i;
355207618Srdivacky	struct resvaddr *resv;
356207618Srdivacky
357207618Srdivacky	for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs);
358207618Srdivacky	     i < rid && resv;
359207618Srdivacky	     i++, resv = LIST_NEXT(resv, links))
360208599Srdivacky		;
361208599Srdivacky
362207618Srdivacky	return resv;
363208599Srdivacky}
364193323Sed
365204961Srdivackystatic int
366204961Srdivackyeisa_read_ivar(device_t dev, device_t child, int which, u_long *result)
367212904Sdim{
368221345Sdim	struct eisa_device *e_dev = device_get_ivars(child);
369221345Sdim	struct irq_node *irq;
370193323Sed
371199481Srdivacky	switch (which) {
372199481Srdivacky	case EISA_IVAR_SLOT:
373193323Sed		*result = e_dev->ioconf.slot;
374199989Srdivacky		break;
375199989Srdivacky
376199989Srdivacky	case EISA_IVAR_ID:
377226633Sdim		*result = e_dev->id;
378226633Sdim		break;
379226633Sdim
380234353Sdim	case EISA_IVAR_IRQ:
381234353Sdim		/* XXX only first irq */
382207618Srdivacky		if ((irq = eisa_find_irq(e_dev, 0)) != NULL) {
383226633Sdim			*result = irq->irq_no;
384226633Sdim		} else {
385226633Sdim			*result = -1;
386226633Sdim		}
387226633Sdim		break;
388226633Sdim
389226633Sdim	default:
390226633Sdim		return (ENOENT);
391226633Sdim	}
392226633Sdim
393226633Sdim	return (0);
394208599Srdivacky}
395208599Srdivacky
396207618Srdivackystatic int
397210299Sedeisa_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
398234353Sdim{
399207618Srdivacky	return (EINVAL);
400204961Srdivacky}
401204961Srdivacky
402204961Srdivackystatic struct resource *
403204961Srdivackyeisa_alloc_resource(device_t dev, device_t child, int type, int *rid,
404207618Srdivacky		    u_long start, u_long end, u_long count, u_int flags)
405223017Sdim{
406221345Sdim	int isdefault;
407221345Sdim	struct eisa_device *e_dev = device_get_ivars(child);
408193323Sed	struct resource *rv, **rvp = 0;
409226633Sdim
410226633Sdim	isdefault = (device_get_parent(child) == dev
411226633Sdim		     && start == 0UL && end == ~0UL && count == 1);
412226633Sdim
413226633Sdim	switch (type) {
414226633Sdim	case SYS_RES_IRQ:
415226633Sdim		if (isdefault) {
416226633Sdim			struct irq_node * irq = eisa_find_irq(e_dev, *rid);
417226633Sdim			if (irq == NULL)
418226633Sdim				return 0;
419226633Sdim			start = end = irq->irq_no;
420226633Sdim			count = 1;
421226633Sdim			if (irq->irq_trigger == EISA_TRIGGER_LEVEL) {
422226633Sdim				flags |= RF_SHAREABLE;
423226633Sdim			} else {
424226633Sdim				flags &= ~RF_SHAREABLE;
425226633Sdim			}
426226633Sdim		}
427226633Sdim		break;
428226633Sdim
429199481Srdivacky	case SYS_RES_MEMORY:
430199481Srdivacky		if (isdefault) {
431199481Srdivacky			struct resvaddr *resv;
432199481Srdivacky
433226633Sdim			resv = eisa_find_maddr(e_dev, *rid);
434226633Sdim			if (!resv)
435226633Sdim				return 0;
436226633Sdim
437208599Srdivacky			start = resv->addr;
438208599Srdivacky			end = resv->addr + (resv->size - 1);
439199481Srdivacky			count = resv->size;
440199481Srdivacky			rvp = &resv->res;
441234353Sdim		}
442208599Srdivacky		break;
443199481Srdivacky
444204961Srdivacky	case SYS_RES_IOPORT:
445199481Srdivacky		if (isdefault) {
446199481Srdivacky			struct resvaddr *resv;
447234353Sdim
448234353Sdim			resv = eisa_find_ioaddr(e_dev, *rid);
449221345Sdim			if (!resv)
450199481Srdivacky				return 0;
451234353Sdim
452234353Sdim			start = resv->addr;
453234353Sdim			end = resv->addr + (resv->size - 1);
454234353Sdim			count = resv->size;
455199481Srdivacky			rvp = &resv->res;
456193323Sed		}
457193323Sed		break;
458199989Srdivacky
459226633Sdim	default:
460204961Srdivacky		return 0;
461204961Srdivacky	}
462212904Sdim
463234353Sdim	rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
464221345Sdim				 type, rid, start, end, count, flags);
465221345Sdim	if (rvp)
466226633Sdim		*rvp = rv;
467221345Sdim
468221345Sdim	return rv;
469226633Sdim}
470226633Sdim
471221345Sdimstatic int
472221345Sdimeisa_release_resource(device_t dev, device_t child, int type, int rid,
473226633Sdim		      struct resource *r)
474226633Sdim{
475218893Sdim	int rv;
476226633Sdim	struct eisa_device *e_dev = device_get_ivars(child);
477226633Sdim	struct resvaddr *resv = 0;
478218893Sdim
479226633Sdim	switch (type) {
480218893Sdim	case SYS_RES_IRQ:
481226633Sdim		if (eisa_find_irq(e_dev, rid) == NULL)
482218893Sdim			return EINVAL;
483204961Srdivacky		break;
484204961Srdivacky
485204961Srdivacky	case SYS_RES_MEMORY:
486226633Sdim		if (device_get_parent(child) == dev)
487204961Srdivacky			resv = eisa_find_maddr(e_dev, rid);
488210299Sed		break;
489210299Sed
490226633Sdim
491210299Sed	case SYS_RES_IOPORT:
492210299Sed		if (device_get_parent(child) == dev)
493210299Sed			resv = eisa_find_ioaddr(e_dev, rid);
494210299Sed		break;
495204961Srdivacky
496226633Sdim	default:
497204961Srdivacky		return (ENOENT);
498218893Sdim	}
499218893Sdim
500218893Sdim	rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r);
501218893Sdim
502226633Sdim	if (rv == 0) {
503218893Sdim		if (resv)
504218893Sdim			resv->res = 0;
505206083Srdivacky	}
506212904Sdim
507218893Sdim	return rv;
508218893Sdim}
509218893Sdim
510218893Sdimint
511198090Srdivackyeisa_add_intr(device_t dev, int irq, int trigger)
512212904Sdim{
513234353Sdim	struct eisa_device *e_dev = device_get_ivars(dev);
514212904Sdim	struct irq_node *irq_info;
515234353Sdim
516193323Sed	irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF,
517193323Sed					     M_NOWAIT);
518193323Sed	if (irq_info == NULL)
519193323Sed		return (1);
520193323Sed
521193323Sed	irq_info->irq_no = irq;
522221345Sdim	irq_info->irq_trigger = trigger;
523221345Sdim	irq_info->idesc = NULL;
524218893Sdim	TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links);
525218893Sdim	return 0;
526221345Sdim}
527193323Sed
528234353Sdimstatic int
529234353Sdimeisa_add_resvaddr(struct eisa_device *e_dev, struct resvlist *head, u_long base,
530234353Sdim		  u_long size, int flags)
531221345Sdim{
532234353Sdim	resvaddr_t *reservation;
533193323Sed
534234353Sdim	reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
535234353Sdim					   M_DEVBUF, M_NOWAIT);
536234353Sdim	if(!reservation)
537234353Sdim		return (ENOMEM);
538234353Sdim
539193323Sed	reservation->addr = base;
540234353Sdim	reservation->size = size;
541234353Sdim	reservation->flags = flags;
542234353Sdim
543234353Sdim	if (!head->lh_first) {
544218893Sdim		LIST_INSERT_HEAD(head, reservation, links);
545234353Sdim	}
546193323Sed	else {
547193323Sed		resvaddr_t *node;
548193323Sed		for(node = head->lh_first; node; node = node->links.le_next) {
549193323Sed			if (node->addr > reservation->addr) {
550212904Sdim				/*
551208599Srdivacky				 * List is sorted in increasing
552226633Sdim				 * address order.
553198090Srdivacky				 */
554199989Srdivacky				LIST_INSERT_BEFORE(node, reservation, links);
555234353Sdim				break;
556234353Sdim			}
557193323Sed
558193323Sed			if (node->addr == reservation->addr) {
559234353Sdim				/*
560234353Sdim				 * If the entry we want to add
561221345Sdim				 * matches any already in here,
562221345Sdim				 * fail.
563234353Sdim				 */
564234353Sdim				free(reservation, M_DEVBUF);
565234353Sdim				return (EEXIST);
566234353Sdim			}
567206083Srdivacky
568212904Sdim			if (!node->links.le_next) {
569234353Sdim				LIST_INSERT_AFTER(node, reservation, links);
570223017Sdim				break;
571221345Sdim			}
572212904Sdim		}
573221345Sdim	}
574193323Sed	return (0);
575234353Sdim}
576234353Sdim
577193323Sedint
578221345Sdimeisa_add_mspace(device_t dev, u_long mbase, u_long msize, int flags)
579193323Sed{
580199989Srdivacky	struct eisa_device *e_dev = device_get_ivars(dev);
581199989Srdivacky
582234353Sdim	return	eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize,
583221345Sdim				  flags);
584234353Sdim}
585221345Sdim
586193323Sedint
587193323Sedeisa_add_iospace(device_t dev, u_long iobase, u_long iosize, int flags)
588208599Srdivacky{
589208599Srdivacky	struct eisa_device *e_dev = device_get_ivars(dev);
590208599Srdivacky
591226633Sdim	return	eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase,
592193323Sed				  iosize, flags);
593193323Sed}
594208599Srdivacky
595226633Sdimstatic device_method_t eisa_methods[] = {
596226633Sdim	/* Device interface */
597234353Sdim	DEVMETHOD(device_probe,		eisa_probe),
598234353Sdim	DEVMETHOD(device_attach,	bus_generic_attach),
599234353Sdim	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
600234353Sdim	DEVMETHOD(device_suspend,	bus_generic_suspend),
601234353Sdim	DEVMETHOD(device_resume,	bus_generic_resume),
602198090Srdivacky
603193323Sed	/* Bus interface */
604193323Sed	DEVMETHOD(bus_print_child,	eisa_print_child),
605193323Sed	DEVMETHOD(bus_probe_nomatch,	eisa_probe_nomatch),
606195098Sed	DEVMETHOD(bus_read_ivar,	eisa_read_ivar),
607193323Sed	DEVMETHOD(bus_write_ivar,	eisa_write_ivar),
608226633Sdim	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
609193323Sed	DEVMETHOD(bus_alloc_resource,	eisa_alloc_resource),
610193323Sed	DEVMETHOD(bus_release_resource,	eisa_release_resource),
611208599Srdivacky	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
612193323Sed	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
613193323Sed	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
614221345Sdim	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
615193323Sed
616195098Sed	{ 0, 0 }
617193323Sed};
618193323Sed
619226633Sdimstatic driver_t eisa_driver = {
620226633Sdim	"eisa",
621226633Sdim	eisa_methods,
622226633Sdim	1,			/* no softc */
623226633Sdim};
624226633Sdim
625226633SdimDRIVER_MODULE(eisa, isab, eisa_driver, eisa_devclass, 0, 0);
626226633SdimDRIVER_MODULE(eisa, nexus, eisa_driver, eisa_devclass, 0, 0);
627226633Sdim