Home | History | Annotate | Line # | Download | only in isa
isa.c revision 1.48
      1 /*-
      2  * Copyright (c) 1993, 1994 Charles Hannum.
      3  * Copyright (c) 1991 The Regents of the University of California.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to Berkeley by
      7  * William Jolitz.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *	This product includes software developed by the University of
     20  *	California, Berkeley and its contributors.
     21  * 4. Neither the name of the University nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  *
     37  *	from: @(#)isa.c	7.2 (Berkeley) 5/13/91
     38  *	$Id: isa.c,v 1.48 1994/04/03 22:51:48 mycroft Exp $
     39  */
     40 
     41 /*
     42  * code to manage AT bus
     43  *
     44  * 92/08/18  Frank P. MacLachlan (fpm (at) crash.cts.com):
     45  * Fixed uninitialized variable problem and added code to deal
     46  * with DMA page boundaries in isa_dmarangecheck().  Fixed word
     47  * mode DMA count compution and reorganized DMA setup code in
     48  * isa_dmastart()
     49  */
     50 
     51 #include <sys/param.h>
     52 #include <sys/systm.h>
     53 #include <sys/kernel.h>
     54 #include <sys/conf.h>
     55 #include <sys/file.h>
     56 #include <sys/buf.h>
     57 #include <sys/uio.h>
     58 #include <sys/syslog.h>
     59 #include <sys/malloc.h>
     60 #include <sys/device.h>
     61 
     62 #include <vm/vm.h>
     63 
     64 #include <machine/pio.h>
     65 #include <machine/cpufunc.h>
     66 
     67 #include <i386/isa/isa.h>
     68 #include <i386/isa/isa_device.h>
     69 #include <i386/isa/isavar.h>
     70 #include <i386/isa/icu.h>
     71 #include <i386/isa/ic/i8237.h>
     72 #include <i386/isa/ic/i8042.h>
     73 #include <i386/isa/timerreg.h>
     74 #include <i386/isa/spkr_reg.h>
     75 
     76 /* sorry, has to be here, no place else really suitable */
     77 #include <machine/pc/display.h>
     78 u_short *Crtat = (u_short *)MONO_BUF;
     79 
     80 /*
     81  * Register definitions for DMA controller 1 (channels 0..3):
     82  */
     83 #define	DMA1_CHN(c)	(IO_DMA1 + 1*(2*(c)))	/* addr reg for channel c */
     84 #define	DMA1_SR		(IO_DMA1 + 1*8)		/* status register */
     85 #define	DMA1_SMSK	(IO_DMA1 + 1*10)	/* single mask register */
     86 #define	DMA1_MODE	(IO_DMA1 + 1*11)	/* mode register */
     87 #define	DMA1_FFC	(IO_DMA1 + 1*12)	/* clear first/last FF */
     88 
     89 /*
     90  * Register definitions for DMA controller 2 (channels 4..7):
     91  */
     92 #define	DMA2_CHN(c)	(IO_DMA2 + 2*(2*(c)))	/* addr reg for channel c */
     93 #define	DMA2_SR		(IO_DMA2 + 2*8)		/* status register */
     94 #define	DMA2_SMSK	(IO_DMA2 + 2*10)	/* single mask register */
     95 #define	DMA2_MODE	(IO_DMA2 + 2*11)	/* mode register */
     96 #define	DMA2_FFC	(IO_DMA2 + 2*12)	/* clear first/last FF */
     97 
     98 static void sysbeepstop(int);
     99 
    100 /*
    101  * Configure all ISA devices
    102  *
    103  * XXX This code is a hack.  It wants to be new config, but can't be until the
    104  * interrupt system is redone.  For now, we do some gross hacks to make it look
    105  * 99% like new config.
    106  */
    107 static char *msgs[3] = { "", " not configured\n", " unsupported\n" };
    108 
    109 struct cfdata *
    110 config_search(fn, parent, aux)
    111 	cfmatch_t fn;
    112 	struct device *parent;
    113 	void *aux;
    114 {
    115 	struct cfdata *cf = 0;
    116 	struct device *dv = 0;
    117 	size_t devsize;
    118 	struct cfdriver *cd;
    119 	struct isa_device *id,
    120 	    *idp =  parent ? (void *)parent->dv_cfdata->cf_loc : 0;
    121 
    122 	for (id = isa_devtab; id->id_driver; id++) {
    123 		if (id->id_state == FSTATE_FOUND)
    124 			continue;
    125 		if (id->id_parent != idp)
    126 			continue;
    127 		cd = id->id_driver;
    128 		if (id->id_unit < cd->cd_ndevs) {
    129 			if (cd->cd_devs[id->id_unit] != 0)
    130 				continue;
    131 		} else {
    132 			int old = cd->cd_ndevs, new;
    133 			void **nsp;
    134 
    135 			if (old == 0) {
    136 				nsp = malloc(MINALLOCSIZE, M_DEVBUF, M_NOWAIT);
    137 				if (!nsp)
    138 					panic("config_search: creating dev array");
    139 				bzero(nsp, MINALLOCSIZE);
    140 				cd->cd_ndevs = MINALLOCSIZE / sizeof(void *);
    141 			} else {
    142 				new = old;
    143 				do {
    144 					new *= 2;
    145 				} while (new <= id->id_unit);
    146 				cd->cd_ndevs = new;
    147 				nsp = malloc(new * sizeof(void *), M_DEVBUF,
    148 				    M_NOWAIT);
    149 				if (!nsp)
    150 					panic("config_search: expanding dev array");
    151 				bzero(nsp, new * sizeof(void *));
    152 				bcopy(cd->cd_devs, nsp, old * sizeof(void *));
    153 				free(cd->cd_devs, M_DEVBUF);
    154 			}
    155 			cd->cd_devs = nsp;
    156 		}
    157 		if (!cf) {
    158 			cf = malloc(sizeof(struct cfdata), M_DEVBUF, M_NOWAIT);				if (!cf)
    159 				panic("config_search: creating cfdata");
    160 		}
    161 		cf->cf_driver = cd;
    162 		cf->cf_unit = id->id_unit;
    163 		cf->cf_fstate = 0;
    164 		cf->cf_loc = (void *)id;
    165 		cf->cf_flags = id->id_flags;
    166 		cf->cf_parents = 0;
    167 		cf->cf_ivstubs = 0;
    168 		if (dv && devsize != cd->cd_devsize) {
    169 			free(dv, M_DEVBUF);
    170 			dv = 0;
    171 		}
    172 		if (!dv) {
    173 			devsize = cd->cd_devsize;
    174 			dv = malloc(devsize, M_DEVBUF, M_NOWAIT);
    175 			if (!dv)
    176 				panic("config_search: creating softc");
    177 		}
    178 		bzero(dv, cd->cd_devsize);
    179 		dv->dv_class = cd->cd_class;
    180 		dv->dv_cfdata = cf;
    181 		dv->dv_unit = id->id_unit;
    182 		sprintf(dv->dv_xname, "%s%d", cd->cd_name, id->id_unit);
    183 		dv->dv_parent = parent;
    184 		cd->cd_devs[id->id_unit] = dv;
    185 		if (fn) {
    186 			if ((*fn)(parent, dv, aux))
    187 				return cf;
    188 		} else {
    189 			if ((*cd->cd_match)(parent, dv, aux))
    190 				return cf;
    191 		}
    192 		cd->cd_devs[id->id_unit] = 0;
    193 	}
    194 	if (cf)
    195 		free(cf, M_DEVBUF);
    196 	if (dv)
    197 		free(dv, M_DEVBUF);
    198 	return 0;
    199 }
    200 
    201 void
    202 config_attach(parent, cf, aux, print)
    203 	struct device *parent;
    204 	struct cfdata *cf;
    205 	void *aux;
    206 	cfprint_t print;
    207 {
    208 	struct isa_device *id = (void *)cf->cf_loc;
    209 	struct cfdriver *cd = cf->cf_driver;
    210 	struct device *dv = cd->cd_devs[id->id_unit];
    211 
    212 	cf->cf_fstate = id->id_state = FSTATE_FOUND;
    213 	printf("%s at %s", dv->dv_xname, parent ? parent->dv_xname : "isa0");
    214 	if (print)
    215 		(void) (*print)(aux, (char *)0);
    216 	(*cd->cd_attach)(parent, dv, aux);
    217 }
    218 
    219 int
    220 config_found(parent, aux, print)
    221 	struct device *parent;
    222 	void *aux;
    223 	cfprint_t print;
    224 {
    225 	struct cfdata *cf;
    226 
    227 	if ((cf = config_search((cfmatch_t)NULL, parent, aux)) != NULL) {
    228 		config_attach(parent, cf, aux, print);
    229 		return 1;
    230 	}
    231 	if (print)
    232 		printf(msgs[(*print)(aux, parent->dv_xname)]);
    233 	return 0;
    234 }
    235 
    236 int
    237 isaprint(aux, isa)
    238 	void *aux;
    239 	char *isa;
    240 {
    241 	struct isa_attach_args *ia = aux;
    242 
    243 	if (ia->ia_iosize)
    244 		printf(" port 0x%x", ia->ia_iobase);
    245 	if (ia->ia_iosize > 1)
    246 		printf("-0x%x", ia->ia_iobase + ia->ia_iosize - 1);
    247 	if (ia->ia_msize)
    248 		printf(" iomem 0x%x", ia->ia_maddr - atdevbase + 0xa0000);
    249 	if (ia->ia_msize > 1)
    250 		printf("-0x%x",
    251 		    ia->ia_maddr - atdevbase + 0xa0000 + ia->ia_msize - 1);
    252 	if (ia->ia_irq)
    253 		printf(" irq %d", ffs(ia->ia_irq) - 1);
    254 	if (ia->ia_drq != (u_short)-1)
    255 		printf(" drq %d", ia->ia_drq);
    256 	/* XXXX print flags */
    257 	return QUIET;
    258 }
    259 
    260 int
    261 isasubmatch(parent, self, aux)
    262 	struct device *parent, *self;
    263 	void *aux;
    264 {
    265 	struct isa_device *id = (void *)self->dv_cfdata->cf_loc;
    266 	struct isa_attach_args ia;
    267 
    268 	ia.ia_iobase = id->id_iobase;
    269 	ia.ia_iosize = 0x666;
    270 	ia.ia_irq = id->id_irq;
    271 	ia.ia_drq = id->id_drq;
    272 	ia.ia_maddr = id->id_maddr - 0xa0000 + atdevbase;
    273 	ia.ia_msize = id->id_msize;
    274 
    275 	if (!(*id->id_driver->cd_match)(parent, self, &ia)) {
    276 		/*
    277 		 * If we don't do this, isa_configure() will repeatedly try to
    278 		 * probe devices that weren't found.  But we need to be careful
    279 		 * to do it only for the ISA bus, or we would cause things like
    280 		 * `com0 at ast? slave ?' to not probe on the second ast.
    281 		 */
    282 		if (!parent)
    283 			id->id_state = FSTATE_FOUND;
    284 
    285 		return 0;
    286 	}
    287 
    288 	config_attach(parent, self->dv_cfdata, &ia, isaprint);
    289 
    290 	if (id->id_irq) {
    291 		int intrno;
    292 
    293 		intrno = ffs(id->id_irq) - 1;
    294 		setidt(ICU_OFFSET+intrno, id->id_intr, SDT_SYS386IGT, SEL_KPL);
    295 		if (id->id_mask)
    296 			INTRMASK(*id->id_mask, id->id_irq);
    297 		INTREN(id->id_irq);
    298 	}
    299 
    300 	return 1;
    301 }
    302 
    303 void
    304 isa_configure()
    305 {
    306 
    307 	splhigh();
    308 	INTREN(IRQ_SLAVE);
    309 	enable_intr();
    310 
    311 	while (config_search(isasubmatch, NULL, NULL));
    312 
    313 	printf("biomask %x ttymask %x netmask %x\n",
    314 	       biomask, ttymask, netmask);
    315 
    316 	clockmask |= astmask;
    317 	biomask |= astmask;
    318 	ttymask |= astmask;
    319 	netmask |= astmask;
    320 	impmask = netmask | ttymask;
    321 
    322 	spl0();
    323 }
    324 
    325 #define	IDTVEC(name)	__CONCAT(X,name)
    326 /* default interrupt vector table entries */
    327 extern	IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
    328 	IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
    329 	IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
    330 	IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
    331 
    332 static *defvec[16] = {
    333 	&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
    334 	&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
    335 	&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
    336 	&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
    337 
    338 /* out of range default interrupt vector gate entry */
    339 extern	IDTVEC(intrdefault);
    340 
    341 /*
    342  * Fill in default interrupt table (in case of spuruious interrupt
    343  * during configuration of kernel, setup interrupt control unit
    344  */
    345 void
    346 isa_defaultirq() {
    347 	int i;
    348 
    349 	/* icu vectors */
    350 	for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
    351 		setidt(i, defvec[i],  SDT_SYS386IGT, SEL_KPL);
    352 
    353 	/* out of range vectors */
    354 	for (i = NRSVIDT; i < NIDT; i++)
    355 		setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL);
    356 
    357 	/* initialize 8259's */
    358 	outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
    359 	outb(IO_ICU1+1, NRSVIDT);	/* starting at this vector index */
    360 	outb(IO_ICU1+1, 1<<2);		/* slave on line 2 */
    361 #ifdef AUTO_EOI_1
    362 	outb(IO_ICU1+1, 2 | 1);		/* auto EOI, 8086 mode */
    363 #else
    364 	outb(IO_ICU1+1, 1);		/* 8086 mode */
    365 #endif
    366 	outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
    367 	outb(IO_ICU1, 0x0a);		/* default to IRR on read */
    368 #ifdef REORDER_IRQ
    369 	outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
    370 #endif
    371 
    372 	outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
    373 	outb(IO_ICU2+1, NRSVIDT+8);	/* staring at this vector index */
    374 	outb(IO_ICU2+1,2);		/* my slave id is 2 */
    375 #ifdef AUTO_EOI_2
    376 	outb(IO_ICU2+1, 2 | 1);		/* auto EOI, 8086 mode */
    377 #else
    378 	outb(IO_ICU2+1,1);		/* 8086 mode */
    379 #endif
    380 	outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
    381 	outb(IO_ICU2, 0x0a);		/* default to IRR on read */
    382 }
    383 
    384 /* region of physical memory known to be contiguous */
    385 vm_offset_t isaphysmem;
    386 static caddr_t dma_bounce[8];		/* XXX */
    387 static char bounced[8];		/* XXX */
    388 #define MAXDMASZ 512		/* XXX */
    389 
    390 /* high byte of address is stored in this port for i-th dma channel */
    391 static short dmapageport[8] =
    392 	{ 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
    393 
    394 /*
    395  * isa_dmacascade(): program 8237 DMA controller channel to accept
    396  * external dma control by a board.
    397  */
    398 void
    399 isa_dmacascade(chan)
    400 	int chan;
    401 {
    402 
    403 #ifdef DIAGNOSTIC
    404 	if (chan < 0 || chan > 7)
    405 		panic("isa_dmacascade: impossible request");
    406 #endif
    407 
    408 	/* set dma channel mode, and set dma channel mode */
    409 	if ((chan & 4) == 0) {
    410 		outb(DMA1_MODE, DMA37MD_CASCADE | chan);
    411 		outb(DMA1_SMSK, chan);
    412 	} else {
    413 		outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
    414 		outb(DMA2_SMSK, chan & 3);
    415 	}
    416 }
    417 
    418 /*
    419  * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
    420  * problems by using a bounce buffer.
    421  */
    422 void
    423 isa_dmastart(flags, addr, nbytes, chan)
    424 	int flags;
    425 	caddr_t addr;
    426 	vm_size_t nbytes;
    427 	int chan;
    428 {
    429 	vm_offset_t phys;
    430 	int waport;
    431 	caddr_t newaddr;
    432 
    433 #ifdef DIAGNOSTIC
    434 	if (chan < 0 || chan > 7 ||
    435 	    ((chan & 4) ? (nbytes >= (1<<17) || nbytes & 1 || (u_int)addr & 1) :
    436 	    (nbytes >= (1<<16))))
    437 		panic("isa_dmastart: impossible request");
    438 #endif
    439 
    440 	if (isa_dmarangecheck(addr, nbytes, chan)) {
    441 		if (dma_bounce[chan] == 0)
    442 			dma_bounce[chan] =
    443 			    /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
    444 			    (caddr_t) isaphysmem + NBPG*chan;
    445 		bounced[chan] = 1;
    446 		newaddr = dma_bounce[chan];
    447 		*(int *) newaddr = 0;	/* XXX */
    448 		/* copy bounce buffer on write */
    449 		if ((flags & B_READ) == 0)
    450 			bcopy(addr, newaddr, nbytes);
    451 		addr = newaddr;
    452 	}
    453 
    454 	/* translate to physical */
    455 	phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
    456 
    457 	if ((chan & 4) == 0) {
    458 		/*
    459 		 * Program one of DMA channels 0..3.  These are
    460 		 * byte mode channels.
    461 		 */
    462 		/* set dma channel mode, and reset address ff */
    463 		if (flags & B_READ)
    464 			outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_WRITE);
    465 		else
    466 			outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_READ);
    467 		outb(DMA1_FFC, 0);
    468 
    469 		/* send start address */
    470 		waport =  DMA1_CHN(chan);
    471 		outb(waport, phys);
    472 		outb(waport, phys>>8);
    473 		outb(dmapageport[chan], phys>>16);
    474 
    475 		/* send count */
    476 		outb(waport + 1, --nbytes);
    477 		outb(waport + 1, nbytes>>8);
    478 
    479 		/* unmask channel */
    480 		outb(DMA1_SMSK, chan | DMA37SM_CLEAR);
    481 	} else {
    482 		/*
    483 		 * Program one of DMA channels 4..7.  These are
    484 		 * word mode channels.
    485 		 */
    486 		/* set dma channel mode, and reset address ff */
    487 		if (flags & B_READ)
    488 			outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_WRITE);
    489 		else
    490 			outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_READ);
    491 		outb(DMA2_FFC, 0);
    492 
    493 		/* send start address */
    494 		waport = DMA2_CHN(chan & 3);
    495 		outb(waport, phys>>1);
    496 		outb(waport, phys>>9);
    497 		outb(dmapageport[chan], phys>>16);
    498 
    499 		/* send count */
    500 		nbytes >>= 1;
    501 		outb(waport + 2, --nbytes);
    502 		outb(waport + 2, nbytes>>8);
    503 
    504 		/* unmask channel */
    505 		outb(DMA2_SMSK, (chan & 3) | DMA37SM_CLEAR);
    506 	}
    507 }
    508 
    509 void
    510 isa_dmaabort(chan)
    511 	int chan;
    512 {
    513 
    514 #ifdef DIAGNOSTIC
    515 	if (chan < 0 || chan > 7)
    516 		panic("isa_dmadone: impossible request");
    517 #endif
    518 
    519 	bounced[chan] = 0;
    520 
    521 	/* mask channel */
    522 	if ((chan & 4) == 0)
    523 		outb(DMA1_SMSK, DMA37SM_SET | chan);
    524 	else
    525 		outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
    526 }
    527 
    528 void
    529 isa_dmadone(flags, addr, nbytes, chan)
    530 	int flags;
    531 	caddr_t addr;
    532 	vm_size_t nbytes;
    533 	int chan;
    534 {
    535 	u_char tc;
    536 
    537 #ifdef DIAGNOSTIC
    538 	if (chan < 0 || chan > 7)
    539 		panic("isa_dmadone: impossible request");
    540 #endif
    541 
    542 	/* check that the terminal count was reached */
    543 	if ((chan & 4) == 0)
    544 		tc = inb(DMA1_SR) & (1 << chan);
    545 	else
    546 		tc = inb(DMA2_SR) & (1 << (chan & 3));
    547 	if (tc == 0)
    548 		/* XXX probably should panic or something */
    549 		log(LOG_ERR, "dma channel %d not finished\n", chan);
    550 
    551 	/* copy bounce buffer on read */
    552 	if (bounced[chan]) {
    553 		bcopy(dma_bounce[chan], addr, nbytes);
    554 		bounced[chan] = 0;
    555 	}
    556 
    557 	/* mask channel */
    558 	if ((chan & 4) == 0)
    559 		outb(DMA1_SMSK, DMA37SM_SET | chan);
    560 	else
    561 		outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
    562 }
    563 
    564 /*
    565  * Check for problems with the address range of a DMA transfer
    566  * (non-contiguous physical pages, outside of bus address space,
    567  * crossing DMA page boundaries).
    568  * Return true if special handling needed.
    569  */
    570 int
    571 isa_dmarangecheck(va, length, chan)
    572 	vm_offset_t va;
    573 	u_long length;
    574 	int chan;
    575 {
    576 	vm_offset_t phys, priorpage = 0, endva;
    577 	u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
    578 
    579 	endva = round_page(va + length);
    580 	for (; va < endva ; va += NBPG) {
    581 		phys = trunc_page(pmap_extract(pmap_kernel(), va));
    582 		if (phys == 0)
    583 			panic("isa_dmacheck: no physical page present");
    584 		if (phys >= (1<<24))
    585 			return 1;
    586 		if (priorpage) {
    587 			if (priorpage + NBPG != phys)
    588 				return 1;
    589 			/* check if crossing a DMA page boundary */
    590 			if ((priorpage ^ phys) & dma_pgmsk)
    591 				return 1;
    592 		}
    593 		priorpage = phys;
    594 	}
    595 	return 0;
    596 }
    597 
    598 /* head of queue waiting for physmem to become available */
    599 struct buf isa_physmemq;
    600 
    601 /* blocked waiting for resource to become free for exclusive use */
    602 static isaphysmemflag;
    603 /* if waited for and call requested when free (B_CALL) */
    604 static void (*isaphysmemunblock)(); /* needs to be a list */
    605 
    606 /*
    607  * Allocate contiguous physical memory for transfer, returning
    608  * a *virtual* address to region. May block waiting for resource.
    609  * (assumed to be called at splbio())
    610  */
    611 caddr_t
    612 isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
    613 
    614 	isaphysmemunblock = func;
    615 	while (isaphysmemflag & B_BUSY) {
    616 		isaphysmemflag |= B_WANTED;
    617 		sleep((caddr_t)&isaphysmemflag, PRIBIO);
    618 	}
    619 	isaphysmemflag |= B_BUSY;
    620 
    621 	return((caddr_t)isaphysmem);
    622 }
    623 
    624 /*
    625  * Free contiguous physical memory used for transfer.
    626  * (assumed to be called at splbio())
    627  */
    628 void
    629 isa_freephysmem(caddr_t va, unsigned length) {
    630 
    631 	isaphysmemflag &= ~B_BUSY;
    632 	if (isaphysmemflag & B_WANTED) {
    633 		isaphysmemflag &= B_WANTED;
    634 		wakeup((caddr_t)&isaphysmemflag);
    635 		if (isaphysmemunblock)
    636 			(*isaphysmemunblock)();
    637 	}
    638 }
    639 
    640 /*
    641  * Handle a NMI, possibly a machine check.
    642  * return true to panic system, false to ignore.
    643  */
    644 int
    645 isa_nmi(cd) {
    646 
    647 	log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
    648 	return(0);
    649 }
    650 
    651 /*
    652  * Caught a stray interrupt, notify
    653  */
    654 void
    655 isa_strayintr(d) {
    656 
    657 	/* DON'T BOTHER FOR NOW! */
    658 	/* for some reason, we get bursts of intr #7, even if not enabled! */
    659 	/*
    660 	 * Well the reason you got bursts of intr #7 is because someone
    661 	 * raised an interrupt line and dropped it before the 8259 could
    662 	 * prioritize it.  This is documented in the intel data book.  This
    663 	 * means you have BAD hardware!  I have changed this so that only
    664 	 * the first 5 get logged, then it quits logging them, and puts
    665 	 * out a special message. rgrimes 3/25/1993
    666 	 */
    667 	extern u_long intrcnt_stray;
    668 
    669 	intrcnt_stray++;
    670 	if (intrcnt_stray <= 5)
    671 		log(LOG_ERR,"ISA strayintr %x\n", d);
    672 	if (intrcnt_stray == 5)
    673 		log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
    674 }
    675 
    676 static beeping;
    677 static void
    678 sysbeepstop(int f)
    679 {
    680 	int s = splhigh();
    681 
    682 	/* disable counter 2 */
    683 	disable_intr();
    684 	outb(PITAUX_PORT, inb(PITAUX_PORT) & ~PIT_SPKR);
    685 	enable_intr();
    686 	if (f)
    687 		timeout((timeout_t)sysbeepstop, (caddr_t)0, f);
    688 	else
    689 		beeping = 0;
    690 
    691 	splx(s);
    692 }
    693 
    694 void
    695 sysbeep(int pitch, int period)
    696 {
    697 	int s = splhigh();
    698 	static int last_pitch, last_period;
    699 
    700 	if (beeping) {
    701 		untimeout((timeout_t)sysbeepstop, (caddr_t)(last_period/2));
    702 		untimeout((timeout_t)sysbeepstop, (caddr_t)0);
    703 	}
    704 	if (!beeping || last_pitch != pitch) {
    705 		/*
    706 	 	* XXX - move timer stuff to clock.c.
    707 	 	*/
    708 		disable_intr();
    709 		outb(TIMER_MODE, TIMER_SEL2|TIMER_16BIT|TIMER_SQWAVE);
    710 		outb(TIMER_CNTR2, TIMER_DIV(pitch)%256);
    711 		outb(TIMER_CNTR2, TIMER_DIV(pitch)/256);
    712 		outb(PITAUX_PORT, inb(PITAUX_PORT) | PIT_SPKR);	/* enable counter 2 */
    713 		enable_intr();
    714 	}
    715 	last_pitch = pitch;
    716 	beeping = last_period = period;
    717 	timeout((timeout_t)sysbeepstop, (caddr_t)(period/2), period);
    718 
    719 	splx(s);
    720 }
    721 
    722 /*
    723  * Return nonzero if a (masked) irq is pending for a given device.
    724  */
    725 int
    726 isa_irq_pending(dvp)
    727 	struct isa_device *dvp;
    728 {
    729 	unsigned id_irq;
    730 
    731 	id_irq = (unsigned short) dvp->id_irq;	/* XXX silly type in struct */
    732 	if (id_irq & 0xff)
    733 		return (inb(IO_ICU1) & id_irq);
    734 	return (inb(IO_ICU2) & (id_irq >> 8));
    735 }
    736