Initial commit
This commit is contained in:
378
LIB386/LIB_SAMP/DMA_CODE.ASM
Normal file
378
LIB386/LIB_SAMP/DMA_CODE.ASM
Normal file
@@ -0,0 +1,378 @@
|
||||
.DATA
|
||||
|
||||
Status EQU 08h ;DMAC status port (read) \ same port
|
||||
Command EQU 08h ;DMAC command port (write) / (read/write)
|
||||
Request EQU 09h ;DMAC channel request (write-only)
|
||||
DMA_Mask EQU 0Ah ;DMAC DMA_Mask (write-only)
|
||||
Mode EQU 0Bh ;DMAC mode (write)
|
||||
byte_ptr EQU 0Ch ;byte pointer flip-flop
|
||||
|
||||
addr EQU 000h ; per-channel base address
|
||||
count EQU 001h ; per-channel byte count
|
||||
|
||||
read_cmd EQU 058h ; autoinitialising read
|
||||
write_cmd EQU 054h ; auto write
|
||||
|
||||
set_cmd EQU 000h ; DMA_Mask set (enable dma)
|
||||
reset_cmd EQU 004h ; DMA_Mask reset (disable)
|
||||
|
||||
page_table DW 00087h ; channel 0
|
||||
DW 00083h ; channel 1
|
||||
DW 00081h ; channel 2
|
||||
DW 00082h ; channel 3
|
||||
DW 0FFFFh ; ch 4 (not used)
|
||||
DW 0008Bh ; ch 5
|
||||
DW 00089h ; ch 6
|
||||
DW 0008Ah ; ch 7
|
||||
|
||||
dmac2 DB 0 ; Flag set to non-zero when using the 2nd DMA controller
|
||||
|
||||
.CODE
|
||||
|
||||
MACRO adjust reg ; Adjust register port for 2nd DMA cont
|
||||
local no_adjust
|
||||
|
||||
cmp byte ptr[dmac2], 0
|
||||
jz no_adjust
|
||||
shl reg, 1
|
||||
add reg, 0C0h
|
||||
no_adjust:
|
||||
|
||||
ENDM adjust
|
||||
|
||||
;+---------------------------------------------------------------------------+
|
||||
;| int dma_setup(int Channel, char far *Buffer, unsigned Length) |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Channel = 0-7 |
|
||||
;| Buffer = Address of data to transfer |
|
||||
;| Length = Length of data to transfer |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Returns: 0 if no errors (dma_errno == 0) |
|
||||
;| -1 if errors occurred (dma_errno set to indicate error.) |
|
||||
;+---------------------------------------------------------------------------+
|
||||
|
||||
dma_setup PROC USES EBX,\
|
||||
Channel:DWORD, Buffer:DWORD, Len:DWORD
|
||||
|
||||
;Convert 20-bit physical address of buffer into page:offset
|
||||
|
||||
|
||||
mov edi, Buffer
|
||||
mov ecx, edi
|
||||
shr ecx, 8
|
||||
|
||||
; ch:di == The physical buffer base.
|
||||
|
||||
; Adjust channel number
|
||||
|
||||
mov byte ptr[dmac2], 0
|
||||
mov bx, Channel
|
||||
cmp bx, 4
|
||||
jb OkChannel
|
||||
and bx, 3
|
||||
mov byte ptr[dmac2], 1
|
||||
OkChannel:
|
||||
|
||||
; BX contains the adjusted channel number
|
||||
|
||||
mov si, read_cmd
|
||||
add si, bx
|
||||
mov cl, set_cmd ;allow dma requests
|
||||
add cl, bl
|
||||
|
||||
;si contains READ/WRITE command for DMA controller
|
||||
;cl contains confirmation command for DMA controller
|
||||
|
||||
shl bx, 1
|
||||
|
||||
;bx == Port # Channel*2
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
; Calculations have been done ahead of time to minimize time with
|
||||
; interrupts disabled.
|
||||
;
|
||||
; edi (ch:di) == physical base address (must be on word boundary for 16 bits)
|
||||
;
|
||||
; cl == Confirmation command (Unmasks the channel)
|
||||
;
|
||||
; bx == I/O port Channel*2 (This is where the address is written)
|
||||
;
|
||||
; si == Mode command for DMA
|
||||
;-------------------------------------------------------------------------
|
||||
|
||||
; Now we shift the address and word count right one bit if in 16 bit mode.
|
||||
|
||||
cmp [dmac2], 0
|
||||
jz AddrOk
|
||||
|
||||
shr ch, 1
|
||||
rcr di, 1
|
||||
shl ch, 1
|
||||
shr [Len], 1 ;Odd byte lengths are rounded down
|
||||
AddrOk:
|
||||
|
||||
;The "byte pointer" is also known as the LSB/MSB flip flop.
|
||||
;By writing any value to it, the DMA controller registers are prepared
|
||||
;to accept the address and length values LSB first.
|
||||
|
||||
mov dx, byte_pt ;Reset byte pointer Flip/flop
|
||||
adjust dx
|
||||
out dx, al
|
||||
|
||||
mov dx, bx ;dx=DMAC Base Address port
|
||||
adjust dx
|
||||
mov ax, di ;ax=LSW of 20-bit address
|
||||
out dx, al ;Store LSB
|
||||
mov al, ah
|
||||
out dx, al ;Store MSB
|
||||
|
||||
;Write length to port (Channel * 2 + 1)
|
||||
|
||||
inc dx ;dx=DMAC Count port
|
||||
mov eax, Len
|
||||
out dx, al ;Write LSB of Length
|
||||
mov al, ah
|
||||
out dx, al ;Write MSB
|
||||
|
||||
;Write page to port page_table[channel]
|
||||
|
||||
mov ebx, Channel
|
||||
shl bx, 1
|
||||
mov dx, word ptr[OFFSET page_table + bx]
|
||||
mov al, ch ;al=Page number
|
||||
out dx, al ;Store the page
|
||||
|
||||
;Write Readcmd for channel to Mode port
|
||||
|
||||
mov dx, Mode ;dx=DMAC mode register
|
||||
adjust dx
|
||||
mov ax, si ;Load pre-calculated mode
|
||||
out dx, al ;Write it to the DSP
|
||||
|
||||
mov dx, DMA_Mask ;dx=DMAX DMA_Mask register
|
||||
adjust dx
|
||||
mov al, cl ;al=pre-calulated DMA_Mask value
|
||||
out dx, al ;Write DMA_Mask (allow dma on this channel)
|
||||
|
||||
ret
|
||||
|
||||
dma_setup ENDP
|
||||
|
||||
;+---------------------------------------------------------------------------+
|
||||
;| int prevent_dma(int Channel) |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Channel = 0-7 |
|
||||
;| Prevents DMA requests from Channel by masking bit in DMA_C. |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;+---------------------------------------------------------------------------+
|
||||
|
||||
prevent_dma PROC ,\
|
||||
Channel:DWORD
|
||||
|
||||
|
||||
; Check channel number range
|
||||
|
||||
mov dx, DMA_Mask
|
||||
|
||||
mov eax, Channel
|
||||
cmp al, 4
|
||||
jb OkChannel
|
||||
and al, 3
|
||||
shl dx, 1
|
||||
add dx, 0C0h
|
||||
OkChannel:
|
||||
add al, reset_cmd ; Add disable DMA requests
|
||||
out dx, al
|
||||
|
||||
ret
|
||||
|
||||
prevent_dma ENDP
|
||||
|
||||
;+---------------------------------------------------------------------------+
|
||||
;| int allow_dma(int Channel) |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Channel = 0-7 |
|
||||
;| Unmasks DMA on the specified channel. |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;+---------------------------------------------------------------------------+
|
||||
|
||||
allow_dma PROC ,\
|
||||
Channel:DWORD
|
||||
|
||||
; Check channel number range
|
||||
|
||||
mov dx, DMA_Mask
|
||||
|
||||
mov eax, Channel
|
||||
cmp al, 4
|
||||
jb OkChannel
|
||||
and al, 3
|
||||
shl dx, 1
|
||||
add dx, 0C0h
|
||||
OkChannel:
|
||||
add al, set_cmd ; Add enable DMA requests
|
||||
out dx, al
|
||||
|
||||
ret
|
||||
|
||||
allow_dma ENDP
|
||||
|
||||
;+---------------------------------------------------------------------------+
|
||||
;| int dma_count(Channel) |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Channel = 0-7 |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Returns: -1 if DMA transaction completed |
|
||||
;| else returns the number of bytes/words left to transfer |
|
||||
;+---------------------------------------------------------------------------+
|
||||
|
||||
PROC dma_count ,\
|
||||
Channel:DWORD
|
||||
|
||||
mov eax, Channel
|
||||
|
||||
mov dx, ax
|
||||
and dx, 3
|
||||
shl dx, 1
|
||||
add dx, count
|
||||
|
||||
cmp al, 4
|
||||
jb OkChannel
|
||||
shl dx, 1
|
||||
add dx, 0C0h
|
||||
OkChannel:
|
||||
xor eax, eax
|
||||
cli
|
||||
in al, dx
|
||||
mov ah, al
|
||||
in al, dx
|
||||
sti
|
||||
xchg al, ah
|
||||
|
||||
ret
|
||||
|
||||
dma_count ENDP
|
||||
|
||||
;+---------------------------------------------------------------------------+
|
||||
;| unsigned dma_addr(Channel) |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Channel = 0-7 |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Returns: Current address word of that channel |
|
||||
;| Value must be multiplied by 2 for a 16-bit channel. |
|
||||
;| It is best to start at offset 0, ie on a 64K boundary |
|
||||
;+---------------------------------------------------------------------------+
|
||||
|
||||
dma_addr PROC ,\
|
||||
Channel:DWORD
|
||||
|
||||
mov eax, Channel
|
||||
|
||||
mov dx, ax
|
||||
and dx, 3
|
||||
shl dx, 1
|
||||
|
||||
cmp al, 4
|
||||
jb OkChannel
|
||||
shl dx, 1
|
||||
add dx, 0C0h
|
||||
OkChannel:
|
||||
xor eax, eax
|
||||
cli
|
||||
in al, dx
|
||||
mov ah, al
|
||||
in al, dx
|
||||
sti
|
||||
xchg al, ah
|
||||
|
||||
ret
|
||||
|
||||
dma_addr ENDP
|
||||
|
||||
|
||||
|
||||
VOID *DMABuffer, *DMAAllocBuffer;
|
||||
BYTE LockedDMARegion;
|
||||
|
||||
#define MAX_DMABUFFERATTEMPTS 10;
|
||||
|
||||
;+---------------------------------------------------------------------------+
|
||||
;| BYTE *AlignOn4KBoundry( BYTE *Buf ) |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Align Buf to the nearest 4K page |
|
||||
;+---------------------------------------------------------------------------+
|
||||
|
||||
#define AlignOn4KBoundry(Buf) ((Buf + 0x00000FFF) & 0xFFFFF000)
|
||||
|
||||
;+---------------------------------------------------------------------------+
|
||||
;| BYTE *AllocateDMABuffer( WORD BufferSize ) |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| BufferSize = 0-64K |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Returns: Buffer if successful |
|
||||
;| NULL if error |
|
||||
;+---------------------------------------------------------------------------+
|
||||
|
||||
BYTE *AllocateDMABuffer( WORD BufferSize )
|
||||
{
|
||||
VOID *Tried[ MAX_DMABUFFERATTEMPTS ] ;
|
||||
VOID *Buf, *DMAAddr ;
|
||||
int Tries, Error ;
|
||||
|
||||
for (Tries = 0; Tries < MAX_DMABUFFERATTEMPTS; Tries++)
|
||||
Tried[ Tries ] = NULL ;
|
||||
|
||||
Tries = 0;
|
||||
LockedDMARegion = FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
// printf( "DMA buffer allocation attempt: %d\n", Tries + 1 ) ;
|
||||
if ((DMAAllocBuffer = (VOID *)DosMalloc( BufferSize + 0xFFF)) != NULL)
|
||||
{
|
||||
DMABuffer = AlignOn4KBoundry(DMAAllocBuffer);
|
||||
|
||||
if ( ((LONG)DMABuffer & 0xF0000) !=
|
||||
(((LONG)DMABuffer + BufferSize) & 0xF0000) )
|
||||
{
|
||||
Tried[ Tries ] = DMAAllocBuffer ;
|
||||
DMAAllocBuffer = NULL ;
|
||||
DMABuffer = NULL ;
|
||||
|
||||
}
|
||||
}
|
||||
Tries++ ;
|
||||
DMAAllocBuf = Buf;
|
||||
DMABuffer = DMAAddr ;
|
||||
}
|
||||
while ((DMAAllocBuf == NULL) && (Tries < MAX_DMABUFFERATTEMPTS)) ;
|
||||
|
||||
for (wTries = 0; wTries < MAX_DMABUFFERATTEMPTS; wTries++)
|
||||
{
|
||||
if (alpTried[ wTries ])
|
||||
free( alpTried[ wTries ] ) ;
|
||||
else
|
||||
break ;
|
||||
}
|
||||
|
||||
return( DMABuffer ) ;
|
||||
|
||||
|
||||
;+---------------------------------------------------------------------------+
|
||||
;| VOID FreeDMABuffer( VOID ) |
|
||||
;| ------------------------------------------------------------------------- |
|
||||
;| Free the DMA buffer |
|
||||
;+---------------------------------------------------------------------------+
|
||||
|
||||
VOID FreeDMABuffer( VOID )
|
||||
{
|
||||
if (LockedDMARegion)
|
||||
UnlockDMARegion( &gDDS, 0 ) ;
|
||||
|
||||
if (DMAAllocBuf)
|
||||
{
|
||||
free( glpDMAAllocBuf ) ;
|
||||
DMAAllocBuf = NULL ;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user