isa_common.c revision 139279
147398Sdfr/*-
247398Sdfr * Copyright (c) 1999 Doug Rabson
347398Sdfr * All rights reserved.
447398Sdfr *
547398Sdfr * Redistribution and use in source and binary forms, with or without
647398Sdfr * modification, are permitted provided that the following conditions
747398Sdfr * are met:
847398Sdfr * 1. Redistributions of source code must retain the above copyright
947398Sdfr *    notice, this list of conditions and the following disclaimer.
1047398Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1147398Sdfr *    notice, this list of conditions and the following disclaimer in the
1247398Sdfr *    documentation and/or other materials provided with the distribution.
1347398Sdfr *
1447398Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1547398Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1647398Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1747398Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1847398Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1947398Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2047398Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2147398Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2247398Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2347398Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2447398Sdfr * SUCH DAMAGE.
2547398Sdfr */
2647398Sdfr/*
2747398Sdfr * Modifications for Intel architecture by Garrett A. Wollman.
2847398Sdfr * Copyright 1998 Massachusetts Institute of Technology
2947398Sdfr *
3047398Sdfr * Permission to use, copy, modify, and distribute this software and
3147398Sdfr * its documentation for any purpose and without fee is hereby
3247398Sdfr * granted, provided that both the above copyright notice and this
3347398Sdfr * permission notice appear in all copies, that both the above
3447398Sdfr * copyright notice and this permission notice appear in all
3547398Sdfr * supporting documentation, and that the name of M.I.T. not be used
3647398Sdfr * in advertising or publicity pertaining to distribution of the
3747398Sdfr * software without specific, written prior permission.  M.I.T. makes
3847398Sdfr * no representations about the suitability of this software for any
3947398Sdfr * purpose.  It is provided "as is" without express or implied
4047398Sdfr * warranty.
4147398Sdfr *
4247398Sdfr * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
4347398Sdfr * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
4447398Sdfr * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
4547398Sdfr * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
4647398Sdfr * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4747398Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4847398Sdfr * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
4947398Sdfr * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5047398Sdfr * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5147398Sdfr * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
5247398Sdfr * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5347398Sdfr * SUCH DAMAGE.
5447398Sdfr */
5547398Sdfr
5647398Sdfr/*
5747398Sdfr * Parts of the ISA bus implementation common to all architectures.
5847398Sdfr */
5947398Sdfr
60116181Sobrien#include <sys/cdefs.h>
61116181Sobrien__FBSDID("$FreeBSD: head/sys/isa/isa_common.c 139279 2004-12-24 23:03:17Z imp $");
62116181Sobrien
6347398Sdfr#include <sys/param.h>
6447398Sdfr#include <sys/systm.h>
6547398Sdfr#include <sys/kernel.h>
6647398Sdfr#include <sys/bus.h>
6747398Sdfr#include <sys/malloc.h>
6847398Sdfr#include <sys/module.h>
6947398Sdfr#include <machine/bus.h>
7047398Sdfr#include <sys/rman.h>
7147398Sdfr
7247398Sdfr#include <machine/resource.h>
7347398Sdfr
7447398Sdfr#include <isa/isavar.h>
7547398Sdfr#include <isa/isa_common.h>
7647398Sdfr#ifdef __alpha__		/* XXX workaround a stupid warning */
7747398Sdfr#include <alpha/isa/isavar.h>
7847398Sdfr#endif
7947398Sdfr
8062987Sjhbstatic int	isa_print_child(device_t bus, device_t dev);
8162987Sjhb
8269774Sphkstatic MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device");
8347398Sdfr
8453094Sdfrstatic int isa_running;
8547398Sdfr
8647398Sdfr/*
8747398Sdfr * At 'probe' time, we add all the devices which we know about to the
8847398Sdfr * bus.  The generic attach routine will probe and attach them if they
8947398Sdfr * are alive.
9047398Sdfr */
9147398Sdfrstatic int
9247398Sdfrisa_probe(device_t dev)
9347398Sdfr{
9447398Sdfr	device_set_desc(dev, "ISA bus");
9588376Stmm	isa_init(dev);		/* Allow machdep code to initialise */
96139273Simp	return (0);
9747398Sdfr}
9847398Sdfr
9947398Sdfrextern device_t isa_bus_device;
10047398Sdfr
10147398Sdfrstatic int
10247398Sdfrisa_attach(device_t dev)
10347398Sdfr{
10447398Sdfr	/*
10550769Sdfr	 * Arrange for isa_probe_children(dev) to be called later. XXX
10647398Sdfr	 */
10747398Sdfr	isa_bus_device = dev;
108139273Simp	return (0);
10947398Sdfr}
11047398Sdfr
11147398Sdfr/*
11250769Sdfr * Find a working set of memory regions for a child using the ranges
11350769Sdfr * in *config  and return the regions in *result. Returns non-zero if
11450769Sdfr * a set of ranges was found.
11550769Sdfr */
11650769Sdfrstatic int
117139273Simpisa_find_memory(device_t child, struct isa_config *config,
118139273Simp    struct isa_config *result)
11950769Sdfr{
12050769Sdfr	int success, i;
12150769Sdfr	struct resource *res[ISA_NMEM];
12250769Sdfr
12350769Sdfr	/*
12450769Sdfr	 * First clear out any existing resource definitions.
12550769Sdfr	 */
12650769Sdfr	for (i = 0; i < ISA_NMEM; i++) {
12752174Sdfr		bus_delete_resource(child, SYS_RES_MEMORY, i);
12850769Sdfr		res[i] = NULL;
12950769Sdfr	}
13050769Sdfr
13150769Sdfr	success = 1;
13250769Sdfr	result->ic_nmem = config->ic_nmem;
13350769Sdfr	for (i = 0; i < config->ic_nmem; i++) {
134139273Simp		uint32_t start, end, size, align;
13583051Syokota
13683051Syokota		size = config->ic_mem[i].ir_size;
13783051Syokota
13883051Syokota		/* the PnP device may have a null resource as filler */
13983051Syokota		if (size == 0) {
14083051Syokota			result->ic_mem[i].ir_start = 0;
14183051Syokota			result->ic_mem[i].ir_end = 0;
14283051Syokota			result->ic_mem[i].ir_size = 0;
14383051Syokota			result->ic_mem[i].ir_align = 0;
14483051Syokota			continue;
14583051Syokota		}
14683051Syokota
14750769Sdfr		for (start = config->ic_mem[i].ir_start,
14850769Sdfr			     end = config->ic_mem[i].ir_end,
14950769Sdfr			     align = config->ic_mem[i].ir_align;
15050769Sdfr		     start + size - 1 <= end;
15150769Sdfr		     start += align) {
15252174Sdfr			bus_set_resource(child, SYS_RES_MEMORY, i,
15350769Sdfr					 start, size);
154127135Snjl			res[i] = bus_alloc_resource_any(child,
155127135Snjl							SYS_RES_MEMORY, &i,
156127135Snjl							0 /* !RF_ACTIVE */);
15750769Sdfr			if (res[i]) {
15850769Sdfr				result->ic_mem[i].ir_start = start;
15950769Sdfr				result->ic_mem[i].ir_end = start + size - 1;
16050769Sdfr				result->ic_mem[i].ir_size = size;
16150769Sdfr				result->ic_mem[i].ir_align = align;
16250769Sdfr				break;
16350769Sdfr			}
16450769Sdfr		}
16550769Sdfr
16650769Sdfr		/*
16750769Sdfr		 * If we didn't find a place for memory range i, then
16850769Sdfr		 * give up now.
16950769Sdfr		 */
17050769Sdfr		if (!res[i]) {
17150769Sdfr			success = 0;
17250769Sdfr			break;
17350769Sdfr		}
17450769Sdfr	}
17550769Sdfr
17650769Sdfr	for (i = 0; i < ISA_NMEM; i++) {
17750769Sdfr		if (res[i])
17850769Sdfr			bus_release_resource(child, SYS_RES_MEMORY,
17950769Sdfr					     i, res[i]);
18050769Sdfr	}
18150769Sdfr
182139273Simp	return (success);
18350769Sdfr}
18450769Sdfr
18550769Sdfr/*
18650769Sdfr * Find a working set of port regions for a child using the ranges
18750769Sdfr * in *config  and return the regions in *result. Returns non-zero if
18850769Sdfr * a set of ranges was found.
18950769Sdfr */
19050769Sdfrstatic int
191139273Simpisa_find_port(device_t child, struct isa_config *config,
192139273Simp    struct isa_config *result)
19350769Sdfr{
19450769Sdfr	int success, i;
19550769Sdfr	struct resource *res[ISA_NPORT];
19650769Sdfr
19750769Sdfr	/*
19850769Sdfr	 * First clear out any existing resource definitions.
19950769Sdfr	 */
20050769Sdfr	for (i = 0; i < ISA_NPORT; i++) {
20152174Sdfr		bus_delete_resource(child, SYS_RES_IOPORT, i);
20250769Sdfr		res[i] = NULL;
20350769Sdfr	}
20450769Sdfr
20550769Sdfr	success = 1;
20650769Sdfr	result->ic_nport = config->ic_nport;
20750769Sdfr	for (i = 0; i < config->ic_nport; i++) {
208139273Simp		uint32_t start, end, size, align;
20983051Syokota
21083051Syokota		size = config->ic_port[i].ir_size;
21183051Syokota
21283051Syokota		/* the PnP device may have a null resource as filler */
21383051Syokota		if (size == 0) {
21483051Syokota			result->ic_port[i].ir_start = 0;
21583051Syokota			result->ic_port[i].ir_end = 0;
21683051Syokota			result->ic_port[i].ir_size = 0;
21783051Syokota			result->ic_port[i].ir_align = 0;
21883051Syokota			continue;
21983051Syokota		}
22083051Syokota
22150769Sdfr		for (start = config->ic_port[i].ir_start,
22250769Sdfr			     end = config->ic_port[i].ir_end,
22350769Sdfr			     align = config->ic_port[i].ir_align;
22450769Sdfr		     start + size - 1 <= end;
22550769Sdfr		     start += align) {
22652174Sdfr			bus_set_resource(child, SYS_RES_IOPORT, i,
22750769Sdfr					 start, size);
228127135Snjl			res[i] = bus_alloc_resource_any(child,
229127135Snjl							SYS_RES_IOPORT, &i,
230127135Snjl							0 /* !RF_ACTIVE */);
23150769Sdfr			if (res[i]) {
23250769Sdfr				result->ic_port[i].ir_start = start;
23350769Sdfr				result->ic_port[i].ir_end = start + size - 1;
23450769Sdfr				result->ic_port[i].ir_size = size;
23550769Sdfr				result->ic_port[i].ir_align = align;
23650769Sdfr				break;
23750769Sdfr			}
23850769Sdfr		}
23950769Sdfr
24050769Sdfr		/*
24150769Sdfr		 * If we didn't find a place for port range i, then
24250769Sdfr		 * give up now.
24350769Sdfr		 */
24450769Sdfr		if (!res[i]) {
24550769Sdfr			success = 0;
24650769Sdfr			break;
24750769Sdfr		}
24850769Sdfr	}
24950769Sdfr
25050769Sdfr	for (i = 0; i < ISA_NPORT; i++) {
25150769Sdfr		if (res[i])
25250769Sdfr			bus_release_resource(child, SYS_RES_IOPORT,
25350769Sdfr					     i, res[i]);
25450769Sdfr	}
25550769Sdfr
25650769Sdfr	return success;
25750769Sdfr}
25850769Sdfr
25950769Sdfr/*
26050769Sdfr * Return the index of the first bit in the mask (or -1 if mask is empty.
26150769Sdfr */
26250769Sdfrstatic int
263139273Simpfind_first_bit(uint32_t mask)
26450769Sdfr{
265139273Simp	return (ffs(mask) - 1);
26650769Sdfr}
26750769Sdfr
26850769Sdfr/*
26950769Sdfr * Return the index of the next bit in the mask, or -1 if there are no more.
27050769Sdfr */
27150769Sdfrstatic int
272139273Simpfind_next_bit(uint32_t mask, int bit)
27350769Sdfr{
27450769Sdfr	bit++;
27550769Sdfr	while (bit < 32 && !(mask & (1 << bit)))
27650769Sdfr		bit++;
27750769Sdfr	if (bit != 32)
278139273Simp		return (bit);
279139273Simp	return (-1);
28050769Sdfr}
28150769Sdfr
28250769Sdfr/*
28350769Sdfr * Find a working set of irqs for a child using the masks in *config
28450769Sdfr * and return the regions in *result. Returns non-zero if a set of
28550769Sdfr * irqs was found.
28650769Sdfr */
28750769Sdfrstatic int
288139273Simpisa_find_irq(device_t child, struct isa_config *config,
289139273Simp    struct isa_config *result)
29050769Sdfr{
29150769Sdfr	int success, i;
29250769Sdfr	struct resource *res[ISA_NIRQ];
29350769Sdfr
29450769Sdfr	/*
29550769Sdfr	 * First clear out any existing resource definitions.
29650769Sdfr	 */
29750769Sdfr	for (i = 0; i < ISA_NIRQ; i++) {
29852174Sdfr		bus_delete_resource(child, SYS_RES_IRQ, i);
29950769Sdfr		res[i] = NULL;
30050769Sdfr	}
30150769Sdfr
30250769Sdfr	success = 1;
30350769Sdfr	result->ic_nirq = config->ic_nirq;
30450769Sdfr	for (i = 0; i < config->ic_nirq; i++) {
305139273Simp		uint32_t mask = config->ic_irqmask[i];
30650769Sdfr		int irq;
30783051Syokota
30883051Syokota		/* the PnP device may have a null resource as filler */
30983051Syokota		if (mask == 0) {
31083051Syokota			result->ic_irqmask[i] = 0;
31183051Syokota			continue;
31283051Syokota		}
31383051Syokota
31450769Sdfr		for (irq = find_first_bit(mask);
31550769Sdfr		     irq != -1;
31650769Sdfr		     irq = find_next_bit(mask, irq)) {
31752174Sdfr			bus_set_resource(child, SYS_RES_IRQ, i,
31850769Sdfr					 irq, 1);
319127135Snjl			res[i] = bus_alloc_resource_any(child,
320127135Snjl							SYS_RES_IRQ, &i,
321127135Snjl							0 /* !RF_ACTIVE */ );
32250769Sdfr			if (res[i]) {
32350769Sdfr				result->ic_irqmask[i] = (1 << irq);
32450769Sdfr				break;
32550769Sdfr			}
32650769Sdfr		}
32750769Sdfr
32850769Sdfr		/*
32950769Sdfr		 * If we didn't find a place for irq range i, then
33050769Sdfr		 * give up now.
33150769Sdfr		 */
33250769Sdfr		if (!res[i]) {
33350769Sdfr			success = 0;
33450769Sdfr			break;
33550769Sdfr		}
33650769Sdfr	}
33750769Sdfr
33850769Sdfr	for (i = 0; i < ISA_NIRQ; i++) {
33950769Sdfr		if (res[i])
34050769Sdfr			bus_release_resource(child, SYS_RES_IRQ,
34150769Sdfr					     i, res[i]);
34250769Sdfr	}
34350769Sdfr
344139273Simp	return (success);
34550769Sdfr}
34650769Sdfr
34750769Sdfr/*
34850769Sdfr * Find a working set of drqs for a child using the masks in *config
34950769Sdfr * and return the regions in *result. Returns non-zero if a set of
35050769Sdfr * drqs was found.
35150769Sdfr */
35250769Sdfrstatic int
353139273Simpisa_find_drq(device_t child, struct isa_config *config,
354139273Simp    struct isa_config *result)
35550769Sdfr{
35650769Sdfr	int success, i;
35750769Sdfr	struct resource *res[ISA_NDRQ];
35850769Sdfr
35950769Sdfr	/*
36050769Sdfr	 * First clear out any existing resource definitions.
36150769Sdfr	 */
36250769Sdfr	for (i = 0; i < ISA_NDRQ; i++) {
36352174Sdfr		bus_delete_resource(child, SYS_RES_DRQ, i);
36450769Sdfr		res[i] = NULL;
36550769Sdfr	}
36650769Sdfr
36750769Sdfr	success = 1;
36850769Sdfr	result->ic_ndrq = config->ic_ndrq;
36950769Sdfr	for (i = 0; i < config->ic_ndrq; i++) {
370139273Simp		uint32_t mask = config->ic_drqmask[i];
37150769Sdfr		int drq;
37283051Syokota
37383051Syokota		/* the PnP device may have a null resource as filler */
37483051Syokota		if (mask == 0) {
37583051Syokota			result->ic_drqmask[i] = 0;
37683051Syokota			continue;
37783051Syokota		}
37883051Syokota
37950769Sdfr		for (drq = find_first_bit(mask);
38050769Sdfr		     drq != -1;
38150769Sdfr		     drq = find_next_bit(mask, drq)) {
38252174Sdfr			bus_set_resource(child, SYS_RES_DRQ, i,
38350769Sdfr					 drq, 1);
384127135Snjl			res[i] = bus_alloc_resource_any(child,
385127135Snjl							SYS_RES_DRQ, &i,
386127135Snjl							0 /* !RF_ACTIVE */);
38750769Sdfr			if (res[i]) {
38850769Sdfr				result->ic_drqmask[i] = (1 << drq);
38950769Sdfr				break;
39050769Sdfr			}
39150769Sdfr		}
39250769Sdfr
39350769Sdfr		/*
39450769Sdfr		 * If we didn't find a place for drq range i, then
39550769Sdfr		 * give up now.
39650769Sdfr		 */
39750769Sdfr		if (!res[i]) {
39850769Sdfr			success = 0;
39950769Sdfr			break;
40050769Sdfr		}
40150769Sdfr	}
40250769Sdfr
40350769Sdfr	for (i = 0; i < ISA_NDRQ; i++) {
40450769Sdfr		if (res[i])
40550769Sdfr			bus_release_resource(child, SYS_RES_DRQ,
40650769Sdfr					     i, res[i]);
40750769Sdfr	}
40850769Sdfr
409139273Simp	return (success);
41050769Sdfr}
41150769Sdfr
41250769Sdfr/*
41350769Sdfr * Attempt to find a working set of resources for a device. Return
41450769Sdfr * non-zero if a working configuration is found.
41550769Sdfr */
41650769Sdfrstatic int
41750769Sdfrisa_assign_resources(device_t child)
41850769Sdfr{
41950769Sdfr	struct isa_device *idev = DEVTOISA(child);
42050769Sdfr	struct isa_config_entry *ice;
42181401Sjulian	struct isa_config *cfg;
42291206Salfred	const char *reason;
42391206Salfred
42491206Salfred	reason = "Empty ISA id_configs";
42581401Sjulian	cfg = malloc(sizeof(struct isa_config), M_TEMP, M_NOWAIT|M_ZERO);
42681401Sjulian	if (cfg == NULL)
42781401Sjulian		return(0);
42850769Sdfr	TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
42991202Salfred		reason = "memory";
43081401Sjulian		if (!isa_find_memory(child, &ice->ice_config, cfg))
43150769Sdfr			continue;
43291202Salfred		reason = "port";
43381401Sjulian		if (!isa_find_port(child, &ice->ice_config, cfg))
43450769Sdfr			continue;
43591202Salfred		reason = "irq";
43681401Sjulian		if (!isa_find_irq(child, &ice->ice_config, cfg))
43750769Sdfr			continue;
43891202Salfred		reason = "drq";
43981401Sjulian		if (!isa_find_drq(child, &ice->ice_config, cfg))
44050769Sdfr			continue;
44150769Sdfr
44250769Sdfr		/*
44350769Sdfr		 * A working configuration was found enable the device
44450769Sdfr		 * with this configuration.
44550769Sdfr		 */
44691202Salfred		reason = "no callback";
44750769Sdfr		if (idev->id_config_cb) {
44850769Sdfr			idev->id_config_cb(idev->id_config_arg,
44981401Sjulian					   cfg, 1);
45081401Sjulian			free(cfg, M_TEMP);
451139273Simp			return (1);
45250769Sdfr		}
45350769Sdfr	}
45450769Sdfr
45550769Sdfr	/*
45650769Sdfr	 * Disable the device.
45750769Sdfr	 */
45862987Sjhb	bus_print_child_header(device_get_parent(child), child);
45991202Salfred	printf(" can't assign resources (%s)\n", reason);
46062987Sjhb	if (bootverbose)
461139273Simp		isa_print_child(device_get_parent(child), child);
46281401Sjulian	bzero(cfg, sizeof (*cfg));
46350769Sdfr	if (idev->id_config_cb)
46481401Sjulian		idev->id_config_cb(idev->id_config_arg, cfg, 0);
46550769Sdfr	device_disable(child);
46650769Sdfr
46781401Sjulian	free(cfg, M_TEMP);
468139273Simp	return (0);
46950769Sdfr}
47050769Sdfr
47150769Sdfr/*
47283051Syokota * Return non-zero if the device has a single configuration, that is,
47383051Syokota * a fixed set of resoruces.
47483051Syokota */
47583051Syokotastatic int
47683051Syokotaisa_has_single_config(device_t dev)
47783051Syokota{
47883051Syokota	struct isa_device *idev = DEVTOISA(dev);
47983051Syokota	struct isa_config_entry *ice;
480139273Simp	uint32_t mask;
48183051Syokota	int i;
48283051Syokota
48383051Syokota	ice = TAILQ_FIRST(&idev->id_configs);
48483051Syokota	if (TAILQ_NEXT(ice, ice_link))
485139273Simp		return (0);
48683051Syokota
48783051Syokota	for (i = 0; i < ice->ice_config.ic_nmem; ++i) {
48883051Syokota		if (ice->ice_config.ic_mem[i].ir_size == 0)
48983051Syokota			continue;
49083051Syokota		if (ice->ice_config.ic_mem[i].ir_end !=
49183051Syokota		    ice->ice_config.ic_mem[i].ir_start +
49283051Syokota		    ice->ice_config.ic_mem[i].ir_size - 1)
493139273Simp			return (0);
49483051Syokota	}
49583051Syokota	for (i = 0; i < ice->ice_config.ic_nport; ++i) {
49683051Syokota		if (ice->ice_config.ic_port[i].ir_size == 0)
49783051Syokota			continue;
49883051Syokota		if (ice->ice_config.ic_port[i].ir_end !=
49983051Syokota		    ice->ice_config.ic_port[i].ir_start +
50083051Syokota		    ice->ice_config.ic_port[i].ir_size - 1)
501139273Simp			return (0);
50283051Syokota	}
50383051Syokota	for (i = 0; i < ice->ice_config.ic_nirq; ++i) {
50483051Syokota		mask = ice->ice_config.ic_irqmask[i];
50583051Syokota		if (mask == 0)
50683051Syokota			continue;
50783051Syokota		if (find_next_bit(mask, find_first_bit(mask)) != -1)
508139273Simp			return (0);
50983051Syokota	}
51083051Syokota	for (i = 0; i < ice->ice_config.ic_ndrq; ++i) {
51183051Syokota		mask = ice->ice_config.ic_drqmask[i];
51283051Syokota		if (mask == 0)
51383051Syokota			continue;
51483051Syokota		if (find_next_bit(mask, find_first_bit(mask)) != -1)
515139273Simp			return (0);
51683051Syokota	}
517139273Simp	return (1);
51883051Syokota}
51983051Syokota
52083051Syokota/*
52150769Sdfr * Called after other devices have initialised to probe for isa devices.
52250769Sdfr */
52350769Sdfrvoid
52450769Sdfrisa_probe_children(device_t dev)
52550769Sdfr{
52650769Sdfr	device_t *children;
52781401Sjulian	struct isa_config *cfg;
52850769Sdfr	int nchildren, i;
52950769Sdfr
53053094Sdfr	/*
53153094Sdfr	 * Create all the children by calling driver's identify methods.
53253094Sdfr	 */
53353094Sdfr	bus_generic_probe(dev);
53453094Sdfr
53550769Sdfr	if (device_get_children(dev, &children, &nchildren))
53650769Sdfr		return;
53750769Sdfr
53850769Sdfr	/*
53951905Sdfr	 * First disable all pnp devices so that they don't get
54051905Sdfr	 * matched by legacy probes.
54151905Sdfr	 */
54253094Sdfr	if (bootverbose)
54353094Sdfr		printf("isa_probe_children: disabling PnP devices\n");
54481401Sjulian
54581401Sjulian	cfg = malloc(sizeof(*cfg), M_TEMP, M_NOWAIT|M_ZERO);
54681401Sjulian	if (cfg == NULL) {
54781401Sjulian		free(children, M_TEMP);
54881401Sjulian		return;
54981401Sjulian	}
55081401Sjulian
55151905Sdfr	for (i = 0; i < nchildren; i++) {
55251905Sdfr		device_t child = children[i];
55351905Sdfr		struct isa_device *idev = DEVTOISA(child);
55451905Sdfr
55581401Sjulian		bzero(cfg, sizeof(*cfg));
55651905Sdfr		if (idev->id_config_cb)
55781401Sjulian			idev->id_config_cb(idev->id_config_arg, cfg, 0);
55851905Sdfr	}
55951905Sdfr
56081401Sjulian	free(cfg, M_TEMP);
56181401Sjulian
56251905Sdfr	/*
56351905Sdfr	 * Next probe all non-pnp devices so that they claim their
56450769Sdfr	 * resources first.
56550769Sdfr	 */
56653094Sdfr	if (bootverbose)
56753094Sdfr		printf("isa_probe_children: probing non-PnP devices\n");
56850769Sdfr	for (i = 0; i < nchildren; i++) {
56950769Sdfr		device_t child = children[i];
57050769Sdfr		struct isa_device *idev = DEVTOISA(child);
57150769Sdfr
57250769Sdfr		if (TAILQ_FIRST(&idev->id_configs))
57350769Sdfr			continue;
57450769Sdfr
57550769Sdfr		device_probe_and_attach(child);
57650769Sdfr	}
57750769Sdfr
57850769Sdfr	/*
57951905Sdfr	 * Finally assign resource to pnp devices and probe them.
58050769Sdfr	 */
58153094Sdfr	if (bootverbose)
58253094Sdfr		printf("isa_probe_children: probing PnP devices\n");
58350769Sdfr	for (i = 0; i < nchildren; i++) {
58450769Sdfr		device_t child = children[i];
58550769Sdfr		struct isa_device* idev = DEVTOISA(child);
58650769Sdfr
58750769Sdfr		if (!TAILQ_FIRST(&idev->id_configs))
58850769Sdfr			continue;
58950769Sdfr
59050769Sdfr		if (isa_assign_resources(child)) {
59152174Sdfr			struct resource_list *rl = &idev->id_resources;
59250769Sdfr			struct resource_list_entry *rle;
59350769Sdfr
59450769Sdfr			device_probe_and_attach(child);
59550769Sdfr
59650769Sdfr			/*
59750769Sdfr			 * Claim any unallocated resources to keep other
59850769Sdfr			 * devices from using them.
59950769Sdfr			 */
60052174Sdfr			SLIST_FOREACH(rle, rl, link) {
60150769Sdfr				if (!rle->res) {
60250769Sdfr					int rid = rle->rid;
60352174Sdfr					resource_list_alloc(rl, dev, child,
60450769Sdfr							    rle->type,
60550769Sdfr							    &rid,
60662059Sdfr							    0, ~0, 1, 0);
60750769Sdfr				}
60850769Sdfr			}
60950769Sdfr		}
61050769Sdfr	}
61150769Sdfr
61250769Sdfr	free(children, M_TEMP);
61353094Sdfr
61453094Sdfr	isa_running = 1;
61550769Sdfr}
61650769Sdfr
61750769Sdfr/*
61847398Sdfr * Add a new child with default ivars.
61947398Sdfr */
62047398Sdfrstatic device_t
62147578Sdfrisa_add_child(device_t dev, int order, const char *name, int unit)
62247398Sdfr{
62354073Smdodd	device_t child;
62447398Sdfr	struct	isa_device *idev;
62547398Sdfr
626104179Sphk	child = device_add_child_ordered(dev, order, name, unit);
627104179Sphk	if (child == NULL)
628104179Sphk		return (child);
629104179Sphk
63069781Sdwmalone	idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT | M_ZERO);
63147398Sdfr	if (!idev)
632139273Simp		return (0);
63347398Sdfr
63447398Sdfr	resource_list_init(&idev->id_resources);
63550769Sdfr	TAILQ_INIT(&idev->id_configs);
63647398Sdfr
637104179Sphk	device_set_ivars(child, idev);
63854073Smdodd
639104179Sphk	return (child);
64047398Sdfr}
64147398Sdfr
64262059Sdfrstatic int
64362059Sdfrisa_print_all_resources(device_t dev)
64447398Sdfr{
64547398Sdfr	struct	isa_device *idev = DEVTOISA(dev);
64647398Sdfr	struct resource_list *rl = &idev->id_resources;
64749195Smdodd	int retval = 0;
64847398Sdfr
64951052Sdfr	if (SLIST_FIRST(rl) || device_get_flags(dev))
65049195Smdodd		retval += printf(" at");
65147398Sdfr
65288376Stmm	retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
65388376Stmm	retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
65488376Stmm	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
65588376Stmm	retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld");
65651052Sdfr	if (device_get_flags(dev))
65751052Sdfr		retval += printf(" flags %#x", device_get_flags(dev));
65847398Sdfr
659139273Simp	return (retval);
66062059Sdfr}
66162059Sdfr
66262059Sdfrstatic int
66362059Sdfrisa_print_child(device_t bus, device_t dev)
66462059Sdfr{
66562059Sdfr	int retval = 0;
66662059Sdfr
66762059Sdfr	retval += bus_print_child_header(bus, dev);
66862059Sdfr	retval += isa_print_all_resources(dev);
66949195Smdodd	retval += bus_print_child_footer(bus, dev);
67049195Smdodd
67149195Smdodd	return (retval);
67247398Sdfr}
67347398Sdfr
67462059Sdfrstatic void
67562059Sdfrisa_probe_nomatch(device_t dev, device_t child)
67662059Sdfr{
67762987Sjhb	if (bootverbose) {
67862987Sjhb		bus_print_child_header(dev, child);
67962987Sjhb		printf(" failed to probe");
68062059Sdfr		isa_print_all_resources(child);
68162987Sjhb		bus_print_child_footer(dev, child);
68262987Sjhb	}
68362059Sdfr
68462059Sdfr	return;
68562059Sdfr}
68662059Sdfr
68747398Sdfrstatic int
68847398Sdfrisa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
68947398Sdfr{
69047398Sdfr	struct isa_device* idev = DEVTOISA(dev);
69147398Sdfr	struct resource_list *rl = &idev->id_resources;
69247398Sdfr	struct resource_list_entry *rle;
69347398Sdfr
69447398Sdfr	switch (index) {
69547398Sdfr	case ISA_IVAR_PORT_0:
69647398Sdfr		rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
69747398Sdfr		if (rle)
69847398Sdfr			*result = rle->start;
69947398Sdfr		else
70047398Sdfr			*result = -1;
70147398Sdfr		break;
70247398Sdfr
70347398Sdfr	case ISA_IVAR_PORT_1:
70447398Sdfr		rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
70547398Sdfr		if (rle)
70647398Sdfr			*result = rle->start;
70747398Sdfr		else
70847398Sdfr			*result = -1;
70947398Sdfr		break;
71047398Sdfr
71147398Sdfr	case ISA_IVAR_PORTSIZE_0:
71247398Sdfr		rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
71347398Sdfr		if (rle)
71447398Sdfr			*result = rle->count;
71547398Sdfr		else
71647398Sdfr			*result = 0;
71747398Sdfr		break;
71847398Sdfr
71947398Sdfr	case ISA_IVAR_PORTSIZE_1:
72047398Sdfr		rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
72147398Sdfr		if (rle)
72247398Sdfr			*result = rle->count;
72347398Sdfr		else
72447398Sdfr			*result = 0;
72547398Sdfr		break;
72647398Sdfr
72747398Sdfr	case ISA_IVAR_MADDR_0:
72847398Sdfr		rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
72947398Sdfr		if (rle)
73047398Sdfr			*result = rle->start;
73147398Sdfr		else
73247398Sdfr			*result = -1;
73347398Sdfr		break;
73447398Sdfr
73547398Sdfr	case ISA_IVAR_MADDR_1:
73647398Sdfr		rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
73747398Sdfr		if (rle)
73847398Sdfr			*result = rle->start;
73947398Sdfr		else
74047398Sdfr			*result = -1;
74147398Sdfr		break;
74247398Sdfr
743105139Sjhb	case ISA_IVAR_MEMSIZE_0:
74447398Sdfr		rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
74547398Sdfr		if (rle)
74647398Sdfr			*result = rle->count;
74747398Sdfr		else
74847398Sdfr			*result = 0;
74947398Sdfr		break;
75047398Sdfr
751105139Sjhb	case ISA_IVAR_MEMSIZE_1:
75247398Sdfr		rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
75347398Sdfr		if (rle)
75447398Sdfr			*result = rle->count;
75547398Sdfr		else
75647398Sdfr			*result = 0;
75747398Sdfr		break;
75847398Sdfr
75947398Sdfr	case ISA_IVAR_IRQ_0:
76047398Sdfr		rle = resource_list_find(rl, SYS_RES_IRQ, 0);
76147398Sdfr		if (rle)
76247398Sdfr			*result = rle->start;
76347398Sdfr		else
76447398Sdfr			*result = -1;
76547398Sdfr		break;
76647398Sdfr
76747398Sdfr	case ISA_IVAR_IRQ_1:
76847398Sdfr		rle = resource_list_find(rl, SYS_RES_IRQ, 1);
76947398Sdfr		if (rle)
77047398Sdfr			*result = rle->start;
77147398Sdfr		else
77247398Sdfr			*result = -1;
77347398Sdfr		break;
77447398Sdfr
77547398Sdfr	case ISA_IVAR_DRQ_0:
77647398Sdfr		rle = resource_list_find(rl, SYS_RES_DRQ, 0);
77747398Sdfr		if (rle)
77847398Sdfr			*result = rle->start;
77947398Sdfr		else
78047398Sdfr			*result = -1;
78147398Sdfr		break;
78247398Sdfr
78347398Sdfr	case ISA_IVAR_DRQ_1:
78447398Sdfr		rle = resource_list_find(rl, SYS_RES_DRQ, 1);
78547398Sdfr		if (rle)
78647398Sdfr			*result = rle->start;
78747398Sdfr		else
78847398Sdfr			*result = -1;
78947398Sdfr		break;
79047398Sdfr
79147613Sdfr	case ISA_IVAR_VENDORID:
79247613Sdfr		*result = idev->id_vendorid;
79347613Sdfr		break;
79447613Sdfr
79547613Sdfr	case ISA_IVAR_SERIAL:
79647613Sdfr		*result = idev->id_serial;
79747613Sdfr		break;
79847613Sdfr
79947613Sdfr	case ISA_IVAR_LOGICALID:
80047613Sdfr		*result = idev->id_logicalid;
80147613Sdfr		break;
80247613Sdfr
80347613Sdfr	case ISA_IVAR_COMPATID:
80447613Sdfr		*result = idev->id_compatid;
80547613Sdfr		break;
80647613Sdfr
80782863Syokota	case ISA_IVAR_CONFIGATTR:
80882863Syokota		*result = idev->id_config_attr;
80982863Syokota		break;
81082863Syokota
81147613Sdfr	default:
812139273Simp		return (ENOENT);
81347398Sdfr	}
81447613Sdfr
815139273Simp	return (0);
81647398Sdfr}
81747398Sdfr
81847398Sdfrstatic int
819139273Simpisa_write_ivar(device_t bus, device_t dev, int index, uintptr_t value)
82047398Sdfr{
82147398Sdfr	struct isa_device* idev = DEVTOISA(dev);
82247398Sdfr
82347398Sdfr	switch (index) {
82447398Sdfr	case ISA_IVAR_PORT_0:
82547398Sdfr	case ISA_IVAR_PORT_1:
82647398Sdfr	case ISA_IVAR_PORTSIZE_0:
82747398Sdfr	case ISA_IVAR_PORTSIZE_1:
82847398Sdfr	case ISA_IVAR_MADDR_0:
82947398Sdfr	case ISA_IVAR_MADDR_1:
830105139Sjhb	case ISA_IVAR_MEMSIZE_0:
831105139Sjhb	case ISA_IVAR_MEMSIZE_1:
83247398Sdfr	case ISA_IVAR_IRQ_0:
83347398Sdfr	case ISA_IVAR_IRQ_1:
83447398Sdfr	case ISA_IVAR_DRQ_0:
83547398Sdfr	case ISA_IVAR_DRQ_1:
836139273Simp		return (EINVAL);
83747398Sdfr
83847613Sdfr	case ISA_IVAR_VENDORID:
83947613Sdfr		idev->id_vendorid = value;
84047613Sdfr		break;
84147613Sdfr
84247613Sdfr	case ISA_IVAR_SERIAL:
84347613Sdfr		idev->id_serial = value;
84447613Sdfr		break;
84547613Sdfr
84647613Sdfr	case ISA_IVAR_LOGICALID:
84747613Sdfr		idev->id_logicalid = value;
84847613Sdfr		break;
84947613Sdfr
85047613Sdfr	case ISA_IVAR_COMPATID:
85147613Sdfr		idev->id_compatid = value;
85247613Sdfr		break;
85347613Sdfr
85482863Syokota	case ISA_IVAR_CONFIGATTR:
85582863Syokota		idev->id_config_attr = value;
85682863Syokota		break;
85782863Syokota
85847398Sdfr	default:
85947398Sdfr		return (ENOENT);
86047398Sdfr	}
86147613Sdfr
86247398Sdfr	return (0);
86347398Sdfr}
86447398Sdfr
86550769Sdfr/*
86650769Sdfr * Free any resources which the driver missed or which we were holding for
86750769Sdfr * it (see isa_probe_children).
86850769Sdfr */
86950769Sdfrstatic void
87050769Sdfrisa_child_detached(device_t dev, device_t child)
87150769Sdfr{
87250769Sdfr	struct isa_device* idev = DEVTOISA(child);
87352174Sdfr	struct resource_list *rl = &idev->id_resources;
87450769Sdfr	struct resource_list_entry *rle;
87550769Sdfr
87662059Sdfr	if (TAILQ_FIRST(&idev->id_configs)) {
87762059Sdfr		/*
87862059Sdfr		 * Claim any unallocated resources to keep other
87962059Sdfr		 * devices from using them.
88062059Sdfr		 */
88162059Sdfr		SLIST_FOREACH(rle, rl, link) {
88262059Sdfr			if (!rle->res) {
88362059Sdfr				int rid = rle->rid;
88462059Sdfr				resource_list_alloc(rl, dev, child,
88562059Sdfr						    rle->type,
88662059Sdfr						    &rid, 0, ~0, 1, 0);
88762059Sdfr			}
88862059Sdfr		}
88950769Sdfr	}
89050769Sdfr}
89150769Sdfr
89253094Sdfrstatic void
89353094Sdfrisa_driver_added(device_t dev, driver_t *driver)
89453094Sdfr{
89553094Sdfr	device_t *children;
89653094Sdfr	int nchildren, i;
89753094Sdfr
89853094Sdfr	/*
89953094Sdfr	 * Don't do anything if drivers are dynamically
90053094Sdfr	 * added during autoconfiguration (cf. ymf724).
90153094Sdfr	 * since that would end up calling identify
90253094Sdfr	 * twice.
90353094Sdfr	 */
90453094Sdfr	if (!isa_running)
90553094Sdfr		return;
90653094Sdfr
90753094Sdfr	DEVICE_IDENTIFY(driver, dev);
90853094Sdfr	if (device_get_children(dev, &children, &nchildren))
90953094Sdfr		return;
91053094Sdfr
91153094Sdfr	for (i = 0; i < nchildren; i++) {
91253094Sdfr		device_t child = children[i];
91353094Sdfr		struct isa_device *idev = DEVTOISA(child);
91453094Sdfr		struct resource_list *rl = &idev->id_resources;
91553094Sdfr		struct resource_list_entry *rle;
91653094Sdfr
91753094Sdfr		if (device_get_state(child) != DS_NOTPRESENT)
91853094Sdfr			continue;
91962059Sdfr		if (!device_is_enabled(child))
92062059Sdfr			continue;
92153094Sdfr
92262059Sdfr		/*
92362059Sdfr		 * Free resources which we were holding on behalf of
92462059Sdfr		 * the device.
92562059Sdfr		 */
92662059Sdfr		SLIST_FOREACH(rle, &idev->id_resources, link) {
92762059Sdfr			if (rle->res)
92862059Sdfr				resource_list_release(rl, dev, child,
92962059Sdfr						      rle->type,
93062059Sdfr						      rle->rid,
93162059Sdfr						      rle->res);
93262059Sdfr		}
93362059Sdfr
93453094Sdfr		if (TAILQ_FIRST(&idev->id_configs))
93553094Sdfr			if (!isa_assign_resources(child))
93653094Sdfr				continue;
93753094Sdfr
93853094Sdfr		device_probe_and_attach(child);
93953094Sdfr
94053094Sdfr		if (TAILQ_FIRST(&idev->id_configs)) {
94153094Sdfr			/*
94253094Sdfr			 * Claim any unallocated resources to keep other
94353094Sdfr			 * devices from using them.
94453094Sdfr			 */
94553094Sdfr			SLIST_FOREACH(rle, rl, link) {
94653094Sdfr				if (!rle->res) {
94753094Sdfr					int rid = rle->rid;
94853094Sdfr					resource_list_alloc(rl, dev, child,
94953094Sdfr							    rle->type,
95062059Sdfr							    &rid, 0, ~0, 1, 0);
95153094Sdfr				}
95253094Sdfr			}
95353094Sdfr		}
95453094Sdfr	}
95553094Sdfr
95653094Sdfr	free(children, M_TEMP);
95753094Sdfr}
95853094Sdfr
95947398Sdfrstatic int
96047398Sdfrisa_set_resource(device_t dev, device_t child, int type, int rid,
961139273Simp    u_long start, u_long count)
96247398Sdfr{
96347398Sdfr	struct isa_device* idev = DEVTOISA(child);
96447398Sdfr	struct resource_list *rl = &idev->id_resources;
96547398Sdfr
96647398Sdfr	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
96747398Sdfr	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
968139273Simp		return (EINVAL);
96950769Sdfr	if (rid < 0)
970139273Simp		return (EINVAL);
97150769Sdfr	if (type == SYS_RES_IOPORT && rid >= ISA_NPORT)
972139273Simp		return (EINVAL);
97350769Sdfr	if (type == SYS_RES_MEMORY && rid >= ISA_NMEM)
974139273Simp		return (EINVAL);
97550769Sdfr	if (type == SYS_RES_IRQ && rid >= ISA_NIRQ)
976139273Simp		return (EINVAL);
97750769Sdfr	if (type == SYS_RES_DRQ && rid >= ISA_NDRQ)
978139273Simp		return (EINVAL);
97947398Sdfr
98047398Sdfr	resource_list_add(rl, type, rid, start, start + count - 1, count);
98147398Sdfr
982139273Simp	return (0);
98347398Sdfr}
98447398Sdfr
98569295Smdoddstatic struct resource_list *
98669295Smdoddisa_get_resource_list (device_t dev, device_t child)
98747398Sdfr{
98847398Sdfr	struct isa_device* idev = DEVTOISA(child);
98947398Sdfr	struct resource_list *rl = &idev->id_resources;
99047398Sdfr
99169295Smdodd	if (!rl)
99269295Smdodd		return (NULL);
99347398Sdfr
99469295Smdodd	return (rl);
99547398Sdfr}
99647398Sdfr
99750769Sdfrstatic int
998139273Simpisa_add_config(device_t dev, device_t child, int priority,
999139273Simp    struct isa_config *config)
100050769Sdfr{
100150769Sdfr	struct isa_device* idev = DEVTOISA(child);
100250769Sdfr	struct isa_config_entry *newice, *ice;
100350769Sdfr
100450769Sdfr	newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT);
100550769Sdfr	if (!newice)
1006139273Simp		return (ENOMEM);
100750769Sdfr
100850769Sdfr	newice->ice_priority = priority;
100950769Sdfr	newice->ice_config = *config;
101050769Sdfr
101150769Sdfr	TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
101250769Sdfr		if (ice->ice_priority > priority)
101350769Sdfr			break;
101450769Sdfr	}
101550769Sdfr	if (ice)
101650769Sdfr		TAILQ_INSERT_BEFORE(ice, newice, ice_link);
101750769Sdfr	else
101850769Sdfr		TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link);
101950769Sdfr
102083051Syokota	if (isa_has_single_config(child))
102183051Syokota		idev->id_config_attr &= ~ISACFGATTR_MULTI;
102283051Syokota	else
102383051Syokota		idev->id_config_attr |= ISACFGATTR_MULTI;
102483051Syokota
1025139273Simp	return (0);
102650769Sdfr}
102750769Sdfr
102850769Sdfrstatic void
1029139273Simpisa_set_config_callback(device_t dev, device_t child, isa_config_cb *fn,
1030139273Simp    void *arg)
103150769Sdfr{
103250769Sdfr	struct isa_device* idev = DEVTOISA(child);
103350769Sdfr
103450769Sdfr	idev->id_config_cb = fn;
103550769Sdfr	idev->id_config_arg = arg;
103650769Sdfr}
103750769Sdfr
103850769Sdfrstatic int
103950769Sdfrisa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids)
104050769Sdfr{
104150769Sdfr	struct isa_device* idev = DEVTOISA(child);
104250769Sdfr
104350769Sdfr	if (!idev->id_vendorid)
1044139273Simp		return (ENOENT);
104550769Sdfr
104682553Smsmith	while (ids && ids->ip_id) {
104750769Sdfr		/*
104850769Sdfr		 * Really ought to support >1 compat id per device.
104950769Sdfr		 */
105050769Sdfr		if (idev->id_logicalid == ids->ip_id
105150769Sdfr		    || idev->id_compatid == ids->ip_id) {
105250910Sdfr			if (ids->ip_desc)
105350910Sdfr				device_set_desc(child, ids->ip_desc);
1054139273Simp			return (0);
105550769Sdfr		}
105650769Sdfr		ids++;
105750769Sdfr	}
105850769Sdfr
1059139273Simp	return (ENXIO);
106050769Sdfr}
106150769Sdfr
106247398Sdfrstatic device_method_t isa_methods[] = {
106347398Sdfr	/* Device interface */
106447398Sdfr	DEVMETHOD(device_probe,		isa_probe),
106547398Sdfr	DEVMETHOD(device_attach,	isa_attach),
106647398Sdfr	DEVMETHOD(device_detach,	bus_generic_detach),
106747398Sdfr	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
106847398Sdfr	DEVMETHOD(device_suspend,	bus_generic_suspend),
106947398Sdfr	DEVMETHOD(device_resume,	bus_generic_resume),
107047398Sdfr
107147398Sdfr	/* Bus interface */
107247398Sdfr	DEVMETHOD(bus_add_child,	isa_add_child),
107347398Sdfr	DEVMETHOD(bus_print_child,	isa_print_child),
107462059Sdfr	DEVMETHOD(bus_probe_nomatch,	isa_probe_nomatch),
107547398Sdfr	DEVMETHOD(bus_read_ivar,	isa_read_ivar),
107647398Sdfr	DEVMETHOD(bus_write_ivar,	isa_write_ivar),
107750769Sdfr	DEVMETHOD(bus_child_detached,	isa_child_detached),
107853094Sdfr	DEVMETHOD(bus_driver_added,	isa_driver_added),
107969295Smdodd	DEVMETHOD(bus_setup_intr,	isa_setup_intr),
108069295Smdodd	DEVMETHOD(bus_teardown_intr,	isa_teardown_intr),
108169295Smdodd
108269295Smdodd	DEVMETHOD(bus_get_resource_list,isa_get_resource_list),
108347398Sdfr	DEVMETHOD(bus_alloc_resource,	isa_alloc_resource),
108447398Sdfr	DEVMETHOD(bus_release_resource,	isa_release_resource),
108569295Smdodd	DEVMETHOD(bus_set_resource,	isa_set_resource),
108669295Smdodd	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
108769295Smdodd	DEVMETHOD(bus_delete_resource,	bus_generic_rl_delete_resource),
108847398Sdfr	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
108947398Sdfr	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
109047398Sdfr
109147398Sdfr	/* ISA interface */
109250769Sdfr	DEVMETHOD(isa_add_config,	isa_add_config),
109350769Sdfr	DEVMETHOD(isa_set_config_callback, isa_set_config_callback),
109450769Sdfr	DEVMETHOD(isa_pnp_probe,	isa_pnp_probe),
109547398Sdfr
109647398Sdfr	{ 0, 0 }
109747398Sdfr};
109847398Sdfr
1099139279Simpdriver_t isa_driver = {
110047398Sdfr	"isa",
110147398Sdfr	isa_methods,
110247398Sdfr	1,			/* no softc */
110347398Sdfr};
110447398Sdfr
1105139279Simpdevclass_t isa_devclass;
1106139279Simp
110747398Sdfr/*
1108139279Simp * ISA can be attached to a PCI-ISA bridge, or other locations on some
1109139279Simp * platforms.
111047398Sdfr */
111147398SdfrDRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0);
111269942SmsmithDRIVER_MODULE(isa, eisab, isa_driver, isa_devclass, 0, 0);
1113113498SmdoddMODULE_VERSION(isa, 1);
1114117337Sjhb
1115117337Sjhb/*
1116117337Sjhb * Code common to ISA bridges.
1117117337Sjhb */
1118117337Sjhb
1119117337Sjhbdevclass_t isab_devclass;
1120117337Sjhb
1121117337Sjhbint
1122117337Sjhbisab_attach(device_t dev)
1123117337Sjhb{
1124117337Sjhb	device_t child;
1125117337Sjhb
1126117337Sjhb	child = device_add_child(dev, "isa", 0);
1127117337Sjhb	if (child != NULL)
1128117337Sjhb		return (bus_generic_attach(dev));
1129117337Sjhb	return (ENXIO);
1130117337Sjhb}
1131