isa.c revision 29613
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
3729613Sjmg *	$Id: isa.c,v 1.103 1997/08/28 03:36:40 msmith 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>
5113644Sbde#include <sys/systm.h>
522056Swollman#include <sys/buf.h>
532056Swollman#include <sys/malloc.h>
5426309Speter#include <machine/ipl.h>
5516733Sbde#include <machine/md_var.h>
5626949Sfsmp#ifdef APIC_IO
5725164Speter#include <machine/smp.h>
5825164Speter#endif /* APIC_IO */
592056Swollman#include <vm/vm.h>
6012662Sdg#include <vm/vm_param.h>
6112662Sdg#include <vm/pmap.h>
622056Swollman#include <i386/isa/isa_device.h>
6326373Sdfr#include <i386/isa/intr_machdep.h>
642056Swollman#include <i386/isa/isa.h>
652056Swollman#include <i386/isa/ic/i8237.h>
664Srgrimes
6726157Sse#include <sys/interrupt.h>
6826157Sse
6929613Sjmg#include "pnp.h"
7029613Sjmg#if NPNP > 0
7129613Sjmg#include <i386/isa/pnp.h>
7229613Sjmg#endif
7329613Sjmg
744Srgrimes/*
754Srgrimes**  Register definitions for DMA controller 1 (channels 0..3):
764Srgrimes*/
774Srgrimes#define	DMA1_CHN(c)	(IO_DMA1 + 1*(2*(c)))	/* addr reg for channel c */
784Srgrimes#define	DMA1_SMSK	(IO_DMA1 + 1*10)	/* single mask register */
794Srgrimes#define	DMA1_MODE	(IO_DMA1 + 1*11)	/* mode register */
804Srgrimes#define	DMA1_FFC	(IO_DMA1 + 1*12)	/* clear first/last FF */
814Srgrimes
824Srgrimes/*
834Srgrimes**  Register definitions for DMA controller 2 (channels 4..7):
844Srgrimes*/
85630Srgrimes#define	DMA2_CHN(c)	(IO_DMA2 + 2*(2*(c)))	/* addr reg for channel c */
864Srgrimes#define	DMA2_SMSK	(IO_DMA2 + 2*10)	/* single mask register */
874Srgrimes#define	DMA2_MODE	(IO_DMA2 + 2*11)	/* mode register */
884Srgrimes#define	DMA2_FFC	(IO_DMA2 + 2*12)	/* clear first/last FF */
894Srgrimes
902103Sdgstatic void config_isadev __P((struct isa_device *isdp, u_int *mp));
917430Sbdestatic void config_isadev_c __P((struct isa_device *isdp, u_int *mp,
927430Sbde				 int reconfig));
932103Sdgstatic void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp,
942103Sdg			  int item, char const *whatnot, char const *reason,
952103Sdg			  char const *format));
962103Sdgstatic int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp,
972103Sdg			 u_int checkbits));
9815147Ssmpatelstatic int isa_dmarangecheck __P((caddr_t va, u_int length, int chan));
992103Sdg
1002103Sdg/*
101593Srgrimes * print a conflict message
1024Srgrimes */
1032103Sdgstatic void
1042103Sdgconflict(dvp, tmpdvp, item, whatnot, reason, format)
1052103Sdg	struct isa_device	*dvp;
1062103Sdg	struct isa_device	*tmpdvp;
107593Srgrimes	int			item;
1082103Sdg	char const		*whatnot;
1092103Sdg	char const		*reason;
1102103Sdg	char const		*format;
111593Srgrimes{
1122103Sdg	printf("%s%d not %sed due to %s conflict with %s%d at ",
1132103Sdg		dvp->id_driver->name, dvp->id_unit, whatnot, reason,
114593Srgrimes		tmpdvp->id_driver->name, tmpdvp->id_unit);
115593Srgrimes	printf(format, item);
116593Srgrimes	printf("\n");
1174Srgrimes}
1184Srgrimes
1194Srgrimes/*
1208431Sjkh * Check to see if things are already in use, like IRQ's, I/O addresses
121593Srgrimes * and Memory addresses.
1224Srgrimes */
1232103Sdgstatic int
1242103Sdghaveseen(dvp, tmpdvp, checkbits)
1252103Sdg	struct isa_device *dvp;
1262103Sdg	struct isa_device *tmpdvp;
1272103Sdg	u_int	checkbits;
1284Srgrimes{
129593Srgrimes	/*
13028755Sbde	 * Ignore all conflicts except IRQ ones if conflicts are allowed.
131593Srgrimes	 */
13228755Sbde	if (dvp->id_conflicts)
13328755Sbde		checkbits &= ~(CC_DRQ | CC_IOADDR | CC_MEMADDR);
13428755Sbde	/*
13528755Sbde	 * Only check against devices that have already been found.
13628755Sbde	 */
13728755Sbde	if (tmpdvp->id_alive) {
1382103Sdg		char const *whatnot;
1392103Sdg
1402466Sats		whatnot = checkbits & CC_ATTACH ? "attach" : "prob";
141593Srgrimes		/*
142593Srgrimes		 * Check for I/O address conflict.  We can only check the
143593Srgrimes		 * starting address of the device against the range of the
144593Srgrimes		 * device that has already been probed since we do not
145593Srgrimes		 * know how many I/O addresses this device uses.
146593Srgrimes		 */
1472103Sdg		if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) {
148593Srgrimes			if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
149593Srgrimes			    (dvp->id_iobase <=
150593Srgrimes				  (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
1512103Sdg				conflict(dvp, tmpdvp, dvp->id_iobase, whatnot,
152593Srgrimes					 "I/O address", "0x%x");
1533670Sphk				return 1;
154593Srgrimes			}
1554Srgrimes		}
156593Srgrimes		/*
157593Srgrimes		 * Check for Memory address conflict.  We can check for
158593Srgrimes		 * range overlap, but it will not catch all cases since the
159593Srgrimes		 * driver may adjust the msize paramater during probe, for
160593Srgrimes		 * now we just check that the starting address does not
161593Srgrimes		 * fall within any allocated region.
162593Srgrimes		 * XXX could add a second check after the probe for overlap,
163593Srgrimes		 * since at that time we would know the full range.
164593Srgrimes		 * XXX KERNBASE is a hack, we should have vaddr in the table!
165593Srgrimes		 */
1662103Sdg		if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) {
1672103Sdg			if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
1682103Sdg			    (KERNBASE + dvp->id_maddr <=
1692103Sdg			     (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
1702103Sdg				conflict(dvp, tmpdvp, (int)dvp->id_maddr,
1712103Sdg					 whatnot, "maddr", "0x%x");
1723670Sphk				return 1;
1734Srgrimes			}
174593Srgrimes		}
175593Srgrimes		/*
176593Srgrimes		 * Check for IRQ conflicts.
177593Srgrimes		 */
1782103Sdg		if (checkbits & CC_IRQ && tmpdvp->id_irq) {
179593Srgrimes			if (tmpdvp->id_irq == dvp->id_irq) {
180593Srgrimes				conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1,
1812103Sdg					 whatnot, "irq", "%d");
1823670Sphk				return 1;
1834Srgrimes			}
184593Srgrimes		}
185593Srgrimes		/*
186593Srgrimes		 * Check for DRQ conflicts.
187593Srgrimes		 */
1882103Sdg		if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) {
189593Srgrimes			if (tmpdvp->id_drq == dvp->id_drq) {
1902103Sdg				conflict(dvp, tmpdvp, dvp->id_drq, whatnot,
1912103Sdg					 "drq", "%d");
1923670Sphk				return 1;
1934Srgrimes			}
194593Srgrimes		}
195593Srgrimes	}
1963670Sphk	return 0;
197593Srgrimes}
1984Srgrimes
19926157Sse#ifdef RESOURCE_CHECK
20026157Sse#include <sys/drvresource.h>
20126157Sse
20226157Ssestatic int
20326157Ssecheckone (struct isa_device *dvp, int type, addr_t low, addr_t high,
20426157Sse	  char *resname, char *resfmt, int attaching)
20526157Sse{
20626157Sse	int result = 0;
20726157Sse	if (bootverbose) {
20826157Sse		if (low == high)
20926157Sse			printf("\tcheck %s: 0x%x\n", resname, low);
21026157Sse		else
21126157Sse			printf("\tcheck %s: 0x%x to 0x%x\n",
21226157Sse			       resname, low, high);
21326157Sse	}
21426157Sse	if (resource_check(type, RESF_NONE, low, high) != NULL) {
21526157Sse		char *whatnot = attaching ? "attach" : "prob";
21626157Sse		static struct isa_device dummydev;
21726157Sse		static struct isa_driver dummydrv;
21826157Sse		struct isa_device *tmpdvp = &dummydev;
21926157Sse
22026157Sse		dummydev.id_driver = &dummydrv;
22126157Sse		dummydev.id_unit = 0;
22226157Sse		dummydrv.name = "pci";
22326157Sse		conflict(dvp, tmpdvp, low, whatnot, resname, resfmt);
22426157Sse		result = 1;
22526157Sse	} else if (attaching) {
22626157Sse		if (low == high)
22726157Sse			printf("\tregister %s: 0x%x\n", resname, low);
22826157Sse		else
22926157Sse			printf("\tregister %s: 0x%x to 0x%x\n",
23026157Sse			       resname, low, high);
23126157Sse		resource_claim(dvp, type, RESF_NONE, low, high);
23226157Sse	}
23326157Sse	return (result);
23426157Sse}
23526157Sse
23626157Ssestatic int
23726157Ssecheck_pciconflict(struct isa_device *dvp, int checkbits)
23826157Sse{
23926157Sse	int result = 0;
24026157Sse	int attaching = (checkbits & CC_ATTACH) != 0;
24126157Sse
24226157Sse	if (checkbits & CC_MEMADDR) {
24326157Sse		long maddr = dvp->id_maddr;
24426157Sse		long msize = dvp->id_msize;
24526157Sse		if (msize > 0) {
24626157Sse			if (checkone(dvp, REST_MEM, maddr, maddr + msize - 1,
24726157Sse				     "maddr", "0x%x", attaching) != 0) {
24826157Sse				result = 1;
24926157Sse				attaching = 0;
25026157Sse			}
25126157Sse		}
25226157Sse	}
25326157Sse	if (checkbits & CC_IOADDR) {
25426157Sse		unsigned iobase = dvp->id_iobase;
25526157Sse		unsigned iosize = dvp->id_alive;
25626157Sse		if (iosize == -1)
25726157Sse			iosize = 1; /* XXX can't do much about this ... */
25826157Sse		if (iosize > 0) {
25926157Sse			if (checkone(dvp, REST_PORT, iobase, iobase + iosize -1,
26026157Sse				     "I/O address", "0x%x", attaching) != 0) {
26126157Sse				result = 1;
26226157Sse				attaching = 0;
26326157Sse			}
26426157Sse		}
26526157Sse	}
26626157Sse	if (checkbits & CC_IRQ) {
26726157Sse		int irq = ffs(dvp->id_irq) - 1;
26826157Sse		if (irq >= 0) {
26926157Sse			if (checkone(dvp, REST_INT, irq, irq,
27026157Sse				     "irq", "%d", attaching) != 0) {
27126157Sse				result = 1;
27226157Sse				attaching = 0;
27326157Sse			}
27426157Sse		}
27526157Sse	}
27626157Sse	if (checkbits & CC_DRQ) {
27726157Sse		int drq = dvp->id_drq;
27826157Sse		if (drq >= 0) {
27926157Sse			if (checkone(dvp, REST_DMA, drq, drq,
28026157Sse				     "drq", "%d", attaching) != 0) {
28126157Sse				result = 1;
28226157Sse				attaching = 0;
28326157Sse			}
28426157Sse		}
28526157Sse	}
28626157Sse	if (result != 0)
28726157Sse		resource_free (dvp);
28826157Sse	return (result);
28926157Sse}
29026157Sse#endif /* RESOURCE_CHECK */
29126157Sse
292593Srgrimes/*
293593Srgrimes * Search through all the isa_devtab_* tables looking for anything that
294593Srgrimes * conflicts with the current device.
295593Srgrimes */
2968014Sjulianint
2972103Sdghaveseen_isadev(dvp, checkbits)
298593Srgrimes	struct isa_device *dvp;
2992103Sdg	u_int	checkbits;
300593Srgrimes{
30129613Sjmg#if NPNP > 0
30229613Sjmg	struct pnp_dlist_node *nod;
30329613Sjmg#endif
304593Srgrimes	struct isa_device *tmpdvp;
305593Srgrimes	int	status = 0;
3064Srgrimes
3073670Sphk	for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
3082103Sdg		status |= haveseen(dvp, tmpdvp, checkbits);
3093670Sphk		if (status)
3103670Sphk			return status;
3113670Sphk	}
3123670Sphk	for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
3132103Sdg		status |= haveseen(dvp, tmpdvp, checkbits);
3143670Sphk		if (status)
3153670Sphk			return status;
3163670Sphk	}
3173670Sphk	for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
3182103Sdg		status |= haveseen(dvp, tmpdvp, checkbits);
3193670Sphk		if (status)
3203670Sphk			return status;
3213670Sphk	}
3223670Sphk	for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
3232103Sdg		status |= haveseen(dvp, tmpdvp, checkbits);
3243670Sphk		if (status)
3253670Sphk			return status;
3263670Sphk	}
32729613Sjmg#if NPNP > 0
32829613Sjmg	for (nod = pnp_device_list; nod != NULL; nod = nod->next)
32929613Sjmg		if (status |= haveseen(dvp, &(nod->dev), checkbits))
33029613Sjmg			return status;
33129613Sjmg#endif
33226157Sse#ifdef RESOURCE_CHECK
33326157Sse	if (!dvp->id_conflicts) {
33426157Sse		status = check_pciconflict(dvp, checkbits);
33526157Sse	} else if (bootverbose)
33626157Sse		printf("\tnot checking for resource conflicts ...\n");
33726157Sse	}
33826157Sse#endif /* RESOURCE_CHECK */
339593Srgrimes	return(status);
3404Srgrimes}
341593Srgrimes
3424Srgrimes/*
3434Srgrimes * Configure all ISA devices
3444Srgrimes */
345593Srgrimesvoid
3464Srgrimesisa_configure() {
3474Srgrimes	struct isa_device *dvp;
3484Srgrimes
3492103Sdg	splhigh();
350593Srgrimes	printf("Probing for devices on the ISA bus:\n");
3513670Sphk	/* First probe all the sensitive probes */
3522103Sdg	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
3533670Sphk		if (dvp->id_driver->sensitive_hw)
3543670Sphk			config_isadev(dvp, &tty_imask);
3552103Sdg	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
3563670Sphk		if (dvp->id_driver->sensitive_hw)
3573670Sphk			config_isadev(dvp, &bio_imask);
3582103Sdg	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
3593670Sphk		if (dvp->id_driver->sensitive_hw)
3603670Sphk			config_isadev(dvp, &net_imask);
3612103Sdg	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
3623670Sphk		if (dvp->id_driver->sensitive_hw)
3633670Sphk			config_isadev(dvp, (u_int *)NULL);
3643670Sphk
3653670Sphk	/* Then all the bad ones */
3663670Sphk	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
3673670Sphk		if (!dvp->id_driver->sensitive_hw)
3683670Sphk			config_isadev(dvp, &tty_imask);
3693670Sphk	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
3703670Sphk		if (!dvp->id_driver->sensitive_hw)
3713670Sphk			config_isadev(dvp, &bio_imask);
3723670Sphk	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
3733670Sphk		if (!dvp->id_driver->sensitive_hw)
3743670Sphk			config_isadev(dvp, &net_imask);
3753670Sphk	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
3763670Sphk		if (!dvp->id_driver->sensitive_hw)
3773670Sphk			config_isadev(dvp, (u_int *)NULL);
3783670Sphk
3791321Sdg	bio_imask |= SWI_CLOCK_MASK;
3801321Sdg	net_imask |= SWI_NET_MASK;
3811321Sdg	tty_imask |= SWI_TTY_MASK;
3821321Sdg
383593Srgrimes/*
3841321Sdg * XXX we should really add the tty device to net_imask when the line is
385593Srgrimes * switched to SLIPDISC, and then remove it when it is switched away from
3861321Sdg * SLIPDISC.  No need to block out ALL ttys during a splimp when only one
387593Srgrimes * of them is running slip.
3881321Sdg *
3898876Srgrimes * XXX actually, blocking all ttys during a splimp doesn't matter so much
3901321Sdg * with sio because the serial interrupt layer doesn't use tty_imask.  Only
3911321Sdg * non-serial ttys suffer.  It's more stupid that ALL 'net's are blocked
3921321Sdg * during spltty.
393593Srgrimes */
3944Srgrimes#include "sl.h"
39513644Sbde#if NSL > 0
3961321Sdg	net_imask |= tty_imask;
3971321Sdg	tty_imask = net_imask;
3984Srgrimes#endif
39911978Speter
4001321Sdg	/* bio_imask |= tty_imask ;  can some tty devices use buffers? */
40111978Speter
40211978Speter	if (bootverbose)
40311978Speter		printf("imasks: bio %x, tty %x, net %x\n",
40413644Sbde		       bio_imask, tty_imask, net_imask);
40511978Speter
4062103Sdg	/*
4072103Sdg	 * Finish initializing intr_mask[].  Note that the partly
4082103Sdg	 * constructed masks aren't actually used since we're at splhigh.
4092103Sdg	 * For fully dynamic initialization, register_intr() and
41026157Sse	 * icu_unset() will have to adjust the masks for _all_
4112103Sdg	 * interrupts and for tty_imask, etc.
4122103Sdg	 */
4132103Sdg	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
4142103Sdg		register_imask(dvp, tty_imask);
4152103Sdg	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
4162103Sdg		register_imask(dvp, bio_imask);
4172103Sdg	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
4182103Sdg		register_imask(dvp, net_imask);
4192103Sdg	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
4202103Sdg		register_imask(dvp, SWI_CLOCK_MASK);
4212918Sbde	spl0();
4224Srgrimes}
4234Srgrimes
4244Srgrimes/*
4254Srgrimes * Configure an ISA device.
4264Srgrimes */
4278876Srgrimes
4288876Srgrimes
4292103Sdgstatic void
4304Srgrimesconfig_isadev(isdp, mp)
43126157Sse	struct isa_device *isdp;
43226157Sse	u_int *mp;
4333258Sdg{
4343258Sdg	config_isadev_c(isdp, mp, 0);
4353258Sdg}
4368876Srgrimes
4373258Sdgvoid
4383258Sdgreconfig_isadev(isdp, mp)
4394Srgrimes	struct isa_device *isdp;
4404Srgrimes	u_int *mp;
4414Srgrimes{
4423258Sdg	config_isadev_c(isdp, mp, 1);
4433258Sdg}
4443258Sdg
4453258Sdgstatic void
4463258Sdgconfig_isadev_c(isdp, mp, reconfig)
4473258Sdg	struct isa_device *isdp;
4483258Sdg	u_int *mp;
4493258Sdg	int reconfig;
4503258Sdg{
4512103Sdg	u_int checkbits;
4522103Sdg	int id_alive;
4533258Sdg	int last_alive;
454593Srgrimes	struct isa_driver *dp = isdp->id_driver;
4558876Srgrimes
4564109Sjkh	if (!isdp->id_enabled) {
4574109Sjkh		printf("%s%d: disabled, not probed.\n",
4584109Sjkh			dp->name, isdp->id_unit);
4594109Sjkh		return;
4604109Sjkh	}
46113644Sbde	checkbits = CC_DRQ | CC_IOADDR | CC_MEMADDR;
4623258Sdg	if (!reconfig && haveseen_isadev(isdp, checkbits))
4632103Sdg		return;
4643258Sdg	if (!reconfig && isdp->id_maddr) {
46521415Snate		isdp->id_maddr -= ISA_HOLE_START;
466593Srgrimes		isdp->id_maddr += atdevbase;
467593Srgrimes	}
4683258Sdg	if (reconfig) {
4693258Sdg		last_alive = isdp->id_alive;
4706512Sphk		isdp->id_reconfig = 1;
4713258Sdg	}
4723258Sdg	else {
4733258Sdg		last_alive = 0;
4746512Sphk		isdp->id_reconfig = 0;
4753258Sdg	}
4762103Sdg	id_alive = (*dp->probe)(isdp);
4772103Sdg	if (id_alive) {
478593Srgrimes		/*
479593Srgrimes		 * Only print the I/O address range if id_alive != -1
480593Srgrimes		 * Right now this is a temporary fix just for the new
481593Srgrimes		 * NPX code so that if it finds a 486 that can use trap
482593Srgrimes		 * 16 it will not report I/O addresses.
483593Srgrimes		 * Rod Grimes 04/26/94
484593Srgrimes		 */
4853258Sdg		if (!isdp->id_reconfig) {
4863258Sdg			printf("%s%d", dp->name, isdp->id_unit);
4873258Sdg			if (id_alive != -1) {
48824236Sache				if (isdp->id_iobase == -1)
48924237Sache					printf(" at ?");
49024334Sache				else {
49124236Sache					printf(" at 0x%x", isdp->id_iobase);
49224236Sache					if (isdp->id_iobase + id_alive - 1 !=
49324236Sache					    isdp->id_iobase) {
49424236Sache						printf("-0x%x",
49524236Sache						       isdp->id_iobase + id_alive - 1);
49624236Sache					}
4973258Sdg				}
498593Srgrimes			}
4993258Sdg			if (isdp->id_irq)
5003258Sdg				printf(" irq %d", ffs(isdp->id_irq) - 1);
5013258Sdg			if (isdp->id_drq != -1)
5023258Sdg				printf(" drq %d", isdp->id_drq);
5033258Sdg			if (isdp->id_maddr)
5043258Sdg				printf(" maddr 0x%lx", kvtop(isdp->id_maddr));
5053258Sdg			if (isdp->id_msize)
5063258Sdg				printf(" msize %d", isdp->id_msize);
5073258Sdg			if (isdp->id_flags)
5083258Sdg				printf(" flags 0x%x", isdp->id_flags);
5097645Sache			if (isdp->id_iobase && !(isdp->id_iobase & 0xf300)) {
5107624Sache				printf(" on motherboard");
5117624Sache			} else if (isdp->id_iobase >= 0x1000 &&
5127624Sache				    !(isdp->id_iobase & 0x300)) {
5137624Sache				printf (" on eisa slot %d",
5147624Sache					isdp->id_iobase >> 12);
5157624Sache			} else {
5167624Sache				printf (" on isa");
5171002Srgrimes			}
5187345Sswallace			printf("\n");
5193258Sdg			/*
5208876Srgrimes			 * Check for conflicts again.  The driver may have
5218876Srgrimes			 * changed *dvp.  We should weaken the early check
5228876Srgrimes			 * since the driver may have been able to change
5238876Srgrimes			 * *dvp to avoid conflicts if given a chance.  We
5248876Srgrimes			 * already skip the early check for IRQs and force
5253258Sdg			 * a check for IRQs in the next group of checks.
52613644Sbde			 */
5273258Sdg			checkbits |= CC_IRQ;
52828755Sbde			if (haveseen_isadev(isdp, checkbits))
5293258Sdg				return;
5303258Sdg			isdp->id_alive = id_alive;
5313258Sdg		}
532593Srgrimes		(*dp->attach)(isdp);
5332103Sdg		if (isdp->id_irq) {
53426949Sfsmp#ifdef APIC_IO
53526262Speter			/*
53626262Speter			 * Some motherboards use upper IRQs for traditional
53726262Speter			 * ISA INTerrupt sources.  In particular we have
53826262Speter			 * seen the secondary IDE connected to IRQ20.
53926262Speter			 * This code detects and fixes this situation.
54026262Speter			 */
54125498Sfsmp			u_int	apic_mask;
54225498Sfsmp			int	rirq;
54325498Sfsmp
54426949Sfsmp			apic_mask = isa_apic_mask(isdp->id_irq);
54526262Speter			if (apic_mask != isdp->id_irq) {
54626262Speter				rirq = ffs(isdp->id_irq) - 1;
54725498Sfsmp				isdp->id_irq = apic_mask;
54826262Speter				undirect_isa_irq(rirq);	/* free for ISA */
54925498Sfsmp			}
55026949Sfsmp#endif /* APIC_IO */
55127296Sache			register_intr(ffs(isdp->id_irq) - 1, isdp->id_id,
55227296Sache				      isdp->id_ri_flags, isdp->id_intr,
55327296Sache				      mp, isdp->id_unit);
5544Srgrimes		}
555593Srgrimes	} else {
5563258Sdg		if (isdp->id_reconfig) {
5573258Sdg			(*dp->attach)(isdp); /* reconfiguration attach */
558593Srgrimes		}
5593258Sdg		if (!last_alive) {
5603258Sdg			if (!isdp->id_reconfig) {
56113644Sbde				printf("%s%d not found",
56213644Sbde				       dp->name, isdp->id_unit);
56324334Sache				if (isdp->id_iobase != -1)
5643258Sdg					printf(" at 0x%x", isdp->id_iobase);
5653258Sdg				printf("\n");
5663258Sdg			}
56729613Sjmg		} else {
56826157Sse#if 0
5693258Sdg			/* This code has not been tested.... */
5703258Sdg			if (isdp->id_irq) {
57126157Sse				icu_unset(ffs(isdp->id_irq) - 1,
5723258Sdg						isdp->id_intr);
5733258Sdg				if (mp)
5743258Sdg					INTRUNMASK(*mp, isdp->id_irq);
5753258Sdg			}
57626157Sse#else
57726157Sse			printf ("icu_unset() not supported here ...\n");
57826157Sse#endif
5793258Sdg		}
580593Srgrimes	}
5814Srgrimes}
5824Srgrimes
58313646Sbdestatic caddr_t	dma_bouncebuf[8];
58415147Ssmpatelstatic u_int	dma_bouncebufsize[8];
58515147Ssmpatelstatic u_int8_t	dma_bounced = 0;
58615147Ssmpatelstatic u_int8_t	dma_busy = 0;		/* Used in isa_dmastart() */
58715147Ssmpatelstatic u_int8_t	dma_inuse = 0;		/* User for acquire/release */
58828847Smsmithstatic u_int8_t dma_auto_mode = 0;
5894Srgrimes
59015147Ssmpatel#define VALID_DMA_MASK (7)
59115147Ssmpatel
5924Srgrimes/* high byte of address is stored in this port for i-th dma channel */
59318819Sbdestatic int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
5944Srgrimes
5954Srgrimes/*
59615147Ssmpatel * Setup a DMA channel's bounce buffer.
59713646Sbde */
59813646Sbdevoid
59913646Sbdeisa_dmainit(chan, bouncebufsize)
60015147Ssmpatel	int chan;
60115147Ssmpatel	u_int bouncebufsize;
60213646Sbde{
60313646Sbde	void *buf;
60413646Sbde
60515147Ssmpatel#ifdef DIAGNOSTIC
60615147Ssmpatel	if (chan & ~VALID_DMA_MASK)
60715147Ssmpatel		panic("isa_dmainit: channel out of range");
60815147Ssmpatel
60915147Ssmpatel	if (dma_bouncebuf[chan] != NULL)
61013646Sbde		panic("isa_dmainit: impossible request");
61115147Ssmpatel#endif
61215147Ssmpatel
61313646Sbde	dma_bouncebufsize[chan] = bouncebufsize;
61413646Sbde
61513646Sbde	/* Try malloc() first.  It works better if it works. */
61613646Sbde	buf = malloc(bouncebufsize, M_DEVBUF, M_NOWAIT);
61713646Sbde	if (buf != NULL) {
61813646Sbde		if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) {
61913646Sbde			dma_bouncebuf[chan] = buf;
62013646Sbde			return;
62113646Sbde		}
62213646Sbde		free(buf, M_DEVBUF);
62313646Sbde	}
62413646Sbde	buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful,
62513646Sbde			   1ul, chan & 4 ? 0x20000ul : 0x10000ul);
62613646Sbde	if (buf == NULL)
62713646Sbde		printf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize);
62813646Sbde	else
62913646Sbde		dma_bouncebuf[chan] = buf;
63013646Sbde}
63113646Sbde
63213646Sbde/*
63315147Ssmpatel * Register a DMA channel's usage.  Usually called from a device driver
63415147Ssmpatel * in open() or during it's initialization.
63515147Ssmpatel */
63615147Ssmpatelint
63715147Ssmpatelisa_dma_acquire(chan)
63815147Ssmpatel	int chan;
63915147Ssmpatel{
64015147Ssmpatel#ifdef DIAGNOSTIC
64115147Ssmpatel	if (chan & ~VALID_DMA_MASK)
64215147Ssmpatel		panic("isa_dma_acquire: channel out of range");
64315147Ssmpatel#endif
64415147Ssmpatel
64515147Ssmpatel	if (dma_inuse & (1 << chan)) {
64615147Ssmpatel		printf("isa_dma_acquire: channel %d already in use\n", chan);
64715147Ssmpatel		return (EBUSY);
64815147Ssmpatel	}
64915147Ssmpatel	dma_inuse |= (1 << chan);
65028847Smsmith	dma_auto_mode &= ~(1 << chan);
65115147Ssmpatel
65215147Ssmpatel	return (0);
65315147Ssmpatel}
65415147Ssmpatel
65515147Ssmpatel/*
65615147Ssmpatel * Unregister a DMA channel's usage.  Usually called from a device driver
65715147Ssmpatel * during close() or during it's shutdown.
65815147Ssmpatel */
65915147Ssmpatelvoid
66015147Ssmpatelisa_dma_release(chan)
66115147Ssmpatel	int chan;
66215147Ssmpatel{
66315147Ssmpatel#ifdef DIAGNOSTIC
66415147Ssmpatel	if (chan & ~VALID_DMA_MASK)
66515147Ssmpatel		panic("isa_dma_release: channel out of range");
66615147Ssmpatel
66728138Ssteve	if ((dma_inuse & (1 << chan)) == 0)
66815147Ssmpatel		printf("isa_dma_release: channel %d not in use\n", chan);
66915147Ssmpatel#endif
67015147Ssmpatel
67115147Ssmpatel	if (dma_busy & (1 << chan)) {
67215147Ssmpatel		dma_busy &= ~(1 << chan);
67315147Ssmpatel		/*
67415147Ssmpatel		 * XXX We should also do "dma_bounced &= (1 << chan);"
67515147Ssmpatel		 * because we are acting on behalf of isa_dmadone() which
67615147Ssmpatel		 * was not called to end the last DMA operation.  This does
67715147Ssmpatel		 * not matter now, but it may in the future.
67815147Ssmpatel		 */
67915147Ssmpatel	}
68015147Ssmpatel
68115147Ssmpatel	dma_inuse &= ~(1 << chan);
68228847Smsmith	dma_auto_mode &= ~(1 << chan);
68315147Ssmpatel}
68415147Ssmpatel
68515147Ssmpatel/*
6864Srgrimes * isa_dmacascade(): program 8237 DMA controller channel to accept
6874Srgrimes * external dma control by a board.
6884Srgrimes */
68915147Ssmpatelvoid isa_dmacascade(chan)
69015147Ssmpatel	int chan;
6914Srgrimes{
69215147Ssmpatel#ifdef DIAGNOSTIC
69315147Ssmpatel	if (chan & ~VALID_DMA_MASK)
69415147Ssmpatel		panic("isa_dmacascade: channel out of range");
69515147Ssmpatel#endif
6964Srgrimes
6974Srgrimes	/* set dma channel mode, and set dma channel mode */
6984Srgrimes	if ((chan & 4) == 0) {
6994Srgrimes		outb(DMA1_MODE, DMA37MD_CASCADE | chan);
7004Srgrimes		outb(DMA1_SMSK, chan);
7014Srgrimes	} else {
7024Srgrimes		outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
7034Srgrimes		outb(DMA2_SMSK, chan & 3);
7044Srgrimes	}
7054Srgrimes}
7064Srgrimes
7074Srgrimes/*
7084Srgrimes * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
7094Srgrimes * problems by using a bounce buffer.
7104Srgrimes */
71115147Ssmpatelvoid isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
71215147Ssmpatel{
71315147Ssmpatel	vm_offset_t phys;
7144Srgrimes	int waport;
7154Srgrimes	caddr_t newaddr;
7164Srgrimes
71715147Ssmpatel#ifdef DIAGNOSTIC
71815147Ssmpatel	if (chan & ~VALID_DMA_MASK)
71915147Ssmpatel		panic("isa_dmastart: channel out of range");
72015147Ssmpatel
72115147Ssmpatel	if ((chan < 4 && nbytes > (1<<16))
7224Srgrimes	    || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
7238876Srgrimes		panic("isa_dmastart: impossible request");
7244Srgrimes
72528138Ssteve	if ((dma_inuse & (1 << chan)) == 0)
72615147Ssmpatel		printf("isa_dmastart: channel %d not acquired\n", chan);
72714447Sjkh#endif
72815147Ssmpatel
72925498Sfsmp#if 0
73025498Sfsmp	/*
73125498Sfsmp	 * XXX This should be checked, but drivers like ad1848 only call
73225498Sfsmp	 * isa_dmastart() once because they use Auto DMA mode.  If we
73325498Sfsmp	 * leave this in, drivers that do this will print this continuously.
73425498Sfsmp	 */
73515147Ssmpatel	if (dma_busy & (1 << chan))
73615147Ssmpatel		printf("isa_dmastart: channel %d busy\n", chan);
73725498Sfsmp#endif
73815147Ssmpatel
73915147Ssmpatel	dma_busy |= (1 << chan);
74015147Ssmpatel
7414Srgrimes	if (isa_dmarangecheck(addr, nbytes, chan)) {
74213646Sbde		if (dma_bouncebuf[chan] == NULL
74313646Sbde		    || dma_bouncebufsize[chan] < nbytes)
74413646Sbde			panic("isa_dmastart: bad bounce buffer");
74515147Ssmpatel		dma_bounced |= (1 << chan);
74613646Sbde		newaddr = dma_bouncebuf[chan];
7474Srgrimes
7484Srgrimes		/* copy bounce buffer on write */
7494Srgrimes		if (!(flags & B_READ))
7504Srgrimes			bcopy(addr, newaddr, nbytes);
7514Srgrimes		addr = newaddr;
7524Srgrimes	}
7534Srgrimes
7544Srgrimes	/* translate to physical */
7554Srgrimes	phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
7564Srgrimes
75728847Smsmith	if (flags & B_RAW) {
75828847Smsmith	    dma_auto_mode |= (1 << chan);
75928847Smsmith	} else {
76028847Smsmith	    dma_auto_mode &= ~(1 << chan);
76128847Smsmith	}
76228847Smsmith
7634Srgrimes	if ((chan & 4) == 0) {
7644Srgrimes		/*
7654Srgrimes		 * Program one of DMA channels 0..3.  These are
7664Srgrimes		 * byte mode channels.
7674Srgrimes		 */
7684Srgrimes		/* set dma channel mode, and reset address ff */
7694051Sache
7704051Sache		/* If B_RAW flag is set, then use autoinitialise mode */
7714051Sache		if (flags & B_RAW) {
7724051Sache		  if (flags & B_READ)
7734051Sache			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
7744051Sache		  else
7754051Sache			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
7764051Sache		}
7774051Sache		else
7784Srgrimes		if (flags & B_READ)
7794Srgrimes			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
7804Srgrimes		else
7814Srgrimes			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
7824Srgrimes		outb(DMA1_FFC, 0);
7834Srgrimes
7844Srgrimes		/* send start address */
7854Srgrimes		waport =  DMA1_CHN(chan);
7864Srgrimes		outb(waport, phys);
7874Srgrimes		outb(waport, phys>>8);
7884Srgrimes		outb(dmapageport[chan], phys>>16);
7894Srgrimes
7904Srgrimes		/* send count */
7914Srgrimes		outb(waport + 1, --nbytes);
7924Srgrimes		outb(waport + 1, nbytes>>8);
7934Srgrimes
7944Srgrimes		/* unmask channel */
7954Srgrimes		outb(DMA1_SMSK, chan);
7964Srgrimes	} else {
7974Srgrimes		/*
7984Srgrimes		 * Program one of DMA channels 4..7.  These are
7994Srgrimes		 * word mode channels.
8004Srgrimes		 */
8014Srgrimes		/* set dma channel mode, and reset address ff */
8024051Sache
8034051Sache		/* If B_RAW flag is set, then use autoinitialise mode */
8044051Sache		if (flags & B_RAW) {
8054051Sache		  if (flags & B_READ)
8064051Sache			outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3));
8074051Sache		  else
8084051Sache			outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3));
8094051Sache		}
8104051Sache		else
8114Srgrimes		if (flags & B_READ)
8124Srgrimes			outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
8134Srgrimes		else
8144Srgrimes			outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
8154Srgrimes		outb(DMA2_FFC, 0);
8164Srgrimes
8174Srgrimes		/* send start address */
8184Srgrimes		waport = DMA2_CHN(chan - 4);
8194Srgrimes		outb(waport, phys>>1);
8204Srgrimes		outb(waport, phys>>9);
8214Srgrimes		outb(dmapageport[chan], phys>>16);
8224Srgrimes
8234Srgrimes		/* send count */
8244Srgrimes		nbytes >>= 1;
8254Srgrimes		outb(waport + 2, --nbytes);
8264Srgrimes		outb(waport + 2, nbytes>>8);
8274Srgrimes
8284Srgrimes		/* unmask channel */
8294Srgrimes		outb(DMA2_SMSK, chan & 3);
8304Srgrimes	}
8314Srgrimes}
8324Srgrimes
8334Srgrimesvoid isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
83415147Ssmpatel{
83515147Ssmpatel#ifdef DIAGNOSTIC
83615147Ssmpatel	if (chan & ~VALID_DMA_MASK)
83715147Ssmpatel		panic("isa_dmadone: channel out of range");
8384Srgrimes
83928138Ssteve	if ((dma_inuse & (1 << chan)) == 0)
84015147Ssmpatel		printf("isa_dmadone: channel %d not acquired\n", chan);
84115147Ssmpatel#endif
84215147Ssmpatel
84328847Smsmith	if (((dma_busy & (1 << chan)) == 0) &&
84428847Smsmith	    (dma_auto_mode & (1 << chan)) == 0 )
84513646Sbde		printf("isa_dmadone: channel %d not busy\n", chan);
84615147Ssmpatel
84728847Smsmith
84815147Ssmpatel	if (dma_bounced & (1 << chan)) {
84913646Sbde		/* copy bounce buffer on read */
85013646Sbde		if (flags & B_READ)
85113646Sbde			bcopy(dma_bouncebuf[chan], addr, nbytes);
85213646Sbde
85315147Ssmpatel		dma_bounced &= ~(1 << chan);
8544Srgrimes	}
85515147Ssmpatel	dma_busy &= ~(1 << chan);
8564Srgrimes}
8574Srgrimes
8584Srgrimes/*
8594Srgrimes * Check for problems with the address range of a DMA transfer
8604Srgrimes * (non-contiguous physical pages, outside of bus address space,
8614Srgrimes * crossing DMA page boundaries).
8624Srgrimes * Return true if special handling needed.
8634Srgrimes */
8644Srgrimes
8652103Sdgstatic int
86615147Ssmpatelisa_dmarangecheck(caddr_t va, u_int length, int chan) {
8674Srgrimes	vm_offset_t phys, priorpage = 0, endva;
8684Srgrimes	u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
8694Srgrimes
8704Srgrimes	endva = (vm_offset_t)round_page(va + length);
87115538Sphk	for (; va < (caddr_t) endva ; va += PAGE_SIZE) {
8724Srgrimes		phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
8734Srgrimes#define ISARAM_END	RAM_END
8744Srgrimes		if (phys == 0)
8754Srgrimes			panic("isa_dmacheck: no physical page present");
8761323Sache		if (phys >= ISARAM_END)
8774Srgrimes			return (1);
8784Srgrimes		if (priorpage) {
87915538Sphk			if (priorpage + PAGE_SIZE != phys)
8804Srgrimes				return (1);
8814Srgrimes			/* check if crossing a DMA page boundary */
8824Srgrimes			if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
8834Srgrimes				return (1);
8844Srgrimes		}
8854Srgrimes		priorpage = phys;
8864Srgrimes	}
8874Srgrimes	return (0);
8884Srgrimes}
8894Srgrimes
8904Srgrimes/*
89127639Smsmith * Query the progress of a transfer on a DMA channel.
89227639Smsmith *
89327639Smsmith * To avoid having to interrupt a transfer in progress, we sample
89427639Smsmith * each of the high and low databytes twice, and apply the following
89527639Smsmith * logic to determine the correct count.
89627639Smsmith *
89727639Smsmith * Reads are performed with interrupts disabled, thus it is to be
89827639Smsmith * expected that the time between reads is very small.  At most
89927639Smsmith * one rollover in the low count byte can be expected within the
90027639Smsmith * four reads that are performed.
90127639Smsmith *
90227639Smsmith * There are three gaps in which a rollover can occur :
90327639Smsmith *
90427639Smsmith * - read low1
90527639Smsmith *              gap1
90627639Smsmith * - read high1
90727639Smsmith *              gap2
90827639Smsmith * - read low2
90927639Smsmith *              gap3
91027639Smsmith * - read high2
91127639Smsmith *
91227639Smsmith * If a rollover occurs in gap1 or gap2, the low2 value will be
91327639Smsmith * greater than the low1 value.  In this case, low2 and high2 are a
91427639Smsmith * corresponding pair.
91527639Smsmith *
91627639Smsmith * In any other case, low1 and high1 can be considered to be correct.
91727639Smsmith *
91827639Smsmith * The function returns the number of bytes remaining in the transfer,
91927639Smsmith * or -1 if the channel requested is not active.
92027639Smsmith *
92127639Smsmith */
92227639Smsmithint
92327639Smsmithisa_dmastatus(int chan)
92427639Smsmith{
92527639Smsmith	u_long	cnt = 0;
92627737Smsmith	int	ffport, waport;
92727738Smsmith	u_long	low1, high1, low2, high2;
92827639Smsmith
92927639Smsmith	/* channel active? */
93028138Ssteve	if ((dma_inuse & (1 << chan)) == 0) {
93127639Smsmith		printf("isa_dmastatus: channel %d not active\n", chan);
93227639Smsmith		return(-1);
93327639Smsmith	}
93428847Smsmith	/* channel busy? */
93527639Smsmith
93628847Smsmith	if (((dma_busy & (1 << chan)) == 0) &&
93728847Smsmith	    (dma_auto_mode & (1 << chan)) == 0 ) {
93828847Smsmith	    printf("chan %d not busy\n", chan);
93928847Smsmith	    return -2 ;
94028847Smsmith	}
94127639Smsmith	if (chan < 4) {			/* low DMA controller */
94227639Smsmith		ffport = DMA1_FFC;
94327639Smsmith		waport = DMA1_CHN(chan) + 1;
94427639Smsmith	} else {			/* high DMA controller */
94527639Smsmith		ffport = DMA2_FFC;
94627639Smsmith		waport = DMA2_CHN(chan - 4) + 2;
94727639Smsmith	}
94827639Smsmith
94927737Smsmith	disable_intr();			/* no interrupts Mr Jones! */
95027639Smsmith	outb(ffport, 0);		/* clear register LSB flipflop */
95127738Smsmith	low1 = inb(waport);
95227738Smsmith	high1 = inb(waport);
95327749Smsmith	outb(ffport, 0);		/* clear again */
95427639Smsmith	low2 = inb(waport);
95527639Smsmith	high2 = inb(waport);
95627749Smsmith	enable_intr();			/* enable interrupts again */
95727639Smsmith
95827749Smsmith	/*
95927749Smsmith	 * Now decide if a wrap has tried to skew our results.
96027749Smsmith	 * Note that after TC, the count will read 0xffff, while we want
96127749Smsmith	 * to return zero, so we add and then mask to compensate.
96227749Smsmith	 */
96327738Smsmith	if (low1 >= low2) {
96427749Smsmith		cnt = (low1 + (high1 << 8) + 1) & 0xffff;
96527639Smsmith	} else {
96627749Smsmith		cnt = (low2 + (high2 << 8) + 1) & 0xffff;
96727639Smsmith	}
96827639Smsmith
96927639Smsmith	if (chan >= 4)			/* high channels move words */
97027639Smsmith		cnt *= 2;
97127639Smsmith	return(cnt);
97227639Smsmith}
97327639Smsmith
97427639Smsmith/*
97528847Smsmith * Stop a DMA transfer currently in progress.
97628847Smsmith */
97728847Smsmithint
97828847Smsmithisa_dmastop(int chan)
97928847Smsmith{
98028847Smsmith	if ((dma_inuse & (1 << chan)) == 0)
98128847Smsmith		printf("isa_dmastop: channel %d not acquired\n", chan);
98228847Smsmith
98328847Smsmith	if (((dma_busy & (1 << chan)) == 0) &&
98428847Smsmith	    ((dma_auto_mode & (1 << chan)) == 0)) {
98528847Smsmith		printf("chan %d not busy\n", chan);
98628847Smsmith		return -2 ;
98728847Smsmith	}
98828847Smsmith
98928847Smsmith	if ((chan & 4) == 0) {
99028847Smsmith		outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */);
99128847Smsmith	} else {
99228847Smsmith		outb(DMA2_SMSK, (chan & 3) | 4 /* disable mask */);
99328847Smsmith	}
99428847Smsmith	return(isa_dmastatus(chan));
99528847Smsmith}
99628847Smsmith
99728847Smsmith/*
99810666Sbde * Find the highest priority enabled display device.  Since we can't
99910666Sbde * distinguish display devices from ttys, depend on display devices
100011670Sbde * being sensitive and before sensitive non-display devices (if any)
100111670Sbde * in isa_devtab_tty.
100211670Sbde *
100311670Sbde * XXX we should add capability flags IAMDISPLAY and ISUPPORTCONSOLES.
100410666Sbde */
100510666Sbdestruct isa_device *
100610666Sbdefind_display()
100710666Sbde{
100810666Sbde	struct isa_device *dvp;
100910666Sbde
101010666Sbde	for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
101111670Sbde		if (dvp->id_driver->sensitive_hw && dvp->id_enabled)
101210666Sbde			return (dvp);
101310666Sbde	return (NULL);
101410666Sbde}
101510666Sbde
101610666Sbde/*
10174Srgrimes * find an ISA device in a given isa_devtab_* table, given
10184Srgrimes * the table to search, the expected id_driver entry, and the unit number.
10194Srgrimes *
10204Srgrimes * this function is defined in isa_device.h, and this location is debatable;
10214Srgrimes * i put it there because it's useless w/o, and directly operates on
10224Srgrimes * the other stuff in that file.
10234Srgrimes *
10244Srgrimes */
10254Srgrimes
10264Srgrimesstruct isa_device *find_isadev(table, driverp, unit)
102726157Sse	struct isa_device *table;
102826157Sse	struct isa_driver *driverp;
102926157Sse	int unit;
10304Srgrimes{
103126157Sse	if (driverp == NULL) /* sanity check */
103226157Sse		return (NULL);
10334Srgrimes
103426157Sse	while ((table->id_driver != driverp) || (table->id_unit != unit)) {
103526157Sse		if (table->id_driver == 0)
103626157Sse			return NULL;
10378876Srgrimes
103826157Sse		table++;
103926157Sse	}
10404Srgrimes
104126157Sse	return (table);
10424Srgrimes}
1043