
        page    64,131
	Title	MVOUT  --  Pro Audio Spectrum direct I/O

;   /*\
;---|*|-------------------------====< MVOUT >====-------------------------
;---|*|
;---|*|  This module contains some code for supporting direct I/O to the PAS
;---|*|  where the hardware is write only. All calls reference the state
;---|*|  table to guarrantee proper I/O values.
;---|*|
;---|*|  Media Vision, Inc. Copyright (c) 1991,1992. All Rights Reserved.
;---|*|
;   \*/


	.xlist
	include model.inc
        include masm.inc
	include state.inc
	include common.inc
	.list

	.data
;
; The following label allows us to calculate an offset for the tables of
; addresses
;
FirstDataByte   label   byte            ; !!!!!! must be the 1st entry in
;					; the data segmment!!!
;
; our first pass flag - set to -1 for first entry, will be zeroed out
;
invmso_first	db	-1		; -1 for first pass, to be zeroed out

;
; Hardware Shadowing Table of Registers
;
        public  shadowregtable
shadowregtable	label	word
	dw	SYSSPKRTMR		; 00042h ; System Speaker Timer Address
	dw	SYSTMRCTLR		; 00043h ; System Timer Control Register
	dw	SYSSPKRREG		; 00061h ; System Speaker Register
	dw	JOYSTICK		; 00201h ; Joystick Register
	dw	LFMADDR 		; 00388h ; Left  FM Synthesizer Address Register
	dw	LFMDATA 		; 00389h ; Left  FM Synthesizer Data Register
	dw	RFMADDR 		; 0038Ah ; Right FM Synthesizer Address Register
	dw	RFMDATA 		; 0038Bh ; Right FM Synthesizer Data Register
	dw	DFMADDR 	;AUXADDR; 00788h ; Dual  FM Synthesizer Address Register
	dw	DFMDATA 	;AUXDATA; 00789h ; Dual  FM Synthesizer Data Register
        dw      0                       ; 0078Ah ; reserved for future use
	dw	0			; 0078Bh ; reserved for future use
        dw      AUDIOMIXR               ; 00B88h ; Audio Mixer Control Register
	dw	INTRCTLRST		; 00B89h ; Interrupt Status Register
	dw	AUDIOFILT		; 00B8Ah ; Audio Filter Control Register
	dw	INTRCTLR		; 00B8Bh ; Interrupt Control Register
	dw	PCMDATA 		; 00F88h ; PCM data I/O register
	dw	0			; 00F89h ; reserved for future use
	dw	CROSSCHANNEL		; 00F8Ah ; Cross Channel
	dw	0			; 00F8Bh ; reserved for future use
        dw      SAMPLERATE              ; 01388h ; Sample Rate Timer Register
	dw	SAMPLECNT		; 01389h ; Sample Count Register
	dw	SPKRTMR 		; 0138Ah ; Local Speaker Timer Address
	dw	TMRCTLR 		; 0138Bh ; Local Timer Control Register
	dw	MDIRQVECT		; 01788H ; MIDI IRQ Vector Register
	dw	MDSYSCTLR		; 01789H ; MIDI System Control Register
	dw	MDSYSSTAT		; 0178AH ; MIDI IRQ Status Register
	dw	MDIRQCLR		; 0178BH ; MIDI IRQ Clear Register
	dw	MDGROUP4		; 01B88H ; MIDI Group #4 Register
	dw	MDGROUP5		; 01B89H ; MIDI Group #5 Register
	dw	MDGROUP6		; 01B8AH ; MIDI Group #6 Register
	dw	MDGROUP7		; 01B8BH ; MIDI Group #7 Register

SHADOWTABLELEN  equ     28              ; 28 entries in the shadow data table

;
; Storage Locations for the data
;
	public	shadowdatatable
shadowdatatable label	word
	dw	offset _sysspkrtmr	; 00042h ; System Speaker Timer Address
	dw	offset _systmrctlr	; 00043h ; System Timer Control Register
	dw	offset _sysspkrreg	; 00061h ; System Speaker Register
	dw	offset _joystick	; 00201h ; Joystick Register
	dw	offset _lfmaddr 	; 00388h ; Left  FM Synthesizer Address Register
	dw	offset _lfmdata 	; 00389h ; Left  FM Synthesizer Data Register
	dw	offset _rfmaddr 	; 0038Ah ; Right FM Synthesizer Address Register
	dw	offset _rfmdata 	; 0038Bh ; Right FM Synthesizer Data Register
	dw	offset _dfmaddr 	; 00788h ; Dual  FM Synthesizer Address Register
	dw	offset _dfmdata 	; 00789h ; Dual  FM Synthesizer Data Register
	dw	0			; 0078Ah ; reserved for future use
	dw	0			; 0078Bh ; reserved for future use
        dw      offset _audiomixr       ; 00B88h ; Audio Mixer Control Register
	dw	offset _intrctlrst	; 00B89h ; Interrupt Status Register
	dw	offset _audiofilt	; 00B8Ah ; Audio Filter Control Register
	dw	offset _intrctlr	; 00B8Bh ; Interrupt Control Register
	dw	offset _pcmdata 	; 00F88h ; PCM data I/O register
        dw      0                       ; 00F89h ; reserved for future use
        dw      offset _crosschannel    ; 00F8Ah ; Cross Channel
	dw	0			; 00F8Bh ; reserved for future use
        dw      offset _samplerate      ; 01388h ; Sample Rate Timer Register
	dw	offset _samplecnt	; 01389h ; Sample Count Register
	dw	offset _spkrtmr 	; 0138Ah ; Local Speaker Timer Address
	dw	offset _tmrctlr 	; 0138Bh ; Local Timer Control Register
	dw	offset _mdirqvect	; 01788H ; MIDI IRQ Vector Register
	dw	offset _mdsysctlr	; 01789H ; MIDI System Control Register
	dw	offset _mdsysstat	; 0178AH ; MIDI IRQ Status Register
	dw	offset _mdirqclr	; 0178BH ; MIDI IRQ Clear Register
	dw	offset _mdgroup1	; 01B88H ; MIDI Group #4 Register
	dw	offset _mdgroup2	; 01B89H ; MIDI Group #5 Register
	dw	offset _mdgroup3	; 01B8AH ; MIDI Group #6 Register
	dw	offset _mdgroup4	; 01B8BH ; MIDI Group #7 Register

	extrn	mvhwShadowPointer	:dword
	extrn	_MVTranslateCode	:word	 ; hardware I/O offset
	extrn	_MVHWVersionBits	:word	 ; hardware bits

