isa.c revision 13644
1139749Simp/*-
239234Sgibbs * Copyright (c) 1991 The Regents of the University of California.
339234Sgibbs * All rights reserved.
439234Sgibbs *
539234Sgibbs * This code is derived from software contributed to Berkeley by
639234Sgibbs * William Jolitz.
739234Sgibbs *
839234Sgibbs * Redistribution and use in source and binary forms, with or without
939234Sgibbs * modification, are permitted provided that the following conditions
1039234Sgibbs * are met:
1139234Sgibbs * 1. Redistributions of source code must retain the above copyright
1239234Sgibbs *    notice, this list of conditions and the following disclaimer.
1339234Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1439234Sgibbs *    notice, this list of conditions and the following disclaimer in the
1539234Sgibbs *    documentation and/or other materials provided with the distribution.
1639234Sgibbs * 3. All advertising materials mentioning features or use of this software
1739234Sgibbs *    must display the following acknowledgement:
1839234Sgibbs *	This product includes software developed by the University of
1939234Sgibbs *	California, Berkeley and its contributors.
2039234Sgibbs * 4. Neither the name of the University nor the names of its contributors
2139234Sgibbs *    may be used to endorse or promote products derived from this software
2239234Sgibbs *    without specific prior written permission.
2339234Sgibbs *
2439234Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2539234Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2639234Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2739234Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2839234Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29201807Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3039234Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3139234Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3239234Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3339234Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3439234Sgibbs * SUCH DAMAGE.
3539234Sgibbs *
3639234Sgibbs *	from: @(#)isa.c	7.2 (Berkeley) 5/13/91
3739234Sgibbs *	$Id: isa.c,v 1.61 1996/01/19 23:38:06 phk Exp $
3839234Sgibbs */
3939234Sgibbs
4039234Sgibbs/*
4139234Sgibbs * code to manage AT bus
4239234Sgibbs *
4339234Sgibbs * 92/08/18  Frank P. MacLachlan (fpm@crash.cts.com):
4439234Sgibbs * Fixed uninitialized variable problem and added code to deal
4539234Sgibbs * with DMA page boundaries in isa_dmarangecheck().  Fixed word
4639234Sgibbs * mode DMA count compution and reorganized DMA setup code in
4739234Sgibbs * isa_dmastart()
4839234Sgibbs */
4939234Sgibbs
5039234Sgibbs#include <sys/param.h>
5139234Sgibbs#include <sys/systm.h>
5239234Sgibbs#include <sys/sysctl.h>
5339234Sgibbs#include <sys/buf.h>
5439234Sgibbs#include <sys/syslog.h>
5539234Sgibbs#include <sys/malloc.h>
5639234Sgibbs#include <machine/segments.h>
5739234Sgibbs#include <vm/vm.h>
5839234Sgibbs#include <vm/vm_param.h>
5939234Sgibbs#include <vm/pmap.h>
6039234Sgibbs#include <machine/cpu.h>
6139234Sgibbs#include <i386/isa/isa_device.h>
6239234Sgibbs#include <i386/isa/isa.h>
6339234Sgibbs#include <i386/isa/icu.h>
6439234Sgibbs#include <i386/isa/ic/i8237.h>
6539234Sgibbs#include <sys/devconf.h>
6639234Sgibbs#include "vector.h"
6739234Sgibbs
6839234Sgibbs/*
6939234Sgibbs**  Register definitions for DMA controller 1 (channels 0..3):
7039234Sgibbs*/
7139234Sgibbs#define	DMA1_CHN(c)	(IO_DMA1 + 1*(2*(c)))	/* addr reg for channel c */
7239234Sgibbs#define	DMA1_SMSK	(IO_DMA1 + 1*10)	/* single mask register */
7339234Sgibbs#define	DMA1_MODE	(IO_DMA1 + 1*11)	/* mode register */
7439234Sgibbs#define	DMA1_FFC	(IO_DMA1 + 1*12)	/* clear first/last FF */
7539234Sgibbs
7639234Sgibbs/*
7739234Sgibbs**  Register definitions for DMA controller 2 (channels 4..7):
7839234Sgibbs*/
7939234Sgibbs#define	DMA2_CHN(c)	(IO_DMA2 + 2*(2*(c)))	/* addr reg for channel c */
8039234Sgibbs#define	DMA2_SMSK	(IO_DMA2 + 2*10)	/* single mask register */
8139234Sgibbs#define	DMA2_MODE	(IO_DMA2 + 2*11)	/* mode register */
8239234Sgibbs#define	DMA2_FFC	(IO_DMA2 + 2*12)	/* clear first/last FF */
8339234Sgibbs
8439234Sgibbsu_long	*intr_countp[ICU_LEN];
8539234Sgibbsinthand2_t *intr_handler[ICU_LEN];
8639234Sgibbsu_int	intr_mask[ICU_LEN];
8739234Sgibbsu_int*	intr_mptr[ICU_LEN];
8839234Sgibbsint	intr_unit[ICU_LEN];
8939234Sgibbs
9039515Sgibbsextern struct kern_devconf kdc_cpu0;
9139234Sgibbs
9239234Sgibbsstruct kern_devconf kdc_isa0 = {
9339234Sgibbs	0, 0, 0,		/* filled in by dev_attach */
9439234Sgibbs	"isa", 0, { MDDT_BUS, 0 },
9539234Sgibbs	0, 0, 0, BUS_EXTERNALLEN,
9639234Sgibbs	&kdc_cpu0,		/* parent is the CPU */
9739234Sgibbs	0,			/* no parentdata */
9839234Sgibbs	DC_BUSY,		/* busses are always busy */
9939234Sgibbs	"ISA or EISA bus",
10039234Sgibbs	DC_CLS_BUS		/* class */
10139234Sgibbs};
10239234Sgibbs
10339234Sgibbsstatic inthand_t *fastintr[ICU_LEN] = {
10439234Sgibbs	&IDTVEC(fastintr0), &IDTVEC(fastintr1),
10539234Sgibbs	&IDTVEC(fastintr2), &IDTVEC(fastintr3),
10639234Sgibbs	&IDTVEC(fastintr4), &IDTVEC(fastintr5),
10739234Sgibbs	&IDTVEC(fastintr6), &IDTVEC(fastintr7),
10839234Sgibbs	&IDTVEC(fastintr8), &IDTVEC(fastintr9),
10939234Sgibbs	&IDTVEC(fastintr10), &IDTVEC(fastintr11),
11039234Sgibbs	&IDTVEC(fastintr12), &IDTVEC(fastintr13),
11139234Sgibbs	&IDTVEC(fastintr14), &IDTVEC(fastintr15)
11239234Sgibbs};
11339234Sgibbs
11439234Sgibbsstatic inthand_t *slowintr[ICU_LEN] = {
11539234Sgibbs	&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
11639234Sgibbs	&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
11739234Sgibbs	&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
11839234Sgibbs	&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
11939234Sgibbs};
12039234Sgibbs
12139234Sgibbsstatic void config_isadev __P((struct isa_device *isdp, u_int *mp));
12239234Sgibbsstatic void config_isadev_c __P((struct isa_device *isdp, u_int *mp,
12339234Sgibbs				 int reconfig));
12439234Sgibbsstatic void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp,
12539234Sgibbs			  int item, char const *whatnot, char const *reason,
12639234Sgibbs			  char const *format));
12739234Sgibbsstatic int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp,
12839234Sgibbs			 u_int checkbits));
12939234Sgibbsstatic int isa_dmarangecheck __P((caddr_t va, unsigned length, unsigned chan));
13039234Sgibbsstatic inthand2_t isa_strayintr;
13139234Sgibbsstatic void register_imask __P((struct isa_device *dvp, u_int mask));
13239234Sgibbs
13339234Sgibbs/*
13439234Sgibbs * print a conflict message
13539234Sgibbs */
13639234Sgibbsstatic void
13739234Sgibbsconflict(dvp, tmpdvp, item, whatnot, reason, format)
13839234Sgibbs	struct isa_device	*dvp;
13939234Sgibbs	struct isa_device	*tmpdvp;
14039234Sgibbs	int			item;
14139234Sgibbs	char const		*whatnot;
14239234Sgibbs	char const		*reason;
14339234Sgibbs	char const		*format;
14439234Sgibbs{
145234540Sdim	printf("%s%d not %sed due to %s conflict with %s%d at ",
14639234Sgibbs		dvp->id_driver->name, dvp->id_unit, whatnot, reason,
14739234Sgibbs		tmpdvp->id_driver->name, tmpdvp->id_unit);
14839234Sgibbs	printf(format, item);
14939234Sgibbs	printf("\n");
15039234Sgibbs}
15139234Sgibbs
15239234Sgibbs/*
15339234Sgibbs * Check to see if things are already in use, like IRQ's, I/O addresses
15439234Sgibbs * and Memory addresses.
15539234Sgibbs */
15639234Sgibbsstatic int
15739234Sgibbshaveseen(dvp, tmpdvp, checkbits)
15839234Sgibbs	struct isa_device *dvp;
15939234Sgibbs	struct isa_device *tmpdvp;
16039234Sgibbs	u_int	checkbits;
16139234Sgibbs{
16239234Sgibbs	/*
16339234Sgibbs	 * Only check against devices that have already been found and are not
16439234Sgibbs	 * unilaterally allowed to conflict anyway.
16539234Sgibbs	 */
16639234Sgibbs	if (tmpdvp->id_alive && !dvp->id_conflicts) {
16739234Sgibbs		char const *whatnot;
16839234Sgibbs
16939234Sgibbs		whatnot = checkbits & CC_ATTACH ? "attach" : "prob";
17039234Sgibbs		/*
17139234Sgibbs		 * Check for I/O address conflict.  We can only check the
17239234Sgibbs		 * starting address of the device against the range of the
17339234Sgibbs		 * device that has already been probed since we do not
17439234Sgibbs		 * know how many I/O addresses this device uses.
17539234Sgibbs		 */
17639234Sgibbs		if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) {
17739234Sgibbs			if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
17839234Sgibbs			    (dvp->id_iobase <=
17939234Sgibbs				  (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
18039234Sgibbs				conflict(dvp, tmpdvp, dvp->id_iobase, whatnot,
18139234Sgibbs					 "I/O address", "0x%x");
18239234Sgibbs				return 1;
18339234Sgibbs			}
18439234Sgibbs		}
18539234Sgibbs		/*
18639234Sgibbs		 * Check for Memory address conflict.  We can check for
18739234Sgibbs		 * range overlap, but it will not catch all cases since the
18839234Sgibbs		 * driver may adjust the msize paramater during probe, for
18939234Sgibbs		 * now we just check that the starting address does not
19039234Sgibbs		 * fall within any allocated region.
19139234Sgibbs		 * XXX could add a second check after the probe for overlap,
19239234Sgibbs		 * since at that time we would know the full range.
19339234Sgibbs		 * XXX KERNBASE is a hack, we should have vaddr in the table!
19439234Sgibbs		 */
19539234Sgibbs		if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) {
19639234Sgibbs			if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
19739234Sgibbs			    (KERNBASE + dvp->id_maddr <=
19839234Sgibbs			     (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
19939234Sgibbs				conflict(dvp, tmpdvp, (int)dvp->id_maddr,
20039234Sgibbs					 whatnot, "maddr", "0x%x");
20139234Sgibbs				return 1;
20239234Sgibbs			}
20339234Sgibbs		}
20439234Sgibbs		/*
20539234Sgibbs		 * Check for IRQ conflicts.
20639234Sgibbs		 */
20739234Sgibbs		if (checkbits & CC_IRQ && tmpdvp->id_irq) {
20839234Sgibbs			if (tmpdvp->id_irq == dvp->id_irq) {
20939234Sgibbs				conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1,
21039234Sgibbs					 whatnot, "irq", "%d");
21139234Sgibbs				return 1;
21239234Sgibbs			}
21339234Sgibbs		}
21439234Sgibbs		/*
21539234Sgibbs		 * Check for DRQ conflicts.
21639234Sgibbs		 */
21739234Sgibbs		if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) {
21839234Sgibbs			if (tmpdvp->id_drq == dvp->id_drq) {
21939234Sgibbs				conflict(dvp, tmpdvp, dvp->id_drq, whatnot,
22039234Sgibbs					 "drq", "%d");
22139234Sgibbs				return 1;
22239234Sgibbs			}
22339234Sgibbs		}
22489056Smsmith	}
22539234Sgibbs	return 0;
22639234Sgibbs}
22739234Sgibbs
22839234Sgibbs/*
22939234Sgibbs * Search through all the isa_devtab_* tables looking for anything that
23039234Sgibbs * conflicts with the current device.
23139234Sgibbs */
23239234Sgibbsint
23339234Sgibbshaveseen_isadev(dvp, checkbits)
23439234Sgibbs	struct isa_device *dvp;
23539234Sgibbs	u_int	checkbits;
23689056Smsmith{
23739234Sgibbs	struct isa_device *tmpdvp;
23839234Sgibbs	int	status = 0;
23939234Sgibbs
24039234Sgibbs	for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
24139234Sgibbs		status |= haveseen(dvp, tmpdvp, checkbits);
24239234Sgibbs		if (status)
24339234Sgibbs			return status;
24439234Sgibbs	}
24539234Sgibbs	for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
24639234Sgibbs		status |= haveseen(dvp, tmpdvp, checkbits);
24739234Sgibbs		if (status)
24839234Sgibbs			return status;
24939234Sgibbs	}
25039234Sgibbs	for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
25139234Sgibbs		status |= haveseen(dvp, tmpdvp, checkbits);
25239234Sgibbs		if (status)
25339234Sgibbs			return status;
25439234Sgibbs	}
25539234Sgibbs	for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
25639234Sgibbs		status |= haveseen(dvp, tmpdvp, checkbits);
25739234Sgibbs		if (status)
25839234Sgibbs			return status;
25939234Sgibbs	}
26039234Sgibbs	return(status);
26139234Sgibbs}
26239234Sgibbs
26339234Sgibbs/*
26439234Sgibbs * Configure all ISA devices
26539234Sgibbs */
26639234Sgibbsvoid
26739234Sgibbsisa_configure() {
26839234Sgibbs	struct isa_device *dvp;
26939234Sgibbs
27039234Sgibbs	dev_attach(&kdc_isa0);
27139234Sgibbs
27239234Sgibbs	splhigh();
27339234Sgibbs	enable_intr();
27489056Smsmith	INTREN(IRQ_SLAVE);
27539234Sgibbs	printf("Probing for devices on the ISA bus:\n");
27639234Sgibbs	/* First probe all the sensitive probes */
27739234Sgibbs	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
27839234Sgibbs		if (dvp->id_driver->sensitive_hw)
27939234Sgibbs			config_isadev(dvp, &tty_imask);
28039234Sgibbs	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
28139234Sgibbs		if (dvp->id_driver->sensitive_hw)
28239234Sgibbs			config_isadev(dvp, &bio_imask);
28339234Sgibbs	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
28439234Sgibbs		if (dvp->id_driver->sensitive_hw)
28539234Sgibbs			config_isadev(dvp, &net_imask);
28639234Sgibbs	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
28739234Sgibbs		if (dvp->id_driver->sensitive_hw)
28839234Sgibbs			config_isadev(dvp, (u_int *)NULL);
28939234Sgibbs
29039234Sgibbs	/* Then all the bad ones */
29139234Sgibbs	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
29239234Sgibbs		if (!dvp->id_driver->sensitive_hw)
29339234Sgibbs			config_isadev(dvp, &tty_imask);
29439234Sgibbs	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
29539234Sgibbs		if (!dvp->id_driver->sensitive_hw)
29639234Sgibbs			config_isadev(dvp, &bio_imask);
29789056Smsmith	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
29839234Sgibbs		if (!dvp->id_driver->sensitive_hw)
29939234Sgibbs			config_isadev(dvp, &net_imask);
30039234Sgibbs	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
30139234Sgibbs		if (!dvp->id_driver->sensitive_hw)
30239234Sgibbs			config_isadev(dvp, (u_int *)NULL);
30339234Sgibbs
30439234Sgibbs	bio_imask |= SWI_CLOCK_MASK;
30539234Sgibbs	net_imask |= SWI_NET_MASK;
30639234Sgibbs	tty_imask |= SWI_TTY_MASK;
30739234Sgibbs
30839234Sgibbs/*
30939234Sgibbs * XXX we should really add the tty device to net_imask when the line is
31039234Sgibbs * switched to SLIPDISC, and then remove it when it is switched away from
31139234Sgibbs * SLIPDISC.  No need to block out ALL ttys during a splimp when only one
31239234Sgibbs * of them is running slip.
31339234Sgibbs *
31439234Sgibbs * XXX actually, blocking all ttys during a splimp doesn't matter so much
31539234Sgibbs * with sio because the serial interrupt layer doesn't use tty_imask.  Only
31639234Sgibbs * non-serial ttys suffer.  It's more stupid that ALL 'net's are blocked
31739234Sgibbs * during spltty.
31839234Sgibbs */
31939234Sgibbs#include "sl.h"
32039234Sgibbs#if NSL > 0
32139234Sgibbs	net_imask |= tty_imask;
32239234Sgibbs	tty_imask = net_imask;
32339234Sgibbs#endif
32439234Sgibbs
32539234Sgibbs	/* bio_imask |= tty_imask ;  can some tty devices use buffers? */
32639234Sgibbs
32739234Sgibbs	if (bootverbose)
32839234Sgibbs		printf("imasks: bio %x, tty %x, net %x\n",
32939234Sgibbs		       bio_imask, tty_imask, net_imask);
33039234Sgibbs
33139234Sgibbs	/*
33239234Sgibbs	 * Finish initializing intr_mask[].  Note that the partly
33339234Sgibbs	 * constructed masks aren't actually used since we're at splhigh.
33439234Sgibbs	 * For fully dynamic initialization, register_intr() and
33539234Sgibbs	 * unregister_intr() will have to adjust the masks for _all_
33639234Sgibbs	 * interrupts and for tty_imask, etc.
33739234Sgibbs	 */
33839234Sgibbs	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
33939234Sgibbs		register_imask(dvp, tty_imask);
34039234Sgibbs	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
34139234Sgibbs		register_imask(dvp, bio_imask);
34239234Sgibbs	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
34339234Sgibbs		register_imask(dvp, net_imask);
34439234Sgibbs	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
34539234Sgibbs		register_imask(dvp, SWI_CLOCK_MASK);
34639234Sgibbs	spl0();
34739234Sgibbs}
34839234Sgibbs
34939234Sgibbs/*
35039234Sgibbs * Configure an ISA device.
35139234Sgibbs */
35239234Sgibbs
35339234Sgibbs
35439234Sgibbsstatic void
35539234Sgibbsconfig_isadev(isdp, mp)
35639234Sgibbs     struct isa_device *isdp;
35739234Sgibbs     u_int *mp;
35839234Sgibbs{
35939234Sgibbs	config_isadev_c(isdp, mp, 0);
36039234Sgibbs}
36139234Sgibbs
36239234Sgibbsvoid
36339234Sgibbsreconfig_isadev(isdp, mp)
36439234Sgibbs	struct isa_device *isdp;
36539234Sgibbs	u_int *mp;
36639234Sgibbs{
36739234Sgibbs	config_isadev_c(isdp, mp, 1);
36839234Sgibbs}
36939234Sgibbs
37039234Sgibbsstatic void
37139234Sgibbsconfig_isadev_c(isdp, mp, reconfig)
37239234Sgibbs	struct isa_device *isdp;
37339234Sgibbs	u_int *mp;
37439234Sgibbs	int reconfig;
37539234Sgibbs{
37639234Sgibbs	u_int checkbits;
37739234Sgibbs	int id_alive;
37839234Sgibbs	int last_alive;
37939234Sgibbs	struct isa_driver *dp = isdp->id_driver;
38039234Sgibbs
38139234Sgibbs	if (!isdp->id_enabled) {
38239234Sgibbs		printf("%s%d: disabled, not probed.\n",
38339234Sgibbs			dp->name, isdp->id_unit);
38439234Sgibbs		return;
38539234Sgibbs	}
38639234Sgibbs	checkbits = CC_DRQ | CC_IOADDR | CC_MEMADDR;
38739234Sgibbs	if (!reconfig && haveseen_isadev(isdp, checkbits))
38839234Sgibbs		return;
38939234Sgibbs	if (!reconfig && isdp->id_maddr) {
39039234Sgibbs		isdp->id_maddr -= 0xa0000; /* XXX should be a define */
39139234Sgibbs		isdp->id_maddr += atdevbase;
39239234Sgibbs	}
39339234Sgibbs	if (reconfig) {
39439234Sgibbs		last_alive = isdp->id_alive;
39539234Sgibbs		isdp->id_reconfig = 1;
39639234Sgibbs	}
39739234Sgibbs	else {
39839234Sgibbs		last_alive = 0;
39939234Sgibbs		isdp->id_reconfig = 0;
40039234Sgibbs	}
40139234Sgibbs	id_alive = (*dp->probe)(isdp);
40239234Sgibbs	if (id_alive) {
40339234Sgibbs		/*
40439234Sgibbs		 * Only print the I/O address range if id_alive != -1
40539234Sgibbs		 * Right now this is a temporary fix just for the new
40639234Sgibbs		 * NPX code so that if it finds a 486 that can use trap
40739234Sgibbs		 * 16 it will not report I/O addresses.
40839234Sgibbs		 * Rod Grimes 04/26/94
40939234Sgibbs		 */
41039234Sgibbs		if (!isdp->id_reconfig) {
41139234Sgibbs			printf("%s%d", dp->name, isdp->id_unit);
41239234Sgibbs			if (id_alive != -1) {
41339234Sgibbs				printf(" at 0x%x", isdp->id_iobase);
41439234Sgibbs				if (isdp->id_iobase + id_alive - 1 !=
41539234Sgibbs				    isdp->id_iobase) {
41639234Sgibbs					printf("-0x%x",
41739234Sgibbs					       isdp->id_iobase + id_alive - 1);
41839234Sgibbs				}
41939234Sgibbs			}
42039234Sgibbs			if (isdp->id_irq)
42139234Sgibbs				printf(" irq %d", ffs(isdp->id_irq) - 1);
42239234Sgibbs			if (isdp->id_drq != -1)
42339234Sgibbs				printf(" drq %d", isdp->id_drq);
42439234Sgibbs			if (isdp->id_maddr)
42539234Sgibbs				printf(" maddr 0x%lx", kvtop(isdp->id_maddr));
42639234Sgibbs			if (isdp->id_msize)
42739234Sgibbs				printf(" msize %d", isdp->id_msize);
42839234Sgibbs			if (isdp->id_flags)
42939234Sgibbs				printf(" flags 0x%x", isdp->id_flags);
43039234Sgibbs			if (isdp->id_iobase && !(isdp->id_iobase & 0xf300)) {
43139234Sgibbs				printf(" on motherboard");
43239234Sgibbs			} else if (isdp->id_iobase >= 0x1000 &&
43339234Sgibbs				    !(isdp->id_iobase & 0x300)) {
43439234Sgibbs				printf (" on eisa slot %d",
43539234Sgibbs					isdp->id_iobase >> 12);
43639234Sgibbs			} else {
43739234Sgibbs				printf (" on isa");
43839234Sgibbs			}
43939234Sgibbs			printf("\n");
44039234Sgibbs			/*
44139234Sgibbs			 * Check for conflicts again.  The driver may have
44239234Sgibbs			 * changed *dvp.  We should weaken the early check
44339234Sgibbs			 * since the driver may have been able to change
44439234Sgibbs			 * *dvp to avoid conflicts if given a chance.  We
44539234Sgibbs			 * already skip the early check for IRQs and force
44639234Sgibbs			 * a check for IRQs in the next group of checks.
44739234Sgibbs			 */
44839234Sgibbs			checkbits |= CC_IRQ;
44939234Sgibbs			if (haveseen_isadev(isdp, checkbits))
45039234Sgibbs				return;
45139234Sgibbs			isdp->id_alive = id_alive;
45239234Sgibbs		}
45339234Sgibbs		(*dp->attach)(isdp);
45439234Sgibbs		if (isdp->id_irq) {
45539234Sgibbs			if (mp)
45639234Sgibbs				INTRMASK(*mp, isdp->id_irq);
45739234Sgibbs			register_intr(ffs(isdp->id_irq) - 1, isdp->id_id,
45839234Sgibbs				      isdp->id_ri_flags, isdp->id_intr,
45939234Sgibbs				      mp, isdp->id_unit);
46039234Sgibbs			INTREN(isdp->id_irq);
46139234Sgibbs		}
46239234Sgibbs	} else {
46339234Sgibbs		if (isdp->id_reconfig) {
46439234Sgibbs			(*dp->attach)(isdp); /* reconfiguration attach */
46539234Sgibbs		}
46639234Sgibbs		if (!last_alive) {
46739234Sgibbs			if (!isdp->id_reconfig) {
46839234Sgibbs				printf("%s%d not found",
46939234Sgibbs				       dp->name, isdp->id_unit);
47039234Sgibbs				if (isdp->id_iobase) {
47139234Sgibbs					printf(" at 0x%x", isdp->id_iobase);
47239234Sgibbs				}
47339234Sgibbs				printf("\n");
47439234Sgibbs			}
47539234Sgibbs		}
47639234Sgibbs		else {
47739234Sgibbs			/* This code has not been tested.... */
47839234Sgibbs			if (isdp->id_irq) {
47939234Sgibbs				INTRDIS(isdp->id_irq);
48039234Sgibbs				unregister_intr(ffs(isdp->id_irq) - 1,
48139234Sgibbs						isdp->id_intr);
48239234Sgibbs				if (mp)
48339234Sgibbs					INTRUNMASK(*mp, isdp->id_irq);
48439234Sgibbs			}
48539234Sgibbs		}
48639234Sgibbs	}
48739234Sgibbs}
48839234Sgibbs
48939234Sgibbs/*
49039234Sgibbs * Provide ISA-specific device information to user programs using the
49139234Sgibbs * hw.devconf interface.
49239234Sgibbs */
49339234Sgibbsint
49439234Sgibbsisa_externalize(struct isa_device *id, struct sysctl_req *req)
49539234Sgibbs{
49639234Sgibbs	return (SYSCTL_OUT(req, id, sizeof *id));
49739234Sgibbs}
49839234Sgibbs
49939234Sgibbs/*
50039234Sgibbs * This is used to forcibly reconfigure an ISA device.  It currently just
50139234Sgibbs * returns an error 'cos you can't do that yet.  It is here to demonstrate
50239234Sgibbs * what the `internalize' routine is supposed to do.
50339234Sgibbs */
50439234Sgibbsint
50539234Sgibbsisa_internalize(struct isa_device *id, struct sysctl_req *req)
50639234Sgibbs{
50739234Sgibbs	struct isa_device myid;
50839234Sgibbs	int rv;
50939234Sgibbs
51039234Sgibbs	rv = SYSCTL_IN(req, &myid, sizeof *id);
51139234Sgibbs	if(rv)
51239234Sgibbs		return rv;
51339234Sgibbs
51439234Sgibbs	rv = EOPNOTSUPP;
51539234Sgibbs	/* code would go here to validate the configuration request */
51639234Sgibbs	/* code would go here to actually perform the reconfiguration */
51739234Sgibbs	return rv;
51839234Sgibbs}
51939234Sgibbs
52039234Sgibbsint
52139234Sgibbsisa_generic_externalize(struct kern_devconf *kdc, struct sysctl_req *req)
52239234Sgibbs{
52339234Sgibbs	return isa_externalize(kdc->kdc_isa, req);
52439234Sgibbs}
52539234Sgibbs
52639234Sgibbs/*
52739234Sgibbs * Fill in default interrupt table (in case of spuruious interrupt
52839234Sgibbs * during configuration of kernel, setup interrupt control unit
52939234Sgibbs */
53039234Sgibbsvoid
53139234Sgibbsisa_defaultirq()
53239234Sgibbs{
53339234Sgibbs	int i;
53439234Sgibbs
53539234Sgibbs	/* icu vectors */
53639234Sgibbs	for (i = 0; i < ICU_LEN; i++)
53739234Sgibbs		unregister_intr(i, (inthand2_t *)NULL);
53839234Sgibbs
53939234Sgibbs	/* initialize 8259's */
54039234Sgibbs	outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
54139234Sgibbs	outb(IO_ICU1+1, NRSVIDT);	/* starting at this vector index */
54239234Sgibbs	outb(IO_ICU1+1, 1<<2);		/* slave on line 2 */
54339234Sgibbs#ifdef AUTO_EOI_1
54439234Sgibbs	outb(IO_ICU1+1, 2 | 1);		/* auto EOI, 8086 mode */
54539234Sgibbs#else
54639234Sgibbs	outb(IO_ICU1+1, 1);		/* 8086 mode */
54739234Sgibbs#endif
54839234Sgibbs	outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
54939234Sgibbs	outb(IO_ICU1, 0x0a);		/* default to IRR on read */
55039234Sgibbs	outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
55139234Sgibbs
55239234Sgibbs	outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
55339234Sgibbs	outb(IO_ICU2+1, NRSVIDT+8);	/* staring at this vector index */
55439234Sgibbs	outb(IO_ICU2+1,2);		/* my slave id is 2 */
55539234Sgibbs#ifdef AUTO_EOI_2
55639234Sgibbs	outb(IO_ICU2+1, 2 | 1);		/* auto EOI, 8086 mode */
55739234Sgibbs#else
55839234Sgibbs	outb(IO_ICU2+1,1);		/* 8086 mode */
55939234Sgibbs#endif
56039234Sgibbs	outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
56139234Sgibbs	outb(IO_ICU2, 0x0a);		/* default to IRR on read */
56239234Sgibbs}
56339234Sgibbs
56439234Sgibbs/* region of physical memory known to be contiguous */
56539234Sgibbsvm_offset_t isaphysmem;
56639234Sgibbsstatic caddr_t dma_bounce[8];		/* XXX */
56739234Sgibbsstatic char bounced[8];		/* XXX */
56839234Sgibbs#define MAXDMASZ 512		/* XXX */
56939234Sgibbs
57039234Sgibbs/* high byte of address is stored in this port for i-th dma channel */
57139234Sgibbsstatic short dmapageport[8] =
57239234Sgibbs	{ 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
57339234Sgibbs
57439234Sgibbs/*
57539234Sgibbs * isa_dmacascade(): program 8237 DMA controller channel to accept
57639234Sgibbs * external dma control by a board.
57739234Sgibbs */
57839234Sgibbsvoid isa_dmacascade(unsigned chan)
57939234Sgibbs{
58039234Sgibbs	if (chan > 7)
58139234Sgibbs		panic("isa_dmacascade: impossible request");
58239234Sgibbs
58339234Sgibbs	/* set dma channel mode, and set dma channel mode */
58439234Sgibbs	if ((chan & 4) == 0) {
58539234Sgibbs		outb(DMA1_MODE, DMA37MD_CASCADE | chan);
58639234Sgibbs		outb(DMA1_SMSK, chan);
58739234Sgibbs	} else {
58839234Sgibbs		outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
58939234Sgibbs		outb(DMA2_SMSK, chan & 3);
59039234Sgibbs	}
59139234Sgibbs}
59239234Sgibbs
59339234Sgibbs/*
59439234Sgibbs * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
59539234Sgibbs * problems by using a bounce buffer.
59639234Sgibbs */
59739234Sgibbsvoid isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
59839234Sgibbs{	vm_offset_t phys;
59939234Sgibbs	int waport;
60039234Sgibbs	caddr_t newaddr;
60139234Sgibbs
60239234Sgibbs	if (    chan > 7
60339234Sgibbs	    || (chan < 4 && nbytes > (1<<16))
60439234Sgibbs	    || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
60539553Sgibbs		panic("isa_dmastart: impossible request");
60639234Sgibbs
60739234Sgibbs	if (isa_dmarangecheck(addr, nbytes, chan)) {
60839234Sgibbs		if (dma_bounce[chan] == 0)
60939234Sgibbs			dma_bounce[chan] =
61039234Sgibbs				(caddr_t) isaphysmem + NBPG*chan;
61139234Sgibbs		bounced[chan] = 1;
61239234Sgibbs		newaddr = dma_bounce[chan];
61339234Sgibbs		*(int *) newaddr = 0;	/* XXX */
61439234Sgibbs
61539234Sgibbs		/* copy bounce buffer on write */
61639234Sgibbs		if (!(flags & B_READ))
61739234Sgibbs			bcopy(addr, newaddr, nbytes);
61839234Sgibbs		addr = newaddr;
61939234Sgibbs	}
62039234Sgibbs
62139234Sgibbs	/* translate to physical */
62239234Sgibbs	phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
62339234Sgibbs
62439234Sgibbs	if ((chan & 4) == 0) {
62539234Sgibbs		/*
62639234Sgibbs		 * Program one of DMA channels 0..3.  These are
62739234Sgibbs		 * byte mode channels.
62839234Sgibbs		 */
62939234Sgibbs		/* set dma channel mode, and reset address ff */
63039234Sgibbs
63139234Sgibbs		/* If B_RAW flag is set, then use autoinitialise mode */
63239234Sgibbs		if (flags & B_RAW) {
63339234Sgibbs		  if (flags & B_READ)
63439234Sgibbs			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
63539234Sgibbs		  else
63639234Sgibbs			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
63739234Sgibbs		}
63839234Sgibbs		else
63939234Sgibbs		if (flags & B_READ)
64039234Sgibbs			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
64139234Sgibbs		else
64239234Sgibbs			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
64339234Sgibbs		outb(DMA1_FFC, 0);
64439234Sgibbs
64539234Sgibbs		/* send start address */
64639234Sgibbs		waport =  DMA1_CHN(chan);
64739234Sgibbs		outb(waport, phys);
64839234Sgibbs		outb(waport, phys>>8);
64939234Sgibbs		outb(dmapageport[chan], phys>>16);
65039234Sgibbs
65139234Sgibbs		/* send count */
65239234Sgibbs		outb(waport + 1, --nbytes);
65339234Sgibbs		outb(waport + 1, nbytes>>8);
65439234Sgibbs
65539234Sgibbs		/* unmask channel */
65639234Sgibbs		outb(DMA1_SMSK, chan);
65739234Sgibbs	} else {
65839234Sgibbs		/*
65939234Sgibbs		 * Program one of DMA channels 4..7.  These are
66039234Sgibbs		 * word mode channels.
66139234Sgibbs		 */
66239234Sgibbs		/* set dma channel mode, and reset address ff */
66339234Sgibbs
66439234Sgibbs		/* If B_RAW flag is set, then use autoinitialise mode */
66539234Sgibbs		if (flags & B_RAW) {
66639234Sgibbs		  if (flags & B_READ)
66739234Sgibbs			outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3));
66839234Sgibbs		  else
66939234Sgibbs			outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3));
67039234Sgibbs		}
67139234Sgibbs		else
67239234Sgibbs		if (flags & B_READ)
67339234Sgibbs			outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
67439234Sgibbs		else
67539234Sgibbs			outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
67639234Sgibbs		outb(DMA2_FFC, 0);
67739234Sgibbs
67839234Sgibbs		/* send start address */
67939234Sgibbs		waport = DMA2_CHN(chan - 4);
68039234Sgibbs		outb(waport, phys>>1);
68139234Sgibbs		outb(waport, phys>>9);
68239234Sgibbs		outb(dmapageport[chan], phys>>16);
68339234Sgibbs
68439234Sgibbs		/* send count */
68539234Sgibbs		nbytes >>= 1;
68639234Sgibbs		outb(waport + 2, --nbytes);
68739234Sgibbs		outb(waport + 2, nbytes>>8);
68839234Sgibbs
68939234Sgibbs		/* unmask channel */
69039234Sgibbs		outb(DMA2_SMSK, chan & 3);
69139234Sgibbs	}
69239234Sgibbs}
69339234Sgibbs
69439234Sgibbsvoid isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
69539234Sgibbs{
69639234Sgibbs
69739234Sgibbs	/* copy bounce buffer on read */
69839234Sgibbs	/*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
69939234Sgibbs	if (bounced[chan]) {
70039234Sgibbs		bcopy(dma_bounce[chan], addr, nbytes);
70139234Sgibbs		bounced[chan] = 0;
70239234Sgibbs	}
70339234Sgibbs}
70439234Sgibbs
70539234Sgibbs/*
70639234Sgibbs * Check for problems with the address range of a DMA transfer
70739234Sgibbs * (non-contiguous physical pages, outside of bus address space,
70839234Sgibbs * crossing DMA page boundaries).
70939234Sgibbs * Return true if special handling needed.
71039234Sgibbs */
71139234Sgibbs
71239234Sgibbsstatic int
71339234Sgibbsisa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
71439234Sgibbs	vm_offset_t phys, priorpage = 0, endva;
71539234Sgibbs	u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
71639234Sgibbs
71739234Sgibbs	endva = (vm_offset_t)round_page(va + length);
71839234Sgibbs	for (; va < (caddr_t) endva ; va += NBPG) {
71939234Sgibbs		phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
72039234Sgibbs#define ISARAM_END	RAM_END
72139234Sgibbs		if (phys == 0)
72239234Sgibbs			panic("isa_dmacheck: no physical page present");
72339234Sgibbs		if (phys >= ISARAM_END)
72439234Sgibbs			return (1);
72539234Sgibbs		if (priorpage) {
72639234Sgibbs			if (priorpage + NBPG != phys)
72739234Sgibbs				return (1);
72839234Sgibbs			/* check if crossing a DMA page boundary */
72939234Sgibbs			if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
73039234Sgibbs				return (1);
73139234Sgibbs		}
73239234Sgibbs		priorpage = phys;
73339234Sgibbs	}
73439234Sgibbs	return (0);
73539234Sgibbs}
73639234Sgibbs
73739234Sgibbs#define NMI_PARITY (1 << 7)
73839234Sgibbs#define NMI_IOCHAN (1 << 6)
73939234Sgibbs#define ENMI_WATCHDOG (1 << 7)
74039234Sgibbs#define ENMI_BUSTIMER (1 << 6)
74139234Sgibbs#define ENMI_IOSTATUS (1 << 5)
74239234Sgibbs
74339234Sgibbs/*
74439234Sgibbs * Handle a NMI, possibly a machine check.
74539234Sgibbs * return true to panic system, false to ignore.
74639234Sgibbs */
74739234Sgibbsint
74839234Sgibbsisa_nmi(cd)
74939234Sgibbs	int cd;
75039234Sgibbs{
75139234Sgibbs	int isa_port = inb(0x61);
75239234Sgibbs	int eisa_port = inb(0x461);
75339234Sgibbs	if(isa_port & NMI_PARITY) {
75439234Sgibbs		panic("RAM parity error, likely hardware failure.");
75539234Sgibbs	} else if(isa_port & NMI_IOCHAN) {
75639234Sgibbs		panic("I/O channel check, likely hardware failure.");
75739234Sgibbs	} else if(eisa_port & ENMI_WATCHDOG) {
75839234Sgibbs		panic("EISA watchdog timer expired, likely hardware failure.");
75939234Sgibbs	} else if(eisa_port & ENMI_BUSTIMER) {
76039234Sgibbs		panic("EISA bus timeout, likely hardware failure.");
76139234Sgibbs	} else if(eisa_port & ENMI_IOSTATUS) {
76239234Sgibbs		panic("EISA I/O port status error.");
76339234Sgibbs	} else {
76439234Sgibbs		printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
76539234Sgibbs		return(0);
76639234Sgibbs	}
76739234Sgibbs}
76839234Sgibbs
76939234Sgibbs/*
77039234Sgibbs * Caught a stray interrupt, notify
77139234Sgibbs */
77239234Sgibbsstatic void
77339234Sgibbsisa_strayintr(d)
77439234Sgibbs	int d;
77539234Sgibbs{
77639234Sgibbs
77739234Sgibbs	/* DON'T BOTHER FOR NOW! */
77839234Sgibbs	/* for some reason, we get bursts of intr #7, even if not enabled! */
77939234Sgibbs	/*
78039234Sgibbs	 * Well the reason you got bursts of intr #7 is because someone
78139234Sgibbs	 * raised an interrupt line and dropped it before the 8259 could
78239234Sgibbs	 * prioritize it.  This is documented in the intel data book.  This
78339234Sgibbs	 * means you have BAD hardware!  I have changed this so that only
78439234Sgibbs	 * the first 5 get logged, then it quits logging them, and puts
78539234Sgibbs	 * out a special message. rgrimes 3/25/1993
78639234Sgibbs	 */
78739234Sgibbs	/*
78839234Sgibbs	 * XXX TODO print a different message for #7 if it is for a
78939234Sgibbs	 * glitch.  Glitches can be distinguished from real #7's by
79039234Sgibbs	 * testing that the in-service bit is _not_ set.  The test
79139234Sgibbs	 * must be done before sending an EOI so it can't be done if
79239234Sgibbs	 * we are using AUTO_EOI_1.
79339234Sgibbs	 */
79439234Sgibbs	if (intrcnt[NR_DEVICES + d] <= 5)
79539234Sgibbs		log(LOG_ERR, "stray irq %d\n", d);
79639234Sgibbs	if (intrcnt[NR_DEVICES + d] == 5)
79739234Sgibbs		log(LOG_CRIT,
79839234Sgibbs		    "too many stray irq %d's; not logging any more\n", d);
79939234Sgibbs}
80039234Sgibbs
80139234Sgibbs/*
80239234Sgibbs * Find the highest priority enabled display device.  Since we can't
80339234Sgibbs * distinguish display devices from ttys, depend on display devices
80439234Sgibbs * being sensitive and before sensitive non-display devices (if any)
80539234Sgibbs * in isa_devtab_tty.
80639234Sgibbs *
80739234Sgibbs * XXX we should add capability flags IAMDISPLAY and ISUPPORTCONSOLES.
80839234Sgibbs */
80939234Sgibbsstruct isa_device *
81039234Sgibbsfind_display()
81139234Sgibbs{
81239234Sgibbs	struct isa_device *dvp;
81339234Sgibbs
81439234Sgibbs	for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
81539234Sgibbs		if (dvp->id_driver->sensitive_hw && dvp->id_enabled)
81639234Sgibbs			return (dvp);
81739234Sgibbs	return (NULL);
81839234Sgibbs}
81939234Sgibbs
82039234Sgibbs/*
82139234Sgibbs * find an ISA device in a given isa_devtab_* table, given
82239234Sgibbs * the table to search, the expected id_driver entry, and the unit number.
82339234Sgibbs *
82439234Sgibbs * this function is defined in isa_device.h, and this location is debatable;
82539234Sgibbs * i put it there because it's useless w/o, and directly operates on
82639234Sgibbs * the other stuff in that file.
82739234Sgibbs *
82839234Sgibbs */
82939234Sgibbs
83039234Sgibbsstruct isa_device *find_isadev(table, driverp, unit)
83139234Sgibbs     struct isa_device *table;
83239234Sgibbs     struct isa_driver *driverp;
83339234Sgibbs     int unit;
83439234Sgibbs{
83539234Sgibbs  if (driverp == NULL) /* sanity check */
83639234Sgibbs    return NULL;
83739234Sgibbs
83839234Sgibbs  while ((table->id_driver != driverp) || (table->id_unit != unit)) {
83939234Sgibbs    if (table->id_driver == 0)
84039234Sgibbs      return NULL;
84139234Sgibbs
84239234Sgibbs    table++;
84339234Sgibbs  }
84439234Sgibbs
84539234Sgibbs  return table;
84639234Sgibbs}
84739234Sgibbs
84839234Sgibbs/*
84939234Sgibbs * Return nonzero if a (masked) irq is pending for a given device.
85039234Sgibbs */
85139234Sgibbsint
85239234Sgibbsisa_irq_pending(dvp)
85339234Sgibbs	struct isa_device *dvp;
85439234Sgibbs{
85539234Sgibbs	unsigned id_irq;
85639234Sgibbs
85739234Sgibbs	id_irq = dvp->id_irq;
85839234Sgibbs	if (id_irq & 0xff)
85939234Sgibbs		return (inb(IO_ICU1) & id_irq);
86039234Sgibbs	return (inb(IO_ICU2) & (id_irq >> 8));
86139234Sgibbs}
86239234Sgibbs
86339234Sgibbsint
86439234Sgibbsupdate_intr_masks(void)
86539234Sgibbs{
86639234Sgibbs	int intr, n=0;
86739234Sgibbs	u_int mask,*maskptr;
86839234Sgibbs
86939234Sgibbs	for (intr=0; intr < ICU_LEN; intr ++) {
87039234Sgibbs		if (intr==2) continue;
87139234Sgibbs		maskptr = intr_mptr[intr];
87239234Sgibbs		if (!maskptr) continue;
87339234Sgibbs		*maskptr |= 1 << intr;
87439234Sgibbs		mask = *maskptr;
87539234Sgibbs		if (mask != intr_mask[intr]) {
87639234Sgibbs#if 0
87739234Sgibbs			printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
87839234Sgibbs				intr, intr_mask[intr], mask, maskptr);
879241593Sjhb#endif
88039234Sgibbs			intr_mask[intr]=mask;
88139234Sgibbs			n++;
88239234Sgibbs		}
88339234Sgibbs
88439234Sgibbs	}
88539515Sgibbs	return (n);
88639234Sgibbs}
88739515Sgibbs
88839515Sgibbsint
88939234Sgibbsregister_intr(intr, device_id, flags, handler, maskptr, unit)
89039234Sgibbs	int	intr;
89139234Sgibbs	int	device_id;
89239234Sgibbs	u_int	flags;
89360938Sjake	inthand2_t *handler;
89439234Sgibbs	u_int	*maskptr;
89539234Sgibbs	int	unit;
89639234Sgibbs{
89739234Sgibbs	char	*cp;
89839234Sgibbs	u_long	ef;
89939234Sgibbs	int	id;
90039234Sgibbs	u_int	mask = (maskptr ? *maskptr : 0);
90139234Sgibbs
90239234Sgibbs	if ((u_int)intr >= ICU_LEN || intr == 2
90372093Sasmodai	    || (u_int)device_id >= NR_DEVICES)
90439234Sgibbs		return (EINVAL);
90539234Sgibbs	if (intr_handler[intr] != isa_strayintr)
90639234Sgibbs		return (EBUSY);
90739234Sgibbs	ef = read_eflags();
90839234Sgibbs	disable_intr();
90939234Sgibbs	intr_countp[intr] = &intrcnt[device_id];
91039234Sgibbs	intr_handler[intr] = handler;
91139234Sgibbs	intr_mptr[intr] = maskptr;
91239234Sgibbs	intr_mask[intr] = mask | (1 << intr);
91339234Sgibbs	intr_unit[intr] = unit;
91439234Sgibbs	setidt(ICU_OFFSET + intr,
91539234Sgibbs	       flags & RI_FAST ? fastintr[intr] : slowintr[intr],
91639234Sgibbs	       SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
91739234Sgibbs	write_eflags(ef);
91839234Sgibbs	for (cp = intrnames, id = 0; id <= device_id; id++)
91939234Sgibbs		while (*cp++ != '\0')
92039234Sgibbs			;
92139234Sgibbs	if (cp > eintrnames)
92239234Sgibbs		return (0);
92339234Sgibbs	if (intr < 10) {
92439234Sgibbs		cp[-3] = intr + '0';
92539234Sgibbs		cp[-2] = ' ';
92639234Sgibbs	} else {
92739234Sgibbs		cp[-3] = '1';
92839234Sgibbs		cp[-2] = intr - 10 + '0';
92939234Sgibbs	}
93039234Sgibbs	return (0);
93139234Sgibbs}
93239234Sgibbs
93339234Sgibbsstatic void
93439234Sgibbsregister_imask(dvp, mask)
93539234Sgibbs	struct isa_device *dvp;
93639234Sgibbs	u_int	mask;
93739234Sgibbs{
93839234Sgibbs	if (dvp->id_alive && dvp->id_irq) {
93939234Sgibbs		int	intr;
94039234Sgibbs
94139234Sgibbs		intr = ffs(dvp->id_irq) - 1;
94239234Sgibbs		intr_mask[intr] = mask | (1 <<intr);
94339234Sgibbs	}
94439234Sgibbs	(void) update_intr_masks();
94539234Sgibbs}
94639234Sgibbs
94739234Sgibbsint
94839234Sgibbsunregister_intr(intr, handler)
94939234Sgibbs	int	intr;
95039234Sgibbs	inthand2_t *handler;
95139234Sgibbs{
95239234Sgibbs	u_long	ef;
95339234Sgibbs
95439234Sgibbs	if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
95539234Sgibbs		return (EINVAL);
95639234Sgibbs	ef = read_eflags();
95739234Sgibbs	disable_intr();
95839234Sgibbs	intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
95939234Sgibbs	intr_handler[intr] = isa_strayintr;
96039234Sgibbs	intr_mptr[intr] = NULL;
96139234Sgibbs	intr_mask[intr] = HWI_MASK | SWI_MASK;
96239234Sgibbs	intr_unit[intr] = intr;
96339234Sgibbs	setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
96439234Sgibbs	    GSEL(GCODE_SEL, SEL_KPL));
96539234Sgibbs	write_eflags(ef);
96639234Sgibbs	return (0);
96739234Sgibbs}
96839234Sgibbs