isa.c revision 6512
14Srgrimes/*-
24Srgrimes * Copyright (c) 1991 The Regents of the University of California.
34Srgrimes * All rights reserved.
44Srgrimes *
54Srgrimes * This code is derived from software contributed to Berkeley by
64Srgrimes * William Jolitz.
74Srgrimes *
84Srgrimes * Redistribution and use in source and binary forms, with or without
94Srgrimes * modification, are permitted provided that the following conditions
104Srgrimes * are met:
114Srgrimes * 1. Redistributions of source code must retain the above copyright
124Srgrimes *    notice, this list of conditions and the following disclaimer.
134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
144Srgrimes *    notice, this list of conditions and the following disclaimer in the
154Srgrimes *    documentation and/or other materials provided with the distribution.
164Srgrimes * 3. All advertising materials mentioning features or use of this software
174Srgrimes *    must display the following acknowledgement:
184Srgrimes *	This product includes software developed by the University of
194Srgrimes *	California, Berkeley and its contributors.
204Srgrimes * 4. Neither the name of the University nor the names of its contributors
214Srgrimes *    may be used to endorse or promote products derived from this software
224Srgrimes *    without specific prior written permission.
234Srgrimes *
244Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
254Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
264Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
274Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
284Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
294Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
304Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
314Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
324Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
334Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
344Srgrimes * SUCH DAMAGE.
354Srgrimes *
36593Srgrimes *	from: @(#)isa.c	7.2 (Berkeley) 5/13/91
376512Sphk *	$Id: isa.c,v 1.36 1994/11/03 04:15:03 jkh Exp $
384Srgrimes */
394Srgrimes
404Srgrimes/*
414Srgrimes * code to manage AT bus
424Srgrimes *
434Srgrimes * 92/08/18  Frank P. MacLachlan (fpm@crash.cts.com):
444Srgrimes * Fixed uninitialized variable problem and added code to deal
454Srgrimes * with DMA page boundaries in isa_dmarangecheck().  Fixed word
464Srgrimes * mode DMA count compution and reorganized DMA setup code in
474Srgrimes * isa_dmastart()
484Srgrimes */
494Srgrimes
502056Swollman#include <sys/param.h>
512056Swollman#include <sys/systm.h>		/* isn't it a joy */
522056Swollman#include <sys/kernel.h>		/* to have three of these */
533871Sphk#include <sys/proc.h>
542056Swollman#include <sys/conf.h>
552056Swollman#include <sys/file.h>
562056Swollman#include <sys/buf.h>
572056Swollman#include <sys/uio.h>
582056Swollman#include <sys/syslog.h>
592056Swollman#include <sys/malloc.h>
602056Swollman#include <sys/rlist.h>
612056Swollman#include <machine/segments.h>
622056Swollman#include <vm/vm.h>
631549Srgrimes#include <machine/spl.h>
642056Swollman#include <i386/isa/isa_device.h>
652056Swollman#include <i386/isa/isa.h>
662056Swollman#include <i386/isa/icu.h>
672056Swollman#include <i386/isa/ic/i8237.h>
682056Swollman#include <i386/isa/ic/i8042.h>
693713Swollman#include <sys/devconf.h>
702103Sdg#include "vector.h"
714Srgrimes
724Srgrimes/*
734Srgrimes**  Register definitions for DMA controller 1 (channels 0..3):
744Srgrimes*/
754Srgrimes#define	DMA1_CHN(c)	(IO_DMA1 + 1*(2*(c)))	/* addr reg for channel c */
764Srgrimes#define	DMA1_SMSK	(IO_DMA1 + 1*10)	/* single mask register */
774Srgrimes#define	DMA1_MODE	(IO_DMA1 + 1*11)	/* mode register */
784Srgrimes#define	DMA1_FFC	(IO_DMA1 + 1*12)	/* clear first/last FF */
794Srgrimes
804Srgrimes/*
814Srgrimes**  Register definitions for DMA controller 2 (channels 4..7):
824Srgrimes*/
83630Srgrimes#define	DMA2_CHN(c)	(IO_DMA2 + 2*(2*(c)))	/* addr reg for channel c */
844Srgrimes#define	DMA2_SMSK	(IO_DMA2 + 2*10)	/* single mask register */
854Srgrimes#define	DMA2_MODE	(IO_DMA2 + 2*11)	/* mode register */
864Srgrimes#define	DMA2_FFC	(IO_DMA2 + 2*12)	/* clear first/last FF */
874Srgrimes
882103Sdg/*
892103Sdg * Bits to specify the type and amount of conflict checking.
902103Sdg */
912103Sdg#define	CC_ATTACH	(1 << 0)
922103Sdg#define	CC_DRQ		(1 << 1)
932103Sdg#define	CC_IOADDR	(1 << 2)
942103Sdg#define	CC_IRQ		(1 << 3)
952103Sdg#define	CC_MEMADDR	(1 << 4)
964Srgrimes
974Srgrimes/*
982103Sdg * XXX these defines should be in a central place.
992103Sdg */
1002103Sdg#define	read_eflags()		({u_long ef; \
1012103Sdg				  __asm("pushfl; popl %0" : "=a" (ef)); \
1022103Sdg				  ef; })
1032103Sdg#define	write_eflags(ef)	__asm("pushl %0; popfl" : : "a" ((u_long)(ef)))
1042103Sdg
1052103Sdgu_long	*intr_countp[ICU_LEN];
1062103Sdginthand2_t *intr_handler[ICU_LEN];
1072103Sdgu_int	intr_mask[ICU_LEN];
1082103Sdgint	intr_unit[ICU_LEN];
1092103Sdg
1103816Swollmanstruct kern_devconf kdc_isa0 = {
1113816Swollman	0, 0, 0,		/* filled in by dev_attach */
1123816Swollman	"isa", 0, { MDDT_BUS, 0 },
1133816Swollman	0, 0, 0, BUS_EXTERNALLEN,
1143816Swollman	0,			/* no parent yet; parent should be CPU */
1153816Swollman	0,			/* no parentdata */
1163816Swollman	DC_BUSY,		/* busses are always busy */
1173816Swollman	"ISA or EISA bus"
1183816Swollman};
1193816Swollman
1202103Sdgstatic inthand_t *fastintr[ICU_LEN] = {
1212103Sdg	&IDTVEC(fastintr0), &IDTVEC(fastintr1),
1222103Sdg	&IDTVEC(fastintr2), &IDTVEC(fastintr3),
1232103Sdg	&IDTVEC(fastintr4), &IDTVEC(fastintr5),
1242103Sdg	&IDTVEC(fastintr6), &IDTVEC(fastintr7),
1252103Sdg	&IDTVEC(fastintr8), &IDTVEC(fastintr9),
1262103Sdg	&IDTVEC(fastintr10), &IDTVEC(fastintr11),
1272103Sdg	&IDTVEC(fastintr12), &IDTVEC(fastintr13),
1282103Sdg	&IDTVEC(fastintr14), &IDTVEC(fastintr15)
1292103Sdg};
1302103Sdg
1312103Sdgstatic inthand_t *slowintr[ICU_LEN] = {
1322103Sdg	&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
1332103Sdg	&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
1342103Sdg	&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
1352103Sdg	&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
1362103Sdg};
1372103Sdg
1382103Sdgstatic void config_isadev __P((struct isa_device *isdp, u_int *mp));
1392103Sdgstatic void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp,
1402103Sdg			  int item, char const *whatnot, char const *reason,
1412103Sdg			  char const *format));
1422103Sdgstatic int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp,
1432103Sdg			 u_int checkbits));
1442103Sdgstatic int haveseen_isadev __P((struct isa_device *dvp, u_int checkbits));
1452103Sdgstatic inthand2_t isa_strayintr;
1462103Sdgstatic void register_imask __P((struct isa_device *dvp, u_int mask));
1472103Sdg
1482103Sdg/*
149593Srgrimes * print a conflict message
1504Srgrimes */
1512103Sdgstatic void
1522103Sdgconflict(dvp, tmpdvp, item, whatnot, reason, format)
1532103Sdg	struct isa_device	*dvp;
1542103Sdg	struct isa_device	*tmpdvp;
155593Srgrimes	int			item;
1562103Sdg	char const		*whatnot;
1572103Sdg	char const		*reason;
1582103Sdg	char const		*format;
159593Srgrimes{
1602103Sdg	printf("%s%d not %sed due to %s conflict with %s%d at ",
1612103Sdg		dvp->id_driver->name, dvp->id_unit, whatnot, reason,
162593Srgrimes		tmpdvp->id_driver->name, tmpdvp->id_unit);
163593Srgrimes	printf(format, item);
164593Srgrimes	printf("\n");
1654Srgrimes}
1664Srgrimes
1674Srgrimes/*
168593Srgrimes * Check to see if things are alread in use, like IRQ's, I/O addresses
169593Srgrimes * and Memory addresses.
1704Srgrimes */
1712103Sdgstatic int
1722103Sdghaveseen(dvp, tmpdvp, checkbits)
1732103Sdg	struct isa_device *dvp;
1742103Sdg	struct isa_device *tmpdvp;
1752103Sdg	u_int	checkbits;
1764Srgrimes{
177593Srgrimes	/*
178593Srgrimes	 * Only check against devices that have already been found
179593Srgrimes	 */
180593Srgrimes	if (tmpdvp->id_alive) {
1812103Sdg		char const *whatnot;
1822103Sdg
1832466Sats		whatnot = checkbits & CC_ATTACH ? "attach" : "prob";
184593Srgrimes		/*
185593Srgrimes		 * Check for I/O address conflict.  We can only check the
186593Srgrimes		 * starting address of the device against the range of the
187593Srgrimes		 * device that has already been probed since we do not
188593Srgrimes		 * know how many I/O addresses this device uses.
189593Srgrimes		 */
1902103Sdg		if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) {
191593Srgrimes			if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
192593Srgrimes			    (dvp->id_iobase <=
193593Srgrimes				  (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
1942103Sdg				conflict(dvp, tmpdvp, dvp->id_iobase, whatnot,
195593Srgrimes					 "I/O address", "0x%x");
1963670Sphk				return 1;
197593Srgrimes			}
1984Srgrimes		}
199593Srgrimes		/*
200593Srgrimes		 * Check for Memory address conflict.  We can check for
201593Srgrimes		 * range overlap, but it will not catch all cases since the
202593Srgrimes		 * driver may adjust the msize paramater during probe, for
203593Srgrimes		 * now we just check that the starting address does not
204593Srgrimes		 * fall within any allocated region.
205593Srgrimes		 * XXX could add a second check after the probe for overlap,
206593Srgrimes		 * since at that time we would know the full range.
207593Srgrimes		 * XXX KERNBASE is a hack, we should have vaddr in the table!
208593Srgrimes		 */
2092103Sdg		if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) {
2102103Sdg			if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
2112103Sdg			    (KERNBASE + dvp->id_maddr <=
2122103Sdg			     (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
2132103Sdg				conflict(dvp, tmpdvp, (int)dvp->id_maddr,
2142103Sdg					 whatnot, "maddr", "0x%x");
2153670Sphk				return 1;
2164Srgrimes			}
217593Srgrimes		}
218593Srgrimes		/*
219593Srgrimes		 * Check for IRQ conflicts.
220593Srgrimes		 */
2212103Sdg		if (checkbits & CC_IRQ && tmpdvp->id_irq) {
222593Srgrimes			if (tmpdvp->id_irq == dvp->id_irq) {
223593Srgrimes				conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1,
2242103Sdg					 whatnot, "irq", "%d");
2253670Sphk				return 1;
2264Srgrimes			}
227593Srgrimes		}
228593Srgrimes		/*
229593Srgrimes		 * Check for DRQ conflicts.
230593Srgrimes		 */
2312103Sdg		if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) {
232593Srgrimes			if (tmpdvp->id_drq == dvp->id_drq) {
2332103Sdg				conflict(dvp, tmpdvp, dvp->id_drq, whatnot,
2342103Sdg					 "drq", "%d");
2353670Sphk				return 1;
2364Srgrimes			}
237593Srgrimes		}
238593Srgrimes	}
2393670Sphk	return 0;
240593Srgrimes}
2414Srgrimes
242593Srgrimes/*
243593Srgrimes * Search through all the isa_devtab_* tables looking for anything that
244593Srgrimes * conflicts with the current device.
245593Srgrimes */
2462103Sdgstatic int
2472103Sdghaveseen_isadev(dvp, checkbits)
248593Srgrimes	struct isa_device *dvp;
2492103Sdg	u_int	checkbits;
250593Srgrimes{
251593Srgrimes	struct isa_device *tmpdvp;
252593Srgrimes	int	status = 0;
2534Srgrimes
2543670Sphk	for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
2552103Sdg		status |= haveseen(dvp, tmpdvp, checkbits);
2563670Sphk		if (status)
2573670Sphk			return status;
2583670Sphk	}
2593670Sphk	for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
2602103Sdg		status |= haveseen(dvp, tmpdvp, checkbits);
2613670Sphk		if (status)
2623670Sphk			return status;
2633670Sphk	}
2643670Sphk	for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
2652103Sdg		status |= haveseen(dvp, tmpdvp, checkbits);
2663670Sphk		if (status)
2673670Sphk			return status;
2683670Sphk	}
2693670Sphk	for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
2702103Sdg		status |= haveseen(dvp, tmpdvp, checkbits);
2713670Sphk		if (status)
2723670Sphk			return status;
2733670Sphk	}
274593Srgrimes	return(status);
2754Srgrimes}
276593Srgrimes
2774Srgrimes/*
2784Srgrimes * Configure all ISA devices
2794Srgrimes */
280593Srgrimesvoid
2814Srgrimesisa_configure() {
2824Srgrimes	struct isa_device *dvp;
2834Srgrimes
2843816Swollman	dev_attach(&kdc_isa0);
2853816Swollman
2862103Sdg	splhigh();
2874Srgrimes	enable_intr();
2884Srgrimes	INTREN(IRQ_SLAVE);
289593Srgrimes	printf("Probing for devices on the ISA bus:\n");
2903670Sphk	/* First probe all the sensitive probes */
2912103Sdg	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
2923670Sphk		if (dvp->id_driver->sensitive_hw)
2933670Sphk			config_isadev(dvp, &tty_imask);
2942103Sdg	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
2953670Sphk		if (dvp->id_driver->sensitive_hw)
2963670Sphk			config_isadev(dvp, &bio_imask);
2972103Sdg	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
2983670Sphk		if (dvp->id_driver->sensitive_hw)
2993670Sphk			config_isadev(dvp, &net_imask);
3002103Sdg	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
3013670Sphk		if (dvp->id_driver->sensitive_hw)
3023670Sphk			config_isadev(dvp, (u_int *)NULL);
3033670Sphk
3043670Sphk	/* Then all the bad ones */
3053670Sphk	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
3063670Sphk		if (!dvp->id_driver->sensitive_hw)
3073670Sphk			config_isadev(dvp, &tty_imask);
3083670Sphk	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
3093670Sphk		if (!dvp->id_driver->sensitive_hw)
3103670Sphk			config_isadev(dvp, &bio_imask);
3113670Sphk	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
3123670Sphk		if (!dvp->id_driver->sensitive_hw)
3133670Sphk			config_isadev(dvp, &net_imask);
3143670Sphk	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
3153670Sphk		if (!dvp->id_driver->sensitive_hw)
3163670Sphk			config_isadev(dvp, (u_int *)NULL);
3173670Sphk
3181321Sdg	bio_imask |= SWI_CLOCK_MASK;
3191321Sdg	net_imask |= SWI_NET_MASK;
3201321Sdg	tty_imask |= SWI_TTY_MASK;
3211321Sdg
322593Srgrimes/*
3231321Sdg * XXX we should really add the tty device to net_imask when the line is
324593Srgrimes * switched to SLIPDISC, and then remove it when it is switched away from
3251321Sdg * SLIPDISC.  No need to block out ALL ttys during a splimp when only one
326593Srgrimes * of them is running slip.
3271321Sdg *
3281321Sdg * XXX actually, blocking all ttys during a splimp doesn't matter so much
3291321Sdg * with sio because the serial interrupt layer doesn't use tty_imask.  Only
3301321Sdg * non-serial ttys suffer.  It's more stupid that ALL 'net's are blocked
3311321Sdg * during spltty.
332593Srgrimes */
3334Srgrimes#include "sl.h"
3343705Swollman#include "ppp.h"
3353705Swollman
3363705Swollman#if (NSL > 0) || (NPPP > 0)
3371321Sdg	net_imask |= tty_imask;
3381321Sdg	tty_imask = net_imask;
3394Srgrimes#endif
3401321Sdg	/* bio_imask |= tty_imask ;  can some tty devices use buffers? */
3411321Sdg#ifdef DIAGNOSTIC
3421321Sdg	printf("bio_imask %x tty_imask %x net_imask %x\n",
3431321Sdg	       bio_imask, tty_imask, net_imask);
3441321Sdg#endif
3452103Sdg	/*
3462103Sdg	 * Finish initializing intr_mask[].  Note that the partly
3472103Sdg	 * constructed masks aren't actually used since we're at splhigh.
3482103Sdg	 * For fully dynamic initialization, register_intr() and
3492103Sdg	 * unregister_intr() will have to adjust the masks for _all_
3502103Sdg	 * interrupts and for tty_imask, etc.
3512103Sdg	 */
3522103Sdg	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
3532103Sdg		register_imask(dvp, tty_imask);
3542103Sdg	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
3552103Sdg		register_imask(dvp, bio_imask);
3562103Sdg	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
3572103Sdg		register_imask(dvp, net_imask);
3582103Sdg	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
3592103Sdg		register_imask(dvp, SWI_CLOCK_MASK);
3602918Sbde	spl0();
3614Srgrimes}
3624Srgrimes
3634Srgrimes/*
3644Srgrimes * Configure an ISA device.
3654Srgrimes */
3663258Sdg
3673258Sdg
3683258Sdgstatic void config_isadev_c();
3693258Sdg
3702103Sdgstatic void
3714Srgrimesconfig_isadev(isdp, mp)
3723258Sdg     struct isa_device *isdp;
3733258Sdg     u_int *mp;
3743258Sdg{
3753258Sdg	config_isadev_c(isdp, mp, 0);
3763258Sdg}
3773258Sdg
3783258Sdgvoid
3793258Sdgreconfig_isadev(isdp, mp)
3804Srgrimes	struct isa_device *isdp;
3814Srgrimes	u_int *mp;
3824Srgrimes{
3833258Sdg	config_isadev_c(isdp, mp, 1);
3843258Sdg}
3853258Sdg
3863258Sdgstatic void
3873258Sdgconfig_isadev_c(isdp, mp, reconfig)
3883258Sdg	struct isa_device *isdp;
3893258Sdg	u_int *mp;
3903258Sdg	int reconfig;
3913258Sdg{
3922103Sdg	u_int checkbits;
3932103Sdg	int id_alive;
3943258Sdg	int last_alive;
395593Srgrimes	struct isa_driver *dp = isdp->id_driver;
3964Srgrimes
3972103Sdg 	checkbits = 0;
3982103Sdg#ifndef ALLOW_CONFLICT_DRQ
3992103Sdg	checkbits |= CC_DRQ;
4002103Sdg#endif
4012103Sdg#ifndef ALLOW_CONFLICT_IOADDR
4022103Sdg	checkbits |= CC_IOADDR;
4032103Sdg#endif
4042103Sdg#ifndef ALLOW_CONFLICT_MEMADDR
4052103Sdg	checkbits |= CC_MEMADDR;
4062103Sdg#endif
4074109Sjkh	if (!isdp->id_enabled) {
4084109Sjkh		printf("%s%d: disabled, not probed.\n",
4094109Sjkh			dp->name, isdp->id_unit);
4104109Sjkh		return;
4114109Sjkh	}
4123258Sdg	if (!reconfig && haveseen_isadev(isdp, checkbits))
4132103Sdg		return;
4143258Sdg	if (!reconfig && isdp->id_maddr) {
415593Srgrimes		isdp->id_maddr -= 0xa0000; /* XXX should be a define */
416593Srgrimes		isdp->id_maddr += atdevbase;
417593Srgrimes	}
4183258Sdg	if (reconfig) {
4193258Sdg		last_alive = isdp->id_alive;
4206512Sphk		isdp->id_reconfig = 1;
4213258Sdg	}
4223258Sdg	else {
4233258Sdg		last_alive = 0;
4246512Sphk		isdp->id_reconfig = 0;
4253258Sdg	}
4262103Sdg	id_alive = (*dp->probe)(isdp);
4272103Sdg	if (id_alive) {
428593Srgrimes		/*
429593Srgrimes		 * Only print the I/O address range if id_alive != -1
430593Srgrimes		 * Right now this is a temporary fix just for the new
431593Srgrimes		 * NPX code so that if it finds a 486 that can use trap
432593Srgrimes		 * 16 it will not report I/O addresses.
433593Srgrimes		 * Rod Grimes 04/26/94
434593Srgrimes		 */
4353258Sdg		if (!isdp->id_reconfig) {
4363258Sdg			printf("%s%d", dp->name, isdp->id_unit);
4373258Sdg			if (id_alive != -1) {
4383258Sdg 				printf(" at 0x%x", isdp->id_iobase);
4393258Sdg 				if ((isdp->id_iobase + id_alive - 1) !=
4403258Sdg 				     isdp->id_iobase) {
4413258Sdg 					printf("-0x%x",
4423258Sdg					       isdp->id_iobase + id_alive - 1);
4433258Sdg				}
444593Srgrimes			}
4453258Sdg			if (isdp->id_irq)
4463258Sdg				printf(" irq %d", ffs(isdp->id_irq) - 1);
4473258Sdg			if (isdp->id_drq != -1)
4483258Sdg				printf(" drq %d", isdp->id_drq);
4493258Sdg			if (isdp->id_maddr)
4503258Sdg				printf(" maddr 0x%lx", kvtop(isdp->id_maddr));
4513258Sdg			if (isdp->id_msize)
4523258Sdg				printf(" msize %d", isdp->id_msize);
4533258Sdg			if (isdp->id_flags)
4543258Sdg				printf(" flags 0x%x", isdp->id_flags);
4553258Sdg			if (isdp->id_iobase) {
4563258Sdg				if (isdp->id_iobase < 0x100) {
4573258Sdg					printf(" on motherboard\n");
4581002Srgrimes				} else {
4593258Sdg					if (isdp->id_iobase >= 0x1000) {
4603258Sdg						printf (" on eisa\n");
4613258Sdg					} else {
4623258Sdg						printf (" on isa\n");
4633258Sdg					}
4641002Srgrimes				}
4651002Srgrimes			}
4663258Sdg			/*
4673258Sdg			 * Check for conflicts again.  The driver may have
4683258Sdg			 * changed *dvp.  We should weaken the early check
4693258Sdg			 * since the driver may have been able to change
4703258Sdg			 * *dvp to avoid conflicts if given a chance.  We
4713258Sdg			 * already skip the early check for IRQs and force
4723258Sdg			 * a check for IRQs in the next group of checks.
4733258Sdg		 	 */
4743224Sswallace#ifndef ALLOW_CONFLICT_IRQ
4753258Sdg			checkbits |= CC_IRQ;
4763224Sswallace#endif
4773258Sdg			if (haveseen_isadev(isdp, checkbits))
4783258Sdg				return;
4793258Sdg			isdp->id_alive = id_alive;
4803258Sdg		}
481593Srgrimes		(*dp->attach)(isdp);
4822103Sdg		if (isdp->id_irq) {
4832103Sdg			if (mp)
4842103Sdg				INTRMASK(*mp, isdp->id_irq);
4852103Sdg			register_intr(ffs(isdp->id_irq) - 1, isdp->id_id,
4862103Sdg				      isdp->id_ri_flags, isdp->id_intr,
4873869Sse				      mp, isdp->id_unit);
488593Srgrimes			INTREN(isdp->id_irq);
4894Srgrimes		}
490593Srgrimes	} else {
4913258Sdg		if (isdp->id_reconfig) {
4923258Sdg			(*dp->attach)(isdp); /* reconfiguration attach */
493593Srgrimes		}
4943258Sdg		if (!last_alive) {
4953258Sdg			if (!isdp->id_reconfig) {
4963258Sdg				printf("%s%d not found", dp->name, isdp->id_unit);
4973258Sdg				if (isdp->id_iobase) {
4983258Sdg					printf(" at 0x%x", isdp->id_iobase);
4993258Sdg				}
5003258Sdg				printf("\n");
5013258Sdg			}
5023258Sdg		}
5033258Sdg		else {
5043258Sdg			/* This code has not been tested.... */
5053258Sdg			if (isdp->id_irq) {
5063258Sdg				INTRDIS(isdp->id_irq);
5073258Sdg				unregister_intr(ffs(isdp->id_irq) - 1,
5083258Sdg						isdp->id_intr);
5093258Sdg				if (mp)
5103258Sdg					INTRUNMASK(*mp, isdp->id_irq);
5113258Sdg			}
5123258Sdg		}
513593Srgrimes	}
5144Srgrimes}
5154Srgrimes
5164Srgrimes/*
5173705Swollman * Provide ISA-specific device information to user programs using the
5183705Swollman * hw.devconf interface.
5193705Swollman */
5203705Swollmanint
5213705Swollmanisa_externalize(struct isa_device *id, void *userp, size_t *maxlen)
5223705Swollman{
5233705Swollman	if(*maxlen < sizeof *id) {
5243705Swollman		return ENOMEM;
5253705Swollman	}
5263705Swollman
5273705Swollman	*maxlen -= sizeof *id;
5283705Swollman	return copyout(id, userp, sizeof *id);
5293705Swollman}
5303705Swollman
5313705Swollman/*
5323705Swollman * Do the same thing for EISA information.  EISA information is currently
5333705Swollman * the same as ISA information plus a slot number, but could be extended in
5343705Swollman * the future.
5353705Swollman */
5363705Swollmanint
5373705Swollmaneisa_externalize(struct isa_device *id, int slot, void *userp, size_t *maxlen)
5383705Swollman{
5393705Swollman	int rv;
5403705Swollman
5413705Swollman	if(*maxlen < (sizeof *id) + (sizeof slot)) {
5423705Swollman		return ENOMEM;
5433705Swollman	}
5443705Swollman	*maxlen -= (sizeof *id) + (sizeof slot);
5453705Swollman
5463705Swollman	rv = copyout(id, userp, sizeof *id);
5473705Swollman	if(rv) return rv;
5483705Swollman
5493705Swollman	return copyout(&slot, (char *)userp + sizeof *id, sizeof slot);
5503705Swollman}
5513705Swollman
5523705Swollman/*
5533705Swollman * This is used to forcibly reconfigure an ISA device.  It currently just
5543705Swollman * returns an error 'cos you can't do that yet.  It is here to demonstrate
5553705Swollman * what the `internalize' routine is supposed to do.
5563705Swollman */
5573705Swollmanint
5583705Swollmanisa_internalize(struct isa_device *id, void **userpp, size_t *len)
5593705Swollman{
5603705Swollman	struct isa_device myid;
5613705Swollman	char *userp = *userpp;
5623705Swollman	int rv;
5633705Swollman
5643705Swollman	if(*len < sizeof *id) {
5653705Swollman		return EINVAL;
5663705Swollman	}
5673705Swollman
5683705Swollman	rv = copyin(userp, &myid, sizeof myid);
5693705Swollman	if(rv) return rv;
5703705Swollman	*userpp = userp + sizeof myid;
5713705Swollman	*len -= sizeof myid;
5723705Swollman
5733705Swollman	rv = EOPNOTSUPP;
5743705Swollman	/* code would go here to validate the configuration request */
5753705Swollman	/* code would go here to actually perform the reconfiguration */
5763705Swollman	return rv;
5773705Swollman}
5783705Swollman
5793713Swollmanint
5803713Swollmanisa_generic_externalize(struct proc *p, struct kern_devconf *kdc,
5813713Swollman			void *userp, size_t l)
5823713Swollman{
5833713Swollman	return isa_externalize(kdc->kdc_isa, userp, &l);
5843713Swollman}
5853713Swollman
5863713Swollmanint
5873713Swollmaneisa_generic_externalize(struct proc *p, struct kern_devconf *kdc,
5883713Swollman			 void *userp, size_t l)
5893713Swollman{
5903713Swollman	return eisa_externalize(kdc->kdc_isa, -1, userp, &l);
5913713Swollman}
5923713Swollman
5933705Swollman/*
5944Srgrimes * Fill in default interrupt table (in case of spuruious interrupt
5954Srgrimes * during configuration of kernel, setup interrupt control unit
5964Srgrimes */
597798Swollmanvoid
598798Swollmanisa_defaultirq()
599798Swollman{
6004Srgrimes	int i;
6014Srgrimes
6024Srgrimes	/* icu vectors */
6031321Sdg	for (i = 0; i < ICU_LEN; i++)
6042103Sdg		unregister_intr(i, (inthand2_t *)NULL);
6054Srgrimes
6064Srgrimes	/* initialize 8259's */
6074Srgrimes	outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
6084Srgrimes	outb(IO_ICU1+1, NRSVIDT);	/* starting at this vector index */
6094Srgrimes	outb(IO_ICU1+1, 1<<2);		/* slave on line 2 */
6104Srgrimes#ifdef AUTO_EOI_1
6114Srgrimes	outb(IO_ICU1+1, 2 | 1);		/* auto EOI, 8086 mode */
6124Srgrimes#else
6134Srgrimes	outb(IO_ICU1+1, 1);		/* 8086 mode */
6144Srgrimes#endif
6154Srgrimes	outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
6164Srgrimes	outb(IO_ICU1, 0x0a);		/* default to IRR on read */
6174Srgrimes	outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
6184Srgrimes
6194Srgrimes	outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
6204Srgrimes	outb(IO_ICU2+1, NRSVIDT+8);	/* staring at this vector index */
6214Srgrimes	outb(IO_ICU2+1,2);		/* my slave id is 2 */
6224Srgrimes#ifdef AUTO_EOI_2
6234Srgrimes	outb(IO_ICU2+1, 2 | 1);		/* auto EOI, 8086 mode */
6244Srgrimes#else
6254Srgrimes	outb(IO_ICU2+1,1);		/* 8086 mode */
6264Srgrimes#endif
6274Srgrimes	outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
6284Srgrimes	outb(IO_ICU2, 0x0a);		/* default to IRR on read */
6294Srgrimes}
6304Srgrimes
6314Srgrimes/* region of physical memory known to be contiguous */
6324Srgrimesvm_offset_t isaphysmem;
6334Srgrimesstatic caddr_t dma_bounce[8];		/* XXX */
6344Srgrimesstatic char bounced[8];		/* XXX */
6354Srgrimes#define MAXDMASZ 512		/* XXX */
6364Srgrimes
6374Srgrimes/* high byte of address is stored in this port for i-th dma channel */
6384Srgrimesstatic short dmapageport[8] =
6394Srgrimes	{ 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
6404Srgrimes
6414Srgrimes/*
6424Srgrimes * isa_dmacascade(): program 8237 DMA controller channel to accept
6434Srgrimes * external dma control by a board.
6444Srgrimes */
6454Srgrimesvoid isa_dmacascade(unsigned chan)
6464Srgrimes{
6474Srgrimes	if (chan > 7)
6484Srgrimes		panic("isa_dmacascade: impossible request");
6494Srgrimes
6504Srgrimes	/* set dma channel mode, and set dma channel mode */
6514Srgrimes	if ((chan & 4) == 0) {
6524Srgrimes		outb(DMA1_MODE, DMA37MD_CASCADE | chan);
6534Srgrimes		outb(DMA1_SMSK, chan);
6544Srgrimes	} else {
6554Srgrimes		outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
6564Srgrimes		outb(DMA2_SMSK, chan & 3);
6574Srgrimes	}
6584Srgrimes}
6594Srgrimes
6602103Sdgstatic int
6612103Sdgisa_dmarangecheck(caddr_t va, unsigned length, unsigned chan);
6622103Sdg
6634Srgrimes/*
6644Srgrimes * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
6654Srgrimes * problems by using a bounce buffer.
6664Srgrimes */
6674Srgrimesvoid isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
6684Srgrimes{	vm_offset_t phys;
6694Srgrimes	int waport;
6704Srgrimes	caddr_t newaddr;
6714Srgrimes
6724Srgrimes	if (    chan > 7
6734Srgrimes	    || (chan < 4 && nbytes > (1<<16))
6744Srgrimes	    || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
6754Srgrimes		panic("isa_dmastart: impossible request");
6764Srgrimes
6774Srgrimes	if (isa_dmarangecheck(addr, nbytes, chan)) {
6784Srgrimes		if (dma_bounce[chan] == 0)
6794Srgrimes			dma_bounce[chan] =
6804Srgrimes				/*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
6814Srgrimes				(caddr_t) isaphysmem + NBPG*chan;
6824Srgrimes		bounced[chan] = 1;
6834Srgrimes		newaddr = dma_bounce[chan];
6844Srgrimes		*(int *) newaddr = 0;	/* XXX */
6854Srgrimes
6864Srgrimes		/* copy bounce buffer on write */
6874Srgrimes		if (!(flags & B_READ))
6884Srgrimes			bcopy(addr, newaddr, nbytes);
6894Srgrimes		addr = newaddr;
6904Srgrimes	}
6914Srgrimes
6924Srgrimes	/* translate to physical */
6934Srgrimes	phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
6944Srgrimes
6954Srgrimes	if ((chan & 4) == 0) {
6964Srgrimes		/*
6974Srgrimes		 * Program one of DMA channels 0..3.  These are
6984Srgrimes		 * byte mode channels.
6994Srgrimes		 */
7004Srgrimes		/* set dma channel mode, and reset address ff */
7014051Sache
7024051Sache		/* If B_RAW flag is set, then use autoinitialise mode */
7034051Sache		if (flags & B_RAW) {
7044051Sache		  if (flags & B_READ)
7054051Sache			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
7064051Sache		  else
7074051Sache			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
7084051Sache		}
7094051Sache		else
7104Srgrimes		if (flags & B_READ)
7114Srgrimes			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
7124Srgrimes		else
7134Srgrimes			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
7144Srgrimes		outb(DMA1_FFC, 0);
7154Srgrimes
7164Srgrimes		/* send start address */
7174Srgrimes		waport =  DMA1_CHN(chan);
7184Srgrimes		outb(waport, phys);
7194Srgrimes		outb(waport, phys>>8);
7204Srgrimes		outb(dmapageport[chan], phys>>16);
7214Srgrimes
7224Srgrimes		/* send count */
7234Srgrimes		outb(waport + 1, --nbytes);
7244Srgrimes		outb(waport + 1, nbytes>>8);
7254Srgrimes
7264Srgrimes		/* unmask channel */
7274Srgrimes		outb(DMA1_SMSK, chan);
7284Srgrimes	} else {
7294Srgrimes		/*
7304Srgrimes		 * Program one of DMA channels 4..7.  These are
7314Srgrimes		 * word mode channels.
7324Srgrimes		 */
7334Srgrimes		/* set dma channel mode, and reset address ff */
7344051Sache
7354051Sache		/* If B_RAW flag is set, then use autoinitialise mode */
7364051Sache		if (flags & B_RAW) {
7374051Sache		  if (flags & B_READ)
7384051Sache			outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3));
7394051Sache		  else
7404051Sache			outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3));
7414051Sache		}
7424051Sache		else
7434Srgrimes		if (flags & B_READ)
7444Srgrimes			outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
7454Srgrimes		else
7464Srgrimes			outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
7474Srgrimes		outb(DMA2_FFC, 0);
7484Srgrimes
7494Srgrimes		/* send start address */
7504Srgrimes		waport = DMA2_CHN(chan - 4);
7514Srgrimes		outb(waport, phys>>1);
7524Srgrimes		outb(waport, phys>>9);
7534Srgrimes		outb(dmapageport[chan], phys>>16);
7544Srgrimes
7554Srgrimes		/* send count */
7564Srgrimes		nbytes >>= 1;
7574Srgrimes		outb(waport + 2, --nbytes);
7584Srgrimes		outb(waport + 2, nbytes>>8);
7594Srgrimes
7604Srgrimes		/* unmask channel */
7614Srgrimes		outb(DMA2_SMSK, chan & 3);
7624Srgrimes	}
7634Srgrimes}
7644Srgrimes
7654Srgrimesvoid isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
7664Srgrimes{
7674Srgrimes
7684Srgrimes	/* copy bounce buffer on read */
7694Srgrimes	/*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
7704Srgrimes	if (bounced[chan]) {
7714Srgrimes		bcopy(dma_bounce[chan], addr, nbytes);
7724Srgrimes		bounced[chan] = 0;
7734Srgrimes	}
7744Srgrimes}
7754Srgrimes
7764Srgrimes/*
7774Srgrimes * Check for problems with the address range of a DMA transfer
7784Srgrimes * (non-contiguous physical pages, outside of bus address space,
7794Srgrimes * crossing DMA page boundaries).
7804Srgrimes * Return true if special handling needed.
7814Srgrimes */
7824Srgrimes
7832103Sdgstatic int
7844Srgrimesisa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
7854Srgrimes	vm_offset_t phys, priorpage = 0, endva;
7864Srgrimes	u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
7874Srgrimes
7884Srgrimes	endva = (vm_offset_t)round_page(va + length);
7894Srgrimes	for (; va < (caddr_t) endva ; va += NBPG) {
7904Srgrimes		phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
7914Srgrimes#define ISARAM_END	RAM_END
7924Srgrimes		if (phys == 0)
7934Srgrimes			panic("isa_dmacheck: no physical page present");
7941323Sache		if (phys >= ISARAM_END)
7954Srgrimes			return (1);
7964Srgrimes		if (priorpage) {
7974Srgrimes			if (priorpage + NBPG != phys)
7984Srgrimes				return (1);
7994Srgrimes			/* check if crossing a DMA page boundary */
8004Srgrimes			if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
8014Srgrimes				return (1);
8024Srgrimes		}
8034Srgrimes		priorpage = phys;
8044Srgrimes	}
8054Srgrimes	return (0);
8064Srgrimes}
8074Srgrimes
8084Srgrimes/* head of queue waiting for physmem to become available */
8094Srgrimesstruct buf isa_physmemq;
8104Srgrimes
8114Srgrimes/* blocked waiting for resource to become free for exclusive use */
8124Srgrimesstatic isaphysmemflag;
8134Srgrimes/* if waited for and call requested when free (B_CALL) */
8144Srgrimesstatic void (*isaphysmemunblock)(); /* needs to be a list */
8154Srgrimes
8164Srgrimes/*
8174Srgrimes * Allocate contiguous physical memory for transfer, returning
8184Srgrimes * a *virtual* address to region. May block waiting for resource.
8194Srgrimes * (assumed to be called at splbio())
8204Srgrimes */
8214Srgrimescaddr_t
8224Srgrimesisa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
8234Srgrimes
8244Srgrimes	isaphysmemunblock = func;
8254Srgrimes	while (isaphysmemflag & B_BUSY) {
8264Srgrimes		isaphysmemflag |= B_WANTED;
827798Swollman		tsleep((caddr_t)&isaphysmemflag, PRIBIO, "isaphys", 0);
8284Srgrimes	}
8294Srgrimes	isaphysmemflag |= B_BUSY;
8304Srgrimes
8314Srgrimes	return((caddr_t)isaphysmem);
8324Srgrimes}
8334Srgrimes
8344Srgrimes/*
8354Srgrimes * Free contiguous physical memory used for transfer.
8364Srgrimes * (assumed to be called at splbio())
8374Srgrimes */
8384Srgrimesvoid
8394Srgrimesisa_freephysmem(caddr_t va, unsigned length) {
8404Srgrimes
8414Srgrimes	isaphysmemflag &= ~B_BUSY;
8424Srgrimes	if (isaphysmemflag & B_WANTED) {
8434Srgrimes		isaphysmemflag &= B_WANTED;
844798Swollman		wakeup((caddr_t)&isaphysmemflag);
8454Srgrimes		if (isaphysmemunblock)
8464Srgrimes			(*isaphysmemunblock)();
8474Srgrimes	}
8484Srgrimes}
8494Srgrimes
8502001Swollman#define NMI_PARITY (1 << 7)
8512001Swollman#define NMI_IOCHAN (1 << 6)
8522001Swollman#define ENMI_WATCHDOG (1 << 7)
8532001Swollman#define ENMI_BUSTIMER (1 << 6)
8542001Swollman#define ENMI_IOSTATUS (1 << 5)
8552001Swollman
8564Srgrimes/*
8574Srgrimes * Handle a NMI, possibly a machine check.
8584Srgrimes * return true to panic system, false to ignore.
8594Srgrimes */
860798Swollmanint
861798Swollmanisa_nmi(cd)
862798Swollman	int cd;
863798Swollman{
8642001Swollman	int isa_port = inb(0x61);
8652001Swollman	int eisa_port = inb(0x461);
8662001Swollman	if(isa_port & NMI_PARITY) {
8672001Swollman		panic("RAM parity error, likely hardware failure.");
8682001Swollman	} else if(isa_port & NMI_IOCHAN) {
8692001Swollman		panic("I/O channel check, likely hardware failure.");
8702001Swollman	} else if(eisa_port & ENMI_WATCHDOG) {
8712001Swollman		panic("EISA watchdog timer expired, likely hardware failure.");
8722001Swollman	} else if(eisa_port & ENMI_BUSTIMER) {
8732001Swollman		panic("EISA bus timeout, likely hardware failure.");
8742001Swollman	} else if(eisa_port & ENMI_IOSTATUS) {
8752001Swollman		panic("EISA I/O port status error.");
8762001Swollman	} else {
8772001Swollman		printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
8782001Swollman		return(0);
8792001Swollman	}
8804Srgrimes}
8814Srgrimes
8824Srgrimes/*
8834Srgrimes * Caught a stray interrupt, notify
8844Srgrimes */
8852103Sdgstatic void
886798Swollmanisa_strayintr(d)
887798Swollman	int d;
888798Swollman{
8894Srgrimes
8904Srgrimes	/* DON'T BOTHER FOR NOW! */
8914Srgrimes	/* for some reason, we get bursts of intr #7, even if not enabled! */
8924Srgrimes	/*
8934Srgrimes	 * Well the reason you got bursts of intr #7 is because someone
8944Srgrimes	 * raised an interrupt line and dropped it before the 8259 could
8954Srgrimes	 * prioritize it.  This is documented in the intel data book.  This
8964Srgrimes	 * means you have BAD hardware!  I have changed this so that only
8974Srgrimes	 * the first 5 get logged, then it quits logging them, and puts
8984Srgrimes	 * out a special message. rgrimes 3/25/1993
8994Srgrimes	 */
9002103Sdg	/*
9012103Sdg	 * XXX TODO print a different message for #7 if it is for a
9022103Sdg	 * glitch.  Glitches can be distinguished from real #7's by
9032103Sdg	 * testing that the in-service bit is _not_ set.  The test
9042103Sdg	 * must be done before sending an EOI so it can't be done if
9052103Sdg	 * we are using AUTO_EOI_1.
9062103Sdg	 */
9072103Sdg	if (intrcnt[NR_DEVICES + d] <= 5)
9082103Sdg		log(LOG_ERR, "stray irq %d\n", d);
9092103Sdg	if (intrcnt[NR_DEVICES + d] == 5)
9102103Sdg		log(LOG_CRIT,
9112103Sdg		    "too many stray irq %d's; not logging any more\n", d);
9124Srgrimes}
9134Srgrimes
9144Srgrimes/*
9154Srgrimes * find an ISA device in a given isa_devtab_* table, given
9164Srgrimes * the table to search, the expected id_driver entry, and the unit number.
9174Srgrimes *
9184Srgrimes * this function is defined in isa_device.h, and this location is debatable;
9194Srgrimes * i put it there because it's useless w/o, and directly operates on
9204Srgrimes * the other stuff in that file.
9214Srgrimes *
9224Srgrimes */
9234Srgrimes
9244Srgrimesstruct isa_device *find_isadev(table, driverp, unit)
9254Srgrimes     struct isa_device *table;
9264Srgrimes     struct isa_driver *driverp;
9274Srgrimes     int unit;
9284Srgrimes{
9294Srgrimes  if (driverp == NULL) /* sanity check */
9304Srgrimes    return NULL;
9314Srgrimes
9324Srgrimes  while ((table->id_driver != driverp) || (table->id_unit != unit)) {
9334Srgrimes    if (table->id_driver == 0)
9344Srgrimes      return NULL;
9354Srgrimes
9364Srgrimes    table++;
9374Srgrimes  }
9384Srgrimes
9394Srgrimes  return table;
9404Srgrimes}
9414Srgrimes
9424Srgrimes/*
9434Srgrimes * Return nonzero if a (masked) irq is pending for a given device.
9444Srgrimes */
9454Srgrimesint
9464Srgrimesisa_irq_pending(dvp)
9474Srgrimes	struct isa_device *dvp;
9484Srgrimes{
9494Srgrimes	unsigned id_irq;
9504Srgrimes
9512103Sdg	id_irq = dvp->id_irq;
9524Srgrimes	if (id_irq & 0xff)
9534Srgrimes		return (inb(IO_ICU1) & id_irq);
9544Srgrimes	return (inb(IO_ICU2) & (id_irq >> 8));
9554Srgrimes}
9562103Sdg
9572103Sdgint
9583869Sseregister_intr(intr, device_id, flags, handler, maskptr, unit)
9592103Sdg	int	intr;
9602103Sdg	int	device_id;
9612103Sdg	u_int	flags;
9622103Sdg	inthand2_t *handler;
9633869Sse	u_int	*maskptr;
9642103Sdg	int	unit;
9652103Sdg{
9662103Sdg	char	*cp;
9672103Sdg	u_long	ef;
9682103Sdg	int	id;
9693869Sse	u_int	mask = (maskptr ? *maskptr : 0);
9702103Sdg
9712103Sdg	if ((u_int)intr >= ICU_LEN || intr == 2
9722103Sdg	    || (u_int)device_id >= NR_DEVICES)
9732103Sdg		return (EINVAL);
9742103Sdg	if (intr_handler[intr] != isa_strayintr)
9752103Sdg		return (EBUSY);
9762103Sdg	ef = read_eflags();
9772103Sdg	disable_intr();
9782103Sdg	intr_countp[intr] = &intrcnt[device_id];
9792103Sdg	intr_handler[intr] = handler;
9802103Sdg	intr_mask[intr] = mask | (1 << intr);
9812103Sdg	intr_unit[intr] = unit;
9822103Sdg	setidt(ICU_OFFSET + intr,
9832103Sdg	       flags & RI_FAST ? fastintr[intr] : slowintr[intr],
9842103Sdg	       SDT_SYS386IGT, SEL_KPL);
9852103Sdg	write_eflags(ef);
9862103Sdg	for (cp = intrnames, id = 0; id <= device_id; id++)
9872103Sdg		while (*cp++ != '\0')
9882103Sdg			;
9892103Sdg	if (cp > eintrnames)
9902103Sdg		return (0);
9912103Sdg	if (intr < 10) {
9922103Sdg		cp[-3] = intr + '0';
9932103Sdg		cp[-2] = ' ';
9942103Sdg	} else {
9952103Sdg		cp[-3] = '1';
9962103Sdg		cp[-2] = intr - 10 + '0';
9972103Sdg	}
9982103Sdg	return (0);
9992103Sdg}
10002103Sdg
10012103Sdgstatic void
10022103Sdgregister_imask(dvp, mask)
10032103Sdg	struct isa_device *dvp;
10042103Sdg	u_int	mask;
10052103Sdg{
10062103Sdg	if (dvp->id_alive && dvp->id_irq) {
10072103Sdg		int	intr;
10082103Sdg
10092103Sdg		intr = ffs(dvp->id_irq) - 1;
10102103Sdg		intr_mask[intr] = mask | (1 <<intr);
10112103Sdg	}
10122103Sdg}
10132103Sdg
10142103Sdgint
10152103Sdgunregister_intr(intr, handler)
10162103Sdg	int	intr;
10172103Sdg	inthand2_t *handler;
10182103Sdg{
10192103Sdg	u_long	ef;
10202103Sdg
10212103Sdg	if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
10222103Sdg		return (EINVAL);
10232103Sdg	ef = read_eflags();
10242103Sdg	disable_intr();
10252103Sdg	intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
10262103Sdg	intr_handler[intr] = isa_strayintr;
10272103Sdg	intr_mask[intr] = HWI_MASK | SWI_MASK;
10282103Sdg	intr_unit[intr] = intr;
10292103Sdg	setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL);
10302103Sdg	write_eflags(ef);
10312103Sdg	return (0);
10322103Sdg}
1033