;
;---------------------------========================---------------------------
;---------------------------====< CODE SECTION >====---------------------------
;---------------------------========================---------------------------
;
	.code

	externADDR MVInitStatePtr	; state table pointer stuff
	externADDR mvGetHWVersion	; find the board address...

;
;   /*\
;---|*|
;---|*|---------------====< Prototypes >====---------------
;---|*|
;---|*| void MVOut( int, int, int )
;---|*|
;---|*| Output a masked byte directly to the hardware, and return the new value
;---|*|
;---|*| Entry Conditions:
;---|*|     wParm1 is the port address
;---|*|     wParm2 is the and mask of bits to be written
;---|*|     wParm3 is the xor data to be written
;---|*|
;---|*| Exit Conditions:
;---|*|     if wParm2 = 0,  al = read from hardware, ah = shadowed data
;---|*|     if wParm2 = !0, value is written to the hardware & shadow table
;   \*/
;
	public	MVOut
MVOut   PROC
	push	bp
	mov	bp,sp
;
; this code can only be processed once per loading
;
	cmp	[invmso_first],-1	; have we been here?
	jnz	@F			; yes, don't do this again
	mov	[invmso_first],0	; no, so pass by just once
	call	__initmvout
	call	MVInitStatePtr		; initialize the state table
    @@:
;
; perform the read from the state table, or write to the hardware
;
        push    es

	mov	dx,wParm1		; port address

	call	_getregisterptr 	; get the shadow hardware register ptr
        jc      mvout_exit              ; IO address not found

	mov	cx,wParm2		; mask
        mov     ax,wParm3               ; data

	jcxz	mvout_read		; read request, just return the data

	and	al,cl			; merge new and old bits
	not	cl			; get the other bits
	and	cl,es:[bx]		; from the shadow state
	or	al,cl			; and merge them in
	xor	dx,[_MVTranslateCode]	; xlate the board address
	out	dx,al			; output to the hardware
	mov	es:[bx],al		; save the new state
;
mvout_exit:
	pop	es
	pop	bp
	ret
;
mvout_read:
	mov	al,es:[bx]		; gets the value from the state table
	jmp	short mvout_exit

MVOut	endp

;
;   /*\
;---|*|---------------====< __initmvout() >====---------------
;---|*|
;---|*| Initializes this body of code. It will try to find the int 2F DOS
;---|*| interface to the MVPROAS device. Once found, the new state table
;---|*| pointer will be loaded.
;---|*|
;---|*| Entry Conditions:
;---|*|     None
;---|*|
;---|*| Exit Conditions:
;---|*|     DX:AX point to the state table
;   \*/

__initmvout	proc	near
	push	es
	push	di
	mov	ax,ds
	mov	es,ax
;
; adjust the shadow data table offsets to the correct linked offset
;
	mov	cx,SHADOWTABLELEN	; table length...
        lea     bx,FirstDataByte        ; the compiled offsets must be adjusted
	lea	di,shadowdatatable	; DI points to the table
    ;
    @@:
	add	es:[di],bx		; move the offsets in the table
	inc	di
        inc     di
	loop	@B

	cmp	[_MVHWVersionBits],-1	; already found?
	jnz	inmv_done		; yes, continue on..

	mov	ax,USE_ACTIVE_ADDR	; defaults to the original address
	push	ax
	call	mvGetHWVersion		; find the board address...
	add	sp,2
;
inmv_done:
        pop     di
	pop	es
	ret

__initmvout	endp

;
;---------------------====< _getregisterptr >====---------------
;
; Get a pointer to the state table
;
; Entry Conditions:
;     DX holds the port address
;
; Exit Conditions:
;     ES:BX holds the pointer, no other registers modified
;
_getregisterptr proc	near
	push	di			; no toucha dees...
	push	cx

	mov	cx,ds
	mov	es,cx
	lea	di,shadowregtable	; look in the register table
	mov	cx,SHADOWTABLELEN

	xchg	ax,dx			; ax holds the port address
	cld
	repne	scasw
	xchg	ax,dx			; restore 'em...

	stc				; just in case we bomb out
        jne     @F                      ; no match, bomb out...

if MODELSIZE eq 0
	assume	es:@code		; tiny (.com) model is same as code
else
	assume	es:@data		; all other has a data segment
endif

        sub     di,offset shadowregtable+2 ; create an offset into the table
	mov	bx,es:[shadowdatatable+di] ; bx = the offset from the 1st ptr
	mov	di,es:[shadowdatatable+0]  ; grab the first ptr
	sub	bx,di			   ; bx holds a zero based offset
	les	di,mvhwShadowPointer	   ; get the true state table pointer
	add	bx,di			   ; bx now points into the true table
        assume  es:nothing

	clc				; was found, indicate so...
;
@@:
	pop	cx
	pop	di
        ret

_getregisterptr endp

;   /*\
;---|*| end of MVOut
;   \*/

        end

