isa.c revision 45720
171SN/A/*-
2551SN/A * Copyright (c) 1998 Doug Rabson
371SN/A * All rights reserved.
471SN/A *
571SN/A * Redistribution and use in source and binary forms, with or without
671SN/A * modification, are permitted provided that the following conditions
7157SN/A * are met:
871SN/A * 1. Redistributions of source code must retain the above copyright
9157SN/A *    notice, this list of conditions and the following disclaimer.
1071SN/A * 2. Redistributions in binary form must reproduce the above copyright
1171SN/A *    notice, this list of conditions and the following disclaimer in the
1271SN/A *    documentation and/or other materials provided with the distribution.
1371SN/A *
1471SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1571SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1671SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1771SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1871SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1971SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2071SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21157SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22157SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23157SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2471SN/A * SUCH DAMAGE.
2571SN/A *
260SN/A *	$Id: isa.c,v 1.4 1998/09/16 08:23:51 dfr Exp $
270SN/A */
280SN/A
290SN/A/*
300SN/A * Modifications for Intel architecture by Garrett A. Wollman.
310SN/A * Copyright 1998 Massachusetts Institute of Technology
320SN/A *
330SN/A * Permission to use, copy, modify, and distribute this software and
340SN/A * its documentation for any purpose and without fee is hereby
350SN/A * granted, provided that both the above copyright notice and this
360SN/A * permission notice appear in all copies, that both the above
370SN/A * copyright notice and this permission notice appear in all
380SN/A * supporting documentation, and that the name of M.I.T. not be used
390SN/A * in advertising or publicity pertaining to distribution of the
400SN/A * software without specific, written prior permission.  M.I.T. makes
410SN/A * no representations about the suitability of this software for any
420SN/A * purpose.  It is provided "as is" without express or implied
430SN/A * warranty.
440SN/A *
450SN/A * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
460SN/A * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
470SN/A * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
480SN/A * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
490SN/A * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
500SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
510SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
520SN/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
530SN/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
540SN/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
550SN/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
560SN/A * SUCH DAMAGE.
570SN/A */
580SN/A
590SN/A#include <sys/param.h>
600SN/A#include <sys/systm.h>
610SN/A#include <sys/kernel.h>
620SN/A#include <sys/bus.h>
630SN/A#include <sys/malloc.h>
640SN/A#include <sys/module.h>
650SN/A#include <machine/bus.h>
660SN/A#include <sys/rman.h>
67263SN/A
68263SN/A#include <machine/resource.h>
69263SN/A
70263SN/A#include <isa/isavar.h>
71452SN/A
72263SN/AMALLOC_DEFINE(M_ISADEV, "isadev", "ISA device");
73263SN/A
74263SN/A/*
75263SN/A * The structure used to attach devices to the isa bus.
76263SN/A */
77263SN/Astruct isa_device {
78263SN/A	short		id_port[ISA_NPORT_IVARS];
79263SN/A	u_short		id_portsize[ISA_NPORT_IVARS];
80263SN/A	vm_offset_t	id_maddr[ISA_NMEM_IVARS];
81263SN/A	vm_size_t	id_msize[ISA_NMEM_IVARS];
82263SN/A	int		id_irq[ISA_NIRQ_IVARS];
83263SN/A	int		id_drq[ISA_NDRQ_IVARS];
84263SN/A	int		id_flags;
85263SN/A	struct resource	*id_portres[ISA_NPORT_IVARS];
86263SN/A	struct resource	*id_memres[ISA_NMEM_IVARS];
87263SN/A	struct resource	*id_irqres[ISA_NIRQ_IVARS];
88263SN/A	struct resource	*id_drqres[ISA_NDRQ_IVARS];
89263SN/A};
90263SN/A
91263SN/A#define DEVTOISA(dev)	((struct isa_device *) device_get_ivars(dev))
92263SN/A
93263SN/Astatic devclass_t isa_devclass;
94263SN/A
95263SN/Astatic void
96263SN/Aisa_add_device(device_t dev, const char *name, int unit)
97263SN/A{
98263SN/A	struct	isa_device *idev;
99263SN/A	device_t	child;
100263SN/A	int		sensitive, t;
101263SN/A	static	device_t last_sensitive;
102263SN/A
103263SN/A	if (resource_int_value(name, unit, "sensitive", &sensitive) != 0)
104263SN/A		sensitive = 0;
105263SN/A
106263SN/A	idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT);
107263SN/A	if (!idev)
108263SN/A		return;
109263SN/A	bzero(idev, sizeof *idev);
110263SN/A
111263SN/A	if (resource_int_value(name, unit, "port", &t) == 0)
112263SN/A		idev->id_port[0] = t;
113561SN/A	else
114263SN/A		idev->id_port[0] = -1;
115263SN/A	idev->id_port[1] = 0;
116263SN/A
117452SN/A	if (resource_int_value(name, unit, "portsize", &t) == 0)
118263SN/A		idev->id_portsize[0] = t;
119263SN/A	else
120263SN/A		idev->id_portsize[0] = 0;
121263SN/A	idev->id_portsize[1] = 0;
122263SN/A
123263SN/A	if (resource_int_value(name, unit, "maddr", &t) == 0)
124263SN/A		idev->id_maddr[0] = t;
125263SN/A	else
126263SN/A		idev->id_maddr[0] = 0;
127263SN/A	idev->id_maddr[1] = 0;
128263SN/A
129263SN/A	if (resource_int_value(name, unit, "msize", &t) == 0)
130263SN/A		idev->id_msize[0] = t;
131263SN/A	else
132263SN/A		idev->id_msize[0] = 0;
133263SN/A	idev->id_msize[1] = 0;
134263SN/A
135263SN/A	if (resource_int_value(name, unit, "flags", &t) == 0)
136263SN/A		idev->id_flags = t;
137263SN/A	else
138263SN/A		idev->id_flags = 0;
139263SN/A
140263SN/A	if (resource_int_value(name, unit, "irq", &t) == 0)
141263SN/A		idev->id_irq[0] = t;
142263SN/A	else
143263SN/A		idev->id_irq[0] = -1;
144263SN/A	idev->id_irq[1] = -1;
145263SN/A
146263SN/A	if (resource_int_value(name, unit, "drq", &t) == 0)
147263SN/A		idev->id_drq[0] = t;
148263SN/A	else
149452SN/A		idev->id_drq[0] = -1;
150263SN/A	idev->id_drq[1] = -1;
151263SN/A
152263SN/A	if (sensitive)
153263SN/A		child = device_add_child_after(dev, last_sensitive, name,
154263SN/A					       unit, idev);
155263SN/A	else
156263SN/A		child = device_add_child(dev, name, unit, idev);
157263SN/A	if (child == 0)
1580SN/A		return;
1590SN/A	else if (sensitive)
1600SN/A		last_sensitive = child;
1610SN/A
1620SN/A	if (resource_int_value(name, unit, "disabled", &t) == 0 && t != 0)
1630SN/A		device_disable(child);
1640SN/A}
1650SN/A
1660SN/A/*
167263SN/A * At 'probe' time, we add all the devices which we know about to the
168263SN/A * bus.  The generic attach routine will probe and attach them if they
169263SN/A * are alive.
170263SN/A */
1710SN/Astatic int
1720SN/Aisa_probe(device_t dev)
1730SN/A{
1740SN/A	int i;
1750SN/A	static char buf[] = "isaXXX";
176452SN/A
1770SN/A	device_set_desc(dev, "ISA bus");
178
179	/*
180	 * Add all devices configured to be attached to isa0.
181	 */
182	sprintf(buf, "isa%d", device_get_unit(dev));
183	for (i = resource_query_string(-1, "at", buf);
184	     i != -1;
185	     i = resource_query_string(i, "at", buf)) {
186		isa_add_device(dev, resource_query_name(i),
187			       resource_query_unit(i));
188	}
189
190	/*
191	 * and isa?
192	 */
193	for (i = resource_query_string(-1, "at", "isa");
194	     i != -1;
195	     i = resource_query_string(i, "at", "isa")) {
196		isa_add_device(dev, resource_query_name(i),
197			       resource_query_unit(i));
198	}
199
200	isa_wrap_old_drivers();
201
202	return 0;
203}
204
205extern device_t isa_bus_device;
206
207static int
208isa_attach(device_t dev)
209{
210	/*
211	 * Arrange for bus_generic_attach(dev) to be called later.
212	 */
213	isa_bus_device = dev;
214	return 0;
215}
216
217static void
218isa_print_child(device_t bus, device_t dev)
219{
220	struct	isa_device *id = DEVTOISA(dev);
221
222	if (id->id_port[0] > 0 || id->id_port[1] > 0
223	    || id->id_maddr[0] > 0 || id->id_maddr[1] > 0
224	    || id->id_irq[0] >= 0 || id->id_irq[1] >= 0
225	    || id->id_drq[0] >= 0 || id->id_drq[1] >= 0)
226		printf(" at");
227	if (id->id_port[0] > 0 && id->id_port[1] > 0) {
228		printf(" ports %#x", (u_int)id->id_port[0]);
229		if (id->id_portsize[0] > 1)
230			printf("-%#x", (u_int)(id->id_port[0]
231					       + id->id_portsize[0] - 1));
232		printf(" and %#x", (u_int)id->id_port[1]);
233		if (id->id_portsize[1] > 1)
234			printf("-%#x", (u_int)(id->id_port[1]
235					       + id->id_portsize[1] - 1));
236	} else if (id->id_port[0] > 0) {
237		printf(" port %#x", (u_int)id->id_port[0]);
238		if (id->id_portsize[0] > 1)
239			printf("-%#x", (u_int)(id->id_port[0]
240					       + id->id_portsize[0] - 1));
241	} else if (id->id_port[1] > 0) {
242		printf(" port %#x", (u_int)id->id_port[1]);
243		if (id->id_portsize[1] > 1)
244			printf("-%#x", (u_int)(id->id_port[1]
245					       + id->id_portsize[1] - 1));
246	}
247	if (id->id_maddr[0] && id->id_maddr[1]) {
248		printf(" iomem %#x", (u_int)id->id_maddr[0]);
249		if (id->id_msize[0])
250			printf("-%#x", (u_int)(id->id_maddr[0]
251					       + id->id_msize[0] - 1));
252		printf(" and %#x", (u_int)id->id_maddr[1]);
253		if (id->id_msize[1])
254			printf("-%#x", (u_int)(id->id_maddr[1]
255					       + id->id_msize[1] - 1));
256	} else if (id->id_maddr[0]) {
257		printf(" iomem %#x", (u_int)id->id_maddr[0]);
258		if (id->id_msize[0])
259			printf("-%#x", (u_int)(id->id_maddr[0]
260					       + id->id_msize[0] - 1));
261	} else if (id->id_maddr[1]) {
262		printf(" iomem %#x", (u_int)id->id_maddr[1]);
263		if (id->id_msize[1])
264			printf("-%#x", (u_int)(id->id_maddr[1]
265					       + id->id_msize[1] - 1));
266	}
267	if (id->id_irq[0] >= 0 && id->id_irq[1] >= 0)
268		printf(" irqs %d and %d", id->id_irq[0], id->id_irq[1]);
269	else if (id->id_irq[0] >= 0)
270		printf(" irq %d", id->id_irq[0]);
271	else if (id->id_irq[1] >= 0)
272		printf(" irq %d", id->id_irq[1]);
273	if (id->id_drq[0] >= 0 && id->id_drq[1] >= 0)
274		printf(" drqs %d and %d", id->id_drq[0], id->id_drq[1]);
275	else if (id->id_drq[0] >= 0)
276		printf(" drq %d", id->id_drq[0]);
277	else if (id->id_drq[1] >= 0)
278		printf(" drq %d", id->id_drq[1]);
279
280	if (id->id_flags)
281		printf(" flags %#x", id->id_flags);
282
283	printf(" on %s%d",
284	       device_get_name(bus), device_get_unit(bus));
285}
286
287static int
288isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
289{
290	struct isa_device* idev = DEVTOISA(dev);
291
292	switch (index) {
293	case ISA_IVAR_PORT_0:
294		*result = idev->id_port[0];
295		break;
296	case ISA_IVAR_PORT_1:
297		*result = idev->id_port[1];
298		break;
299	case ISA_IVAR_PORTSIZE_0:
300		*result = idev->id_portsize[0];
301		break;
302	case ISA_IVAR_PORTSIZE_1:
303		*result = idev->id_portsize[1];
304		break;
305	case ISA_IVAR_MADDR_0:
306		*result = idev->id_maddr[0];
307		break;
308	case ISA_IVAR_MADDR_1:
309		*result = idev->id_maddr[1];
310		break;
311	case ISA_IVAR_MSIZE_0:
312		*result = idev->id_msize[0];
313		break;
314	case ISA_IVAR_MSIZE_1:
315		*result = idev->id_msize[1];
316		break;
317	case ISA_IVAR_IRQ_0:
318		*result = idev->id_irq[0];
319		break;
320	case ISA_IVAR_IRQ_1:
321		*result = idev->id_irq[1];
322		break;
323	case ISA_IVAR_DRQ_0:
324		*result = idev->id_drq[0];
325		break;
326	case ISA_IVAR_DRQ_1:
327		*result = idev->id_drq[1];
328		break;
329	case ISA_IVAR_FLAGS:
330		*result = idev->id_flags;
331		break;
332	}
333	return ENOENT;
334}
335
336/*
337 * XXX -- this interface is pretty much irrelevant in the presence of
338 * BUS_ALLOC_RESOURCE / BUS_RELEASE_RESOURCE (at least for the ivars which
339 * are defined at this point).
340 */
341static int
342isa_write_ivar(device_t bus, device_t dev,
343	       int index, uintptr_t value)
344{
345	struct isa_device* idev = DEVTOISA(dev);
346
347	switch (index) {
348	case ISA_IVAR_PORT_0:
349		idev->id_port[0] = value;
350		break;
351	case ISA_IVAR_PORT_1:
352		idev->id_port[1] = value;
353		break;
354	case ISA_IVAR_PORTSIZE_0:
355		idev->id_portsize[0] = value;
356		break;
357	case ISA_IVAR_PORTSIZE_1:
358		idev->id_portsize[1] = value;
359		break;
360	case ISA_IVAR_MADDR_0:
361		idev->id_maddr[0] = value;
362		break;
363	case ISA_IVAR_MADDR_1:
364		idev->id_maddr[1] = value;
365		break;
366	case ISA_IVAR_MSIZE_0:
367		idev->id_msize[0] = value;
368		break;
369	case ISA_IVAR_MSIZE_1:
370		idev->id_msize[1] = value;
371		break;
372	case ISA_IVAR_IRQ_0:
373		idev->id_irq[0] = value;
374		break;
375	case ISA_IVAR_IRQ_1:
376		idev->id_irq[1] = value;
377		break;
378	case ISA_IVAR_DRQ_0:
379		idev->id_drq[0] = value;
380		break;
381	case ISA_IVAR_DRQ_1:
382		idev->id_drq[1] = value;
383		break;
384	case ISA_IVAR_FLAGS:
385		idev->id_flags = value;
386		break;
387	default:
388		return (ENOENT);
389	}
390	return (0);
391}
392
393/*
394 * This implementation simply passes the request up to the parent
395 * bus, which in our case is the special i386 nexus, substituting any
396 * configured values if the caller defaulted.  We can get away with
397 * this because there is no special mapping for ISA resources on an Intel
398 * platform.  When porting this code to another architecture, it may be
399 * necessary to interpose a mapping layer here.
400 */
401static struct resource *
402isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
403		   u_long start, u_long end, u_long count, u_int flags)
404{
405	int	isdefault;
406	struct	resource *rv, **rvp = 0;
407	struct	isa_device *id = DEVTOISA(child);
408
409	if (child) {
410		/*
411		 * If this is our child, then use the isa_device to find
412		 * defaults and to record results.
413		 */
414		if (device_get_devclass(device_get_parent(child)) == isa_devclass)
415			id = DEVTOISA(child);
416		else
417			id = NULL;
418	} else
419		id = NULL;
420	isdefault = (id != NULL && start == 0UL && end == ~0UL && *rid == 0);
421	if (*rid > 1)
422		return 0;
423
424	switch (type) {
425	case SYS_RES_IRQ:
426		if (isdefault && id->id_irq[0] >= 0) {
427			start = id->id_irq[0];
428			end = id->id_irq[0];
429			count = 1;
430		}
431		if (id)
432			rvp = &id->id_irqres[*rid];
433		break;
434
435	case SYS_RES_DRQ:
436		if (isdefault && id->id_drq[0] >= 0) {
437			start = id->id_drq[0];
438			end = id->id_drq[0];
439			count = 1;
440		}
441		if (id)
442			rvp = &id->id_drqres[*rid];
443		break;
444
445	case SYS_RES_MEMORY:
446		if (isdefault && id->id_maddr[0]) {
447			start = id->id_maddr[0];
448			count = max(count, (u_long)id->id_msize[0]);
449			end = id->id_maddr[0] + count;
450		}
451		if (id)
452			rvp = &id->id_memres[*rid];
453		break;
454
455	case SYS_RES_IOPORT:
456		if (isdefault && id->id_port[0]) {
457			start = id->id_port[0];
458			count = max(count, (u_long)id->id_portsize[0]);
459			end = id->id_port[0] + count;
460		}
461		if (id)
462			rvp = &id->id_portres[*rid];
463		break;
464
465	default:
466		return 0;
467	}
468
469	/*
470	 * If the client attempts to reallocate a resource without
471	 * releasing what was there previously, die horribly so that
472	 * he knows how he !@#$ed up.
473	 */
474	if (rvp && *rvp != 0)
475		panic("%s%d: (%d, %d) not free for %s%d\n",
476		      device_get_name(bus), device_get_unit(bus),
477		      type, *rid,
478		      device_get_name(child), device_get_unit(child));
479
480	/*
481	 * nexus_alloc_resource had better not change *rid...
482	 */
483	rv = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
484				start, end, count, flags);
485	if (rvp && (*rvp = rv) != 0) {
486		switch (type) {
487		case SYS_RES_MEMORY:
488			id->id_maddr[*rid] = rv->r_start;
489			id->id_msize[*rid] = count;
490			break;
491		case SYS_RES_IOPORT:
492			id->id_port[*rid] = rv->r_start;
493			id->id_portsize[*rid] = count;
494			break;
495		case SYS_RES_IRQ:
496			id->id_irq[*rid] = rv->r_start;
497			break;
498		case SYS_RES_DRQ:
499			id->id_drq[*rid] = rv->r_start;
500			break;
501		}
502	}
503	return rv;
504}
505
506static int
507isa_release_resource(device_t bus, device_t child, int type, int rid,
508		     struct resource *r)
509{
510	int	rv;
511	struct	isa_device *id = DEVTOISA(child);
512
513	if (rid > 1)
514		return EINVAL;
515
516	switch (type) {
517	case SYS_RES_IRQ:
518	case SYS_RES_DRQ:
519	case SYS_RES_IOPORT:
520	case SYS_RES_MEMORY:
521		break;
522	default:
523		return (ENOENT);
524	}
525
526	rv = BUS_RELEASE_RESOURCE(device_get_parent(bus), child, type, rid, r);
527
528#if 0
529	if (rv) {
530		/* Kludge, isa as a child of pci doesn't have mapping regs */
531		printf("WARNING: isa_release_resource: BUS_RELEASE_RESOURCE() failed: %d\n", rv);
532		rv = 0;
533	}
534#endif
535
536	if (rv == 0) {
537		switch (type) {
538		case SYS_RES_IRQ:
539			id->id_irqres[rid] = 0;
540			id->id_irq[rid] = -1;
541			break;
542
543		case SYS_RES_DRQ:
544			id->id_drqres[rid] = 0;
545			id->id_drq[rid] = -1;
546			break;
547
548		case SYS_RES_MEMORY:
549			id->id_memres[rid] = 0;
550			id->id_maddr[rid] = 0;
551			id->id_msize[rid] = 0;
552			break;
553
554		case SYS_RES_IOPORT:
555			id->id_portres[rid] = 0;
556			id->id_port[rid] = 0;
557			id->id_portsize[rid] = 0;
558			break;
559
560		default:
561			return ENOENT;
562		}
563	}
564
565	return rv;
566}
567
568/*
569 * We can't use the bus_generic_* versions of these methods because those
570 * methods always pass the bus param as the requesting device, and we need
571 * to pass the child (the i386 nexus knows about this and is prepared to
572 * deal).
573 */
574static int
575isa_setup_intr(device_t bus, device_t child, struct resource *r,
576	       void (*ihand)(void *), void *arg, void **cookiep)
577{
578	return (BUS_SETUP_INTR(device_get_parent(bus), child, r, ihand, arg,
579			       cookiep));
580}
581
582static int
583isa_teardown_intr(device_t bus, device_t child, struct resource *r,
584		  void *cookie)
585{
586	return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, cookie));
587}
588
589static device_method_t isa_methods[] = {
590	/* Device interface */
591	DEVMETHOD(device_probe,		isa_probe),
592	DEVMETHOD(device_attach,	isa_attach),
593	DEVMETHOD(device_detach,	bus_generic_detach),
594	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
595	DEVMETHOD(device_suspend,	bus_generic_suspend),
596	DEVMETHOD(device_resume,	bus_generic_resume),
597
598	/* Bus interface */
599	DEVMETHOD(bus_print_child,	isa_print_child),
600	DEVMETHOD(bus_read_ivar,	isa_read_ivar),
601	DEVMETHOD(bus_write_ivar,	isa_write_ivar),
602	DEVMETHOD(bus_alloc_resource,	isa_alloc_resource),
603	DEVMETHOD(bus_release_resource,	isa_release_resource),
604	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
605	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
606	DEVMETHOD(bus_setup_intr,	isa_setup_intr),
607	DEVMETHOD(bus_teardown_intr,	isa_teardown_intr),
608
609	{ 0, 0 }
610};
611
612static driver_t isa_driver = {
613	"isa",
614	isa_methods,
615	DRIVER_TYPE_MISC,
616	1,			/* no softc */
617};
618
619/*
620 * ISA can be attached to a PCI-ISA bridge or directly to the nexus.
621 */
622DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0);
623DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0);
624