Windows NT 4.0 source code leak
 
 
 
 
 
 

925 lines
22 KiB

#include "insignia.h"
#include "host_def.h"
/*
* SoftPC-AT Revision 3.0
*
* Title : IBM PC-AT DMA Adaptor Functions
*
* Description : This module contains functions that can be used to
* access the DMA Adaptor emulation
*
* Author : Ross Beresford
*
* Notes : The external interface to these functions is defined
* in the associated header file
*
*/
/*
* static char SccsID[]="@(#)at_dma.c 1.15 12/17/93 Copyright Insignia Solutions Ltd.";
*/
#ifdef SEGMENTATION
/*
* The following #include specifies the code segment into which this
* module will by placed by the MPW C compiler on the Mac II running
* MultiFinder.
*/
#include "AT_STUFF.seg"
#endif
/*
* System include files
*/
#include <stdio.h>
#include StringH
#include TypesH
/*
* SoftPC include files
*/
#include "xt.h"
#include "sas.h"
#include "ios.h"
#include "gmi.h"
#include CpuH
#include "trace.h"
#include "dma.h"
#include "debug.h"
/*
* ============================================================================
* Local static data and defines
* ============================================================================
*/
/* the DMA adaptor state */
static DMA_ADAPT adaptor = { 0 };
/* local function to do the actual transfer of data */
LOCAL void do_transfer IPT6(int, type, int, decrement,
sys_addr, dma_addr, char *, hw_buffer, unsigned long, length,
unsigned long, size);
LOCAL void bwd_dest_copy_to_M IPT3(host_addr, s, sys_addr, d, sys_addr, l);
LOCAL void bwd_dest_copy_from_M IPT3(sys_addr, s, host_addr, d,
sys_addr, l);
#ifdef LIM
static int lim_active = 0;
#endif /* LIM */
/*
* ============================================================================
* External functions
* ============================================================================
*/
#ifdef LIM
/*
** Called from do_transfer() and from init_struc.c in delta
** for the 800 port.
** lim_active is a static int
*/
GLOBAL int get_lim_setup IFN0()
{
return( lim_active );
}
#endif /* LIM */
#ifdef LIM
/*
** called from emm_funcs.c
*/
GLOBAL void dma_lim_setup IFN0()
{
lim_active = 1;
}
#endif /* LIM */
GLOBAL void dma_post IFN0()
{
unsigned int chan, cntrl;
/*
* Reset the DMA Adaptor
*/
for (cntrl = 0; cntrl < DMA_ADAPTOR_CONTROLLERS; cntrl++)
{
adaptor.controller[cntrl].command.all = 0;
adaptor.controller[cntrl].status.all = 0;
adaptor.controller[cntrl].request = 0;
adaptor.controller[cntrl].temporary = 0;
adaptor.controller[cntrl].mask = ~0;
adaptor.controller[cntrl].first_last = 0;
}
/*
* Set the DMA Adaptor channel modes
*/
for (cntrl = 0; cntrl < DMA_ADAPTOR_CONTROLLERS; cntrl++)
{
for (chan = 0; chan < DMA_CONTROLLER_CHANNELS; chan++)
{
adaptor.controller[cntrl].mode[chan].all = 0;
/* put the channels into their correct mode */
if (dma_logical_channel(cntrl, chan) == DMA_CASCADE_CHANNEL)
adaptor.controller[cntrl].mode[chan].bits.mode = DMA_CASCADE_MODE;
else
adaptor.controller[cntrl].mode[chan].bits.mode = DMA_SINGLE_MODE;
}
}
}
GLOBAL void dma_inb IFN2(io_addr, port, half_word *, value)
{
register DMA_CNTRL *dcp;
note_trace0_no_nl(DMA_VERBOSE, "dma_inb() ");
/*
* Get a pointer to the controller and mask out the port's
* redundant bits.
* The first check is commented out as DMA_PORT_START is zero,
* so the check on an unsigned variable is unnecessary.
*/
if (/*port >= DMA_PORT_START &&*/ port <= DMA_PORT_END)
{
dcp = &adaptor.controller[DMA_CONTROLLER];
port &= ~DMA_REDUNDANT_BITS;
}
else
{
dcp = &adaptor.controller[DMA1_CONTROLLER];
port &= ~DMA1_REDUNDANT_BITS;
}
/*
* When the current address and word count are read, the
* first/last flip-flop for the controller is used to
* determine which byte is accessed, and is then toggled.
*/
switch (port)
{
/* read channel current address on controller 0 */
case DMA_CH0_ADDRESS:
case DMA_CH1_ADDRESS:
case DMA_CH2_ADDRESS:
case DMA_CH3_ADDRESS:
*value = dcp->current_address[(port-DMA_CH0_ADDRESS)/2][dcp->first_last];
dcp->first_last ^= 1;
break;
/* read channel current address on controller 1 */
case DMA_CH4_ADDRESS:
case DMA_CH5_ADDRESS:
case DMA_CH6_ADDRESS:
case DMA_CH7_ADDRESS:
*value = dcp->current_address[(port-DMA_CH4_ADDRESS)/4][dcp->first_last];
dcp->first_last ^= 1;
break;
/* read channel current word count on controller 0 */
case DMA_CH0_COUNT:
case DMA_CH1_COUNT:
case DMA_CH2_COUNT:
case DMA_CH3_COUNT:
*value = dcp->current_count[(port-DMA_CH0_COUNT)/2][dcp->first_last];
dcp->first_last ^= 1;
break;
/* read channel current word count on controller 1 */
case DMA_CH4_COUNT:
case DMA_CH5_COUNT:
case DMA_CH6_COUNT:
case DMA_CH7_COUNT:
*value = dcp->current_count[(port-DMA_CH4_COUNT)/4][dcp->first_last];
dcp->first_last ^= 1;
break;
/* read status register - clears terminal counts */
case DMA_SHARED_REG_A:
case DMA1_SHARED_REG_A:
*value = dcp->status.all;
dcp->status.bits.terminal_count = 0;
break;
/* read temporary register */
case DMA_SHARED_REG_B:
case DMA1_SHARED_REG_B:
*value = dcp->temporary;
break;
default:
note_trace0_no_nl(DMA_VERBOSE, "<illegal read>");
break;
}
note_trace2(DMA_VERBOSE, " port 0x%04x, returning 0x%02x", port,
*value);
}
GLOBAL void dma_outb IFN2(io_addr, port, half_word, value)
{
register DMA_CNTRL *dcp;
note_trace0_no_nl(DMA_VERBOSE, "dma_outb() ");
/*
* Get a pointer to the controller and mask out the port's
* redundant bits.
* The first check is commented out as DMA_PORT_START is zero,
* so the check on an unsigned variable is unnecessary.
*/
if (/*port >= DMA_PORT_START &&*/ port <= DMA_PORT_END)
{
dcp = &adaptor.controller[DMA_CONTROLLER];
port &= ~DMA_REDUNDANT_BITS;
}
else
{
dcp = &adaptor.controller[DMA1_CONTROLLER];
port &= ~DMA1_REDUNDANT_BITS;
}
/*
* When the current address and word count are written, the
* first/last flip-flop for the controller is used to
* determine which byte is accessed, and is then toggled.
*/
switch (port)
{
/* write channel addresseess on controller 0 */
case DMA_CH0_ADDRESS:
case DMA_CH1_ADDRESS:
case DMA_CH2_ADDRESS:
case DMA_CH3_ADDRESS:
dcp->current_address[(port-DMA_CH0_ADDRESS)/2][dcp->first_last] = value;
dcp->base_address[(port-DMA_CH0_ADDRESS)/2][dcp->first_last] = value;
dcp->first_last ^= 1;
break;
/* write channel addresses on controller 1 */
case DMA_CH4_ADDRESS:
case DMA_CH5_ADDRESS:
case DMA_CH6_ADDRESS:
case DMA_CH7_ADDRESS:
dcp->current_address[(port-DMA_CH4_ADDRESS)/4][dcp->first_last] = value;
dcp->base_address[(port-DMA_CH4_ADDRESS)/4][dcp->first_last] = value;
dcp->first_last ^= 1;
break;
/* write channel word counts on controller 0 */
case DMA_CH0_COUNT:
case DMA_CH1_COUNT:
case DMA_CH2_COUNT:
case DMA_CH3_COUNT:
dcp->current_count[(port-DMA_CH0_COUNT)/2][dcp->first_last] = value;
dcp->base_count[(port-DMA_CH0_COUNT)/2][dcp->first_last] = value;
dcp->first_last ^= 1;
break;
/* write channel word counts on controller 1 */
case DMA_CH4_COUNT:
case DMA_CH5_COUNT:
case DMA_CH6_COUNT:
case DMA_CH7_COUNT:
dcp->current_count[(port-DMA_CH4_COUNT)/4][dcp->first_last] = value;
dcp->base_count[(port-DMA_CH4_COUNT)/4][dcp->first_last] = value;
dcp->first_last ^= 1;
break;
/* write command register */
case DMA_SHARED_REG_A:
case DMA1_SHARED_REG_A:
dcp->command.all = value;
break;
/* write request register */
case DMA_WRITE_REQUEST_REG:
case DMA1_WRITE_REQUEST_REG:
/* this feature is not supported */
note_trace0_no_nl(DMA_VERBOSE, "<software DMA request>");
break;
/* write single mask register bit */
case DMA_WRITE_ONE_MASK_BIT:
case DMA1_WRITE_ONE_MASK_BIT:
if (value & 0x4)
{
/* set mask bit */
dcp->mask |= (1 << (value & 0x3));
}
else
{
/* clear mask bit */
dcp->mask &= ~(1 << (value & 0x3));
}
break;
/* write mode register */
case DMA_WRITE_MODE_REG:
case DMA1_WRITE_MODE_REG:
/* note that the bottom 2 bits of value disappear into
the mode padding */
dcp->mode[(value & 0x3)].all = value;
break;
/* clear first/last flip-flop */
case DMA_CLEAR_FLIP_FLOP:
case DMA1_CLEAR_FLIP_FLOP:
dcp->first_last = 0;
break;
/* write master clear */
case DMA_SHARED_REG_B:
case DMA1_SHARED_REG_B:
dcp->command.all = 0;
dcp->status.all = 0;
dcp->request = 0;
dcp->temporary = 0;
dcp->mask = ~0;
dcp->first_last = 0;
break;
/* clear mask register */
case DMA_CLEAR_MASK:
case DMA1_CLEAR_MASK:
dcp->mask = 0;
break;
/* write all mask register bits */
case DMA_WRITE_ALL_MASK_BITS:
case DMA1_WRITE_ALL_MASK_BITS:
dcp->mask = value;
default:
note_trace0_no_nl(DMA_VERBOSE, "<illegal write>");
break;
}
note_trace2(DMA_VERBOSE, " port 0x%04x, value 0x%02x", port, value);
}
GLOBAL void dma_page_inb IFN2(io_addr, port, half_word *, value)
{
note_trace0_no_nl(DMA_VERBOSE, "dma_page_inb() ");
/* mask out the port's redundant bits */
port &= ~DMA_PAGE_REDUNDANT_BITS;
/*
* Read the value from the appropriate page register.
* Unfortunately there does not seem to be any logical
* mapping between port numbers and channel numbers so
* we use a big switch again.
*/
switch(port)
{
case DMA_CH0_PAGE_REG:
*value = adaptor.pages.page[DMA_RESERVED_CHANNEL_0];
break;
case DMA_CH1_PAGE_REG:
*value = adaptor.pages.page[DMA_SDLC_CHANNEL];
break;
case DMA_FLA_PAGE_REG:
*value = adaptor.pages.page[DMA_DISKETTE_CHANNEL];
break;
case DMA_HDA_PAGE_REG:
*value = adaptor.pages.page[DMA_DISK_CHANNEL];
break;
case DMA_CH5_PAGE_REG:
*value = adaptor.pages.page[DMA_RESERVED_CHANNEL_5];
break;
case DMA_CH6_PAGE_REG:
*value = adaptor.pages.page[DMA_RESERVED_CHANNEL_6];
break;
case DMA_CH7_PAGE_REG:
*value = adaptor.pages.page[DMA_RESERVED_CHANNEL_7];
break;
case DMA_REFRESH_PAGE_REG:
*value = adaptor.pages.page[DMA_REFRESH_CHANNEL];
break;
case DMA_FAKE1_REG:
*value = adaptor.pages.page[DMA_FAKE_CHANNEL_1];
break;
case DMA_FAKE2_REG:
*value = adaptor.pages.page[DMA_FAKE_CHANNEL_2];
break;
case DMA_FAKE3_REG:
*value = adaptor.pages.page[DMA_FAKE_CHANNEL_3];
break;
case DMA_FAKE4_REG:
*value = adaptor.pages.page[DMA_FAKE_CHANNEL_4];
break;
case DMA_FAKE5_REG:
*value = adaptor.pages.page[DMA_FAKE_CHANNEL_5];
break;
case DMA_FAKE6_REG:
*value = adaptor.pages.page[DMA_FAKE_CHANNEL_6];
break;
case DMA_FAKE7_REG:
*value = adaptor.pages.page[DMA_FAKE_CHANNEL_7];
break;
default:
note_trace0_no_nl(DMA_VERBOSE, "<illegal read>");
break;
}
note_trace2(DMA_VERBOSE, " port 0x%04x, returning 0x%02x", port,
*value);
}
GLOBAL void dma_page_outb IFN2(io_addr, port, half_word, value)
{
note_trace0_no_nl(DMA_VERBOSE, "dma_page_outb() ");
/* mask out the port's redundant bits */
port &= ~DMA_PAGE_REDUNDANT_BITS;
/*
* Write the value into the appropriate page register.
* Unfortunately there does not seem to be any logical
* mapping between port numbers and channel numbers so
* we use a big switch again.
*/
switch(port)
{
case DMA_CH0_PAGE_REG:
adaptor.pages.page[DMA_RESERVED_CHANNEL_0] = value;
break;
case DMA_CH1_PAGE_REG:
adaptor.pages.page[DMA_SDLC_CHANNEL] = value;
break;
case DMA_FLA_PAGE_REG:
adaptor.pages.page[DMA_DISKETTE_CHANNEL] = value;
break;
case DMA_HDA_PAGE_REG:
adaptor.pages.page[DMA_DISK_CHANNEL] = value;
break;
case DMA_CH5_PAGE_REG:
adaptor.pages.page[DMA_RESERVED_CHANNEL_5] = value;
break;
case DMA_CH6_PAGE_REG:
adaptor.pages.page[DMA_RESERVED_CHANNEL_6] = value;
break;
case DMA_CH7_PAGE_REG:
adaptor.pages.page[DMA_RESERVED_CHANNEL_7] = value;
break;
case DMA_REFRESH_PAGE_REG:
adaptor.pages.page[DMA_REFRESH_CHANNEL] = value;
/* this feature is supported */
note_trace0_no_nl(DMA_VERBOSE, "<refresh>");
break;
case MFG_PORT:
/* Manufacturing port */
/* Meaningless 'checkpoint' debug removed from here STF 11/92 */
break;
case DMA_FAKE1_REG:
adaptor.pages.page[DMA_FAKE_CHANNEL_1] = value;
break;
case DMA_FAKE2_REG:
adaptor.pages.page[DMA_FAKE_CHANNEL_2] = value;
break;
case DMA_FAKE3_REG:
adaptor.pages.page[DMA_FAKE_CHANNEL_3] = value;
break;
case DMA_FAKE4_REG:
adaptor.pages.page[DMA_FAKE_CHANNEL_4] = value;
break;
case DMA_FAKE5_REG:
adaptor.pages.page[DMA_FAKE_CHANNEL_5] = value;
break;
case DMA_FAKE6_REG:
adaptor.pages.page[DMA_FAKE_CHANNEL_6] = value;
break;
case DMA_FAKE7_REG:
adaptor.pages.page[DMA_FAKE_CHANNEL_7] = value;
break;
default:
note_trace0_no_nl(DMA_VERBOSE, "<illegal write>");
break;
}
note_trace2(DMA_VERBOSE, " port 0x%04x, value 0x%02x", port, value);
}
GLOBAL int dma_request IFN3(half_word, channel, char *, hw_buffer,
word, length)
{
DMA_CNTRL *dcp;
unsigned int chan;
word offset, count;
sys_addr munch, split_munch1, split_munch2, address;
unsigned int size;
int result = TRUE;
note_trace3(DMA_VERBOSE,
"dma_request() channel %d, hw_buffer 0x%08x+%04x",
channel, hw_buffer, length);
/* get a pointer to the controller, the physical channel
number, and the unit size for the channel */
dcp = &adaptor.controller[dma_physical_controller(channel)];
chan = dma_physical_channel(channel);
size = dma_unit_size(channel);
/* get out if the whole DMA controller is disabled or if DMA
requests are disabled for the channel */
if ( (dcp->command.bits.controller_disable == 0)
&& ((dcp->mask & (1 << chan)) == 0) )
{
/* get the working copies of the DMA offset and count */
offset = ( ( (unsigned int)dcp->current_address[chan][1] << 8)
| (dcp->current_address[chan][0] << 0) );
count = ( ( (unsigned int)dcp->current_count[chan][1] << 8)
| (dcp->current_count[chan][0] << 0) );
/* get the DMA munch size; it is the count programmed
into the registers, up to the limit available in the
device's buffer; NB for a count of n, n+1 units will
actually be transferred */
munch = (sys_addr)count + 1;
if (munch > length)
munch = length;
/* get the base address for the DMA transfer in
system address space */
address = dma_system_address(channel,
adaptor.pages.page[channel], offset);
if (dcp->mode[chan].bits.address_dec == 0)
{
/* increment memory case - check for address wrapping */
if ((sys_addr)offset + munch > 0x10000L)
{
/* transfer must be split */
split_munch1 = 0x10000L - (sys_addr)offset;
split_munch2 = munch - split_munch1;
/* do the first transfer */
do_transfer
(
dcp->mode[chan].bits.transfer_type,
dcp->mode[chan].bits.address_dec,
address,
hw_buffer,
split_munch1,
size
);
/* get addresses for second transfer */
address = dma_system_address(channel,
adaptor.pages.page[channel], 0);
hw_buffer += split_munch1*size;
/* do the second transfer */
do_transfer
(
dcp->mode[chan].bits.transfer_type,
dcp->mode[chan].bits.address_dec,
address,
hw_buffer,
split_munch2,
size
);
}
else
{
/* no wrap - do the transfer */
do_transfer
(
dcp->mode[chan].bits.transfer_type,
dcp->mode[chan].bits.address_dec,
address,
hw_buffer,
munch,
size
);
}
/* get the final offset */
offset += munch;
count -= munch;
}
else
{
/* decrement memory case - check for address wrapping */
if ((sys_addr)offset < munch)
{
/* transfer must be split */
split_munch1 = (sys_addr)offset;
split_munch2 = munch - split_munch1;
/* do the first transfer */
do_transfer
(
dcp->mode[chan].bits.transfer_type,
dcp->mode[chan].bits.address_dec,
address,
hw_buffer,
split_munch1,
size
);
/* get addresses for second transfer */
address = dma_system_address(channel,
adaptor.pages.page[channel], 0xffff);
hw_buffer += split_munch1*size;
/* do the second transfer */
do_transfer
(
dcp->mode[chan].bits.transfer_type,
dcp->mode[chan].bits.address_dec,
address,
hw_buffer,
split_munch2,
size
);
}
else
{
/* no wrap - do the transfer */
do_transfer
(
dcp->mode[chan].bits.transfer_type,
dcp->mode[chan].bits.address_dec,
address,
hw_buffer,
munch,
size
);
}
/* get the final offset and count */
offset -= munch;
count -= munch;
}
/* restore the DMA offset and count from the working copies */
dcp->current_address[chan][1] = offset >> 8;
dcp->current_address[chan][0] = offset;
dcp->current_count[chan][1] = count >> 8;
dcp->current_count[chan][0] = count;
if (count == 0xffff)
{
/*
* Terminal count has been reached
*/
/* no more transfers are required */
result = FALSE;
/* update the status register */
dcp->status.bits.terminal_count |= (1 << chan);
dcp->status.bits.request &= ~(1 << chan);
/* if autoinitialization is enabled, then reset
the channel and wait for a new request */
if (dcp->mode[chan].bits.auto_init != 0)
{
dcp->current_count[chan][0] =
dcp->base_count[chan][0];
dcp->current_count[chan][1] =
dcp->base_count[chan][1];
dcp->current_count[chan][0] =
dcp->base_count[chan][0];
dcp->current_count[chan][1] =
dcp->base_count[chan][1];
}
else
{
/* set the mask bit for the channel */
dcp->mask |= (1 << chan);
}
}
}
return(result);
}
GLOBAL void dma_enquire IFN3(half_word, channel,
sys_addr *, address, word *, length)
{
register DMA_CNTRL *dcp;
register unsigned int chan;
note_trace0_no_nl(DMA_VERBOSE, "dma_enquire() ");
/* get a pointer to the controller and the physical channel
number */
dcp = &adaptor.controller[dma_physical_controller(channel)];
chan = dma_physical_channel(channel);
/* build the address */
*address = dma_system_address(channel,
adaptor.pages.page[channel],
( ( (unsigned int)dcp->current_address[chan][1] << 8)
| ( dcp->current_address[chan][0] << 0) ) );
/* build the count */
*length = ( ((unsigned int)dcp->current_count[chan][1] << 8)
| (dcp->current_count[chan][0] << 0) );
note_trace3(DMA_VERBOSE, " channel %d, returning 0x%08x+%04x",
channel, *address, *length);
}
#ifdef NTVDM
/*
* BOOL dmaGetAdaptor
*
* Used by MS for third party Vdds to retrieve current DMA settings
*
* entry: void
* exit : DMA_ADAPT * , pointer to the DMA_ADAPT structure
*
*/
DMA_ADAPT *dmaGetAdaptor(void)
{
return &adaptor;
}
#endif /* NTVDM */
/*
* ============================================================================
* Internal functions
* ============================================================================
*/
LOCAL void do_transfer IFN6(int, type, int, decrement,
sys_addr, dma_addr, char *, hw_buffer, unsigned long, length,
unsigned long, size)
{
/*
* This function moves the data for a DMA transfer.
*
* The value of "type" may be:
* DMA_WRITE_TRANSFER - data is moved from the I/O
* device's memory space to system address space;
* DMA_READ_TRANSFER - data is moved from system
* address space to the I/O device's memory space
* DMA_VERIFY_TRANSFER - no data is required to be
* moved at all.
*
* If "decrement" is TRUE, the pointer to system address
* space is decremented during the DMA transfer; otherwise
* the pointer is incremented. The pointer to the I/O
* device's memory space is always incremented.
*
* "dma_addr" is the offset in system address space where
* the DMA transfer will start; "hw_buffer" is the address
* of the buffer in the I/O device's memory space where
* the DMA transfer will start.
*
* "length" is the number of units of "size" bytes each
* that must be transferred.
*/
/* convert the length to bytes */
length *= size;
/* do the transfer */
switch(type)
{
case DMA_WRITE_TRANSFER:
if (!decrement)
{
#ifndef PM
#ifdef LIM
if( !get_lim_setup() ){
if( dma_addr >= ROM_START ){
if( dma_addr >= ROM_START )
break;
length = ROM_START - dma_addr - 1;
}
}
#else
/* increment case - check for writing to ROM */
if ((dma_addr + length) >= ROM_START)
{
if (dma_addr >= ROM_START)
break;
length = ROM_START - dma_addr - 1;
}
#endif /* LIM */
#endif /* nPM */
sas_PWS(dma_addr, (host_addr) hw_buffer, length);
}
else
{
/* decrement case - check for writing to ROM */
#ifndef PM
#ifdef LIM
if( !get_lim_setup() ){
if (dma_addr >= ROM_START) {
if (dma_addr-length >= ROM_START)
break;
length = dma_addr-ROM_START+length-1;
dma_addr = ROM_START - 1;
}
}
#else
if (dma_addr >= ROM_START)
{
if (dma_addr-length >= ROM_START)
break;
length = dma_addr - ROM_START + length - 1;
dma_addr = ROM_START - 1;
}
#endif /* LIM */
#endif /* nPM */
bwd_dest_copy_to_M((half_word *)hw_buffer, dma_addr, length);
}
break;
case DMA_READ_TRANSFER:
if (!decrement)
/* increment case */
sas_PRS(dma_addr, (host_addr) hw_buffer, length);
else
/* decrement case */
bwd_dest_copy_from_M(dma_addr, (half_word *)hw_buffer, length);
break;
case DMA_VERIFY_TRANSFER:
break;
default:
note_trace0(DMA_VERBOSE, "dma_request() illegal transfer");
break;
}
}
/*
* backward copy routines - these used to be
* in the host but there seemed to be little point
*/
LOCAL void bwd_dest_copy_to_M IFN3(host_addr, s, sys_addr, d,
sys_addr, l)
{
while (l-- > 0)
sas_PW8(d--, *s++);
}
LOCAL void bwd_dest_copy_from_M IFN3(sys_addr, s, host_addr, d,
sys_addr, l)
{
while (l-- > 0)
*d-- = sas_PR8(s++);
}
#ifdef SEGMENTATION
/*
* The following #include specifies the code segment into which this
* module will by placed by the MPW C compiler on the Mac II running
* MultiFinder.
*/
#include "SOFTPC_INIT.seg"
#endif
GLOBAL void dma_init IFN0()
{
io_addr port;
note_trace0(DMA_VERBOSE, "dma_init() called");
#ifdef LIM
lim_active = 0;
#endif
/*
* Connect the DMA Adaptor chips to the I/O bus
*/
/* establish the DMA Controller I/O functions that will be used */
io_define_inb(DMA_ADAPTOR, dma_inb);
io_define_outb(DMA_ADAPTOR, dma_outb);
/* connect the DMA Controller chips to the I/O bus */
for (port = DMA_PORT_START; port <= DMA_PORT_END; port++)
io_connect_port(port, DMA_ADAPTOR, IO_READ_WRITE);
for (port = DMA1_PORT_START; port <= DMA1_PORT_END; port++)
io_connect_port(port, DMA_ADAPTOR, IO_READ_WRITE);
/* establish the DMA Page Register I/O functions that will be used */
io_define_inb(DMA_PAGE_ADAPTOR, dma_page_inb);
io_define_outb(DMA_PAGE_ADAPTOR, dma_page_outb);
/* connect the DMA Page Register chip to the I/O bus */
for (port = DMA_PAGE_PORT_START; port <= DMA_PAGE_PORT_END; port++)
io_connect_port(port, DMA_PAGE_ADAPTOR, IO_READ_WRITE);
}