blob: 2b6e1e8b561e9b6e0dddfa7e8ff2ab0be27aefd6 [file] [log] [blame]
;****************************************************************************
;*
;* SciTech OS Portability Manager Library
;*
;* ========================================================================
;*
;* The contents of this file are subject to the SciTech MGL Public
;* License Version 1.0 (the "License"); you may not use this file
;* except in compliance with the License. You may obtain a copy of
;* the License at http://www.scitechsoft.com/mgl-license.txt
;*
;* Software distributed under the License is distributed on an
;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
;* implied. See the License for the specific language governing
;* rights and limitations under the License.
;*
;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
;*
;* The Initial Developer of the Original Code is SciTech Software, Inc.
;* All Rights Reserved.
;*
;* ========================================================================
;*
;* Language: 80386 Assembler, TASM 4.0 or NASM
;* Environment: 16/32 bit Ring 0 device driver
;*
;* Description: Assembler support routines for ISA DMA controller.
;*
;****************************************************************************
IDEAL
include "scitech.mac" ; Memory model macros
header _dma ; Set up memory model
begdataseg _dma ; Start of data segment
cpublic _PM_DMADataStart
; DMA register I/O addresses for channels 0-7 (except 4)
DMAC_page db 087h,083h,081h,082h, -1,08Bh,089h,08Ah
DMAC_addr db 000h,002h,004h,006h, -1,0C4h,0C8h,0CCh
DMAC_cnt db 001h,003h,005h,007h, -1,0C6h,0CAh,0CEh
DMAC_mask db 00Ah,00Ah,00Ah,00Ah, -1,0D4h,0D4h,0D4h
DMAC_mode db 00Bh,00Bh,00Bh,00Bh, -1,0D6h,0D6h,0D6h
DMAC_FF db 00Ch,00Ch,00Ch,00Ch, -1,0D8h,0D8h,0D8h
cpublic _PM_DMADataEnd
enddataseg _dma
begcodeseg _dma ; Start of code segment
ifdef flatmodel
cpublic _PM_DMACodeStart
;----------------------------------------------------------------------------
; void PM_DMACDisable(int channel);
;----------------------------------------------------------------------------
; Masks DMA channel, inhibiting DMA transfers
;----------------------------------------------------------------------------
cprocstart PM_DMACDisable
ARG channel:UINT
push ebp
mov ebp,esp
mov ecx,[channel] ; ECX indexes DMAC register tables
mov dh,0 ; DH = 0 for DMAC register port access
mov al,cl
and al,11b
or al,100b ; AL = (channel & 3) | "set mask bit"
mov dl,[DMAC_mask+ecx]
out dx,al
pop ebp
ret
cprocend
;----------------------------------------------------------------------------
; void PM_DMACEnable(int channel);
;----------------------------------------------------------------------------
; Unmasks DMA channel, enabling DMA transfers
;----------------------------------------------------------------------------
cprocstart PM_DMACEnable
ARG channel:UINT
push ebp
mov ebp,esp
mov ecx,[channel] ; ECX indexes DMAC register tables
mov dh,0 ; DH = 0 for DMAC register port access
mov al,cl
and al,11b ; AL = (channel & 3), "set mask bit"=0
mov dl,[DMAC_mask+ecx]
out dx,al
pop ebp
ret
cprocend
;----------------------------------------------------------------------------
; void PM_DMACProgram(int channel,int mode,ulong bufferPhys,int count);
;----------------------------------------------------------------------------
; Purpose: Program DMA controller to perform transfer from first 16MB
; based on previously selected mode and channel. DMA transfer may be enabled
; by subsequent call to PM_DMACEnable.
;
; Entry: channel - DMA channel in use (0-7)
; mode - Selected DMAMODE type for transfer
; buffer - 32-bit physical address of DMA buffer
; count - DMA byte count (1-65536 bytes)
;----------------------------------------------------------------------------
cprocstart PM_DMACProgram
ARG channel:UINT, mode:UINT, bufferPhys:ULONG, count:UINT
enter_c
pushfd
cli ; Disable interrupts
; Mask DMA channel to disable it
mov ebx,[channel] ; EBX indexes DMAC register tables
mov dh,0 ; DH = 0 for DMAC register port access
mov al,bl
and al,11b
or al,100b ; AL = (channel & 3) | "set mask bit"
mov dl,[DMAC_mask+ebx]
out dx,al
; Generate IOW to clear FF toggle state
mov al,0
mov dl,[DMAC_FF+ebx]
out dx,al
; Compute buffer address to program
mov eax,[bufferPhys] ; AX := DMA address offset
mov ecx,eax
shr ecx,16 ; CL := bufferPhys >> 16 (DMA page)
mov esi,[count] ; ESI = # of bytes to transfer
cmp ebx,4 ; 16-bit channel?
jb @@WriteDMAC ; No, program DMAC
shr eax,1 ; Yes, convert address and count
shr esi,1 ; to 16-bit, 128K/page format
; Set the DMA address word (bits 0-15)
@@WriteDMAC:
mov dl,[DMAC_addr+ebx]
out dx,al
mov al,ah
out dx,al
; Set DMA transfer count
mov eax,esi
dec eax ; ESI = # of bytes to transfer - 1
mov dl,[DMAC_cnt+ebx]
out dx,al
mov al,ah
out dx,al
; Set DMA page byte (bits 16-23)
mov al,cl
mov dl,[DMAC_page+ebx]
out dx,al
; Set the DMA channel mode
mov al,bl
and al,11b
or al,[BYTE mode] ; EAX = (channel & 3) | mode
mov dl,[DMAC_mode+ebx]
out dx,al
pop eax ; SMP safe interrupt state restore!
test eax,200h
jz @@1
sti
@@1: leave_c
ret
cprocend
;----------------------------------------------------------------------------
; ulong PMAPI PM_DMACPosition(int channel);
;----------------------------------------------------------------------------
; Returns the current position in a dma transfer. Interrupts should be
; disabled before calling this function.
;----------------------------------------------------------------------------
cprocstart PM_DMACPosition
ARG channel:UINT
enter_c
mov ecx,[channel] ; ECX indexes DMAC register tables
mov dh,0 ; DH = 0 for DMAC register port access
; Generate IOW to clear FF toggle state
mov al,0
mov dl,[DMAC_FF+ebx]
out dx,al
xor eax,eax
xor ecx,ecx
; Now read the current position for the channel
@@ReadLoop:
mov dl,[DMAC_cnt+ebx]
out dx,al
in al,dx
mov cl,al
in al,dx
mov ch,al ; ECX := first count read
in al,dx
mov ah,al
in al,dx
xchg al,ah ; EAX := second count read
sub ecx,eax
cmp ecx,40h
jg @@ReadLoop
cmp ebx,4 ; 16-bit channel?
jb @@Exit ; No, we are done
shl eax,1 ; Yes, adjust to byte address
@@Exit: leave_c
ret
cprocend
cpublic _PM_DMACodeEnd
endif
endcodeseg _dma
END ; End of module