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