; MAR - 7 - 2006 : DMA.ASM direct memory chip support

EnableDMA proc far
;-----------------------------------------------------------------------------
; EnableDMA: enable DMA controller
;-----------------------------------------------------------------------------
; in:  nothing
; out: nothing
;-----------------------------------------------------------------------------
  mov al, 00010000b
  out 08h, al ; enable master
  out 0D0h, al ; enable slave
  ret
EnableDMA endp

DisableDMA proc far
;-----------------------------------------------------------------------------
; DisableDMA: disable DMA controller
;-----------------------------------------------------------------------------
; in:  nothing
; out: nothing
;-----------------------------------------------------------------------------

  mov al, 00010100b
  out 08h, al ; disable master
  out 0D0h, al ; disable slave

  ret
DisableDMA endp



UnmaskDMAChannel proc far
;-----------------------------------------------------------------------------
; UnmaskDMAChannel: unmask (enable) DMA channel
;-----------------------------------------------------------------------------
; in:  bl = channel number
; out: nothing
;-----------------------------------------------------------------------------

  cmp bl, 3 ; IF channel > 3...
  ja slave_dma ; ...THEN slave DMA channel

  ; unmask master DMA channel
  mov al, bl ; al = channel
  out 0Ah, al ; unmask channel
  jmp udma_end

  ; unmask slave DMA channel
slave_dma:
  and bl, 00000011b ; bl = slave channel
  mov al, bl ; al = slave channel
  out 0D4h, al ; unmask channel

udma_end:
  ret
UnmaskDMAChannel endp

MaskDMAChannel proc far
;-----------------------------------------------------------------------------
; MaskDMAChannel: mask (disable) DMA channel
;-----------------------------------------------------------------------------
; in:  bl = channel number
; out: nothing
;-----------------------------------------------------------------------------
  cmp bl, 3 ; IF channel > 3...
  ja mdma_slave_dma ; ...THEN slave DMA channel

  ; mask master DMA channel
  mov al, bl ; al = channel
  or al, 00000100b
  out 0Ah, al ; mask channel
  jmp mdma_end

  ; mask slave DMA channel
mdma_slave_dma:
  and bl, 00000011b ; bl = slave channel
  mov al, bl ; al = slave channel
  or al, 00000100b
  out 0D4h, al ; mask channel

mdma_end:
  ret
MaskDMAChannel endp

reset_dma PROC far
        mov  dx,DMA_Mask
        mov  ax,reset_cmd
        add  ax,cs:[Channel]
        out  dx,al
        mov  ax,0
        ret
DMA_Mask        EQU     0Ah     ;DMAC DMA_Mask (write-only)
Mode            EQU     0Bh     ;DMAC mode (read/write)


byte_ptr        EQU     00ch    ; byte pointer flip-flop

addr	       	EQU	000h	; per-channel base address
ddcount           EQU     001h    ; per-channel byte count

read_cmd        EQU     048h    ; read mode
write_cmd       EQU     044h    ; write mode
set_cmd         EQU     000h    ; DMA_Mask set
reset_cmd       EQU     004h    ; DMA_Mask reset
channel         dw 0
reset_dma  endp

dma_done PROC far
        mov  dx,cs:[Channel]
        shl  dx,1
        add  dx,ddcount
        cli
        in   al,dx
        mov  ah,al
        in   al,dx
        xchg al,ah
        ret
dma_done endp

setup_dma PROC far

        mov  cs:[_dma_errno],0
        mov  bx,cs:[WORD PTR Buffer]
        mov  ax,cs:[WORD PTR Buffer+2]
	mov  cl,4
        rol  ax,cl
        mov  ch,al
        and  al,0F0h
        add  ax,bx
        adc  ch,0
        and  ch,0Fh
        mov  di,ax

        mov  bx,cs:[Channel]
        shl  bx,1

        cmp  cs:[WORD PTR dmadir],0
         jnz SHORT @@Do_Read
        mov  al,write_cmd
         jmp SHORT @@Do_Mode
@@Do_Read:
  	mov  al,read_cmd
@@Do_Mode:
        push cx
        mov  cx,cs:[Channel]
  	add  al,cl
        xor ah,ah
        mov  si,ax
        mov  ax,set_cmd
        add  al,cl
        pop  cx
        mov  cl,al
        mov  ax,di              ;Let's check the address to see if we
        add  ax,cs:[Len]        ;span a page boundary with our length
        ;jnc @@BoundaryOk        ;Do we?
        ;mov  cs:[_dma_errno],2  ; y: Error #2
        ;mov  ax,-1              ;    Return -1
        ;jmp @@ExitPt            ;    See ya...
@@BoundaryOk:                   ; n: Continue with action
        cli                     ;Disable interrupts while mucking with DMA

        mov  dx,byte_ptr        ;Reset byte pointer Flip/flop
        out  dx,al              ;All we have to do is write to it

        mov  ax,di              ;ax=LSW of 20-bit address
        mov  dx,bx              ;dx=DMAC Base Address port
	out  dx,al              ;Store LSB
        mov  al,ah
        out  dx,al              ;Store next byte

        mov  al,ch              ;al=Page number
        mov  dx,cs:[bx + OFFSET page_table]        ;dx=Port is the "Page index"
        out  dx,al              ;Store the page

        mov  ax,cs:[Len]
        mov  dx,bx              ;dx=DMAC Base Adress port
        inc  dx                 ;dx=DMAC Count port (1 after Base address)
        out  dx,al              ;Write LSB of Length
        mov  al,ah
        out  dx,al              ;Write MSB

        mov  ax,si              ;Load pre-calculated mode
        mov  dx,Mode            ;dx=DMAC mode register
        out  dx,al              ;Write it to the DSP

        mov  dx,DMA_Mask        ;dx=DMAX DMA_Mask register
        mov  al,cl              ;al=pre-calulated DMA_Mask value
        out  dx,al              ;Write DMA_Mask
        mov  ax,0               ;Return with no error

@@ExitPt:                       ;Restore stack and return
        ret
;ARG Channel:WORD,Buffer:DWORD,Len:WORD,Dir:WORD
buffer          dw 0,0
len             dw 0
dmadir          dw 0
_dma_errno   DW 0
page_table     	DW	00087h	; channel 0
	       	DW	00083h	; channel 1
	       	DW	00081h	; channel 2
  	       	DW	00082h	; channel 3
setup_dma endp            
