166458Sdfr/*- 266458Sdfr * Copyright (c) 1991 The Regents of the University of California. 366458Sdfr * All rights reserved. 466458Sdfr * 566458Sdfr * This code is derived from software contributed to Berkeley by 666458Sdfr * William Jolitz. 766458Sdfr * 866458Sdfr * Redistribution and use in source and binary forms, with or without 966458Sdfr * modification, are permitted provided that the following conditions 1066458Sdfr * are met: 1166458Sdfr * 1. Redistributions of source code must retain the above copyright 1266458Sdfr * notice, this list of conditions and the following disclaimer. 1366458Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1466458Sdfr * notice, this list of conditions and the following disclaimer in the 1566458Sdfr * documentation and/or other materials provided with the distribution. 1666458Sdfr * 4. Neither the name of the University nor the names of its contributors 1766458Sdfr * may be used to endorse or promote products derived from this software 1866458Sdfr * without specific prior written permission. 1966458Sdfr * 2066458Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2166458Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2266458Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2366458Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2466458Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2566458Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2666458Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2766458Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2866458Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2966458Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3066458Sdfr * SUCH DAMAGE. 3166458Sdfr * 3266458Sdfr * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 3366458Sdfr * from: isa_dma.c,v 1.3 1999/05/09 23:56:00 peter Exp $ 3466458Sdfr * $FreeBSD$ 3566458Sdfr */ 3666458Sdfr 3766458Sdfr/* 3866458Sdfr * code to manage AT bus 3966458Sdfr * 4066458Sdfr * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): 4166458Sdfr * Fixed uninitialized variable problem and added code to deal 4266458Sdfr * with DMA page boundaries in isa_dmarangecheck(). Fixed word 4366458Sdfr * mode DMA count compution and reorganized DMA setup code in 4466458Sdfr * isa_dmastart() 4566458Sdfr */ 4666458Sdfr 4766458Sdfr#include <sys/param.h> 4866458Sdfr#include <sys/systm.h> 4966458Sdfr#include <sys/malloc.h> 50117126Sscottl#include <sys/lock.h> 51117126Sscottl#include <sys/mutex.h> 5266458Sdfr#include <sys/bus.h> 5366458Sdfr#include <vm/vm.h> 5466458Sdfr#include <vm/vm_param.h> 5566458Sdfr#include <vm/pmap.h> 5666458Sdfr#include <isa/isareg.h> 5766458Sdfr#include <isa/isavar.h> 58146214Snyan#include <isa/isa_dmareg.h> 5966458Sdfr#include <machine/bus.h> 6066458Sdfr 6166458Sdfrstatic bus_dma_tag_t dma_tag[8]; 6266458Sdfrstatic bus_dmamap_t dma_map[8]; 6366458Sdfrstatic u_int8_t dma_busy = 0; /* Used in isa_dmastart() */ 6466458Sdfrstatic u_int8_t dma_inuse = 0; /* User for acquire/release */ 6566458Sdfrstatic u_int8_t dma_auto_mode = 0; 6666458Sdfrstatic u_int8_t dma_bounced = 0; 6766458Sdfr 6866458Sdfr#define VALID_DMA_MASK (7) 6966458Sdfr 7066458Sdfr/* high byte of address is stored in this port for i-th dma channel */ 7166458Sdfrstatic int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; 7266458Sdfr 7366458Sdfr/* 7466458Sdfr * Setup a DMA channel's bounce buffer. 7566458Sdfr */ 76135262Sphkint 77135262Sphkisa_dma_init(int chan, u_int bouncebufsize, int flag __unused) 7866458Sdfr{ 7966458Sdfr static int initted = 0; 8066458Sdfr bus_addr_t boundary = chan >= 4 ? 0x20000 : 0x10000; 8166458Sdfr 8266458Sdfr if (!initted) { 8366458Sdfr /* 8466458Sdfr * Reset the DMA hardware. 8566458Sdfr */ 8666458Sdfr outb(DMA1_RESET, 0); 8766458Sdfr outb(DMA2_RESET, 0); 8866458Sdfr isa_dmacascade(4); 8966458Sdfr 9066458Sdfr initted = 1; 9166458Sdfr } 9266458Sdfr 9366458Sdfr#ifdef DIAGNOSTIC 9466458Sdfr if (chan & ~VALID_DMA_MASK) 95135262Sphk panic("isa_dma_init: channel out of range"); 9666458Sdfr 9766458Sdfr if (dma_tag[chan] || dma_map[chan]) 98135262Sphk panic("isa_dma_init: impossible request"); 9966458Sdfr#endif 10066458Sdfr 10166458Sdfr if (bus_dma_tag_create(/*parent*/NULL, 10266458Sdfr /*alignment*/2, 10366458Sdfr /*boundary*/boundary, 10466458Sdfr /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 10566458Sdfr /*highaddr*/BUS_SPACE_MAXADDR, 10666458Sdfr /*filter*/NULL, /*filterarg*/NULL, 10766458Sdfr /*maxsize*/bouncebufsize, 10866458Sdfr /*nsegments*/1, /*maxsegz*/0x3ffff, 109177215Simp /*flags*/0, 110117126Sscottl /*lockfunc*/busdma_lock_mutex, 111117126Sscottl /*lockarg*/&Giant, 11266458Sdfr &dma_tag[chan]) != 0) { 113135262Sphk panic("isa_dma_init: unable to create dma tag\n"); 11466458Sdfr } 11566458Sdfr 11666458Sdfr if (bus_dmamap_create(dma_tag[chan], 0, &dma_map[chan])) { 117135262Sphk panic("isa_dma_init: unable to create dma map\n"); 11866458Sdfr } 11966458Sdfr 120135262Sphk return (0); 12166458Sdfr} 12266458Sdfr 12366458Sdfr/* 12466458Sdfr * Register a DMA channel's usage. Usually called from a device driver 12566458Sdfr * in open() or during its initialization. 12666458Sdfr */ 12766458Sdfrint 12866458Sdfrisa_dma_acquire(chan) 12966458Sdfr int chan; 13066458Sdfr{ 13166458Sdfr#ifdef DIAGNOSTIC 13266458Sdfr if (chan & ~VALID_DMA_MASK) 13366458Sdfr panic("isa_dma_acquire: channel out of range"); 13466458Sdfr#endif 13566458Sdfr 13666458Sdfr if (dma_inuse & (1 << chan)) { 13766458Sdfr printf("isa_dma_acquire: channel %d already in use\n", chan); 13866458Sdfr return (EBUSY); 13966458Sdfr } 14066458Sdfr dma_inuse |= (1 << chan); 14166458Sdfr dma_auto_mode &= ~(1 << chan); 14266458Sdfr 14366458Sdfr return (0); 14466458Sdfr} 14566458Sdfr 14666458Sdfr/* 14766458Sdfr * Unregister a DMA channel's usage. Usually called from a device driver 14866458Sdfr * during close() or during its shutdown. 14966458Sdfr */ 15066458Sdfrvoid 15166458Sdfrisa_dma_release(chan) 15266458Sdfr int chan; 15366458Sdfr{ 15466458Sdfr#ifdef DIAGNOSTIC 15566458Sdfr if (chan & ~VALID_DMA_MASK) 15666458Sdfr panic("isa_dma_release: channel out of range"); 15766458Sdfr 15866458Sdfr if ((dma_inuse & (1 << chan)) == 0) 15966458Sdfr printf("isa_dma_release: channel %d not in use\n", chan); 16066458Sdfr#endif 16166458Sdfr 16266458Sdfr if (dma_busy & (1 << chan)) { 16366458Sdfr dma_busy &= ~(1 << chan); 16466458Sdfr /* 16566458Sdfr * XXX We should also do "dma_bounced &= (1 << chan);" 16666458Sdfr * because we are acting on behalf of isa_dmadone() which 16766458Sdfr * was not called to end the last DMA operation. This does 16866458Sdfr * not matter now, but it may in the future. 16966458Sdfr */ 17066458Sdfr } 17166458Sdfr 17266458Sdfr dma_inuse &= ~(1 << chan); 17366458Sdfr dma_auto_mode &= ~(1 << chan); 17466458Sdfr} 17566458Sdfr 17666458Sdfr/* 17766458Sdfr * isa_dmacascade(): program 8237 DMA controller channel to accept 17866458Sdfr * external dma control by a board. 17966458Sdfr */ 18066458Sdfrvoid 18166458Sdfrisa_dmacascade(chan) 18266458Sdfr int chan; 18366458Sdfr{ 18466458Sdfr#ifdef DIAGNOSTIC 18566458Sdfr if (chan & ~VALID_DMA_MASK) 18666458Sdfr panic("isa_dmacascade: channel out of range"); 18766458Sdfr#endif 18866458Sdfr 18966458Sdfr /* set dma channel mode, and set dma channel mode */ 19066458Sdfr if ((chan & 4) == 0) { 19166458Sdfr outb(DMA1_MODE, DMA37MD_CASCADE | chan); 19266458Sdfr outb(DMA1_SMSK, chan); 19366458Sdfr } else { 19466458Sdfr outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); 19566458Sdfr outb(DMA2_SMSK, chan & 3); 19666458Sdfr } 19766458Sdfr} 19866458Sdfr 19966458Sdfr/* 20066458Sdfr * isa_dmastart(): program 8237 DMA controller channel. 20166458Sdfr */ 20266458Sdfr 20366458Sdfrstruct isa_dmastart_arg { 20466458Sdfr caddr_t addr; 20566458Sdfr int chan; 20666458Sdfr int flags; 20766458Sdfr}; 20866458Sdfr 20966458Sdfrstatic void isa_dmastart_cb(void *arg, bus_dma_segment_t *segs, int nseg, 21066458Sdfr int error) 21166458Sdfr{ 21292676Speter#if 0 21366458Sdfr caddr_t addr = ((struct isa_dmastart_arg *) arg)->addr; 21492676Speter#endif 21566458Sdfr int chan = ((struct isa_dmastart_arg *) arg)->chan; 21666458Sdfr int flags = ((struct isa_dmastart_arg *) arg)->flags; 21766458Sdfr bus_addr_t phys = segs->ds_addr; 21866458Sdfr int nbytes = segs->ds_len; 21966458Sdfr int waport; 22066458Sdfr 22166458Sdfr if (nseg != 1) 22266458Sdfr panic("isa_dmastart: transfer mapping not contiguous"); 22366458Sdfr 22466458Sdfr#if 0 22566458Sdfr if ((chipset.sgmap == NULL) && 22695710Speter (pmap_extract(kernel_pmap, (vm_offset_t)addr) 22766458Sdfr > BUS_SPACE_MAXADDR_24BIT)) { 22866458Sdfr /* we bounced */ 22966458Sdfr dma_bounced |= (1 << chan); 23066458Sdfr /* copy bounce buffer on write */ 23166458Sdfr if (!(flags & ISADMA_READ)) 23266458Sdfr bus_dmamap_sync(dma_tag[chan], dma_map[chan], 23366458Sdfr BUS_DMASYNC_PREWRITE); 23466458Sdfr } 23566458Sdfr#endif 23666458Sdfr 23766458Sdfr if ((chan & 4) == 0) { 23866458Sdfr /* 23966458Sdfr * Program one of DMA channels 0..3. These are 24066458Sdfr * byte mode channels. 24166458Sdfr */ 24266458Sdfr /* set dma channel mode, and reset address ff */ 24366458Sdfr 24466458Sdfr /* If ISADMA_RAW flag is set, then use autoinitialise mode */ 24566458Sdfr if (flags & ISADMA_RAW) { 24666458Sdfr if (flags & ISADMA_READ) 24766458Sdfr outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan); 24866458Sdfr else 24966458Sdfr outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan); 25066458Sdfr } 25166458Sdfr else 25266458Sdfr if (flags & ISADMA_READ) 25366458Sdfr outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); 25466458Sdfr else 25566458Sdfr outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); 25666458Sdfr outb(DMA1_FFC, 0); 25766458Sdfr 25866458Sdfr /* send start address */ 25966458Sdfr waport = DMA1_CHN(chan); 26066458Sdfr outb(waport, phys); 26166458Sdfr outb(waport, phys>>8); 26266458Sdfr outb(dmapageport[chan], phys>>16); 26366458Sdfr 26466458Sdfr /* send count */ 26566458Sdfr outb(waport + 1, --nbytes); 26666458Sdfr outb(waport + 1, nbytes>>8); 26766458Sdfr 26866458Sdfr /* unmask channel */ 26966458Sdfr outb(DMA1_SMSK, chan); 27066458Sdfr } else { 27166458Sdfr /* 27266458Sdfr * Program one of DMA channels 4..7. These are 27366458Sdfr * word mode channels. 27466458Sdfr */ 27566458Sdfr /* set dma channel mode, and reset address ff */ 27666458Sdfr 27766458Sdfr /* If ISADMA_RAW flag is set, then use autoinitialise mode */ 27866458Sdfr if (flags & ISADMA_RAW) { 27966458Sdfr if (flags & ISADMA_READ) 28066458Sdfr outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3)); 28166458Sdfr else 28266458Sdfr outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3)); 28366458Sdfr } 28466458Sdfr else 28566458Sdfr if (flags & ISADMA_READ) 28666458Sdfr outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); 28766458Sdfr else 28866458Sdfr outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); 28966458Sdfr outb(DMA2_FFC, 0); 29066458Sdfr 29166458Sdfr /* send start address */ 29266458Sdfr waport = DMA2_CHN(chan - 4); 29366458Sdfr outb(waport, phys>>1); 29466458Sdfr outb(waport, phys>>9); 29566458Sdfr outb(dmapageport[chan], phys>>16); 29666458Sdfr 29766458Sdfr /* send count */ 29866458Sdfr nbytes >>= 1; 29966458Sdfr outb(waport + 2, --nbytes); 30066458Sdfr outb(waport + 2, nbytes>>8); 30166458Sdfr 30266458Sdfr /* unmask channel */ 30366458Sdfr outb(DMA2_SMSK, chan & 3); 30466458Sdfr } 30566458Sdfr} 30666458Sdfr 30766458Sdfrvoid 30866458Sdfrisa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan) 30966458Sdfr{ 31066458Sdfr struct isa_dmastart_arg args; 31166458Sdfr 31266458Sdfr#ifdef DIAGNOSTIC 31366458Sdfr if (chan & ~VALID_DMA_MASK) 31466458Sdfr panic("isa_dmastart: channel out of range"); 31566458Sdfr 31666458Sdfr if ((chan < 4 && nbytes > (1<<16)) 31766458Sdfr || (chan >= 4 && (nbytes > (1<<17) || (uintptr_t)addr & 1))) 31866458Sdfr panic("isa_dmastart: impossible request"); 31966458Sdfr 32066458Sdfr if ((dma_inuse & (1 << chan)) == 0) 32166458Sdfr printf("isa_dmastart: channel %d not acquired\n", chan); 32266458Sdfr#endif 32366458Sdfr 32466458Sdfr#if 0 32566458Sdfr /* 32666458Sdfr * XXX This should be checked, but drivers like ad1848 only call 32766458Sdfr * isa_dmastart() once because they use Auto DMA mode. If we 32866458Sdfr * leave this in, drivers that do this will print this continuously. 32966458Sdfr */ 33066458Sdfr if (dma_busy & (1 << chan)) 33166458Sdfr printf("isa_dmastart: channel %d busy\n", chan); 33266458Sdfr#endif 33366458Sdfr 334171312Smarcel if (!dma_tag[chan] || !dma_map[chan]) 335135262Sphk panic("isa_dmastart: called without isa_dma_init"); 33666458Sdfr 33766458Sdfr dma_busy |= (1 << chan); 33866458Sdfr 33966458Sdfr if (flags & ISADMA_RAW) { 34066458Sdfr dma_auto_mode |= (1 << chan); 34166458Sdfr } else { 34266458Sdfr dma_auto_mode &= ~(1 << chan); 34366458Sdfr } 34466458Sdfr 34566458Sdfr /* 34666458Sdfr * Freeze dma while updating registers. 34766458Sdfr */ 34866458Sdfr outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4); 34966458Sdfr 35066458Sdfr args.addr = addr; 35166458Sdfr args.chan = chan; 35266458Sdfr args.flags = flags; 35366458Sdfr bus_dmamap_load(dma_tag[chan], dma_map[chan], addr, nbytes, 35466458Sdfr isa_dmastart_cb, &args, 0); 35566458Sdfr} 35666458Sdfr 35766458Sdfrvoid 35866458Sdfrisa_dmadone(int flags, caddr_t addr, int nbytes, int chan) 35966458Sdfr{ 36066458Sdfr#ifdef DIAGNOSTIC 36166458Sdfr if (chan & ~VALID_DMA_MASK) 36266458Sdfr panic("isa_dmadone: channel out of range"); 36366458Sdfr 36466458Sdfr if ((dma_inuse & (1 << chan)) == 0) 36566458Sdfr printf("isa_dmadone: channel %d not acquired\n", chan); 36666458Sdfr#endif 36766458Sdfr 36866458Sdfr if (((dma_busy & (1 << chan)) == 0) && 36966458Sdfr (dma_auto_mode & (1 << chan)) == 0 ) 37066458Sdfr printf("isa_dmadone: channel %d not busy\n", chan); 37166458Sdfr 37266458Sdfr if (dma_bounced & (1 << chan)) { 37366458Sdfr /* copy bounce buffer on read */ 37466458Sdfr if (flags & ISADMA_READ) { 37566458Sdfr bus_dmamap_sync(dma_tag[chan], dma_map[chan], 37666458Sdfr BUS_DMASYNC_POSTREAD); 37766458Sdfr } 37866458Sdfr dma_bounced &= ~(1 << chan); 37966458Sdfr } 38066458Sdfr 38166458Sdfr if ((dma_auto_mode & (1 << chan)) == 0) { 38266458Sdfr outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4); 38366458Sdfr bus_dmamap_unload(dma_tag[chan], dma_map[chan]); 38466458Sdfr } 38566458Sdfr 38666458Sdfr dma_busy &= ~(1 << chan); 38766458Sdfr} 38866458Sdfr 38966458Sdfr/* 39066458Sdfr * Query the progress of a transfer on a DMA channel. 39166458Sdfr * 39266458Sdfr * To avoid having to interrupt a transfer in progress, we sample 39366458Sdfr * each of the high and low databytes twice, and apply the following 39466458Sdfr * logic to determine the correct count. 39566458Sdfr * 39666458Sdfr * Reads are performed with interrupts disabled, thus it is to be 39766458Sdfr * expected that the time between reads is very small. At most 39866458Sdfr * one rollover in the low count byte can be expected within the 39966458Sdfr * four reads that are performed. 40066458Sdfr * 40166458Sdfr * There are three gaps in which a rollover can occur : 40266458Sdfr * 40366458Sdfr * - read low1 40466458Sdfr * gap1 40566458Sdfr * - read high1 40666458Sdfr * gap2 40766458Sdfr * - read low2 40866458Sdfr * gap3 40966458Sdfr * - read high2 41066458Sdfr * 41166458Sdfr * If a rollover occurs in gap1 or gap2, the low2 value will be 41266458Sdfr * greater than the low1 value. In this case, low2 and high2 are a 41366458Sdfr * corresponding pair. 41466458Sdfr * 41566458Sdfr * In any other case, low1 and high1 can be considered to be correct. 41666458Sdfr * 41766458Sdfr * The function returns the number of bytes remaining in the transfer, 41866458Sdfr * or -1 if the channel requested is not active. 41966458Sdfr * 42066458Sdfr */ 42166458Sdfrint 42266458Sdfrisa_dmastatus(int chan) 42366458Sdfr{ 42466458Sdfr u_long cnt = 0; 42566458Sdfr int ffport, waport; 42666458Sdfr u_long low1, high1, low2, high2; 42766458Sdfr int s; 42866458Sdfr 42966458Sdfr /* channel active? */ 43066458Sdfr if ((dma_inuse & (1 << chan)) == 0) { 43166458Sdfr printf("isa_dmastatus: channel %d not active\n", chan); 43266458Sdfr return(-1); 43366458Sdfr } 43466458Sdfr /* channel busy? */ 43566458Sdfr 43666458Sdfr if (((dma_busy & (1 << chan)) == 0) && 43766458Sdfr (dma_auto_mode & (1 << chan)) == 0 ) { 43866458Sdfr printf("chan %d not busy\n", chan); 43966458Sdfr return -2 ; 44066458Sdfr } 44166458Sdfr if (chan < 4) { /* low DMA controller */ 44266458Sdfr ffport = DMA1_FFC; 44366458Sdfr waport = DMA1_CHN(chan) + 1; 44466458Sdfr } else { /* high DMA controller */ 44566458Sdfr ffport = DMA2_FFC; 44666458Sdfr waport = DMA2_CHN(chan - 4) + 2; 44766458Sdfr } 44866458Sdfr 44966458Sdfr s = splhigh(); /* no interrupts Mr Jones! */ 45066458Sdfr outb(ffport, 0); /* clear register LSB flipflop */ 45166458Sdfr low1 = inb(waport); 45266458Sdfr high1 = inb(waport); 45366458Sdfr outb(ffport, 0); /* clear again */ 45466458Sdfr low2 = inb(waport); 45566458Sdfr high2 = inb(waport); 45666458Sdfr splx(s); /* enable interrupts again */ 45766458Sdfr 45866458Sdfr /* 45966458Sdfr * Now decide if a wrap has tried to skew our results. 46066458Sdfr * Note that after TC, the count will read 0xffff, while we want 46166458Sdfr * to return zero, so we add and then mask to compensate. 46266458Sdfr */ 46366458Sdfr if (low1 >= low2) { 46466458Sdfr cnt = (low1 + (high1 << 8) + 1) & 0xffff; 46566458Sdfr } else { 46666458Sdfr cnt = (low2 + (high2 << 8) + 1) & 0xffff; 46766458Sdfr } 46866458Sdfr 46966458Sdfr if (chan >= 4) /* high channels move words */ 47066458Sdfr cnt *= 2; 47166458Sdfr return(cnt); 47266458Sdfr} 47366458Sdfr 47466458Sdfr/* 475141391Sphk * Reached terminal count yet ? 476141391Sphk */ 477141391Sphkint 478141391Sphkisa_dmatc(int chan) 479141391Sphk{ 480141391Sphk 481141391Sphk if (chan < 4) 482141391Sphk return(inb(DMA1_STATUS) & (1 << chan)); 483141391Sphk else 484141391Sphk return(inb(DMA2_STATUS) & (1 << (chan & 3))); 485141391Sphk} 486141391Sphk 487141391Sphk/* 48866458Sdfr * Stop a DMA transfer currently in progress. 48966458Sdfr */ 49066458Sdfrint 49166458Sdfrisa_dmastop(int chan) 49266458Sdfr{ 49366458Sdfr if ((dma_inuse & (1 << chan)) == 0) 49466458Sdfr printf("isa_dmastop: channel %d not acquired\n", chan); 49566458Sdfr 49666458Sdfr if (((dma_busy & (1 << chan)) == 0) && 49766458Sdfr ((dma_auto_mode & (1 << chan)) == 0)) { 49866458Sdfr printf("chan %d not busy\n", chan); 49966458Sdfr return -2 ; 50066458Sdfr } 50166458Sdfr 50266458Sdfr if ((chan & 4) == 0) { 50366458Sdfr outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */); 50466458Sdfr } else { 50566458Sdfr outb(DMA2_SMSK, (chan & 3) | 4 /* disable mask */); 50666458Sdfr } 50766458Sdfr return(isa_dmastatus(chan)); 50866458Sdfr} 509