eisaconf.c revision 143759
11558Srgrimes/*-
21558Srgrimes * EISA bus probe and attach routines
31558Srgrimes *
41558Srgrimes * Copyright (c) 1995, 1996 Justin T. Gibbs.
51558Srgrimes * All rights reserved.
61558Srgrimes *
71558Srgrimes * Redistribution and use in source and binary forms, with or without
81558Srgrimes * modification, are permitted provided that the following conditions
91558Srgrimes * are met:
101558Srgrimes * 1. Redistributions of source code must retain the above copyright
111558Srgrimes *    notice immediately at the beginning of the file, without modification,
121558Srgrimes *    this list of conditions, and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 3. The name of the author may not be used to endorse or promote products
171558Srgrimes *    derived from this software without specific prior written permission.
181558Srgrimes *
191558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
201558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
231558Srgrimes * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291558Srgrimes * SUCH DAMAGE.
301558Srgrimes *
311558Srgrimes */
321558Srgrimes
331558Srgrimes#include <sys/cdefs.h>
341558Srgrimes__FBSDID("$FreeBSD: head/sys/dev/eisa/eisaconf.c 143759 2005-03-17 17:36:07Z imp $");
3541477Sjulian
3623675Speter#include "opt_eisa.h"
3741477Sjulian
3841477Sjulian#include <sys/param.h>
3950476Speter#include <sys/systm.h>
401558Srgrimes#include <sys/queue.h>
411558Srgrimes#include <sys/limits.h>
421558Srgrimes#include <sys/malloc.h>
4366861Sadrian#include <sys/kernel.h>
4466861Sadrian#include <sys/module.h>
4523675Speter#include <sys/bus.h>
461558Srgrimes
471558Srgrimes#include <machine/bus.h>
481558Srgrimes#include <machine/resource.h>
4923799Sbde#include <sys/rman.h>
5023675Speter
5166861Sadrian#include <dev/eisa/eisaconf.h>
5223799Sbde
5366861Sadriantypedef struct resvaddr {
5466861Sadrian        u_long	addr;				/* start address */
5566861Sadrian        u_long	size;				/* size of reserved area */
5666861Sadrian	int	flags;
5766861Sadrian	struct resource *res;			/* resource manager handle */
5823675Speter	LIST_ENTRY(resvaddr) links;		/* List links */
591558Srgrimes} resvaddr_t;
601558Srgrimes
611558SrgrimesLIST_HEAD(resvlist, resvaddr);
621558Srgrimes
6323675Speterstruct irq_node {
647585Sbde	int	irq_no;
657585Sbde	int	irq_trigger;
661558Srgrimes	void	*idesc;
671558Srgrimes	TAILQ_ENTRY(irq_node) links;
681558Srgrimes};
691558Srgrimes
701558SrgrimesTAILQ_HEAD(irqlist, irq_node);
711558Srgrimes
721558Srgrimesstruct eisa_ioconf {
731558Srgrimes	int		slot;
741558Srgrimes	struct resvlist	ioaddrs;	/* list of reserved I/O ranges */
751558Srgrimes	struct resvlist maddrs;		/* list of reserved memory ranges */
761558Srgrimes	struct irqlist	irqs;		/* list of reserved irqs */
771558Srgrimes};
781558Srgrimes
791558Srgrimes/* To be replaced by the "super device" generic device structure... */
801558Srgrimesstruct eisa_device {
811558Srgrimes	eisa_id_t		id;
821558Srgrimes	struct eisa_ioconf	ioconf;
831558Srgrimes};
841558Srgrimes
851558Srgrimes
861558Srgrimes#define MAX_COL		79
877585Sbde#ifndef EISA_SLOTS
881558Srgrimes#define EISA_SLOTS 10   /* PCI clashes with higher ones.. fix later */
891558Srgrimes#endif
901558Srgrimesint num_eisa_slots = EISA_SLOTS;
911558SrgrimesTUNABLE_INT("hw.eisa_slots", &num_eisa_slots);
921558Srgrimes
931558Srgrimesstatic devclass_t eisa_devclass;
941558Srgrimes
951558Srgrimesstatic int eisa_probe_slot(int slot, eisa_id_t *eisa_id);
961558Srgrimesstatic void eisa_reg_print (device_t, char *, char *, int *);
971558Srgrimesstatic struct irq_node * eisa_find_irq(struct eisa_device *e_dev, int rid);
981558Srgrimesstatic struct resvaddr * eisa_find_maddr(struct eisa_device *e_dev, int rid);
991558Srgrimesstatic struct resvaddr * eisa_find_ioaddr(struct eisa_device *e_dev, int rid);
10034266Sjulian
1011558Srgrimesstatic int
1021558Srgrimesmainboard_probe(device_t dev)
1031558Srgrimes{
1041558Srgrimes	char *idstring;
1051558Srgrimes	eisa_id_t id = eisa_get_id(dev);
1061558Srgrimes
1071558Srgrimes	if (eisa_get_slot(dev) != 0)
1081558Srgrimes		return (ENXIO);
1091558Srgrimes
1101558Srgrimes	idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1,
11134266Sjulian	    M_DEVBUF, M_NOWAIT);
11234266Sjulian	if (idstring == NULL)
11334266Sjulian		panic("Eisa probe unable to malloc");
1141558Srgrimes	sprintf(idstring, "%c%c%c%03x%01x (System Board)",
11534266Sjulian	    EISA_MFCTR_CHAR0(id), EISA_MFCTR_CHAR1(id), EISA_MFCTR_CHAR2(id),
11634266Sjulian	    EISA_PRODUCT_ID(id), EISA_REVISION_ID(id));
1171558Srgrimes	device_set_desc(dev, idstring);
1181558Srgrimes
1191558Srgrimes	return (0);
1201558Srgrimes}
12134266Sjulian
1221558Srgrimesstatic int
1231558Srgrimesmainboard_attach(device_t dev)
1241558Srgrimes{
1251558Srgrimes	return (0);
12641474Sjulian}
12741474Sjulian
12841474Sjulianstatic device_method_t mainboard_methods[] = {
12941474Sjulian	/* Device interface */
13041474Sjulian	DEVMETHOD(device_probe,		mainboard_probe),
13141474Sjulian	DEVMETHOD(device_attach,	mainboard_attach),
13241474Sjulian
13341474Sjulian	{ 0, 0 }
13441474Sjulian};
13541474Sjulian
13641474Sjulianstatic driver_t mainboard_driver = {
13741474Sjulian	"mainboard",
13841474Sjulian	mainboard_methods,
13941474Sjulian	1,
14041474Sjulian};
14141474Sjulian
14241474Sjulianstatic devclass_t mainboard_devclass;
14341474Sjulian
14441474SjulianDRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0);
14541474Sjulian
1461558Srgrimes/*
1471558Srgrimes** probe for EISA devices
1487585Sbde*/
1491558Srgrimesstatic int
1501558Srgrimeseisa_probe(device_t dev)
1511558Srgrimes{
1521558Srgrimes	int devices_found, slot;
1531558Srgrimes	struct eisa_device *e_dev;
1541558Srgrimes	device_t child;
1551558Srgrimes	eisa_id_t eisa_id;
1561558Srgrimes
1571558Srgrimes	device_set_desc(dev, "EISA bus");
15823675Speter
1591558Srgrimes	devices_found = 0;
1601558Srgrimes	for (slot = 0; slot < num_eisa_slots; slot++) {
1611558Srgrimes		eisa_id = 0;
1621558Srgrimes		if (eisa_probe_slot(slot, &eisa_id)) {
1631558Srgrimes			/*
1641558Srgrimes			 * If there's no card in the first slot (the
1651558Srgrimes			 * mainboard), then the system doesn't have EISA.
1661558Srgrimes			 * We abort the probe early in this case since
1671558Srgrimes			 * continuing on causes a hang on some systems.
1681558Srgrimes			 * Interestingly enough, the inb has been seen to
1691558Srgrimes			 * cause the hang.
1701558Srgrimes			 */
17123675Speter			if (slot == 0)
1721558Srgrimes				break;
1731558Srgrimes			continue;
1741558Srgrimes		}
1751558Srgrimes
1761558Srgrimes		devices_found++;
1771558Srgrimes
1781558Srgrimes		/* Prepare an eisa_device_node for this slot */
1791558Srgrimes		e_dev = (struct eisa_device *)malloc(sizeof(*e_dev),
1801558Srgrimes		    M_DEVBUF, M_NOWAIT|M_ZERO);
1811558Srgrimes		if (!e_dev) {
1821558Srgrimes			device_printf(dev, "cannot malloc eisa_device");
1831558Srgrimes			break; /* Try to attach what we have already */
1841558Srgrimes		}
1851558Srgrimes
1861558Srgrimes		e_dev->id = eisa_id;
1871558Srgrimes		e_dev->ioconf.slot = slot;
18823675Speter
1891558Srgrimes		/* Initialize our lists of reserved addresses */
1901558Srgrimes		LIST_INIT(&(e_dev->ioconf.ioaddrs));
1911558Srgrimes		LIST_INIT(&(e_dev->ioconf.maddrs));
1921558Srgrimes		TAILQ_INIT(&(e_dev->ioconf.irqs));
1931558Srgrimes
1941558Srgrimes		child = device_add_child(dev, NULL, -1);
1951558Srgrimes		device_set_ivars(child, e_dev);
1961558Srgrimes	}
1971558Srgrimes
1981558Srgrimes	/*
1991558Srgrimes	 * EISA busses themselves are not easily detectable, the easiest way
20023675Speter	 * to tell if there is an eisa bus is if we found something - there
2011558Srgrimes	 * should be a motherboard "card" there somewhere.
2021558Srgrimes	 */
2031558Srgrimes	return (devices_found ? 0 : ENXIO);
2041558Srgrimes}
2051558Srgrimes
2061558Srgrimesstatic int
2071558Srgrimeseisa_probe_slot(int slot, eisa_id_t *eisa_id)
2081558Srgrimes{
2091558Srgrimes	eisa_id_t probe_id;
2101558Srgrimes	int base, i, id_size;
2111558Srgrimes
2121558Srgrimes	probe_id = 0;
2131558Srgrimes	id_size = sizeof(probe_id);
2141558Srgrimes	base = 0x0c80 + (slot * 0x1000);
2151558Srgrimes
2161558Srgrimes	for (i = 0; i < id_size; i++)
2171558Srgrimes		probe_id |= inb(base + i) << ((id_size - i - 1) * CHAR_BIT);
21823675Speter
2191558Srgrimes	/* If we found a card, return its EISA id. */
2201558Srgrimes	if ((probe_id & 0x80000000) == 0) {
22123675Speter		*eisa_id = probe_id;
2221558Srgrimes		return (0);
2231558Srgrimes	}
2241558Srgrimes
2251558Srgrimes	return (ENXIO);
2261558Srgrimes}
2271558Srgrimes
2281558Srgrimesstatic void
2291558Srgrimeseisa_probe_nomatch(device_t dev, device_t child)
2301558Srgrimes{
2311558Srgrimes	u_int32_t	eisa_id = eisa_get_id(child);
2321558Srgrimes	u_int8_t	slot = eisa_get_slot(child);
2337585Sbde
2341558Srgrimes	device_printf(dev, "unknown card %c%c%c%03x%01x (0x%08x) at slot %d\n",
2351558Srgrimes	    EISA_MFCTR_CHAR0(eisa_id), EISA_MFCTR_CHAR1(eisa_id),
2361558Srgrimes	    EISA_MFCTR_CHAR2(eisa_id), EISA_PRODUCT_ID(eisa_id),
2371558Srgrimes	    EISA_REVISION_ID(eisa_id), eisa_id, slot);
2381558Srgrimes	return;
2391558Srgrimes}
2401558Srgrimes
2411558Srgrimesstatic void
2421558Srgrimeseisa_reg_print (device_t dev, char *string, char *separator, int *column)
2431558Srgrimes{
2441558Srgrimes	int length = strlen(string);
2451558Srgrimes
2461558Srgrimes	length += (separator ? 2 : 1);
2471558Srgrimes
2481558Srgrimes	if (((*column) + length) >= MAX_COL) {
2491558Srgrimes		printf("\n");
2501558Srgrimes		(*column) = 0;
2511558Srgrimes	} else if ((*column) != 0) {
2521558Srgrimes		if (separator) {
2531558Srgrimes			printf("%c", *separator);
2541558Srgrimes			(*column)++;
2551558Srgrimes		}
2561558Srgrimes		printf(" ");
2571558Srgrimes		(*column)++;
2581558Srgrimes	}
25923675Speter
2601558Srgrimes	if ((*column) == 0)
2611558Srgrimes		(*column) += device_printf(dev, "%s", string);
26223675Speter	else
2631558Srgrimes		(*column) += printf("%s", string);
2641558Srgrimes
2651558Srgrimes	return;
2661558Srgrimes}
2671558Srgrimes
2681558Srgrimesstatic int
26923675Spetereisa_print_child(device_t dev, device_t child)
2701558Srgrimes{
2711558Srgrimes	char			buf[81];
2727585Sbde	struct eisa_device *	e_dev = device_get_ivars(child);
27323675Speter	int			rid;
27423675Speter	struct irq_node *	irq;
2751558Srgrimes	struct resvaddr *	resv;
2761558Srgrimes	char			separator = ',';
27723675Speter	int			column = 0;
2781558Srgrimes	int			retval = 0;
2791558Srgrimes
2801558Srgrimes	if (device_get_desc(child)) {
2811558Srgrimes		snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
2821558Srgrimes		eisa_reg_print(child, buf, NULL, &column);
2831558Srgrimes	}
2841558Srgrimes
2851558Srgrimes	rid = 0;
2861558Srgrimes	while ((resv = eisa_find_ioaddr(e_dev, rid++))) {
2871558Srgrimes		if (resv->size == 1 || (resv->flags & RESVADDR_BITMASK))
2881558Srgrimes			snprintf(buf, sizeof(buf), "%s%lx",
2891558Srgrimes			    rid == 1 ? "at 0x" : "0x", resv->addr);
2901558Srgrimes		else
2911558Srgrimes			snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
2921558Srgrimes			    rid == 1 ? "at 0x" : "0x", resv->addr,
2931558Srgrimes			    resv->addr + resv->size - 1);
2941558Srgrimes		eisa_reg_print(child, buf, rid == 2 ? &separator : NULL,
2951558Srgrimes		    &column);
2961558Srgrimes	}
2971558Srgrimes
2981558Srgrimes	rid = 0;
2991558Srgrimes	while ((resv = eisa_find_maddr(e_dev, rid++))) {
30041477Sjulian		if (resv->size == 1 || (resv->flags & RESVADDR_BITMASK))
3011558Srgrimes			snprintf(buf, sizeof(buf), "%s%lx",
30241474Sjulian			    rid == 1 ? "at 0x" : "0x", resv->addr);
30341474Sjulian		else
30423675Speter			snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
30523675Speter			    rid == 1 ? "at 0x" : "0x",
30623675Speter				resv->addr, resv->addr + resv->size - 1);
30723675Speter		eisa_reg_print(child, buf, rid == 2 ? &separator : NULL,
30841474Sjulian		    &column);
30941474Sjulian	}
31041474Sjulian
31141474Sjulian	rid = 0;
31241474Sjulian	while ((irq = eisa_find_irq(e_dev, rid++)) != NULL) {
31341474Sjulian		snprintf(buf, sizeof(buf), "irq %d (%s)", irq->irq_no,
31441474Sjulian			 irq->irq_trigger ? "level" : "edge");
31541474Sjulian		eisa_reg_print(child, buf, rid == 1 ? &separator : NULL,
31641474Sjulian		    &column);
31723675Speter	}
3181558Srgrimes
3191558Srgrimes	snprintf(buf, sizeof(buf), "on %s slot %d\n",
3201558Srgrimes	    device_get_nameunit(dev), eisa_get_slot(child));
3211558Srgrimes	eisa_reg_print(child, buf, NULL, &column);
3221558Srgrimes
3231558Srgrimes	return (retval);
3241558Srgrimes}
3257585Sbde
3261558Srgrimesstatic struct irq_node *
3271558Srgrimeseisa_find_irq(struct eisa_device *e_dev, int rid)
3281558Srgrimes{
32923675Speter	int i;
3301558Srgrimes	struct irq_node *irq;
3311558Srgrimes
3321558Srgrimes	for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
3331558Srgrimes	     i < rid && irq != NULL; i++, irq = TAILQ_NEXT(irq, links))
3341558Srgrimes		continue;
3351558Srgrimes
3361558Srgrimes	return (irq);
3371558Srgrimes}
3381558Srgrimes
3391558Srgrimesstatic struct resvaddr *
3401558Srgrimeseisa_find_maddr(struct eisa_device *e_dev, int rid)
3411558Srgrimes{
3421558Srgrimes	int i;
3431558Srgrimes	struct resvaddr *resv;
3441558Srgrimes
3451558Srgrimes	for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs);
34623675Speter	     i < rid && resv != NULL; i++, resv = LIST_NEXT(resv, links))
3471558Srgrimes		continue;
3481558Srgrimes
3491558Srgrimes	return (resv);
3501558Srgrimes}
3511558Srgrimes
3521558Srgrimesstatic struct resvaddr *
3531558Srgrimeseisa_find_ioaddr(struct eisa_device *e_dev, int rid)
3541558Srgrimes{
3551558Srgrimes	int i;
3561558Srgrimes	struct resvaddr *resv;
3571558Srgrimes
3581558Srgrimes	for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs);
3591558Srgrimes	     i < rid && resv != NULL; i++, resv = LIST_NEXT(resv, links))
3601558Srgrimes		continue;
36141474Sjulian
36241474Sjulian	return (resv);
3631558Srgrimes}
3641558Srgrimes
3651558Srgrimesstatic int
3667585Sbdeeisa_read_ivar(device_t dev, device_t child, int which, u_long *result)
3671558Srgrimes{
3681558Srgrimes	struct eisa_device *e_dev = device_get_ivars(child);
3691558Srgrimes	struct irq_node *irq;
37023675Speter
3711558Srgrimes	switch (which) {
3721558Srgrimes	case EISA_IVAR_SLOT:
3731558Srgrimes		*result = e_dev->ioconf.slot;
3741558Srgrimes		break;
3751558Srgrimes
3761558Srgrimes	case EISA_IVAR_ID:
3771558Srgrimes		*result = e_dev->id;
3781558Srgrimes		break;
3791558Srgrimes
3801558Srgrimes	case EISA_IVAR_IRQ:
3811558Srgrimes		/* XXX only first irq */
3821558Srgrimes		if ((irq = eisa_find_irq(e_dev, 0)) != NULL)
3831558Srgrimes			*result = irq->irq_no;
3841558Srgrimes		else
3851558Srgrimes			*result = -1;
3861558Srgrimes		break;
38741474Sjulian
3881558Srgrimes	default:
3891558Srgrimes		return (ENOENT);
3901558Srgrimes	}
3911558Srgrimes
3921558Srgrimes	return (0);
3931558Srgrimes}
3941558Srgrimes
3951558Srgrimesstatic int
3961558Srgrimeseisa_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
3971558Srgrimes{
3981558Srgrimes	return (EINVAL);
3991558Srgrimes}
4001558Srgrimes
4011558Srgrimesstatic struct resource *
4021558Srgrimeseisa_alloc_resource(device_t dev, device_t child, int type, int *rid,
4031558Srgrimes    u_long start, u_long end, u_long count, u_int flags)
40423675Speter{
4051558Srgrimes	int isdefault;
4061558Srgrimes	struct eisa_device *e_dev = device_get_ivars(child);
4071558Srgrimes	struct resource *rv, **rvp = 0;
40834266Sjulian
40934266Sjulian	isdefault = (device_get_parent(child) == dev &&
4101558Srgrimes	     start == 0UL && end == ~0UL && count == 1);
4111558Srgrimes
4121558Srgrimes	switch (type) {
4131558Srgrimes	case SYS_RES_IRQ:
4141558Srgrimes		if (isdefault) {
4151558Srgrimes			struct irq_node * irq = eisa_find_irq(e_dev, *rid);
4161558Srgrimes			if (irq == NULL)
4171558Srgrimes				return (NULL);
4181558Srgrimes			start = end = irq->irq_no;
4191558Srgrimes			count = 1;
4201558Srgrimes			if (irq->irq_trigger == EISA_TRIGGER_LEVEL)
4211558Srgrimes				flags |= RF_SHAREABLE;
4221558Srgrimes			else
4231558Srgrimes				flags &= ~RF_SHAREABLE;
42434266Sjulian		}
42534266Sjulian		break;
42634266Sjulian
42734266Sjulian	case SYS_RES_MEMORY:
42834266Sjulian		if (isdefault) {
42934266Sjulian			struct resvaddr *resv;
4301558Srgrimes
43134266Sjulian			resv = eisa_find_maddr(e_dev, *rid);
43234266Sjulian			if (resv == NULL)
4331558Srgrimes				return (NULL);
43434266Sjulian
43534266Sjulian			start = resv->addr;
43634266Sjulian			end = resv->addr + (resv->size - 1);
43734266Sjulian			count = resv->size;
43834266Sjulian			rvp = &resv->res;
4391558Srgrimes		}
4401558Srgrimes		break;
4411558Srgrimes
4421558Srgrimes	case SYS_RES_IOPORT:
4431558Srgrimes		if (isdefault) {
4441558Srgrimes			struct resvaddr *resv;
4451558Srgrimes
4461558Srgrimes			resv = eisa_find_ioaddr(e_dev, *rid);
4471558Srgrimes			if (resv == NULL)
4487585Sbde				return (NULL);
4491558Srgrimes
45023675Speter			start = resv->addr;
4511558Srgrimes			end = resv->addr + (resv->size - 1);
4521558Srgrimes			count = resv->size;
4531558Srgrimes			rvp = &resv->res;
4541558Srgrimes		}
4551558Srgrimes		break;
4561558Srgrimes
4571558Srgrimes	default:
4581558Srgrimes		return 0;
4591558Srgrimes	}
4601558Srgrimes
4611558Srgrimes	rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
4621558Srgrimes	     type, rid, start, end, count, flags);
4637585Sbde	if (rvp)
4641558Srgrimes		*rvp = rv;
4651558Srgrimes
4661558Srgrimes	return (rv);
4671558Srgrimes}
4681558Srgrimes
4691558Srgrimesstatic int
4701558Srgrimeseisa_release_resource(device_t dev, device_t child, int type, int rid,
4711558Srgrimes		      struct resource *r)
4721558Srgrimes{
4731558Srgrimes	int rv;
4741558Srgrimes	struct eisa_device *e_dev = device_get_ivars(child);
4751558Srgrimes	struct resvaddr *resv = 0;
4761558Srgrimes
4771558Srgrimes	switch (type) {
47841474Sjulian	case SYS_RES_IRQ:
47941474Sjulian		if (eisa_find_irq(e_dev, rid) == NULL)
4801558Srgrimes			return (EINVAL);
4811558Srgrimes		break;
4821558Srgrimes
4831558Srgrimes	case SYS_RES_MEMORY:
48423675Speter		if (device_get_parent(child) == dev)
4851558Srgrimes			resv = eisa_find_maddr(e_dev, rid);
4861558Srgrimes		break;
4871558Srgrimes
4881558Srgrimes
4891558Srgrimes	case SYS_RES_IOPORT:
4901558Srgrimes		if (device_get_parent(child) == dev)
4911558Srgrimes			resv = eisa_find_ioaddr(e_dev, rid);
4921558Srgrimes		break;
4931558Srgrimes
4941558Srgrimes	default:
4951558Srgrimes		return (ENOENT);
4961558Srgrimes	}
4971558Srgrimes
4981558Srgrimes	rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r);
4991558Srgrimes
5001558Srgrimes	if (rv == 0) {
5011558Srgrimes		if (resv != NULL)
5021558Srgrimes			resv->res = 0;
5031558Srgrimes	}
5041558Srgrimes
5051558Srgrimes	return (rv);
5061558Srgrimes}
5071558Srgrimes
50823675Speterstatic int
5091558Srgrimeseisa_add_intr_m(device_t eisa, device_t dev, int irq, int trigger)
5101558Srgrimes{
5111558Srgrimes	struct eisa_device *e_dev = device_get_ivars(dev);
5121558Srgrimes	struct irq_node *irq_info;
5131558Srgrimes
5141558Srgrimes	irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF,
5151558Srgrimes					     M_NOWAIT);
5161558Srgrimes	if (irq_info == NULL)
51723675Speter		return (1);
5181558Srgrimes
5191558Srgrimes	irq_info->irq_no = irq;
5201558Srgrimes	irq_info->irq_trigger = trigger;
52123675Speter	irq_info->idesc = NULL;
52223675Speter	TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links);
5231558Srgrimes	return (0);
5241558Srgrimes}
52523675Speter
5261558Srgrimesstatic int
5271558Srgrimeseisa_add_resvaddr(struct eisa_device *e_dev, struct resvlist *head, u_long base,
5281558Srgrimes		  u_long size, int flags)
5291558Srgrimes{
5301558Srgrimes	resvaddr_t *reservation;
5311558Srgrimes
5321558Srgrimes	reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
5331558Srgrimes					   M_DEVBUF, M_NOWAIT);
5341558Srgrimes	if(!reservation)
53523675Speter		return (ENOMEM);
53623675Speter
5371558Srgrimes	reservation->addr = base;
5381558Srgrimes	reservation->size = size;
5391558Srgrimes	reservation->flags = flags;
5401558Srgrimes
5411558Srgrimes	if (!LIST_FIRST(head)) {
5421558Srgrimes		LIST_INSERT_HEAD(head, reservation, links);
5431558Srgrimes	}
5441558Srgrimes	else {
5451558Srgrimes		resvaddr_t *node;
5461558Srgrimes		LIST_FOREACH(node, head, links) {
5471558Srgrimes			if (node->addr > reservation->addr) {
54823675Speter				/*
54923675Speter				 * List is sorted in increasing
5501558Srgrimes				 * address order.
5511558Srgrimes				 */
5521558Srgrimes				LIST_INSERT_BEFORE(node, reservation, links);
5531558Srgrimes				break;
5541558Srgrimes			}
5551558Srgrimes
5561558Srgrimes			if (node->addr == reservation->addr) {
5571558Srgrimes				/*
5581558Srgrimes				 * If the entry we want to add
5591558Srgrimes				 * matches any already in here,
5607585Sbde				 * fail.
5611558Srgrimes				 */
5621558Srgrimes				free(reservation, M_DEVBUF);
5631558Srgrimes				return (EEXIST);
5641558Srgrimes			}
5651558Srgrimes
5661558Srgrimes			if (!LIST_NEXT(node, links)) {
5671558Srgrimes				LIST_INSERT_AFTER(node, reservation, links);
5681558Srgrimes				break;
5691558Srgrimes			}
5701558Srgrimes		}
5711558Srgrimes	}
57266861Sadrian	return (0);
5731558Srgrimes}
5741558Srgrimes
5751558Srgrimesstatic int
5761558Srgrimeseisa_add_mspace_m(device_t eisa, device_t dev, u_long mbase, u_long msize,
5771558Srgrimes    int flags)
5781558Srgrimes{
5791558Srgrimes	struct eisa_device *e_dev = device_get_ivars(dev);
5801558Srgrimes
5811558Srgrimes	return (eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize,
5821558Srgrimes	    flags));
5831558Srgrimes}
5841558Srgrimes
5851558Srgrimesstatic int
5861558Srgrimeseisa_add_iospace_m(device_t eisa, device_t dev, u_long iobase, u_long iosize,
5871558Srgrimes    int flags)
5881558Srgrimes{
5891558Srgrimes	struct eisa_device *e_dev = device_get_ivars(dev);
5901558Srgrimes
5911558Srgrimes	return (eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase,
5921558Srgrimes	    iosize, flags));
59323675Speter}
5941558Srgrimes
5951558Srgrimesstatic device_method_t eisa_methods[] = {
59623675Speter	/* Device interface */
5971558Srgrimes	DEVMETHOD(device_probe,		eisa_probe),
5981558Srgrimes	DEVMETHOD(device_attach,	bus_generic_attach),
59923675Speter	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
60023675Speter	DEVMETHOD(device_suspend,	bus_generic_suspend),
60123675Speter	DEVMETHOD(device_resume,	bus_generic_resume),
60223675Speter
60323675Speter	/* Bus interface */
6041558Srgrimes	DEVMETHOD(bus_print_child,	eisa_print_child),
6051558Srgrimes	DEVMETHOD(bus_probe_nomatch,	eisa_probe_nomatch),
6061558Srgrimes	DEVMETHOD(bus_read_ivar,	eisa_read_ivar),
60734266Sjulian	DEVMETHOD(bus_write_ivar,	eisa_write_ivar),
60834266Sjulian	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
6091558Srgrimes	DEVMETHOD(bus_alloc_resource,	eisa_alloc_resource),
6107585Sbde	DEVMETHOD(bus_release_resource,	eisa_release_resource),
61123675Speter	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
61223675Speter	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
61323675Speter	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
61423675Speter	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
61523675Speter
61623675Speter	/* EISA interface */
61723675Speter	DEVMETHOD(eisa_add_intr,	eisa_add_intr_m),
6181558Srgrimes	DEVMETHOD(eisa_add_iospace,	eisa_add_iospace_m),
6197585Sbde	DEVMETHOD(eisa_add_mspace,	eisa_add_mspace_m),
62023675Speter
62123675Speter	{ 0, 0 }
62223675Speter};
62323675Speter
62423675Speterstatic driver_t eisa_driver = {
62523675Speter	"eisa",
62623675Speter	eisa_methods,
62723675Speter	1,			/* no softc */
62834266Sjulian};
62934266Sjulian
63041474SjulianDRIVER_MODULE(eisa, eisab, eisa_driver, eisa_devclass, 0, 0);
63123675SpeterDRIVER_MODULE(eisa, legacy, eisa_driver, eisa_devclass, 0, 0);
6321558Srgrimes