;/////////////////////////////////////////////////////////////////////////////
;// dma.asm
;//
;// DMA driver module
;//
;// 09/08/1999	fOSSiL		Initial version
;// 23/10/1999	fOSSiL		minor updates
;// 28/10/1999	fOSSiL		16bit DMA fix
;// 2000/01/14	The Owl		nasm port
;// 2000/01/16	The Owl		cosmetic changes ;-)


global DmaInit


bits 32


struc DmaType
.MaskReg	resb 1	; Mask reg
.ModeReg	resb 1	; Mode reg
.FFReg		resb 1	; Flip-Flop reg
.pad1		resb 1	; 0 ; padding for 4-align
endstruc

struc DmaChan
.AddrReg	resb 1
.CountReg	resb 1
.PageReg	resb 1
.WordType	resb 1	; 0 = 8bit, 1 = 16bit
endstruc


segment _LDATA
	align 4
Types:
istruc DmaType				; 8bit DMA
  at DmaType.MaskReg,	db 00ah
  at DmaType.ModeReg,	db 00bh
  at DmaType.FFReg,	db 00ch
  at DmaType.pad1,	db 0
iend
istruc DmaType				; 16bit DMA
  at DmaType.MaskReg,	db 0d4h
  at DmaType.ModeReg,	db 0d6h
  at DmaType.FFReg,	db 0d8h
  at DmaType.pad1,	db 0
iend


Chans:
istruc DmaChan				; 0
  at DmaChan.AddrReg,	db 000h
  at DmaChan.CountReg,	db 001h
  at DmaChan.PageReg,	db 087h
  at DmaChan.WordType,	db 0
iend
istruc DmaChan				; 1
  at DmaChan.AddrReg,	db 002h
  at DmaChan.CountReg,	db 003h
  at DmaChan.PageReg,	db 083h
  at DmaChan.WordType,	db 0
iend
istruc DmaChan				; 2
  at DmaChan.AddrReg,	db 004h
  at DmaChan.CountReg,	db 005h
  at DmaChan.PageReg,	db 081h
  at DmaChan.WordType,	db 0
iend
istruc DmaChan				; 3
  at DmaChan.AddrReg,	db 006h
  at DmaChan.CountReg,	db 007h
  at DmaChan.PageReg,	db 082h
  at DmaChan.WordType,	db 0
iend
istruc DmaChan				; 4
  at DmaChan.AddrReg,	db 0c0h
  at DmaChan.CountReg,	db 0c2h
  at DmaChan.PageReg,	db 000h
  at DmaChan.WordType,	db 1
iend
istruc DmaChan				; 5
  at DmaChan.AddrReg,	db 0c4h
  at DmaChan.CountReg,	db 0c6h
  at DmaChan.PageReg,	db 08bh
  at DmaChan.WordType,	db 1
iend
istruc DmaChan				; 6
  at DmaChan.AddrReg,	db 0c8h
  at DmaChan.CountReg,	db 0cah
  at DmaChan.PageReg,	db 089h
  at DmaChan.WordType,	db 1
iend
istruc DmaChan				; 7
  at DmaChan.AddrReg,	db 0cch
  at DmaChan.CountReg,	db 0ceh
  at DmaChan.PageReg,	db 08ah
  at DmaChan.WordType,	db 1
iend


segment _LTEXT

DmaInit:
; EAX = chan#
; EBX = mem addr : page+offset
; ECX = block size
	push	esi
	push	edi
	push	ebx

; index into Chans array
	lea	edi, [Chans + eax * DmaChan_size]

; index into Types array
	movzx	edx, byte [edi + DmaChan.WordType]
	ror	ebx, 16

; if 16bit DMA we have to adjust Page/Offset and Count
	or	edx, edx
	jz	.NoAdjust

; offset gets the LSB of Page in its MSB
	ror	ebx, 1
	rcl	bx, 1
	shr	ecx, 1	; adjust block size
	sub	eax, 4	; adjust chan#

.NoAdjust:
	push	eax	; save it
	push	edi	; save it

	lea	edi, [Types + edx * DmaType_size]
	
; get Mask reg
	xor	edx, edx
	mov	dl, [edi + DmaType.MaskReg]
	
; mask DMA chan off
	or	al, 4
	out	dx, al
;	jmp	short $+2
	call	delay
	
	mov	dl, [edi + DmaType.FFReg]
	xor	eax, eax
	out	dx, al		; clear Flip-Flop
;	jmp	short $+2
	call	delay

	mov	dl, [edi + DmaType.ModeReg]
	mov	eax, [esp + 4]	; get saved EAX
	or	al, 058h	; Auto-Init mode
	out	dx, al
;	jmp	short $+2
	call	delay

	xchg	edi, [esp]

; set Count for channel
	mov	dl, [edi + DmaChan.CountReg]
	dec	ecx
	mov	al, cl
	out	dx, al
;	jmp	short $+2
	call	delay

	mov	al, ch
	out	dx, al
;	jmp	short $+2
	call	delay

; set Page
	mov	dl, [edi + DmaChan.PageReg]
	mov	al, bl
	out	dx, al
;	jmp	short $+2
	call	delay

; set Offset (Addr)
	mov	dl, [edi + DmaChan.AddrReg]
	mov	eax, ebx
	shr	eax, 16
	out	dx, al
;	jmp	short $+2
	call	delay

	shr	eax, 8
	out	dx, al
;	jmp	short $+2
	call	delay

; enable channel back
	pop	edi
	mov	dl, [edi + DmaType.MaskReg]
	pop	eax
	out	dx, al
;	jmp	short $+2
	call	delay

	pop	ebx
	pop	edi
	pop	esi
	retn

delay:
	push	ecx
	mov	ecx,16
	loop	$
	pop	ecx
	retn
