/* * SoftPC-AT Revision 2.0 * * Title : IBM PC-AT DMA Adaptor declarations * * Description : This module contains declarations that are used in * accessing the DMA Adaptor emulation * * Author(s) : Ross Beresford * * Notes : For a detailed description of the IBM DMA Adaptor, * and the INTEL DMA Controller chips refer to the following * documents: * * - IBM PC/AT Technical Reference Manual * (Section 1-9 Direct Memory Access) * - INTEL Microsystems Components Handbook * (Section 2-52 DMA Controller 8237A) * * A more succinct account of the DMA adaptor follows: * * DMA Adaptor: * ----------- * * The DMA "adaptor" is really just a part of the AT System Board. This * is its block diagram: * * +-----------+ * 000-01F |8237A-5 | 0| A0-A7 * IOS <-+------> | DMA | 1| -------------------------------------+ * | | CNTRL | 2| +-------+ | * | | 0 | 3| ---> |ALS 573| A8-A15| * | +-----------+ | DMA | ----------------------+ * | ^ |ADDRESS| | * | \ | LATCH | +-------+ | * | \ cascade +-------+ | LS612 | | * |080-09F \ | | A16-A23| * +----------------------------------------> | DMA | -------+ * | \ | PAGE | A17-A23| * | +-----------+ | REG | | * | |8237A-5 | 4| +-------+ | * +------> | DMA | 5| -------------------------------------+ * 0C0-0DF | CNTRL | 6| +-------+ A9-A16| * | 1 | 7| ---> |ALS 573| | * +-----------+ | DMA | ----------------------+-> SAS * |ADDRESS| A1-A8 * | LATCH | * +-------+ * DMA Controllers: * --------------- * * The 8237A-5 DMA controller chips used are restricted to 4 DMA * channels each: thus, 2 DMA controller chips are required to give the * AT's 7 DMA channels. * * The 8237A-5 DMA controller chips support more than one device by * "cascading" them: that is, connecting the control inputs of the * "additional" device to the control outputs of the "initial" device. * One channel in the initial device must be dedicated to serving * each additional device by setting it to "cascade mode". * * On the AT system board, channel 4 of DMA Controller 1 is set to * "cascade mode", and serves DMA Controller 0. * * Channels 0-3 (on DMA Controller 0) are used to support 8-bit I/O * devices and provide transfers of up to 64K bytes: the 16-bit addresses * generated by the DMA Controller are mapped directly onto bits A0-A15 * of a 24 bit system address. * * Channels 5-7 (on DMA Controller 1) are used to support 16-bit I/O * devices and provide transfers of up to 128K bytes: the 16-bit addresses * generated by the DMA Controller are mapped onto bits A1-A16 of a * 24 bit system address, and bit A0 is set to 0. * * The state of a controller is defined by a set of internal registers * and a flip-flop: the internal registers are used in setting up and * performing a DMA transfer; the First/Last Flip-Flop controls which * byte of a 16 bit address is accessed from the I/O bus. * * The state information for a controller is represented by a DMA_CNTRL * object. * DMA Address Latches: * ------------------- * * Each DMA Controller has an ALS573 DMA Address Latch associated with * it. These are required because of a restriction in the design of the * DMA Controller: in order to reduce its pin count it does not directly * output bits A8-A15 onto the address bus, but uses an external latch. * * Since the address latches do not have any separate functional * identity, their state and behaviour is included in with the * controllers. * DMA Page Registers: * ------------------ * * An LS612 DMA Page Register chip is used to establish the constant top * bits of the system address for a DMA transfer; each DMA channel has a * byte register in the chip for this purpose. * * In DMA channels 0-3, bits A16-A23 of the 24 bit system address are * established from bits D0-D7 of the page register for the channel. * * In DMA channels 5-7, bits A17-A23 of the 24 bit system address are * established from bits D1-D7 of the page register for the channel: * Bit D0 is not used for these channels, since bit A16 of the system * address is established by the DMA controller for these channels. * * The state information for the page register chip is represented * by a DMA_PAGE object. */ /* SccsID[]="@(#)dma.h 1.7 11/10/92 Copyright Insignia Solutions Ltd."; */ /* * ============================================================================ * Structure/Data definitions * ============================================================================ */ /* * DMA CONTROLLER */ /* the number of channels per controller */ #define DMA_CONTROLLER_CHANNELS 4 /* a flip-flop; it toggles between the values 0 and 1 */ typedef unsigned int DMA_FLIP_FLOP; /* a DMA address; it is indexed by the flip-flop value */ typedef half_word DMA_WORD[2]; /* a DMA command */ #ifdef BIT_ORDER1 typedef union { half_word all; struct { HALF_WORD_BIT_FIELD DACK_high:1; /* not supported */ HALF_WORD_BIT_FIELD DREQ_high:1; /* not supported */ HALF_WORD_BIT_FIELD extended_write:1; /* not supported */ HALF_WORD_BIT_FIELD rotate_priority:1; HALF_WORD_BIT_FIELD compressed_timing:1;/* not supported */ HALF_WORD_BIT_FIELD controller_disable:1; HALF_WORD_BIT_FIELD ch0_address_hold:1;/* not supported */ HALF_WORD_BIT_FIELD mm_enable:1; /* not supported */ } bits; } DMA_COMMAND; #endif #ifdef BIT_ORDER2 typedef union { half_word all; struct { HALF_WORD_BIT_FIELD mm_enable:1; /* not supported */ HALF_WORD_BIT_FIELD ch0_address_hold:1;/* not supported */ HALF_WORD_BIT_FIELD controller_disable:1; HALF_WORD_BIT_FIELD compressed_timing:1; /* not supported */ HALF_WORD_BIT_FIELD rotate_priority:1; HALF_WORD_BIT_FIELD extended_write:1; /* not supported */ HALF_WORD_BIT_FIELD DREQ_high:1; /* not supported */ HALF_WORD_BIT_FIELD DACK_high:1; /* not supported */ } bits; } DMA_COMMAND; #endif /* a DMA mode */ #ifdef BIT_ORDER1 typedef union { half_word all; struct { HALF_WORD_BIT_FIELD mode:2; /* single/block/demand/cascade */ HALF_WORD_BIT_FIELD address_dec:1; /* inc or dec count */ HALF_WORD_BIT_FIELD auto_init:1; /* autoinitialize ? */ HALF_WORD_BIT_FIELD transfer_type:2; /* read/write/verify */ HALF_WORD_BIT_FIELD scratch:2; /* channel select mapped here */ } bits; } DMA_MODE; #endif #ifdef BIT_ORDER2 typedef union { half_word all; struct { HALF_WORD_BIT_FIELD scratch:2; /* channel select mapped here */ HALF_WORD_BIT_FIELD transfer_type:2; /* read/write/verify */ HALF_WORD_BIT_FIELD auto_init:1; /* autoinitialize ? */ HALF_WORD_BIT_FIELD address_dec:1; /* inc or dec count */ HALF_WORD_BIT_FIELD mode:2; /* single/block/demand/cascade */ } bits; } DMA_MODE; #endif /* DMA Mode register mode bit settings */ #define DMA_DEMAND_MODE 0 #define DMA_SINGLE_MODE 1 #define DMA_BLOCK_MODE 2 #define DMA_CASCADE_MODE 3 /* DMA Mode register transfer type bit settings */ #define DMA_VERIFY_TRANSFER 0 #define DMA_WRITE_TRANSFER 1 #define DMA_READ_TRANSFER 2 #define DMA_ILLEGAL_TRANSFER 3 /* a DMA status */ #ifdef BIT_ORDER1 typedef union { half_word all; struct { HALF_WORD_BIT_FIELD request:4; /* request pending */ HALF_WORD_BIT_FIELD terminal_count:4; /* terminal count reached */ } bits; } DMA_STATUS; #endif #ifdef BIT_ORDER2 typedef union { half_word all; struct { HALF_WORD_BIT_FIELD terminal_count:4; /* terminal count reached */ HALF_WORD_BIT_FIELD request:4; /* request pending */ } bits; } DMA_STATUS; #endif /* a DMA mask register (only the bottom 4 bits are meaningful) */ typedef half_word DMA_MASK; /* a DMA Controller state */ typedef struct { DMA_WORD base_address[DMA_CONTROLLER_CHANNELS]; DMA_WORD base_count[DMA_CONTROLLER_CHANNELS]; DMA_WORD current_address[DMA_CONTROLLER_CHANNELS]; DMA_WORD current_count[DMA_CONTROLLER_CHANNELS]; DMA_WORD temporary_address[DMA_CONTROLLER_CHANNELS]; DMA_WORD temporary_count[DMA_CONTROLLER_CHANNELS]; DMA_STATUS status; DMA_COMMAND command; half_word temporary; DMA_MODE mode[DMA_CONTROLLER_CHANNELS]; DMA_MASK mask; half_word request; DMA_FLIP_FLOP first_last; } DMA_CNTRL; /* * DMA PAGE REGISTERS */ /* the number of channels per page register chip */ #define DMA_PAGE_CHANNELS 16 /* a DMA Page Register chip state */ typedef struct { half_word page[DMA_PAGE_CHANNELS]; } DMA_PAGE; /* * DMA ADAPTOR */ /* the number of controllers per adaptor */ #define DMA_ADAPTOR_CONTROLLERS 2 /* the numbering convention for the controllers */ #define DMA_CONTROLLER 0 #define DMA1_CONTROLLER 1 /* a DMA adaptor state */ typedef struct { DMA_CNTRL controller[DMA_ADAPTOR_CONTROLLERS]; DMA_PAGE pages; } DMA_ADAPT; /* the number of logical channels per adaptor */ #define DMA_ADAPTOR_CHANNELS \ (DMA_ADAPTOR_CONTROLLERS * DMA_CONTROLLER_CHANNELS) /* macros for converting between logical and physical channel numbers */ #define dma_logical_channel(controller, channel) \ (controller*DMA_CONTROLLER_CHANNELS + channel) #define dma_physical_channel(channel) \ (channel%DMA_CONTROLLER_CHANNELS) #define dma_physical_controller(channel) \ (channel/DMA_CONTROLLER_CHANNELS) /* macro for building a system address dependent on the channel */ #define dma_system_address(channel, page, offset) \ ( (channel < 4) \ ? (((sys_addr)(page & 0xff) << 16) | ((sys_addr)(offset & 0xffff) << 0)) \ : (((sys_addr)(page & 0xfe) << 16) | ((sys_addr)(offset & 0xffff) << 1)) ) /* macro for determining the DMA unit size dependent on the channel */ #define dma_unit_size(channel) ( (channel < 4) ? 1 : 2) /* the channel assignments */ #define DMA_RESERVED_CHANNEL_0 0 #define DMA_SDLC_CHANNEL 1 #define DMA_DISKETTE_CHANNEL 2 #define DMA_DISK_CHANNEL 3 #define DMA_CASCADE_CHANNEL 4 #define DMA_RESERVED_CHANNEL_5 5 #define DMA_RESERVED_CHANNEL_6 6 #define DMA_RESERVED_CHANNEL_7 7 #define DMA_FAKE_CHANNEL_1 8 #define DMA_FAKE_CHANNEL_2 9 #define DMA_FAKE_CHANNEL_3 10 #define DMA_FAKE_CHANNEL_4 11 #define DMA_FAKE_CHANNEL_5 12 #define DMA_FAKE_CHANNEL_6 13 #define DMA_FAKE_CHANNEL_7 14 #define DMA_REFRESH_CHANNEL 15 /* these masks define the redundant bits of the I/O addresses */ #define DMA_REDUNDANT_BITS 0x10 #define DMA1_REDUNDANT_BITS 0x01 #define DMA_PAGE_REDUNDANT_BITS 0x10 /* * DMA Address - the following union is used only in the BIOS functions * to help determine how a system address should be expressed in terms * of its component parts. * It is not used within the DMA emulation */ #ifdef BIGEND typedef union { sys_addr all; half_word array[4]; struct { half_word pad; half_word page; half_word high; half_word low; } parts; struct { word high; word low; } words; } DMA_ADDRESS; #endif #ifdef LITTLEND typedef union { sys_addr all; half_word array[4]; struct { half_word low; half_word high; half_word page; half_word pad; } parts; struct { word low; word high; } words; } DMA_ADDRESS; #endif /* * ============================================================================ * External declarations and macros * ============================================================================ */ /* * void dma_init() * { * This function performs several distinct initialisation * tasks associated with the DMA adaptor: * * the DMA Controller chips and the DMA Page Register chip * are connected to the I/O bus; * * a hardware reset is performed for each DMA Controller * chip; * } */ IMPORT VOID dma_init IPT0(); /* * void dma_post() * { * the mode register for each DMA channel is set up to the * normal value for an AT. * } */ IMPORT VOID dma_post IPT0(); /* * void dma_inb(port, value) * io_addr port; * half_word *value; * { * This function is invoked when a read is performed on an * I/O address "port" in the range of one of the DMA * Controller chips. dma_inb() may also be called directly * from the BIOS. * * The function maps the I/O address to the particular DMA * controller and returns the value of the requested * register in "*value". * } */ IMPORT VOID dma_inb IPT2(io_addr, port, half_word *, value); /* * void dma_outb(port, value) * io_addr port; * half_word value; * { * This function is invoked when a write is performed to an * I/O address "port" in the range of one of the DMA * Controller chips. dma_outb() may also be called directly * from the BIOS. * * The function maps the I/O address to the particular DMA * controller and sets the requested register to "value". * } */ IMPORT VOID dma_outb IPT2(io_addr, port, half_word, value); /* * void dma_page_inb(port, value) * io_addr port; * half_word *value; * { * This function is invoked when a read is performed on an * I/O address "port" in the range of the DMA Page Register * chip. dma_page_inb() may also be called directly from the * BIOS. * * The function maps the I/O address to a particular DMA * page register and returns its value in "*value". * } */ IMPORT VOID dma_page_inb IPT2(io_addr, port, half_word *, value); /* * void dma_page_outb(port, value) * io_addr port; * half_word value; * { * This function is invoked when a write is performed to an * I/O address "port" in the range of the DMA Page Register * chip. dma_page_outb() may also be called directly from the * BIOS. * * The function maps the I/O address to a particular DMA * page register and sets it to "value". * } */ IMPORT VOID dma_page_outb IPT2(io_addr, port, half_word, value); /* * dma_request(channel, hw_buffer, length) * half_word channel; * char *hw_buffer; * word length; * { * I/O devices call this function to initiate a DMA * transfer. It is analogous to raising the DREQ line * on the DMA controller for the channel. * * The DMA channel to be used is passed in "channel"; * "hw_buffer" is the address in the device's memory * space of the buffer that should be read from or written * into the system address space; "length" is the maximum * number of units to be transferred: the unit is a * half_word for channels 0-3 and a word for channels 5-7. * * The function returns TRUE if more transfers can be * accepted or FALSE if the terminal count has been * reached. * } */ IMPORT int dma_request IPT3(half_word, port, char *, hw_buffer, word, length); /* * void dma_enquire(channel, address, length) * half_word channel; * sys_addr *address; * word *length; * { * I/O devices call this function to find out how the * DMA controller has been programmed up to do a transfer. * * The DMA channel to be accessed is passed in "channel"; * the address in system address space that will be read * or written in the transfer is returned in "*address"; * "length" is the number of units that have been * requested: the unit is a half_word for channels 0-3 * and a word for channels 5-7. * } */ IMPORT VOID dma_enquire IPT3(half_word, channel, sys_addr *, address, word *, 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(); #endif /* NTVDM */