isa_common.c revision 182103
1264790Sbapt/*-
2264790Sbapt * Copyright (c) 1999 Doug Rabson
3272955Srodrigc * All rights reserved.
4264790Sbapt *
5264790Sbapt * Redistribution and use in source and binary forms, with or without
6264790Sbapt * modification, are permitted provided that the following conditions
7264790Sbapt * are met:
8264790Sbapt * 1. Redistributions of source code must retain the above copyright
9264790Sbapt *    notice, this list of conditions and the following disclaimer.
10264790Sbapt * 2. Redistributions in binary form must reproduce the above copyright
11264790Sbapt *    notice, this list of conditions and the following disclaimer in the
12264790Sbapt *    documentation and/or other materials provided with the distribution.
13264790Sbapt *
14264790Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15264790Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16264790Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17264790Sbapt * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18264790Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19264790Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20264790Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21264790Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22264790Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23264790Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24264790Sbapt * SUCH DAMAGE.
25264790Sbapt */
26264790Sbapt/*
27264790Sbapt * Modifications for Intel architecture by Garrett A. Wollman.
28264790Sbapt * Copyright 1998 Massachusetts Institute of Technology
29264790Sbapt *
30264790Sbapt * Permission to use, copy, modify, and distribute this software and
31264790Sbapt * its documentation for any purpose and without fee is hereby
32264790Sbapt * granted, provided that both the above copyright notice and this
33264790Sbapt * permission notice appear in all copies, that both the above
34264790Sbapt * copyright notice and this permission notice appear in all
35264790Sbapt * supporting documentation, and that the name of M.I.T. not be used
36264790Sbapt * in advertising or publicity pertaining to distribution of the
37264790Sbapt * software without specific, written prior permission.  M.I.T. makes
38264790Sbapt * no representations about the suitability of this software for any
39264790Sbapt * purpose.  It is provided "as is" without express or implied
40264790Sbapt * warranty.
41264790Sbapt *
42264790Sbapt * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
43264790Sbapt * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
44264790Sbapt * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
45264790Sbapt * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
46264790Sbapt * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47264790Sbapt * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48264790Sbapt * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
49264790Sbapt * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
50264790Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
51264790Sbapt * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
52264790Sbapt * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53264790Sbapt * SUCH DAMAGE.
54264790Sbapt */
55264790Sbapt
56264790Sbapt/*
57264790Sbapt * Parts of the ISA bus implementation common to all architectures.
58264790Sbapt */
59264790Sbapt
60264790Sbapt#include <sys/cdefs.h>
61264790Sbapt__FBSDID("$FreeBSD: head/sys/isa/isa_common.c 182103 2008-08-24 07:40:14Z imp $");
62264790Sbapt
63264790Sbapt#include "opt_isa.h"
64264790Sbapt
65264790Sbapt#include <sys/param.h>
66264790Sbapt#include <sys/systm.h>
67264790Sbapt#include <sys/kernel.h>
68264790Sbapt#include <sys/bus.h>
69264790Sbapt#include <sys/malloc.h>
70264790Sbapt#include <sys/module.h>
71264790Sbapt#include <machine/bus.h>
72264790Sbapt#include <sys/rman.h>
73264790Sbapt
74264790Sbapt#include <machine/resource.h>
75264790Sbapt
76264790Sbapt#include <isa/isavar.h>
77264790Sbapt#include <isa/isa_common.h>
78264790Sbapt
79264790Sbaptstatic int	isa_print_child(device_t bus, device_t dev);
80264790Sbapt
81264790Sbaptstatic MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device");
82264790Sbapt
83264790Sbaptstatic int isa_running;
84264790Sbapt
85264790Sbapt/*
86264790Sbapt * At 'probe' time, we add all the devices which we know about to the
87264790Sbapt * bus.  The generic attach routine will probe and attach them if they
88264790Sbapt * are alive.
89264790Sbapt */
90264790Sbaptstatic int
91264790Sbaptisa_probe(device_t dev)
92264790Sbapt{
93264790Sbapt	device_set_desc(dev, "ISA bus");
94264790Sbapt	isa_init(dev);		/* Allow machdep code to initialise */
95264790Sbapt	return (0);
96264790Sbapt}
97264790Sbapt
98264790Sbaptextern device_t isa_bus_device;
99264790Sbapt
100264790Sbaptstatic int
101264790Sbaptisa_attach(device_t dev)
102264790Sbapt{
103264790Sbapt	/*
104264790Sbapt	 * Arrange for isa_probe_children(dev) to be called later. XXX
105264790Sbapt	 */
106264790Sbapt	isa_bus_device = dev;
107264790Sbapt	return (0);
108264790Sbapt}
109264790Sbapt
110264790Sbapt/*
111264790Sbapt * Find a working set of memory regions for a child using the ranges
112264790Sbapt * in *config  and return the regions in *result. Returns non-zero if
113264790Sbapt * a set of ranges was found.
114264790Sbapt */
115264790Sbaptstatic int
116264790Sbaptisa_find_memory(device_t child, struct isa_config *config,
117264790Sbapt    struct isa_config *result)
118264790Sbapt{
119264790Sbapt	int success, i;
120264790Sbapt	struct resource *res[ISA_NMEM];
121264790Sbapt
122264790Sbapt	/*
123264790Sbapt	 * First clear out any existing resource definitions.
124264790Sbapt	 */
125264790Sbapt	for (i = 0; i < ISA_NMEM; i++) {
126264790Sbapt		bus_delete_resource(child, SYS_RES_MEMORY, i);
127264790Sbapt		res[i] = NULL;
128264790Sbapt	}
129264790Sbapt
130264790Sbapt	success = 1;
131264790Sbapt	result->ic_nmem = config->ic_nmem;
132264790Sbapt	for (i = 0; i < config->ic_nmem; i++) {
133264790Sbapt		uint32_t start, end, size, align;
134264790Sbapt
135264790Sbapt		size = config->ic_mem[i].ir_size;
136264790Sbapt
137264790Sbapt		/* the PnP device may have a null resource as filler */
138264790Sbapt		if (size == 0) {
139264790Sbapt			result->ic_mem[i].ir_start = 0;
140264790Sbapt			result->ic_mem[i].ir_end = 0;
141264790Sbapt			result->ic_mem[i].ir_size = 0;
142264790Sbapt			result->ic_mem[i].ir_align = 0;
143264790Sbapt			continue;
144264790Sbapt		}
145264790Sbapt
146264790Sbapt		for (start = config->ic_mem[i].ir_start,
147264790Sbapt			     end = config->ic_mem[i].ir_end,
148264790Sbapt			     align = config->ic_mem[i].ir_align;
149264790Sbapt		     start + size - 1 <= end && start + size > start;
150272955Srodrigc		     start += MAX(align, 1)) {
151264790Sbapt			bus_set_resource(child, SYS_RES_MEMORY, i,
152264790Sbapt					 start, size);
153264790Sbapt			res[i] = bus_alloc_resource(child,
154264790Sbapt			    SYS_RES_MEMORY, &i, 0, ~0, 1,
155264790Sbapt			    rman_make_alignment_flags(align) /* !RF_ACTIVE */);
156264790Sbapt			if (res[i]) {
157264790Sbapt				result->ic_mem[i].ir_start = start;
158264790Sbapt				result->ic_mem[i].ir_end = start + size - 1;
159264790Sbapt				result->ic_mem[i].ir_size = size;
160264790Sbapt				result->ic_mem[i].ir_align = align;
161264790Sbapt				break;
162272955Srodrigc			}
163264790Sbapt		}
164264790Sbapt
165264790Sbapt		/*
166264790Sbapt		 * If we didn't find a place for memory range i, then
167264790Sbapt		 * give up now.
168272955Srodrigc		 */
169264790Sbapt		if (!res[i]) {
170264790Sbapt			success = 0;
171264790Sbapt			break;
172264790Sbapt		}
173264790Sbapt	}
174264790Sbapt
175264790Sbapt	for (i = 0; i < ISA_NMEM; i++) {
176264790Sbapt		if (res[i])
177264790Sbapt			bus_release_resource(child, SYS_RES_MEMORY,
178264790Sbapt					     i, res[i]);
179264790Sbapt	}
180264790Sbapt
181264790Sbapt	return (success);
182264790Sbapt}
183264790Sbapt
184264790Sbapt/*
185264790Sbapt * Find a working set of port regions for a child using the ranges
186264790Sbapt * in *config  and return the regions in *result. Returns non-zero if
187264790Sbapt * a set of ranges was found.
188264790Sbapt */
189264790Sbaptstatic int
190264790Sbaptisa_find_port(device_t child, struct isa_config *config,
191264790Sbapt    struct isa_config *result)
192264790Sbapt{
193264790Sbapt	int success, i;
194264790Sbapt	struct resource *res[ISA_NPORT];
195264790Sbapt
196264790Sbapt	/*
197264790Sbapt	 * First clear out any existing resource definitions.
198264790Sbapt	 */
199264790Sbapt	for (i = 0; i < ISA_NPORT; i++) {
200264790Sbapt		bus_delete_resource(child, SYS_RES_IOPORT, i);
201264790Sbapt		res[i] = NULL;
202264790Sbapt	}
203264790Sbapt
204264790Sbapt	success = 1;
205264790Sbapt	result->ic_nport = config->ic_nport;
206264790Sbapt	for (i = 0; i < config->ic_nport; i++) {
207264790Sbapt		uint32_t start, end, size, align;
208264790Sbapt
209264790Sbapt		size = config->ic_port[i].ir_size;
210264790Sbapt
211264790Sbapt		/* the PnP device may have a null resource as filler */
212264790Sbapt		if (size == 0) {
213264790Sbapt			result->ic_port[i].ir_start = 0;
214264790Sbapt			result->ic_port[i].ir_end = 0;
215264790Sbapt			result->ic_port[i].ir_size = 0;
216264790Sbapt			result->ic_port[i].ir_align = 0;
217264790Sbapt			continue;
218264790Sbapt		}
219264790Sbapt
220264790Sbapt		for (start = config->ic_port[i].ir_start,
221264790Sbapt			     end = config->ic_port[i].ir_end,
222264790Sbapt			     align = config->ic_port[i].ir_align;
223264790Sbapt		     start + size - 1 <= end;
224264790Sbapt		     start += align) {
225264790Sbapt			bus_set_resource(child, SYS_RES_IOPORT, i,
226264790Sbapt					 start, size);
227264790Sbapt			res[i] = bus_alloc_resource(child,
228264790Sbapt			    SYS_RES_IOPORT, &i, 0, ~0, 1,
229264790Sbapt			    rman_make_alignment_flags(align) /* !RF_ACTIVE */);
230264790Sbapt			if (res[i]) {
231264790Sbapt				result->ic_port[i].ir_start = start;
232264790Sbapt				result->ic_port[i].ir_end = start + size - 1;
233264790Sbapt				result->ic_port[i].ir_size = size;
234264790Sbapt				result->ic_port[i].ir_align = align;
235264790Sbapt				break;
236264790Sbapt			}
237264790Sbapt		}
238264790Sbapt
239264790Sbapt		/*
240264790Sbapt		 * If we didn't find a place for port range i, then
241264790Sbapt		 * give up now.
242264790Sbapt		 */
243264790Sbapt		if (!res[i]) {
244264790Sbapt			success = 0;
245264790Sbapt			break;
246264790Sbapt		}
247264790Sbapt	}
248264790Sbapt
249264790Sbapt	for (i = 0; i < ISA_NPORT; i++) {
250264790Sbapt		if (res[i])
251264790Sbapt			bus_release_resource(child, SYS_RES_IOPORT,
252264790Sbapt					     i, res[i]);
253264790Sbapt	}
254264790Sbapt
255264790Sbapt	return success;
256264790Sbapt}
257264790Sbapt
258264790Sbapt/*
259264790Sbapt * Return the index of the first bit in the mask (or -1 if mask is empty.
260264790Sbapt */
261264790Sbaptstatic int
262264790Sbaptfind_first_bit(uint32_t mask)
263264790Sbapt{
264264790Sbapt	return (ffs(mask) - 1);
265264790Sbapt}
266264790Sbapt
267264790Sbapt/*
268264790Sbapt * Return the index of the next bit in the mask, or -1 if there are no more.
269264790Sbapt */
270264790Sbaptstatic int
271264790Sbaptfind_next_bit(uint32_t mask, int bit)
272264790Sbapt{
273264790Sbapt	bit++;
274264790Sbapt	while (bit < 32 && !(mask & (1 << bit)))
275264790Sbapt		bit++;
276272955Srodrigc	if (bit != 32)
277272955Srodrigc		return (bit);
278272955Srodrigc	return (-1);
279272955Srodrigc}
280272955Srodrigc
281272955Srodrigc/*
282272955Srodrigc * Find a working set of irqs for a child using the masks in *config
283272955Srodrigc * and return the regions in *result. Returns non-zero if a set of
284272955Srodrigc * irqs was found.
285272955Srodrigc */
286272955Srodrigcstatic int
287272955Srodrigcisa_find_irq(device_t child, struct isa_config *config,
288272955Srodrigc    struct isa_config *result)
289272955Srodrigc{
290272955Srodrigc	int success, i;
291272955Srodrigc	struct resource *res[ISA_NIRQ];
292272955Srodrigc
293272955Srodrigc	/*
294272955Srodrigc	 * First clear out any existing resource definitions.
295272955Srodrigc	 */
296272955Srodrigc	for (i = 0; i < ISA_NIRQ; i++) {
297272955Srodrigc		bus_delete_resource(child, SYS_RES_IRQ, i);
298272955Srodrigc		res[i] = NULL;
299272955Srodrigc	}
300272955Srodrigc
301272955Srodrigc	success = 1;
302264790Sbapt	result->ic_nirq = config->ic_nirq;
303264790Sbapt	for (i = 0; i < config->ic_nirq; i++) {
304264790Sbapt		uint32_t mask = config->ic_irqmask[i];
305264790Sbapt		int irq;
306264790Sbapt
307264790Sbapt		/* the PnP device may have a null resource as filler */
308264790Sbapt		if (mask == 0) {
309264790Sbapt			result->ic_irqmask[i] = 0;
310264790Sbapt			continue;
311264790Sbapt		}
312264790Sbapt
313264790Sbapt		for (irq = find_first_bit(mask);
314264790Sbapt		     irq != -1;
315264790Sbapt		     irq = find_next_bit(mask, irq)) {
316264790Sbapt			bus_set_resource(child, SYS_RES_IRQ, i,
317264790Sbapt					 irq, 1);
318264790Sbapt			res[i] = bus_alloc_resource_any(child,
319264790Sbapt							SYS_RES_IRQ, &i,
320264790Sbapt							0 /* !RF_ACTIVE */ );
321264790Sbapt			if (res[i]) {
322264790Sbapt				result->ic_irqmask[i] = (1 << irq);
323264790Sbapt				break;
324264790Sbapt			}
325264790Sbapt		}
326264790Sbapt
327264790Sbapt		/*
328264790Sbapt		 * If we didn't find a place for irq range i, then
329264790Sbapt		 * give up now.
330264790Sbapt		 */
331264790Sbapt		if (!res[i]) {
332264790Sbapt			success = 0;
333264790Sbapt			break;
334264790Sbapt		}
335264790Sbapt	}
336264790Sbapt
337264790Sbapt	for (i = 0; i < ISA_NIRQ; i++) {
338264790Sbapt		if (res[i])
339264790Sbapt			bus_release_resource(child, SYS_RES_IRQ,
340264790Sbapt					     i, res[i]);
341264790Sbapt	}
342264790Sbapt
343264790Sbapt	return (success);
344264790Sbapt}
345264790Sbapt
346264790Sbapt/*
347264790Sbapt * Find a working set of drqs for a child using the masks in *config
348264790Sbapt * and return the regions in *result. Returns non-zero if a set of
349264790Sbapt * drqs was found.
350264790Sbapt */
351264790Sbaptstatic int
352264790Sbaptisa_find_drq(device_t child, struct isa_config *config,
353264790Sbapt    struct isa_config *result)
354264790Sbapt{
355264790Sbapt	int success, i;
356264790Sbapt	struct resource *res[ISA_NDRQ];
357264790Sbapt
358264790Sbapt	/*
359264790Sbapt	 * First clear out any existing resource definitions.
360264790Sbapt	 */
361264790Sbapt	for (i = 0; i < ISA_NDRQ; i++) {
362264790Sbapt		bus_delete_resource(child, SYS_RES_DRQ, i);
363264790Sbapt		res[i] = NULL;
364264790Sbapt	}
365264790Sbapt
366264790Sbapt	success = 1;
367264790Sbapt	result->ic_ndrq = config->ic_ndrq;
368264790Sbapt	for (i = 0; i < config->ic_ndrq; i++) {
369264790Sbapt		uint32_t mask = config->ic_drqmask[i];
370264790Sbapt		int drq;
371264790Sbapt
372264790Sbapt		/* the PnP device may have a null resource as filler */
373264790Sbapt		if (mask == 0) {
374264790Sbapt			result->ic_drqmask[i] = 0;
375264790Sbapt			continue;
376264790Sbapt		}
377264790Sbapt
378264790Sbapt		for (drq = find_first_bit(mask);
379264790Sbapt		     drq != -1;
380264790Sbapt		     drq = find_next_bit(mask, drq)) {
381264790Sbapt			bus_set_resource(child, SYS_RES_DRQ, i,
382264790Sbapt					 drq, 1);
383264790Sbapt			res[i] = bus_alloc_resource_any(child,
384264790Sbapt							SYS_RES_DRQ, &i,
385264790Sbapt							0 /* !RF_ACTIVE */);
386264790Sbapt			if (res[i]) {
387264790Sbapt				result->ic_drqmask[i] = (1 << drq);
388264790Sbapt				break;
389264790Sbapt			}
390264790Sbapt		}
391264790Sbapt
392264790Sbapt		/*
393264790Sbapt		 * If we didn't find a place for drq range i, then
394264790Sbapt		 * give up now.
395264790Sbapt		 */
396264790Sbapt		if (!res[i]) {
397264790Sbapt			success = 0;
398264790Sbapt			break;
399264790Sbapt		}
400264790Sbapt	}
401264790Sbapt
402264790Sbapt	for (i = 0; i < ISA_NDRQ; i++) {
403264790Sbapt		if (res[i])
404264790Sbapt			bus_release_resource(child, SYS_RES_DRQ,
405264790Sbapt					     i, res[i]);
406264790Sbapt	}
407264790Sbapt
408264790Sbapt	return (success);
409264790Sbapt}
410264790Sbapt
411264790Sbapt/*
412264790Sbapt * Attempt to find a working set of resources for a device. Return
413264790Sbapt * non-zero if a working configuration is found.
414264790Sbapt */
415264790Sbaptstatic int
416264790Sbaptisa_assign_resources(device_t child)
417264790Sbapt{
418264790Sbapt	struct isa_device *idev = DEVTOISA(child);
419264790Sbapt	struct isa_config_entry *ice;
420264790Sbapt	struct isa_config *cfg;
421264790Sbapt	const char *reason;
422264790Sbapt
423264790Sbapt	reason = "Empty ISA id_configs";
424264790Sbapt	cfg = malloc(sizeof(struct isa_config), M_TEMP, M_NOWAIT|M_ZERO);
425264790Sbapt	if (cfg == NULL)
426264790Sbapt		return(0);
427264790Sbapt	TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
428264790Sbapt		reason = "memory";
429264790Sbapt		if (!isa_find_memory(child, &ice->ice_config, cfg))
430264790Sbapt			continue;
431264790Sbapt		reason = "port";
432264790Sbapt		if (!isa_find_port(child, &ice->ice_config, cfg))
433264790Sbapt			continue;
434264790Sbapt		reason = "irq";
435264790Sbapt		if (!isa_find_irq(child, &ice->ice_config, cfg))
436264790Sbapt			continue;
437264790Sbapt		reason = "drq";
438264790Sbapt		if (!isa_find_drq(child, &ice->ice_config, cfg))
439264790Sbapt			continue;
440264790Sbapt
441264790Sbapt		/*
442264790Sbapt		 * A working configuration was found enable the device
443264790Sbapt		 * with this configuration.
444264790Sbapt		 */
445264790Sbapt		reason = "no callback";
446264790Sbapt		if (idev->id_config_cb) {
447264790Sbapt			idev->id_config_cb(idev->id_config_arg,
448264790Sbapt					   cfg, 1);
449264790Sbapt			free(cfg, M_TEMP);
450264790Sbapt			return (1);
451264790Sbapt		}
452264790Sbapt	}
453264790Sbapt
454264790Sbapt	/*
455264790Sbapt	 * Disable the device.
456264790Sbapt	 */
457264790Sbapt	bus_print_child_header(device_get_parent(child), child);
458264790Sbapt	printf(" can't assign resources (%s)\n", reason);
459264790Sbapt	if (bootverbose)
460264790Sbapt		isa_print_child(device_get_parent(child), child);
461264790Sbapt	bzero(cfg, sizeof (*cfg));
462264790Sbapt	if (idev->id_config_cb)
463264790Sbapt		idev->id_config_cb(idev->id_config_arg, cfg, 0);
464264790Sbapt	device_disable(child);
465264790Sbapt
466264790Sbapt	free(cfg, M_TEMP);
467264790Sbapt	return (0);
468264790Sbapt}
469264790Sbapt
470264790Sbapt/*
471264790Sbapt * Called after other devices have initialised to probe for isa devices.
472264790Sbapt */
473272955Srodrigcvoid
474264790Sbaptisa_probe_children(device_t dev)
475264790Sbapt{
476264790Sbapt	device_t *children;
477264790Sbapt	struct isa_config *cfg;
478264790Sbapt	int nchildren, i;
479264790Sbapt
480264790Sbapt	/*
481264790Sbapt	 * Create all the children by calling driver's identify methods.
482272955Srodrigc	 */
483264790Sbapt	bus_generic_probe(dev);
484264790Sbapt
485272955Srodrigc	if (device_get_children(dev, &children, &nchildren))
486272955Srodrigc		return;
487264790Sbapt
488264790Sbapt	/*
489264790Sbapt	 * First disable all pnp devices so that they don't get
490264790Sbapt	 * matched by legacy probes.
491264790Sbapt	 */
492264790Sbapt	if (bootverbose)
493264790Sbapt		printf("isa_probe_children: disabling PnP devices\n");
494264790Sbapt
495264790Sbapt	cfg = malloc(sizeof(*cfg), M_TEMP, M_NOWAIT|M_ZERO);
496264790Sbapt	if (cfg == NULL) {
497264790Sbapt		free(children, M_TEMP);
498264790Sbapt		return;
499264790Sbapt	}
500264790Sbapt
501264790Sbapt	for (i = 0; i < nchildren; i++) {
502264790Sbapt		device_t child = children[i];
503264790Sbapt		struct isa_device *idev = DEVTOISA(child);
504264790Sbapt
505264790Sbapt		bzero(cfg, sizeof(*cfg));
506264790Sbapt		if (idev->id_config_cb)
507264790Sbapt			idev->id_config_cb(idev->id_config_arg, cfg, 0);
508264790Sbapt	}
509264790Sbapt
510264790Sbapt	free(cfg, M_TEMP);
511264790Sbapt
512264790Sbapt	/*
513264790Sbapt	 * Next probe all non-pnp devices so that they claim their
514264790Sbapt	 * resources first.
515264790Sbapt	 */
516264790Sbapt	if (bootverbose)
517264790Sbapt		printf("isa_probe_children: probing non-PnP devices\n");
518264790Sbapt	for (i = 0; i < nchildren; i++) {
519264790Sbapt		device_t child = children[i];
520264790Sbapt		struct isa_device *idev = DEVTOISA(child);
521264790Sbapt
522264790Sbapt		if (TAILQ_FIRST(&idev->id_configs))
523264790Sbapt			continue;
524264790Sbapt
525264790Sbapt		device_probe_and_attach(child);
526264790Sbapt	}
527264790Sbapt
528264790Sbapt	/*
529264790Sbapt	 * Finally assign resource to pnp devices and probe them.
530264790Sbapt	 */
531264790Sbapt	if (bootverbose)
532264790Sbapt		printf("isa_probe_children: probing PnP devices\n");
533264790Sbapt	for (i = 0; i < nchildren; i++) {
534264790Sbapt		device_t child = children[i];
535264790Sbapt		struct isa_device* idev = DEVTOISA(child);
536264790Sbapt
537264790Sbapt		if (!TAILQ_FIRST(&idev->id_configs))
538264790Sbapt			continue;
539264790Sbapt
540264790Sbapt		if (isa_assign_resources(child)) {
541264790Sbapt			struct resource_list *rl = &idev->id_resources;
542264790Sbapt			struct resource_list_entry *rle;
543264790Sbapt
544264790Sbapt			device_probe_and_attach(child);
545264790Sbapt
546264790Sbapt			/*
547264790Sbapt			 * Claim any unallocated resources to keep other
548264790Sbapt			 * devices from using them.
549264790Sbapt			 */
550264790Sbapt			STAILQ_FOREACH(rle, rl, link) {
551264790Sbapt				if (!rle->res) {
552264790Sbapt					int rid = rle->rid;
553264790Sbapt					resource_list_alloc(rl, dev, child,
554264790Sbapt							    rle->type,
555264790Sbapt							    &rid,
556264790Sbapt							    0, ~0, 1, 0);
557264790Sbapt				}
558264790Sbapt			}
559264790Sbapt		}
560264790Sbapt	}
561264790Sbapt
562264790Sbapt	free(children, M_TEMP);
563264790Sbapt
564264790Sbapt	isa_running = 1;
565264790Sbapt}
566264790Sbapt
567264790Sbapt/*
568264790Sbapt * Add a new child with default ivars.
569264790Sbapt */
570264790Sbaptstatic device_t
571264790Sbaptisa_add_child(device_t dev, int order, const char *name, int unit)
572264790Sbapt{
573264790Sbapt	device_t child;
574264790Sbapt	struct	isa_device *idev;
575264790Sbapt
576264790Sbapt	child = device_add_child_ordered(dev, order, name, unit);
577264790Sbapt	if (child == NULL)
578264790Sbapt		return (child);
579264790Sbapt
580264790Sbapt	idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT | M_ZERO);
581264790Sbapt	if (!idev)
582264790Sbapt		return (0);
583264790Sbapt
584264790Sbapt	resource_list_init(&idev->id_resources);
585264790Sbapt	TAILQ_INIT(&idev->id_configs);
586264790Sbapt
587264790Sbapt	device_set_ivars(child, idev);
588264790Sbapt
589264790Sbapt	return (child);
590264790Sbapt}
591264790Sbapt
592264790Sbaptstatic int
593264790Sbaptisa_print_all_resources(device_t dev)
594264790Sbapt{
595264790Sbapt	struct	isa_device *idev = DEVTOISA(dev);
596264790Sbapt	struct resource_list *rl = &idev->id_resources;
597264790Sbapt	int retval = 0;
598264790Sbapt
599264790Sbapt	if (STAILQ_FIRST(rl) || device_get_flags(dev))
600264790Sbapt		retval += printf(" at");
601264790Sbapt
602264790Sbapt	retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
603264790Sbapt	retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
604264790Sbapt	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
605264790Sbapt	retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld");
606264790Sbapt	if (device_get_flags(dev))
607264790Sbapt		retval += printf(" flags %#x", device_get_flags(dev));
608264790Sbapt#ifdef ISAPNP
609264790Sbapt	if (idev->id_vendorid)
610264790Sbapt		retval += printf(" pnpid %s", pnp_eisaformat(idev->id_vendorid));
611264790Sbapt#endif
612264790Sbapt
613264790Sbapt	return (retval);
614264790Sbapt}
615264790Sbapt
616264790Sbaptstatic int
617264790Sbaptisa_print_child(device_t bus, device_t dev)
618264790Sbapt{
619264790Sbapt	int retval = 0;
620264790Sbapt
621264790Sbapt	retval += bus_print_child_header(bus, dev);
622264790Sbapt	retval += isa_print_all_resources(dev);
623264790Sbapt	retval += bus_print_child_footer(bus, dev);
624264790Sbapt
625264790Sbapt	return (retval);
626264790Sbapt}
627264790Sbapt
628264790Sbaptstatic void
629264790Sbaptisa_probe_nomatch(device_t dev, device_t child)
630264790Sbapt{
631264790Sbapt	if (bootverbose) {
632264790Sbapt		bus_print_child_header(dev, child);
633264790Sbapt		printf(" failed to probe");
634264790Sbapt		isa_print_all_resources(child);
635264790Sbapt		bus_print_child_footer(dev, child);
636264790Sbapt	}
637264790Sbapt
638264790Sbapt	return;
639264790Sbapt}
640264790Sbapt
641264790Sbaptstatic int
642264790Sbaptisa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
643264790Sbapt{
644264790Sbapt	struct isa_device* idev = DEVTOISA(dev);
645264790Sbapt	struct resource_list *rl = &idev->id_resources;
646264790Sbapt	struct resource_list_entry *rle;
647264790Sbapt
648264790Sbapt	switch (index) {
649264790Sbapt	case ISA_IVAR_PORT_0:
650264790Sbapt		rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
651264790Sbapt		if (rle)
652264790Sbapt			*result = rle->start;
653264790Sbapt		else
654264790Sbapt			*result = -1;
655264790Sbapt		break;
656264790Sbapt
657264790Sbapt	case ISA_IVAR_PORT_1:
658264790Sbapt		rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
659264790Sbapt		if (rle)
660264790Sbapt			*result = rle->start;
661264790Sbapt		else
662264790Sbapt			*result = -1;
663264790Sbapt		break;
664264790Sbapt
665264790Sbapt	case ISA_IVAR_PORTSIZE_0:
666264790Sbapt		rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
667264790Sbapt		if (rle)
668264790Sbapt			*result = rle->count;
669264790Sbapt		else
670264790Sbapt			*result = 0;
671264790Sbapt		break;
672264790Sbapt
673264790Sbapt	case ISA_IVAR_PORTSIZE_1:
674264790Sbapt		rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
675264790Sbapt		if (rle)
676264790Sbapt			*result = rle->count;
677264790Sbapt		else
678264790Sbapt			*result = 0;
679264790Sbapt		break;
680264790Sbapt
681264790Sbapt	case ISA_IVAR_MADDR_0:
682264790Sbapt		rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
683264790Sbapt		if (rle)
684264790Sbapt			*result = rle->start;
685264790Sbapt		else
686264790Sbapt			*result = -1;
687264790Sbapt		break;
688264790Sbapt
689264790Sbapt	case ISA_IVAR_MADDR_1:
690264790Sbapt		rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
691264790Sbapt		if (rle)
692264790Sbapt			*result = rle->start;
693264790Sbapt		else
694264790Sbapt			*result = -1;
695264790Sbapt		break;
696264790Sbapt
697264790Sbapt	case ISA_IVAR_MEMSIZE_0:
698264790Sbapt		rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
699264790Sbapt		if (rle)
700264790Sbapt			*result = rle->count;
701264790Sbapt		else
702264790Sbapt			*result = 0;
703264790Sbapt		break;
704264790Sbapt
705264790Sbapt	case ISA_IVAR_MEMSIZE_1:
706264790Sbapt		rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
707264790Sbapt		if (rle)
708264790Sbapt			*result = rle->count;
709264790Sbapt		else
710264790Sbapt			*result = 0;
711264790Sbapt		break;
712264790Sbapt
713264790Sbapt	case ISA_IVAR_IRQ_0:
714264790Sbapt		rle = resource_list_find(rl, SYS_RES_IRQ, 0);
715264790Sbapt		if (rle)
716264790Sbapt			*result = rle->start;
717264790Sbapt		else
718264790Sbapt			*result = -1;
719264790Sbapt		break;
720272955Srodrigc
721272955Srodrigc	case ISA_IVAR_IRQ_1:
722264790Sbapt		rle = resource_list_find(rl, SYS_RES_IRQ, 1);
723264790Sbapt		if (rle)
724264790Sbapt			*result = rle->start;
725264790Sbapt		else
726264790Sbapt			*result = -1;
727264790Sbapt		break;
728264790Sbapt
729264790Sbapt	case ISA_IVAR_DRQ_0:
730264790Sbapt		rle = resource_list_find(rl, SYS_RES_DRQ, 0);
731264790Sbapt		if (rle)
732264790Sbapt			*result = rle->start;
733264790Sbapt		else
734264790Sbapt			*result = -1;
735264790Sbapt		break;
736264790Sbapt
737264790Sbapt	case ISA_IVAR_DRQ_1:
738264790Sbapt		rle = resource_list_find(rl, SYS_RES_DRQ, 1);
739264790Sbapt		if (rle)
740264790Sbapt			*result = rle->start;
741264790Sbapt		else
742264790Sbapt			*result = -1;
743264790Sbapt		break;
744264790Sbapt
745264790Sbapt	case ISA_IVAR_VENDORID:
746264790Sbapt		*result = idev->id_vendorid;
747264790Sbapt		break;
748264790Sbapt
749264790Sbapt	case ISA_IVAR_SERIAL:
750264790Sbapt		*result = idev->id_serial;
751264790Sbapt		break;
752264790Sbapt
753264790Sbapt	case ISA_IVAR_LOGICALID:
754264790Sbapt		*result = idev->id_logicalid;
755264790Sbapt		break;
756264790Sbapt
757264790Sbapt	case ISA_IVAR_COMPATID:
758264790Sbapt		*result = idev->id_compatid;
759264790Sbapt		break;
760264790Sbapt
761264790Sbapt	case ISA_IVAR_CONFIGATTR:
762264790Sbapt		*result = idev->id_config_attr;
763264790Sbapt		break;
764264790Sbapt
765264790Sbapt	default:
766264790Sbapt		return (ENOENT);
767264790Sbapt	}
768264790Sbapt
769264790Sbapt	return (0);
770264790Sbapt}
771264790Sbapt
772264790Sbaptstatic int
773264790Sbaptisa_write_ivar(device_t bus, device_t dev, int index, uintptr_t value)
774264790Sbapt{
775264790Sbapt	struct isa_device* idev = DEVTOISA(dev);
776264790Sbapt
777264790Sbapt	switch (index) {
778264790Sbapt	case ISA_IVAR_PORT_0:
779264790Sbapt	case ISA_IVAR_PORT_1:
780264790Sbapt	case ISA_IVAR_PORTSIZE_0:
781264790Sbapt	case ISA_IVAR_PORTSIZE_1:
782264790Sbapt	case ISA_IVAR_MADDR_0:
783264790Sbapt	case ISA_IVAR_MADDR_1:
784264790Sbapt	case ISA_IVAR_MEMSIZE_0:
785264790Sbapt	case ISA_IVAR_MEMSIZE_1:
786264790Sbapt	case ISA_IVAR_IRQ_0:
787264790Sbapt	case ISA_IVAR_IRQ_1:
788264790Sbapt	case ISA_IVAR_DRQ_0:
789264790Sbapt	case ISA_IVAR_DRQ_1:
790264790Sbapt		return (EINVAL);
791264790Sbapt
792264790Sbapt	case ISA_IVAR_VENDORID:
793264790Sbapt		idev->id_vendorid = value;
794264790Sbapt		break;
795264790Sbapt
796264790Sbapt	case ISA_IVAR_SERIAL:
797264790Sbapt		idev->id_serial = value;
798264790Sbapt		break;
799264790Sbapt
800264790Sbapt	case ISA_IVAR_LOGICALID:
801264790Sbapt		idev->id_logicalid = value;
802264790Sbapt		break;
803264790Sbapt
804264790Sbapt	case ISA_IVAR_COMPATID:
805264790Sbapt		idev->id_compatid = value;
806264790Sbapt		break;
807264790Sbapt
808264790Sbapt	case ISA_IVAR_CONFIGATTR:
809264790Sbapt		idev->id_config_attr = value;
810264790Sbapt		break;
811264790Sbapt
812264790Sbapt	default:
813264790Sbapt		return (ENOENT);
814264790Sbapt	}
815264790Sbapt
816264790Sbapt	return (0);
817272955Srodrigc}
818264790Sbapt
819272955Srodrigc/*
820264790Sbapt * Free any resources which the driver missed or which we were holding for
821264790Sbapt * it (see isa_probe_children).
822272955Srodrigc */
823264790Sbaptstatic void
824264790Sbaptisa_child_detached(device_t dev, device_t child)
825264790Sbapt{
826264790Sbapt	struct isa_device* idev = DEVTOISA(child);
827264790Sbapt	struct resource_list *rl = &idev->id_resources;
828264790Sbapt	struct resource_list_entry *rle;
829264790Sbapt
830264790Sbapt	if (TAILQ_FIRST(&idev->id_configs)) {
831264790Sbapt		/*
832264790Sbapt		 * Claim any unallocated resources to keep other
833264790Sbapt		 * devices from using them.
834264790Sbapt		 */
835264790Sbapt		STAILQ_FOREACH(rle, rl, link) {
836264790Sbapt			if (!rle->res) {
837264790Sbapt				int rid = rle->rid;
838264790Sbapt				resource_list_alloc(rl, dev, child,
839264790Sbapt						    rle->type,
840264790Sbapt						    &rid, 0, ~0, 1, 0);
841264790Sbapt			}
842264790Sbapt		}
843264790Sbapt	}
844264790Sbapt}
845264790Sbapt
846264790Sbaptstatic void
847264790Sbaptisa_driver_added(device_t dev, driver_t *driver)
848264790Sbapt{
849264790Sbapt	device_t *children;
850264790Sbapt	int nchildren, i;
851264790Sbapt
852264790Sbapt	/*
853264790Sbapt	 * Don't do anything if drivers are dynamically
854264790Sbapt	 * added during autoconfiguration (cf. ymf724).
855264790Sbapt	 * since that would end up calling identify
856264790Sbapt	 * twice.
857264790Sbapt	 */
858264790Sbapt	if (!isa_running)
859264790Sbapt		return;
860264790Sbapt
861264790Sbapt	DEVICE_IDENTIFY(driver, dev);
862264790Sbapt	if (device_get_children(dev, &children, &nchildren))
863264790Sbapt		return;
864264790Sbapt
865264790Sbapt	for (i = 0; i < nchildren; i++) {
866264790Sbapt		device_t child = children[i];
867264790Sbapt		struct isa_device *idev = DEVTOISA(child);
868264790Sbapt		struct resource_list *rl = &idev->id_resources;
869264790Sbapt		struct resource_list_entry *rle;
870264790Sbapt
871264790Sbapt		if (device_get_state(child) != DS_NOTPRESENT)
872264790Sbapt			continue;
873264790Sbapt		if (!device_is_enabled(child))
874264790Sbapt			continue;
875264790Sbapt
876264790Sbapt		/*
877272955Srodrigc		 * Free resources which we were holding on behalf of
878264790Sbapt		 * the device.
879264790Sbapt		 */
880264790Sbapt		STAILQ_FOREACH(rle, &idev->id_resources, link) {
881264790Sbapt			if (rle->res)
882264790Sbapt				resource_list_release(rl, dev, child,
883264790Sbapt						      rle->type,
884264790Sbapt						      rle->rid,
885264790Sbapt						      rle->res);
886264790Sbapt		}
887264790Sbapt
888264790Sbapt		if (TAILQ_FIRST(&idev->id_configs))
889264790Sbapt			if (!isa_assign_resources(child))
890264790Sbapt				continue;
891264790Sbapt
892264790Sbapt		device_probe_and_attach(child);
893264790Sbapt
894264790Sbapt		if (TAILQ_FIRST(&idev->id_configs)) {
895264790Sbapt			/*
896264790Sbapt			 * Claim any unallocated resources to keep other
897264790Sbapt			 * devices from using them.
898264790Sbapt			 */
899264790Sbapt			STAILQ_FOREACH(rle, rl, link) {
900264790Sbapt				if (!rle->res) {
901264790Sbapt					int rid = rle->rid;
902264790Sbapt					resource_list_alloc(rl, dev, child,
903264790Sbapt							    rle->type,
904264790Sbapt							    &rid, 0, ~0, 1, 0);
905264790Sbapt				}
906264790Sbapt			}
907264790Sbapt		}
908264790Sbapt	}
909264790Sbapt
910264790Sbapt	free(children, M_TEMP);
911264790Sbapt}
912264790Sbapt
913264790Sbaptstatic int
914264790Sbaptisa_set_resource(device_t dev, device_t child, int type, int rid,
915264790Sbapt    u_long start, u_long count)
916264790Sbapt{
917264790Sbapt	struct isa_device* idev = DEVTOISA(child);
918264790Sbapt	struct resource_list *rl = &idev->id_resources;
919264790Sbapt
920264790Sbapt	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
921264790Sbapt	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
922264790Sbapt		return (EINVAL);
923264790Sbapt	if (rid < 0)
924264790Sbapt		return (EINVAL);
925264790Sbapt	if (type == SYS_RES_IOPORT && rid >= ISA_NPORT)
926264790Sbapt		return (EINVAL);
927264790Sbapt	if (type == SYS_RES_MEMORY && rid >= ISA_NMEM)
928264790Sbapt		return (EINVAL);
929264790Sbapt	if (type == SYS_RES_IRQ && rid >= ISA_NIRQ)
930264790Sbapt		return (EINVAL);
931264790Sbapt	if (type == SYS_RES_DRQ && rid >= ISA_NDRQ)
932264790Sbapt		return (EINVAL);
933264790Sbapt
934264790Sbapt	resource_list_add(rl, type, rid, start, start + count - 1, count);
935264790Sbapt
936264790Sbapt	return (0);
937264790Sbapt}
938264790Sbapt
939264790Sbaptstatic struct resource_list *
940264790Sbaptisa_get_resource_list (device_t dev, device_t child)
941264790Sbapt{
942264790Sbapt	struct isa_device* idev = DEVTOISA(child);
943264790Sbapt	struct resource_list *rl = &idev->id_resources;
944264790Sbapt
945264790Sbapt	if (!rl)
946264790Sbapt		return (NULL);
947264790Sbapt
948264790Sbapt	return (rl);
949264790Sbapt}
950264790Sbapt
951264790Sbaptstatic int
952264790Sbaptisa_add_config(device_t dev, device_t child, int priority,
953264790Sbapt    struct isa_config *config)
954264790Sbapt{
955264790Sbapt	struct isa_device* idev = DEVTOISA(child);
956264790Sbapt	struct isa_config_entry *newice, *ice;
957264790Sbapt
958264790Sbapt	newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT);
959264790Sbapt	if (!newice)
960264790Sbapt		return (ENOMEM);
961264790Sbapt
962264790Sbapt	newice->ice_priority = priority;
963264790Sbapt	newice->ice_config = *config;
964264790Sbapt
965264790Sbapt	TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
966264790Sbapt		if (ice->ice_priority > priority)
967264790Sbapt			break;
968264790Sbapt	}
969264790Sbapt	if (ice)
970264790Sbapt		TAILQ_INSERT_BEFORE(ice, newice, ice_link);
971272955Srodrigc	else
972264790Sbapt		TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link);
973272955Srodrigc
974264790Sbapt	return (0);
975264790Sbapt}
976272955Srodrigc
977264790Sbaptstatic void
978272955Srodrigcisa_set_config_callback(device_t dev, device_t child, isa_config_cb *fn,
979264790Sbapt    void *arg)
980264790Sbapt{
981264790Sbapt	struct isa_device* idev = DEVTOISA(child);
982264790Sbapt
983264790Sbapt	idev->id_config_cb = fn;
984264790Sbapt	idev->id_config_arg = arg;
985264790Sbapt}
986264790Sbapt
987272955Srodrigcstatic int
988264790Sbaptisa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids)
989272955Srodrigc{
990264790Sbapt	struct isa_device* idev = DEVTOISA(child);
991264790Sbapt
992272955Srodrigc	if (!idev->id_vendorid)
993264790Sbapt		return (ENOENT);
994264790Sbapt
995264790Sbapt	while (ids && ids->ip_id) {
996264790Sbapt		/*
997264790Sbapt		 * Really ought to support >1 compat id per device.
998264790Sbapt		 */
999264790Sbapt		if (idev->id_logicalid == ids->ip_id
1000264790Sbapt		    || idev->id_compatid == ids->ip_id) {
1001264790Sbapt			if (ids->ip_desc)
1002264790Sbapt				device_set_desc(child, ids->ip_desc);
1003264790Sbapt			return (0);
1004264790Sbapt		}
1005264790Sbapt		ids++;
1006264790Sbapt	}
1007264790Sbapt
1008264790Sbapt	return (ENXIO);
1009264790Sbapt}
1010264790Sbapt
1011264790Sbaptstatic int
1012264790Sbaptisa_child_pnpinfo_str(device_t bus, device_t child, char *buf,
1013264790Sbapt    size_t buflen)
1014264790Sbapt{
1015264790Sbapt#ifdef ISAPNP
1016264790Sbapt	struct isa_device *idev = DEVTOISA(child);
1017264790Sbapt
1018264790Sbapt	if (idev->id_vendorid)
1019264790Sbapt		snprintf(buf, buflen, "pnpid=%s",
1020264790Sbapt		    pnp_eisaformat(idev->id_vendorid));
1021264790Sbapt#endif
1022272955Srodrigc	return (0);
1023264790Sbapt}
1024272955Srodrigc
1025264790Sbaptstatic int
1026264790Sbaptisa_child_location_str(device_t bus, device_t child, char *buf,
1027272955Srodrigc    size_t buflen)
1028264790Sbapt{
1029264790Sbapt	/* Nothing here yet */
1030264790Sbapt	*buf = '\0';
1031264790Sbapt	return (0);
1032264790Sbapt}
1033264790Sbapt
1034264790Sbaptstatic device_method_t isa_methods[] = {
1035264790Sbapt	/* Device interface */
1036264790Sbapt	DEVMETHOD(device_probe,		isa_probe),
1037264790Sbapt	DEVMETHOD(device_attach,	isa_attach),
1038264790Sbapt	DEVMETHOD(device_detach,	bus_generic_detach),
1039264790Sbapt	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
1040264790Sbapt	DEVMETHOD(device_suspend,	bus_generic_suspend),
1041264790Sbapt	DEVMETHOD(device_resume,	bus_generic_resume),
1042264790Sbapt
1043264790Sbapt	/* Bus interface */
1044264790Sbapt	DEVMETHOD(bus_add_child,	isa_add_child),
1045264790Sbapt	DEVMETHOD(bus_print_child,	isa_print_child),
1046264790Sbapt	DEVMETHOD(bus_probe_nomatch,	isa_probe_nomatch),
1047264790Sbapt	DEVMETHOD(bus_read_ivar,	isa_read_ivar),
1048264790Sbapt	DEVMETHOD(bus_write_ivar,	isa_write_ivar),
1049264790Sbapt	DEVMETHOD(bus_child_detached,	isa_child_detached),
1050264790Sbapt	DEVMETHOD(bus_driver_added,	isa_driver_added),
1051264790Sbapt	DEVMETHOD(bus_setup_intr,	isa_setup_intr),
1052264790Sbapt	DEVMETHOD(bus_teardown_intr,	isa_teardown_intr),
1053264790Sbapt
1054264790Sbapt	DEVMETHOD(bus_get_resource_list,isa_get_resource_list),
1055264790Sbapt	DEVMETHOD(bus_alloc_resource,	isa_alloc_resource),
1056264790Sbapt	DEVMETHOD(bus_release_resource,	isa_release_resource),
1057264790Sbapt	DEVMETHOD(bus_set_resource,	isa_set_resource),
1058264790Sbapt	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
1059264790Sbapt	DEVMETHOD(bus_delete_resource,	bus_generic_rl_delete_resource),
1060264790Sbapt	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
1061264790Sbapt	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
1062264790Sbapt	DEVMETHOD(bus_child_pnpinfo_str, isa_child_pnpinfo_str),
1063264790Sbapt	DEVMETHOD(bus_child_location_str, isa_child_location_str),
1064264790Sbapt
1065264790Sbapt	/* ISA interface */
1066264790Sbapt	DEVMETHOD(isa_add_config,	isa_add_config),
1067264790Sbapt	DEVMETHOD(isa_set_config_callback, isa_set_config_callback),
1068264790Sbapt	DEVMETHOD(isa_pnp_probe,	isa_pnp_probe),
1069264790Sbapt
1070264790Sbapt	{ 0, 0 }
1071264790Sbapt};
1072264790Sbapt
1073264790Sbaptdriver_t isa_driver = {
1074264790Sbapt	"isa",
1075264790Sbapt	isa_methods,
1076264790Sbapt	1,			/* no softc */
1077264790Sbapt};
1078264790Sbapt
1079264790Sbaptdevclass_t isa_devclass;
1080264790Sbapt
1081264790Sbapt/*
1082264790Sbapt * ISA can be attached to a PCI-ISA bridge, or other locations on some
1083264790Sbapt * platforms.
1084264790Sbapt */
1085264790SbaptDRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0);
1086264790SbaptDRIVER_MODULE(isa, eisab, isa_driver, isa_devclass, 0, 0);
1087264790SbaptMODULE_VERSION(isa, 1);
1088264790Sbapt
1089264790Sbapt/*
1090264790Sbapt * Code common to ISA bridges.
1091264790Sbapt */
1092264790Sbapt
1093264790Sbaptdevclass_t isab_devclass;
1094264790Sbapt
1095264790Sbaptint
1096264790Sbaptisab_attach(device_t dev)
1097264790Sbapt{
1098264790Sbapt	device_t child;
1099264790Sbapt
1100264790Sbapt	child = device_add_child(dev, "isa", 0);
1101264790Sbapt	if (child != NULL)
1102264790Sbapt		return (bus_generic_attach(dev));
1103264790Sbapt	return (ENXIO);
1104264790Sbapt}
1105264790Sbapt