Coherent4.2.10/i386/dmac.c
/* $Header: /ker/i386/RCS/dmac.c,v 2.4 93/10/29 00:56:43 nigel Exp Locker: nigel $ */
/* (lgl-
* The information contained herein is a trade secret of Mark Williams
* Company, and is confidential information. It is provided under a
* license agreement, and may be copied or disclosed only under the
* terms of that agreement. Any reproduction or disclosure of this
* material without the express written authorization of Mark Williams
* Company or persuant to the license agreement is unlawful.
*
* COHERENT Version 2.3.37
* Copyright (c) 1982, 1983, 1984.
* An unpublished work by Mark Williams Company, Chicago.
* All rights reserved.
-lgl) */
/*
* Program the 8237 DMA controller on the system board.
* $Log: dmac.c,v $
* Revision 2.4 93/10/29 00:56:43 nigel
* R98 (aka 4.2 Beta) prior to removing System Global memory
*
* Revision 2.3 93/08/19 03:40:01 nigel
* Nigel's R83
*/
#include <sys/types.h>
#define _KERNEL 1
#include <kernel/reg.h>
#include <sys/dmac.h>
/*
* Identify the dma segment of a physical address.
*/
#if 0
/* This variant explains part of hcp's problems with COH ddk dma. */
#define dmaseg(p) ((p) & ~ (NBPC - 1))
#else
/* A "dma segment" is a range of addresses within consecutive 64k physical
boundaries. */
#define dmaseg(p) ((p) & ~ (0xffff))
#endif
/*
* This table maps channel
* numbers into DMA page address
* register ports. The wiring of the
* RA lines on the 74LS670 is a bit
* strange.
*/
static int dmaport[8] = {
DMAPAGE + 7, /* 0 (Free) */
DMAPAGE + 3, /* 1 (Free) */
DMAPAGE + 1, /* 2 (Floppy) */
DMAPAGE + 2, /* 3 (Free) */
DMAPAGE + 15, /* 4 (Cascade) */
DMAPAGE + 11, /* 5 */
DMAPAGE + 9, /* 6 */
DMAPAGE + 10 /* 7 */
};
/*
* Program the channel of the
* 8237 DMA controller specified by
* "chan". The "paddr" is a 20 bit
* physical address. The "count" is
* the byte count. The "wflag" is
* true if this is a write, from the
* point of view of the device.
* True return if the mapping can be
* set up, given the 64K limits.
* The "count" is predecremented, so
* that backplane "+T/C" is issued at
* the expected point in time.
*/
int
dmaon(chan, paddr, count, wflag)
register int chan;
paddr_t paddr;
unsigned count;
int wflag;
{
int port;
int s;
/*
* Change from 0 based transfer count to -1 based.
*/
count --;
/*
* Select byte/word transfer.
* Channels 0-4 use byte transfer.
* Channels 5-7 use word transfers, with low 17 addr bits right shifted.
*/
if (chan >= 5) {
count >>= 1;
paddr >>= 1;
paddr += paddr & 0xFF0000L;
}
/*
* Check for DMA straddle.
*/
if (dmaseg (paddr) != dmaseg (paddr + count))
return 0;
s = sphi ();
/*
* Select DMA controller.
*/
if (chan < 4) {
port = DMA;
/*
* Program for dma read/write operation.
*/
if (wflag != 0)
outb (port + SETMODE * 1, (chan & 3) | RDMEM);
else
outb (port + SETMODE * 1, (chan & 3) | WRMEM);
outb(port + CLEARFL * 1, 0);
} else {
port = SDMA;
/*
* Program for dma read/write operation.
*/
if (wflag != 0)
outb (SDMA + SETMODE * 2, (chan & 3) | RDMEM);
else
outb (SDMA + SETMODE * 2, (chan & 3) | WRMEM);
outb (SDMA + CLEARFL * 2, 0);
}
/*
* Select memory bank.
*/
outb (dmaport [chan], (int) (paddr >> 16));
if (chan < 4)
port += (chan & 3) << 1;
else
port += (chan & 3) << 2;
/*
* Program memory offset in bank.
*/
outb (port, (int) paddr >> 0);
outb (port, (int) paddr >> 8);
port ++;
if (chan >= 4)
port ++;
/*
* Program transfer count.
*/
outb (port, count >> 0);
outb (port, count >> 8);
spl (s);
return 1;
}
/*
* dmago(chan) - initiate dma transfer
*/
void
dmago(chan)
int chan;
{
/*
* Enable dma transfers.
*/
if (chan < 4)
outb (DMA + SETMASK * 1, (chan & 3) | MASKOFF);
else
outb (SDMA + SETMASK * 2, (chan & 3) | MASKOFF);
}
/*
* dmaoff(chan) - turn dma channel off, return residual count
*/
int
dmaoff(chan)
int chan;
{
int port;
int count;
int s;
/*
* Disable DMA transfers.
* Obtain the -1 based residual count.
*/
s = sphi ();
if (chan < 4) {
outb (DMA + SETMASK * 1, (chan & 3) | MASKON);
port = DMA + ((chan & 3) << 1) + 1;
} else {
outb (SDMA + SETMASK * 2, (chan & 3) | MASKON);
port = SDMA + ((chan & 3) << 2) + 2;
}
count = inb (port);
count += inb (port) << 8;
spl (s);
/* Convert residual from -1 based to 0 based. */
count ++;
/* Don't report a count of zero as a count of 65536! */
count &= 0xffff;
/*
* Convert residual from word based to byte based.
*/
if (chan >= 5)
count <<= 1;
/*
* Return residual count in bytes.
*/
return count;
}