home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio 4.94 - Over 11,000 Files
/
audio-11000.iso
/
msdos
/
sndbords
/
proaudio
/
pcmtlsrc
/
pcm.arj
/
MVSOUND.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-09-01
|
54KB
|
2,170 lines
;$Author: BCRANE $
;$Date: 01 Sep 1992 13:33:02 $
;$Header: X:/sccs/sdkapp/mvsound.asv 1.1 01 Sep 1992 13:33:02 BCRANE $
;$Log: X:/sccs/sdkapp/mvsound.asv $
;
; Rev 1.1 01 Sep 1992 13:33:02 BCRANE
; moved data from gethw.asm and state.asm into here, added check for
; previous initialization to not call gethw() or state() again
;
; Rev 1.0 31 Aug 1992 09:42:52 BCRANE
; Initial revision.
;
; Rev 1.4 17 Jul 1992 14:18:22 DCODY
; moved TheDMAchannel and TheIRQchannel out to another module. Made the
; hardware I/O relocatable. Made initmvsound recallable without ill effects.
;
; Rev 1.3 09 Jul 1992 10:07:50 DCODY
; corrected MV101 bit test and jumps
;
; Rev 1.2 26 Jun 1992 14:13:48 DCODY
; added the parameter to GetHWVersion call
;
; Rev 1.1 23 Jun 1992 17:06:04 DCODY
; PAS2 update
;
; Rev 1.0 15 Jun 1992 09:43:46 BCRANE
; Initial revision.
;$Logfile: X:/sccs/sdkapp/mvsound.asv $
;$Modtimes$
;$Revision: 1.1 $
;$Workfile: mvsound.asm $
page 64,131
subttl MVSOUND -- Pro Audio Spectrum Sound Support Code
; /*\
;---|*|----====< MVSOUND >====----
;---|*|
;---|*| This module contains the code for supporting PCM I/O.
;---|*|
;---|*| Media Vision, Inc. Copyright (c) 1991,1992. All Rights Reserved.
;---|*|
; \*/
;
; The following set of equates are used to control what routines are compiled
; by doing this, MVSOUND.ASM can contain all the necessary code in one file,
; but generate separate, linkable objects with just the necessary code.
;
ALLOBJS = 0 ; individual objects are being built
DATAOBJ = 0 ; data code to be compiled
MISC1OBJ = 0 ; minimum code needed from the library
MISC2OBJ = 0 ; other miscellaneous code
PCMOBJ = 0 ; PCM code to be compiled
ifdef BUILDDATA
DATAOBJ = 1 ; data code to be compiled
endif
ifdef BUILDMISC1
MISC1OBJ = 1 ; misc module #1 code to be compiled
endif
ifdef BUILDMISC2
MISC2OBJ = 1 ; misc module #2 code to be compiled
endif
ifdef BUILDPCM
PCMOBJ = 1 ; data code to be compiled
endif
ifdef BUILDALL
ALLOBJS = 1 ; all objects are being built
DATAOBJ = 1 ; data code to be compiled
MISC1OBJ = 1 ; miscellaneous code to be compiled
MISC2OBJ = 1 ; miscellaneous code to be compiled
PCMOBJ = 1 ; PCM code to be compiled
endif
.xlist
include masm.inc
include target.inc
include state.inc
include common.inc
.list
;
; structure for pointing to the above table of DMA addresses
;
dmaaddr struc
_dmach db ? ; DMA channel selected
_dmardstat db ? ; DMA read status
_dmawrcntrl db ? ; DMA write command register
_dmawreq db ? ; DMA write request register
_dmawrsmr db ? ; DMA write single mask register
_dmawrmode db ? ; DMA write mode register
_dmaclear db ? ; DMA clear low/high flip-flop
_dmardtemp db ? ; DMA read temp register
_dmawrclr db ? ; DMA write master clear
_dmaclrmsk db ? ; DMA clear mask register
_dmawrall db ? ; DMA write all mask register bits
dmaaddr ends
;
;---------------------------========================---------------------------
;---------------------------====< DATA SECTION >====---------------------------
;---------------------------========================---------------------------
;
;if MODELSIZE eq 0
; .code
;else
; .data
;endif
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; gethw.asm data
;
;---------------------------========================---------------------------
;---------------------------====< DATA SECTION >====---------------------------
;---------------------------========================---------------------------
;
; .data
;
; The board base address for the original PAS card was based at 388. This will
; be XORed to the new address to derive a translation code. This code can be
; XORed back into any original PAS address resulting in the true card address.
;
public _MVTranslateCode
_MVTranslateCode dw 0 ; I/O base xor default_base
public _MVHWVersionBits
_MVHWVersionBits dw -1 ; holds the product feature bits
VERSION_PAS equ 0 ; Pro Audio Spectrum
VERSION_PASPLUS equ 1 ; Pro Audio Plus card
VERSION_PAS16 equ 2 ; Pro Audio 16 card
VERSION_CDPC equ 3 ; CDPC card & unit
PASdocare equ <NOT (bMVSCSI+bMVENHSCSI+bMV101_REV)>
PASPLUSdocare equ <NOT (bMVSCSI+bMVENHSCSI+bMVSONY+bMV101_REV)>
PAS16docare equ <NOT (bMVSCSI+bMVENHSCSI+bMV101_REV)>
CDPCdocare equ <NOT (bMVSCSI+bMVENHSCSI+bMV101_REV)>
;
ProductIDTable label word
dw PRODUCT_PROAUDIO and PASdocare
dw PRODUCT_PROPLUS and PASPLUSdocare
dw PRODUCT_PRO16 and PAS16docare
dw PRODUCT_CDPC and CDPCdocare
dw -1
;
DoCareBits label word
dw PASdocare
dw PASPLUSdocare
dw PAS16docare
dw CDPCdocare
dw -1 ; table terminator
public TheDMAChannel ; defaults to channel 1
TheDMAChannel db DEFAULTDMA ; defaults to channel 1
public TheIRQChannel ; defaults to IRQ 7
TheIRQChannel db DEFAULTIRQ ; defaults to IRQ 7
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; mvstate.asm data
; .data
;
; This pointer points to a state table of hardware variables
;
public mvhwShadowPointer
mvhwShadowPointer dd 0 ; points to the start of the data table
;
; These variables mirror the hardware state
;
HardwareShadowTable db (size MVState) dup (0)
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
if DATAOBJ ; include if we are building DATA.OBJ
;
; These variables are DMA/Buffer control variables
;
TheIRQMask db INT7MSK ; 8259 interrupt mask
TheDMAMode db 00h ; 44h for input, 48h for output
LinearPtr dd 0 ; holds linear address
SegmentedPtr dd 0 ; holds segmented address (real mode)
DMABuffLength dw 0 ; DMA Length (0 based) (MUST BE EVEN!)
DMABuffDivides db 0 ; # of splits in the DMA buffer
TheSampleRate dd 0 ; 3k through 88k
StereoMono db 0 ; ff for mono, 00 for stereo
PCMDirection db 0 ; bit mask for the DMA controller
SampleSize db 0 ; sample size: 0=8,1=12,2=16
public DMAAutoInit ; TRUE(0ffh) or FALSE(000h)
DMAAutoInit db 0ffh ; to allow auto-init on DMA access
UserRoutine dd 0 ; User Code
StatusWord dw 0 ; Holds current status:
; ; 0 = inactive, available
; ; 1 = currently playing
; ; 2 = currently recording
OldIRQRoutine dd 0 ; holds the original routine
polledmask equ bICsamprate+bICsampbuff ; polled mask
dmamask equ bICsampbuff ; dma mask
DMAOUTPUT equ 0+dmamask ; DMA is used to drive the output
POLLEDOUTPUT equ 0+polledmask ; Polling routine drives output
DMAINPUT equ 1+dmamask ; DMA is used to read input
POLLEDINPUT equ 1+polledmask ; Polling routine reads input
TypeOfSetup db 0 ; polled/dma interrupt masks & stuff..
public NumberOfInterrupts
NumberOfInterrupts dw 0 ; number of interrupts that have occured
;
; These variables direct our code to the proper DMA channel
;
OurDMAPageReg dw CH1PAGEREG ; default to DMA channel 1 page reg
OurDMAddress dw DMAC1ADDR ; default to DMA channel 1 address reg
;
; table of address pointers to the various DMA 2 addresses
;
public DMA1AddrTable
DMA1AddrTable label byte
db DEFAULTDMA ; DMA channel selected
db DMARDSTAT ; DMA read status
db DMAWRCNTRL ; DMA write command register
db DMAWREQ ; DMA write request register
db DMAWRSMR ; DMA write single mask register
db DMAWRMODE ; DMA write mode register
db DMACLEAR ; DMA clear low/high flip-flop
db DMARDTEMP ; DMA read temp register
db DMAWRCLR ; DMA write master clear
db DMACLRMSK ; DMA clear mask register
db DMAWRALL ; DMA write all mask register bits
;
; table of address pointers to the various DMA 2 addresses
;
public DMA2AddrTable
DMA2AddrTable label byte
db DEFAULTDMA ; DMA channel selected
db DMA2RDSTAT ; DMA read status
db DMA2WRCNTRL ; DMA write command register
db DMA2WREQ ; DMA write request register
db DMA2WRSMR ; DMA write single mask register
db DMA2WRMODE ; DMA write mode register
db DMA2CLEAR ; DMA clear low/high flip-flop
db DMA2RDTEMP ; DMA read temp register
db DMA2WRCLR ; DMA write master clear
db DMA2CLRMSK ; DMA clear mask register
db DMA2WRALL ; DMA write all mask register bits
public DMAPointer
DMAPointer dw offset DMA1AddrTable ; default to channel 1 table
;
; working variables
;
;
public TheIRQMask ; 8259 interrupt mask
public TheDMAMode ; 55h for input, 59h for output
public LinearPtr ; holds linear address
public SegmentedPtr ; holds segmented address (real mode)
public DMABuffLength ; DMA Length (0 based) (MUST BE EVEN!)
public DMABuffDivides ; # of splits in the DMA buffer
public TheSampleRate ; 3k through 88k
public StereoMono ; ff for mono, 00 for stereo
public PCMDirection ; bit mask for the DMA controller
public SampleSize ; sample size: 0=8,1=12,2=16
public DMAAutoInit ; TRUE/FALSE flag for DMA autoinit bit
public UserRoutine ; User Code
public StatusWord ; Holds current status:
public OldIRQRoutine ; holds the original routine
polledmask equ bICsamprate+bICsampbuff ; polled mask
dmamask equ bICsampbuff ; dma mask
DMAOUTPUT equ 0+dmamask ; DMA is used to drive the output
POLLEDOUTPUT equ 0+polledmask ; Polling routine drives output
DMAINPUT equ 1+dmamask ; DMA is used to read input
POLLEDINPUT equ 1+polledmask ; Polling routine reads input
public TypeOfSetup ; polled/dma interrupt masks & stuff..
public NumberOfInterrupts ; number of interrupts that have occured
public OurDMAPageReg ; default to DMA channel 1 page reg
public OurDMAddress ; default to DMA channel 1 address reg
else ; not building DATA.OBJ, declare all publics
extrn DMAPointer :word ; pointer to the DMA address table
extrn DMA1AddrTable :byte ; 1st DMA controller table
extrn DMA2AddrTable :byte ; 2nd DMA controller table
extrn TheIRQMask :byte ; 8259 interrupt mask
extrn TheDMAMode :byte ; 55h for input, 59h for output
extrn LinearPtr :dword ; holds linear address
extrn SegmentedPtr :dword ; holds segmented address (real mode)
extrn DMABuffLength :word ; DMA Length (0 based) (MUST BE EVEN!)
extrn DMABuffDivides :byte ; # of splits in the DMA buffer
extrn TheSampleRate :dword ; 3k through 88k
extrn StereoMono :byte ; ff for mono, 00 for stereo
extrn PCMDirection :byte ; bit mask for the DMA controller
extrn SampleSize :byte ; sample size: 0=8,1=12,2=16
extrn DMAAutoInit :byte ; TRUE/FALSE flag for DMA autoinit bit
extrn UserRoutine :dword ; User Code
extrn StatusWord :word ; Holds current status:
extrn OldIRQRoutine :dword ; holds the original routine
extrn TypeOfSetup :byte ; polled/dma interrupt masks & stuff..
extrn NumberOfInterrupts:word ; number of interrupts that have occured
extrn OurDMAPageReg :word ; default to DMA channel 1 page reg
extrn OurDMAddress :word ; default to DMA channel 1 address reg
polledmask equ bICsamprate+bICsampbuff ; polled mask
dmamask equ bICsampbuff ; dma mask
DMAOUTPUT equ 0+dmamask ; DMA is used to drive the output
POLLEDOUTPUT equ 0+polledmask ; Polling routine drives output
DMAINPUT equ 1+dmamask ; DMA is used to read input
POLLEDINPUT equ 1+polledmask ; Polling routine reads input
SHADOWTABLELEN equ 28 ; 28 entries in the shadow data table
endif
; extrn TheDMAChannel :byte ; defaults to channel 1
; extrn TheIRQChannel :byte ; defaults to IRQ 7
; extrn mvhwShadowPointer :dword; a common variable for all
; extrn _MVHWVersionBits :word ; hardware state bits
; extrn _MVTranslateCode :word
.code
; externADDR MVInitStatePtr ; pointer to the state table init code
; externADDR MVGetHWVersion ; returns the hardware bits
;
; TEXT SEGMENT externals for the different modules
;
if PCMOBJ AND (NOT ALLOBJS) ; added for independent PCMOBJ module
externADDR SelectIRQ ; PCM uses "SelectIRQ"
externADDR _unloadirqvector ; PCM uses "_unloadirqvector"
externADDR _getirqoffset ; PCM uses "_getirqoffset"
endif
;
;---------------------------========================---------------------------
;---------------------------====< CODE SECTION >====---------------------------
;---------------------------========================---------------------------
;
; /*\
;---|*|
;---|*|---------------====< Prototypes >====---------------
;---|*|
;---|*| void far *DMABuffer(char far *, int, int )
;---|*|
;---|*| Passes in a pointer and length to the buffer.
;---|*| Also flushes the buffer. Returns 0 or true DMA buffer ptr.
;---|*|
;---|*| int EnablePCMPlay()
;---|*|
;---|*| Sets up the PCM hardware for polled output
;---|*|
;---|*| int EnablePCMRecord()
;---|*|
;---|*| Sets up the PCM hardware for polled input
;---|*|
;---|*| char huge *FindDMABuffer(char huge *, int )
;---|*|
;---|*| Takes a memory address & return the next 64k boundary
;---|*|
;---|*| MVState far *InitMVSound()
;---|*|
;---|*| Initializes the int 2F interface & some global variables.
;---|*|
;---|*| int InitPCM()
;---|*|
;---|*| Initializes the PCM code.
;---|*|
;---|*| void PausePCM()
;---|*|
;---|*| Temporarily stops the PCM I/O by disabling the timers
;---|*|
;---|*| int PCMInfo( long ,int, int, int )
;---|*|
;---|*| Sets up the transfer rate & stereo/mono/compression/data size
;---|*|
;---|*| int PCMPlay()
;---|*|
;---|*| Starts the DMA feeding the DAC
;---|*|
;---|*| int PCMRecord()
;---|*|
;---|*| Starts the DMA reading the ADC
;---|*|
;---|*| void RemovePCM()
;---|*|
;---|*| kills the PCM code.
;---|*|
;---|*| void ResumePCM()
;---|*|
;---|*| Restarts the PCM I/O by enabling the timers
;---|*|
;---|*| int SelectDMA( int )
;---|*|
;---|*| Selects the DMA channel 1, or 3
;---|*|
;---|*| int SelectIRQ( int )
;---|*|
;---|*| Selects the IRQ line for DMA control
;---|*|
;---|*| void StopPCM()
;---|*|
;---|*| Turn off the PCM timers, interrupts, and state machine.
;---|*|
;---|*| void UserFunc((*long)())
;---|*|
;---|*| Call back routine when Half way buffer is full/empty.
;---|*|
; \*/
if PCMOBJ
; /*\
;---|*|------====< void far * DMABuffer( char far *, int, int ) >====------
;---|*|
;---|*| Passes in a pointer and length to the buffer
;---|*|
;---|*| Entry Conditions:
;---|*| dParm1 points to DMA buffer
;---|*| wParm3 points to the length (wParm3 * 1024 is the total length )
;---|*| wParm4 is the # of divisions of the DMA buffer
;---|*|
;---|*| Exit Conditions:
;---|*| DX:AX = 0 - bad buffer
;---|*| DX:AX = returns buffer pointer
;---|*|
; \*/
public DMABuffer
DMABuffer proc
push bp
mov bp,sp
push es
push di
mov cx,wParm3 ; get the dma size (4/8/16/32/64)
or ch, ch
jz @F
mov ax, cx
jmp short savebufferlength
@@: cmp cx,64 ; too high?
ja dmabbad ; yes, bomb out
mov ax,1024
cwd
mul cx ; get the length - 1
savebufferlength:
dec ax
mov [DMABuffLength],ax ; and save for later use
les di,dParm1 ; get the far pointer to the buffer
mov ax,di
mov bx,es ; convert it to a linear address
mov dx,es
mov cl,4
rol dx,cl
and dx,000fh
shl bx,cl ; add offset portion of seg to offset
add ax,bx
jc dmabbad ; bad if extends over a 64k boundary
mov wptr [LinearPtr+0],ax ; save the linear address
mov wptr [LinearPtr+2],dx
mov wptr [SegmentedPtr+0],di
mov wptr [SegmentedPtr+2],es
mov bx,wParm4 ; get the # of DMA buffer divisions
mov [DMABuffDivides],bl
push ax ; save the buffer offset
mov cx,[DMABuffLength] ; get the clearing length
mov al,80h ; PCM silent code
cld
rep stosb ; flush the buffer length...
stosb ; + 1
mov dx,es
pop ax ; return dx:ax
jmp short dmabdone
;
dmabbad:
sub ax,ax
cwd
;
dmabdone:
pop di
pop es
pop bp
ret
DMABuffer endp
; /*\
;---|*|---------------====< EnablePCMPlay() >====---------------
;---|*|
;---|*| Enabled the DAC hardware for polled output (no interrupts)
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0 good start
;---|*| AX = -1 not started, problem occured
; \*/
public EnablePCMPlay
EnablePCMPlay proc
push es
mov ax,wptr [TheSampleRate+0] ; Validate the sample rate
or ax,wptr [TheSampleRate+2]
jz enaPCMPlay_bad ; zero sample rate, bomb out...
call FFAR ptr EnablePlaying ; go for it...
mov ax,0
jmp short enaPCMPlay_exit
;
enaPCMPlay_bad:
mov ax,-1
;
enaPCMPlay_exit:
pop es
ret
EnablePCMPlay endp
; /*\
;---|*|---------------====< EnablePCMRecord() >====---------------
;---|*|
;---|*| Enabled the ADC hardware for polled input (no interrupts)
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0 recording has started
;---|*| AX = -1 recording did not start
;---|*|
; \*/
public EnablePCMRecord
EnablePCMRecord proc
push es
mov ax,wptr [TheSampleRate+0] ; Validate the sample rate
or ax,wptr [TheSampleRate+2]
jz enaPCMRec_bad
call FFAR ptr EnableRecording ; go for it...
mov ax,0
jmp short enaPCMRec_exit
;
enaPCMRec_bad:
mov ax,-1
;
enaPCMRec_exit:
pop es
ret
EnablePCMRecord endp
; /*\
;---|*|------====< char far *FindDMABuffer(char far *,int ) >====------
;---|*|
;---|*| Finds the next 64k boundary starting with dParm1 address
;---|*|
;---|*| Entry Conditions:
;---|*| dParm1 points to a buffer twice the size needed for the DMA
;---|*| wParm2 is the size of the DMA buffer (4/8/16/32/64)
;---|*|
;---|*| Exit Conditions:
;---|*| DX:AX = returns buffer pointer on a 64k boundary
;---|*| DX:AX = 0 if boundary wraps beyond 1 meg.
;---|*|
; \*/
public FindDMABuffer
FindDMABuffer proc
push bp
mov bp,sp
sub ax,ax ; default to bad...
cwd
mov cx,wParm3 ; get the length
cmp cx,64 ; 64k buffer requested?
ja fdb_exit ; too high, exit
jz fdb_64k ; yes, special case it...
cmp cl,4
jb fdb_exit ; too low, exit
mov ax,1024 ; calculate the length of the DMA buffer
mul cx
mov bx,ax ; bx holds the length
mov dx,wptr dParm1+2
mov ax,dx ; accumulate the offset in ax
and ax,0fffh ; get the offset portion of the segment
and dx,0f000h ; make DX a 64k segment register
mov cl,4
shl ax,cl ; make the segment an offset
add ax,wptr dParm1+0 ; accumulate the rest of the offset
add bx,ax ; does the buffer cross a 64k boundary?
cmc ; carry set if 64k crossing
sbb bx,bx ; bx = ffff if no crossing, 0 if crossed
and ax,bx ; clear ax if crossed
not bx ; bx = ffff if crossed, 0000 if not
and bx,1000h
add dx,bx ; advance dx if we crossed a 64k boundary
jmp short fdb_exit
;
fdb_64k:
mov dx,wptr dParm1+2 ; get the segment
sub ax,ax ; offset is zero
and dx,0f000h ; find the next segment
add dx,1000h ; move to next segment
jnc fdb_exit ; if doesn't wraps past 1 meg, it's good
cwd ; bad, flush it...
;
fdb_exit:
pop bp
ret
FindDMABuffer endp
;
endif ; PCMOBJ
if MISC1OBJ
;
; /*\
;---|*|---------------====< InitMVSound() >====---------------
;---|*|
;---|*| 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
; \*/
mvsoundinited db 0
public InitMVSound
InitMVSound proc
mov al, mvsoundinited
or al, al
jz @F
ret
@@: inc al
mov mvsoundinited, al
push es
push di
mov ax,ds
mov es,ax
;
; find the hardware. Should be installed for this to run
;
call MVInitStatePtr ; initialize the state table ptr
cmp _MVHWVersionBits,-1 ; initialized yet?
jnz @F ; yes, continue on...
mov ax,USE_ACTIVE_ADDR ; pass in the base address
push ax
call MVGetHWVersion ; no, checkout the hardware
pop ax
;
@@:
mov ax,wptr [mvhwShadowPointer+0]
mov dx,wptr [mvhwShadowPointer+2]
pop di
pop es
ret
InitMVSound endp
;
endif ; MISC1OBJ
if PCMOBJ
;
; /*\
;---|*|---------------====< InitPCM() >====---------------
;---|*|
;---|*| Initializes the PCM code
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| AX = Version of this Code
; \*/
public InitPCM
InitPCM proc
push es
mov [TypeOfSetup],polledmask ; flushes both interrupts
; for upcoming calls
mov al,TheDMAChannel ; initialize the DMA now...
cbw
push ax
call FFAR ptr SelectDMA
pop ax
mov al,TheIRQChannel ; initialize the IRQ now...
cbw
push ax
call FFAR ptr SelectIRQ ; also removes the IRQ
pop ax
call FFAR ptr StopPCM ; kill the Audio Spectrum board
mov dx,INTRCTLRST ; flush any pending PCM irq
xor dx,[_MVTranslateCode] ; xlate the board address
out dx,al
sub ax,ax
mov [TypeOfSetup],al ; unknown type
mov wptr [UserRoutine+0],ax
mov wptr [UserRoutine+2],ax
mov wptr [LinearPtr+0],ax
mov wptr [LinearPtr+2],ax
mov wptr [SegmentedPtr+0],ax
mov wptr [SegmentedPtr+2],ax
mov wptr [DMABuffLength],ax
not al
mov [StereoMono],al ; mono
mov ax,11025
cwd
call FFAR ptr _calcsamplerate ; setup the default rate
mov wptr [TheSampleRate+0],ax
mov wptr [TheSampleRate+2],dx
mov ax,0003h ; for compatibility, version 00.03
pop es
ret
InitPCM endp
;
endif ; PCMOBJ
if PCMOBJ
;
;
; /*\
;---|*|---------------====< PausePCM >====---------------
;---|*|
;---|*| Turn off the h/w timer enables to effectively stop pcm temporarily.
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| Nothing
;---|*|
; \*/
;
public PausePCM
PausePCM proc
push es
push di
;
; Setup the audio filter sample bits
;
les di,[mvhwShadowPointer]
mov dx,AUDIOFILT
xor dx,[_MVTranslateCode] ; xlate the board address
disable
mov al,es:[di._audiofilt]
and al,not bFIsrate ; flush the enable bits
mov es:[di._audiofilt],al
out dx,al
enable
pop di
pop es
ret
PausePCM endp
;
; /*\
;---|*|---------------====< PCMInfo ( long, int, int, int ) >====---------------
;---|*|
;---|*| Selects xfer rate & stereo/mono
;---|*|
;---|*| Entry Conditions:
;---|*| Parm #1 (wParm1, wParm2) is the rate
;---|*| Parm #2 (wParm3) is the stereo(1) or mono (0)
;---|*| Parm #3 (wParm4) is the compression flag
;---|*| Parm #4 (wParm5) is the data size (8/12/16 bits per sample)
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0, good data
;---|*| AX = -1, bum transfer rate
;---|*|
; \*/
public PCMInfo
PCMInfo proc
push bp
mov bp,sp
mov al,wParm4+2 ; get the data size
cbw
cmp al,8 ; 8 bit channel?
jz @F
inc ah
cmp al,12 ; 12 bit channel
jz @F
inc ah
cmp al,16 ; 16 bit channel?
jnz pcinf_bad ; no, bomb out...
;
@@:
mov [SampleSize],ah
mov cx,wParm3 ; get the stereo flag
shr cx,1
jnz pcinf_bad ; exit bad if not zero
cmc ; set for mono, cleared for stereo
sbb cx,cx ; make a full bit mask
mov [StereoMono],cl ; save only valid values
mov ax,dParm1+0 ; get the sample rate
mov dx,dParm1+2
or cx,cx ; is it mono?
jnz @F ; yes, skip the doubling
shl ax,1 ; no, stereo, so double the sample rate
adc dx,dx
;
@@:
call FFAR ptr _calcsamplerate
jc pcinf_bad
mov wptr [TheSampleRate+0],ax
mov wptr [TheSampleRate+2],dx
sub ax,ax
jmp short pcinf_exit
;
pcinf_bad:
mov ax,-1
;
pcinf_exit:
pop bp
ret
PCMInfo endp
;
;
; /*\
;---|*|---------------====< PCMPlay() >====---------------
;---|*|
;---|*| Starts the DMA feeding the DAC
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0 good start
;---|*| AX = -1 not started, problem occured
; \*/
public PCMPlay
PCMPlay proc
push es
les ax,LinearPtr ; Validate the buffer pointer
mov bx,es
or ax,bx
jz PCMPlay_bad
mov ax,[DMABuffLength] ; Validate the buffer count
or ax,ax
jz PCMPlay_bad
mov ax,wptr [TheSampleRate+0] ; Validate the sample rate
or ax,wptr [TheSampleRate+2]
jz PCMPlay_bad ; zero sample rate, bomb out...
call FFAR ptr StartPlaying ; go for it...
sub ax,ax
jmp short PCMPlay_exit
;
PCMPlay_bad:
mov ax,-1
;
PCMPlay_exit:
pop es
ret
PCMPlay endp
;
;
; /*\
;---|*|---------------====< PCMRecord() >====---------------
;---|*|
;---|*| Starts the DMA reading the ADC
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0 recording has started
;---|*| AX = -1 recording did not start
;---|*|
; \*/
public PCMRecord
PCMRecord proc
push es
les ax,LinearPtr ; Validate the buffer pointer
mov bx,es
or ax,bx
jz PCMRec_bad
mov ax,[DMABuffLength] ; Validate the buffer count
or ax,ax
jz PCMRec_bad
mov ax,wptr [TheSampleRate+0] ; Validate the sample rate
or ax,wptr [TheSampleRate+2]
jz PCMRec_bad
call FFAR ptr StartRecording ; go for it...
mov ax,0
jmp short PCMRec_exit
;
PCMRec_bad:
mov ax,-1
;
PCMRec_exit:
pop es
ret
PCMRecord endp
;
;
; /*\
;---|*|---------------====< RemovePCM () >====---------------
;---|*|
;---|*| Remove our code from the system
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| None
; \*/
public RemovePCM
RemovePCM proc
call FFAR ptr StopPCM ; kill the Audio Spectrum board
mov dx,INTRCTLRST ; flush any pending PCM irq
xor dx,[_MVTranslateCode] ; xlate the board address
out dx,al
call FFAR ptr _unloadirqvector ; restore the original vector
ret
RemovePCM endp
;
;
; /*\
;---|*|---------------====< ResumePCM >====---------------
;---|*|
;---|*| Turn on the h/w from making interrupt and DMA requests. This assumes
;---|*| the hardware has already been setup and is ready to go...
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| Nothing
;---|*|
; \*/
;
public ResumePCM
ResumePCM proc
push es
push di
;
; Setup the audio filter sample bits
;
les di,[mvhwShadowPointer]
call FFAR ptr _ASloadtimer0
disable
mov dx,AUDIOFILT
xor dx,[_MVTranslateCode] ; xlate the board address
mov al,es:[di._audiofilt]
or al,bFIsrate ; enable sample rate and buffer timers
mov es:[di._audiofilt],al
out dx,al
enable
pop di
pop es
ret
ResumePCM endp
;
;
;
; /*\
;---|*|---------------====< SelectDMA( int ) >====---------------
;---|*|
;---|*| Selects the DMA channel 0 - 7, excluding 4
;---|*|
;---|*| Entry Conditions:
;---|*| wParm1 points to DMA number (0, 1, 2, 3, 5, 6, 7 )
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0, good buffer, all okay
;---|*| AX = -1, good buffer, all okay
;---|*|
; \*/
public SelectDMA
SelectDMA proc
push bp
mov bp,sp
mov ax,wParm1 ; get the DMA #
and ax,0111b ; save the channels
mov bx,ax ; get some of the I/O addreses
shl bx,1 ; into DX
jnz seldma_02 ; not channel 0, go use it...
push sp ; 8088/86 class machine?
pop cx
cmp cx,sp
jnz seldma_bad ; yes, can't do channel 0 dma
;
seldma_02:
mov dx,cs:[dmatable+bx]
or dx,dx ; valid entry?
jz seldma_bad ; no, bomb out...
mov TheDMAChannel,al ; select the channel.
mov bptr OurDMAPageReg,dh ; ...the page register,
mov bptr OurDMAddress,dl ; ...the address register,
lea bx,DMA1AddrTable ; get the DMA channel addresses
cmp al,4
jl seldma_05
lea bx,DMA2AddrTable ; get the DMA channel addresses
sub al,4 ; make it zero based
;
seldma_05:
mov [bx._dmach],al ; save the adjusted dma channel #
mov [DMAPointer],bx ; save the pointer to all DMA addrs
sub ax,ax
pop bp
ret
;
seldma_bad:
mov ax,-1
pop bp
ret
;
; dma channels, etc
;
dmatable label word
dw (CH0PAGEREG SHL 8) + DMAC0ADDR
dw (CH1PAGEREG SHL 8) + DMAC1ADDR
dw (CH2PAGEREG SHL 8) + DMAC2ADDR
dw (CH3PAGEREG SHL 8) + DMAC3ADDR
dw 0
dw (CH5PAGEREG SHL 8) + DMA2C5ADDR
dw (CH6PAGEREG SHL 8) + DMA2C6ADDR
dw (CH7PAGEREG SHL 8) + DMA2C7ADDR
SelectDMA endp
endif ; PCMOBJ
if MISC2OBJ
; /*\
;---|*|---------------====< SelectIRQ( int ) >====---------------
;---|*|
;---|*| Selects the IRQ line for DMA control
;---|*|
;---|*| Entry Conditions:
;---|*| wParm1 points to IRQ number (3,5,6,7)
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0, good buffer, all okay
;---|*| AX = -1, bad IRQ #
;---|*|
; \*/
public SelectIRQ
SelectIRQ proc
push bp
mov bp,sp
call FFAR ptr _unloadirqvector ; attempt to restore original vector
sub ax,ax ; flush ax for a bad return
mov cx,wParm1 ; get the irq # (2-7,10-12,14-15)
and cl,0fh ; save only the valid bits
mov bx,01
shl bx,cl
and bx,1001110010111100b ; save the mask bit only if the irq
jz seirqbad ; is a valid selection
mov TheIRQChannel,cl ; save the channel number
cmp cl,8 ; 2nd interrupt controller?
jb @F ; no, skip
xchg bh,bl
;
@@:
mov TheIRQMask,bl
call FFAR ptr _loadirqvector ; load the new vector
mov ax,1
;
seirqbad:
dec ax
pop bp
ret
SelectIRQ endp
;
endif ; MISC2OBJ
if PCMOBJ
;
; /*\
;---|*|--------------------====< void StopPCM() >====--------------------
;---|*|
;---|*| Turn off the PCM timers, interrupts, and state machine.
;---|*|
;---|*| Entry Conditions:
;---|*|
;---|*| Exit Conditions:
;---|*|
;---|*|
; \*/
public StopPCM
StopPCM proc
push es
push di
les di,[mvhwShadowPointer]
;
; clear the audio filter sample bits
;
mov dx,AUDIOFILT
xor dx,[_MVTranslateCode] ; xlate the board address
disable ; drop dead...
mov al,es:[di._audiofilt] ; get the state
and al,not (bFIsrate+bFIsbuff) ; flush the sample timer bits
mov es:[di._audiofilt],al ; save the new state
out dx,al
;
; clear the PCM enable bit
;
mov al,es:[di._crosschannel]; get the current cross channel
and al,not bCCenapcm ; clear the PCM enable bit
or al,bCCdac
mov dx,CROSSCHANNEL
xor dx,[_MVTranslateCode] ; xlate the board address
out dx,al ; end to the hardware
mov es:[di._crosschannel],al
;
; disable the 16 bit stuff
;
test [_MVHWVersionBits],bMV101 ; 101 chip?
jz stpc02 ; no, don't touch this...
mov dx,SYSCONFIG2
xor dx,[_MVTranslateCode] ; xlate the board address
in al,dx
and al,not bSC216bit+bSC212bit ; flush the 16 bit stuff
out dx,al
;
stpc02:
;
; clear the appropriate Interrupt Control Register bit
;
mov ah,TypeOfSetup
and ah,bICsamprate+bICsampbuff
not ah
mov dx,INTRCTLR
xor dx,[_MVTranslateCode] ; xlate the board address
in al,dx
and al,ah ; kill sample timer interrupts
out dx,al
mov es:[di._intrctlr],al
;
; clear the system interrupt mask only if no other ints are used
;
test al,fICintmaskbits XOR (bICsamprate+bICsampbuff)
jnz stpc10
;
; select the correct IRQ controller, then mask it...
;
cmp TheIRQChannel,2 ; Chained IRQ channel?
jz stpc10 ; yes, leave it open...
mov dx,IRQ1MASKREG
cmp TheIRQChannel,8 ; 2nd IRQ controller?
jl stpc05
mov dl,IRQ2MASKREG
;
stpc05:
in al,dx
or al,[TheIRQMask]
out dx,al
enable ; start again...
;
stpc10:
call FFAR ptr KillDMA ; stop the DMA too...
mov [StatusWord],0 ; inactive, available
pop di
pop es
ret
StopPCM endp
;
; /*\
;---|*|---------------====< UserFunc((*long)()) >====---------------
;---|*|
;---|*| Call back routine when Half way buffer is full/empty.
;---|*|
;---|*| Entry Conditions:
;---|*| dParm1 points to the user routine
;---|*|
;---|*| Exit Conditions:
;---|*| Nothing
;---|*|
; \*/
public UserFunc
UserFunc proc
push bp
mov bp,sp
push es
les ax,dParm1 ; get the routine
mov dx,es
or dx,ax
jz usfu_bad
mov wptr [UserRoutine+0],ax
mov wptr [UserRoutine+2],es
;
usfu_bad:
pop es
pop bp
ret
UserFunc endp
endif ; PCMOBJ
;
;
;----------------------------========================--------------------------
;----------------------------========================--------------------------
;----------------------------========================--------------------------
;
;
; PPPPPPPP CCCCCC MMM MMM
; PPPPPPPP CCCCCCC MMMM MMMM
; PPP PPP CCC MMMMM MMMMM
; PPP PPP CCC MMMMMM MMMMMM
; PPPPPPPP CCC MMM MMMMM MMM
; PPPPPPPP CCC MMM MMM MMM
; PPP CCC MMM M MMM
; PPP CCC MMM MMM
; PPP CCCCCCC MMM MMM
; PPP CCCCCC MMM MMM
;
; rrrrr oooo uu uu tttttt iiiiii nn nn eeeee sssss
; rr rr oo oo uu uu tt ii nnn nn ee ss
; rrrrrr oo oo uu uu tt ii nnnnnn eeeeee ssss
; rr rr oo oo uu uu tt ii nn nnn ee ss
; rr rr oooo uuuuuu tt iiiiii nn nn eeeee sssss
;
;
;
;----------------------------========================--------------------------
;----------------------------========================--------------------------
;----------------------------========================--------------------------
if PCMOBJ
;
;----------------------------====< _ASloadtimer0 >====-------------------------
;
;
; Setup the Sample Timer (T0 & square wave output)
;
; Entry Conditions:
; ES:DI point to the state table.
; Exit Conditions:
; The timer is loaded with the new sample rate
;
public _ASloadtimer0
_ASloadtimer0 proc
mov al,00110110b ; 36h Timer 0 & square wave
mov dx,TMRCTLR
xor dx,[_MVTranslateCode] ; xlate the board address
pushf
cli
out dx,al ; setup the mode, etc
mov es:[di._tmrctlr],al
mov ax,es:[di._samplerate] ; pre-calculated & saved in prior code
mov dx,SAMPLERATE
xor dx,[_MVTranslateCode] ; xlate the board address
out dx,al ; output the timer value
pause
xchg ah,al
out dx,al
popf
ret
_ASloadtimer0 endp
;
;----------------------------====< _ASloadtimer1 >====-------------------------
;
public _ASloadtimer1
_ASloadtimer1 proc
push es
push di
les di,[mvhwShadowPointer]
push dx ; do not disturb any register
push ax
mov al,01110100b ; 74h Timer 1 & rate generator
mov dx,TMRCTLR
xor dx,[_MVTranslateCode] ; xlate the board address
disable
out dx,al
mov es:[di._tmrctlr],al ; local timer control register
pop ax
mov dx,SAMPLECNT
xor dx,[_MVTranslateCode] ; xlate the board address
mov es:[di._samplecnt],ax
out dx,al
pause
xchg ah,al
out dx,al
enable
xchg ah,al
pop dx
pop di
pop es
ret
_ASloadtimer1 endp
;
;
;--------------------------====< _calcsamplerate >====-------------------------
;
; Calculate the H/W timer value (internal routine)
;
; Entry Conditions:
; DX:AX hold the users requested sample rate
;
; Exit Conditions:
; carry SET if bad value
; No registers modified
;
;
public _calcsamplerate
_calcsamplerate proc
push es
push di
les di,[mvhwShadowPointer]
push ax
push bx
push cx
push dx
;
; make sure sample rate does not exceed 88200
;
mov cx,ax ; do 32 bit subtraction
sub cx,05888H+1 ; 157C0 is decimal 88200
mov cx,dx ; too high?
sbb cx,00001H ; over 88200 khz is bad
jnc CaSaRa_bad ; bomb out greater than 88200
;
; load 1193180 in bx:cx for 32x32 bit division
;
mov bx,0012h
mov cx,34dch ; load bx:cx with 1193180
xchg bx,dx ; dx:ax = 1193180
xchg cx,ax ; bx:cx = sample rate
;
; since we don't have 32x32 bit division, we'll cheat here. No great loss.
;
or bx,bx ; is value over 64k?
jz @F ; no, continue on...
shr bx,1 ; yes, divide all by 2
rcr cx,1 ; to allow division of 32x16 bits
shr dx,1
rcr ax,1
;
@@:
div cx
mov es:[di._samplerate],ax ; save just the low order
clc
jmp short CaSaRa_exit
;
CaSaRa_bad:
stc
;
CaSaRa_exit:
pop dx
pop cx
pop bx
pop ax
pop di
pop es
ret
_calcsamplerate endp
;
;
;----------------------------====< EnableRecording >====-----------------------
;
public EnableRecording
EnableRecording proc
;
; Save the type of setup. It contains the interrupt masks needed
;
mov [TypeOfSetup],POLLEDINPUT
mov [PCMDirection],0 ; bit 6 is cleared (DAC enable)
;
; enable the onboard sampling timers, disable interrupts
;
call FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
mov StatusWord,2 ; set the global status word
ret
EnableRecording endp
;
;
;----------------------------====< EnablePlaying >====-------------------------
;
public EnablePlaying
EnablePlaying proc
;
; Save the type of setup. It contains the interrupt masks needed
;
mov [TypeOfSetup],POLLEDOUTPUT
mov [PCMDirection],bCCdac ; bit d6 of interrupt control register
;
; enable the onboard sampling timers, etc.
;
call FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
mov StatusWord,1 ; set the global status word
ret
EnablePlaying endp
;
endif ; PCMOBJ
if MISC2OBJ
;
;---------------------------====< _getirqoffset >====--------------------------
;
; takes the IRQ # & converts to offset in vector table
;
;
public _getirqoffset
_getirqoffset proc
sub bh,bh
shl bx,1
mov bx,cs:[irqoffsets+bx]
ret
irqoffsets label word
dw (8+0)*4 ; IRQ 0 clock timer
dw (8+1)*4 ; IRQ 1 keyboard
dw (8+2)*4 ; IRQ 2 available
dw (8+3)*4 ; IRQ 3 COM2
dw (8+4)*4 ; IRQ 4 COM1
dw (8+5)*4 ; IRQ 5 available
dw (8+6)*4 ; IRQ 6 floppy controller
dw (8+7)*4 ; IRQ 7 LPT
dw (70h+0)*4 ; IRQ 8 real time clock
dw (70h+1)*4 ; IRQ 9 Re-Directed IRQ2
dw (70h+2)*4 ; IRQ a available
dw (70h+3)*4 ; IRQ b available
dw (70h+4)*4 ; IRQ c available
dw (70h+5)*4 ; IRQ d coprocessor
dw (70h+6)*4 ; IRQ e Hard Disk
dw (70h+7)*4 ; IRQ f available
_getirqoffset endp
;
endif ; MISC2OBJ
if PCMOBJ
;
;------------------------------====< KillDMA >====-----------------------------
;
; KillDMA -- flush our settings
;
; Entry Conditions:
;
KillDMA proc
push es
push di
cmp StatusWord,0 ; is there any activity?
jz kidm_none
mov di,[DMAPointer] ; get the DMA pointer
sub dx,dx ; clear out the high byte
;
; mask out the DMA to stop it
;
disable
mov al,[di._dmach] ; get the adjusted dma channel #
or al,0100b ; disable the DMA
mov dl,[di._dmawrsmr]
out dx,al
;
; remove control on the DRQ line
;
les di,[mvhwShadowPointer]
mov al,es:[di._crosschannel]; get the state
mov dx,CROSSCHANNEL
xor dx,[_MVTranslateCode] ; xlate the board address
and al,not bCCdrq ; clear the DRQ bit
out dx,al
mov es:[di._crosschannel],al; and save the new state
enable
;
kidm_none:
pop di
pop es
ret
KillDMA endp
;
endif ; PCMOBJ
if PCMOBJ
;
;------------------------------====< LoadDMA >====-----------------------------
;
; LoadDMA -- Load the DMA controller to read/write data to the MV board
;
; Entry Conditions:
;
;
public LoadDMA
LoadDMA proc
push es
push di
push si
les di,[mvhwShadowPointer]
mov si,[DMAPointer] ; point to the DMA controller table
sub dx,dx ; clear out the high byte
;
; kill the dma until all programming is done
;
mov al,[si._dmach] ; get the adjusted dma channel #
or al,0100b ; causes all DMA to be suspended
mov dl,[si._dmawrsmr]
out dx,al
;
; program the mode
;
mov al,[TheDMAmode] ; get the app's desired mode
or al,[si._dmach] ; merge the adjusted dma channel #
mov dl,[si._dmawrmode]
out dx,al
;
; adjust the address for a 16 bit channel
;
mov ax,wptr [LinearPtr+2] ; get the page #
;
; setup the page register
;
mov dx,[OurDMAPageReg]
out dx,al
mov bl,al
;
; reset the flip-flop, then output the address, then count
;
mov dl,[si._dmaclear] ; dh is still clear...
out dx,al ; flush...
mov ax,wptr [LinearPtr+0] ; get the low 16 bits
cmp si,offset DMA1AddrTable ; 1st DMA controller?
jz @F ; yes, continue on...
shr bl,1 ; no, divide the buffer in half
rcr ax,1 ; by shifting 17 bits
;
@@:
mov dx,[OurDMAddress]
out dx,al
pause
xchg ah,al
out dx,al
mov ax,[DMABuffLength]
cmp si,offset DMA1AddrTable ; is this the 2nd dma controller?
jz lodma03 ; no, use the full length
shr ax,1
inc dx ; move to next port address
;
lodma03:
inc dx ; move to next port address
out dx,al
pause
xchg ah,al
out dx,al
;
; before we enable the DMA, let's make sure the DRQ is controlled, not floating
;
mov al,es:[di._crosschannel]; get the state
mov dx,CROSSCHANNEL
xor dx,[_MVTranslateCode] ; xlate the board address
or al,bCCdrq ; set the DRQ bit to control it
out dx,al
mov es:[di._crosschannel],al; and save the new state
;
; re-enable the dma now that all programming is done
;
mov al,[si._dmach] ; get the adjusted dma channel #
sub dx,dx ; clear dh
mov dl,[si._dmawrsmr]
out dx,al ; & let'er loose (not moving though...)
;
; all done, return home...
;
pop si
pop di
pop es
ret
LoadDMA endp
;
endif ; PCMOBJ
if MISC2OBJ
;
;--------------------------====< _loadirqvector >====--------------------------
;
; Restore the original vector
;
; Entry Conditions:
;
; Exit Conditions:
; Nothing
public _loadirqvector
_loadirqvector proc
push es
les ax,OldIRQRoutine
mov bx,es
or bx,ax
jnz @F
lea ax,OurIntVector
mov dx,cs
mov bl,[TheIRQChannel]
call FFAR ptr _getirqoffset
push ds
sub cx,cx
mov ds,cx
disable
xchg ds:[bx+0],ax
xchg ds:[bx+2],dx
enable
pop ds
mov wptr [OldIRQRoutine+0],ax
mov wptr [OldIRQRoutine+2],dx
;
@@:
pop es
ret
_loadirqvector endp
;
endif ; MISC2OBJ
if MISC2OBJ
;
;---------------------------====< OurIntVector >====---------------------------
;
; OurIntVector -- process DMA interrupts
;
intsemaphore db -1 ; -1 free, 0+ locked
public OurIntVector
OurIntVector proc
push dx
push ax
push ds
if MODELSIZE eq 0
mov ax,cs ; tiny (.com) model uses cs segment
else
mov ax,@data ; all others use their data segments
endif
mov ds,ax
mov dx,INTRCTLRST ; clear the interrupt
xor dx,[_MVTranslateCode] ; xlate the board address
in al,dx
test al,bISsampbuff ; our interrupt?
jz skip_int ; no, continue on...
out dx,al ; yes, flush it...
mov al,EOI ; clear the interrupt
cmp TheIRQChannel,8 ; 2nd IRQ controller?
jb @F
out IRQ2ACKREG,al
;
@@:
out IRQ1ACKREG,al
inc [NumberOfInterrupts]
inc cs:[intsemaphore]
jnz oiv_done
sti ; let interrupts go while we work
cmp wptr [UserRoutine+2],0 ; call the user function?
jz oiv_done ; no, just exit
call dword ptr [UserRoutine]
;
oiv_done:
dec cs:[intsemaphore]
;
exit_int:
pop ds
pop ax
pop dx
iret
;
skip_int:
pushf
call dword ptr ds:[OldIRQRoutine] ; perform the old interrupt
jmp short exit_int
OurIntVector endp
;
endif ; MISC2OBJ
if PCMOBJ
;
;---------------------------====< SetupPCMDMAIO >====--------------------------
;
; SetupPCMDMAIO -- Setup to output to the DAC
;
public SetupPCMDMAIO
SetupPCMDMAIO proc
push es
push di
les di,[mvhwShadowPointer]
;
; setup the sample rate timer
;
call _ASloadtimer0
;
; Setup the Sample Buffer Counter Timer (T1 & rate generator)
;
mov ax,[DMABuffLength] ; get the count
sub dx,dx
add ax,1 ; make it 1 based (1 - 64k)
adc dx,dx
mov cl,[DMABUffDivides] ; get the buffer size
sub ch,ch
div cx ; now, we must be flexible
mov bl,[TheDMAChannel] ; is this a 16 bit channel?
mov bh,[SampleSize] ; CX = sample size, channel
sub cx,cx ; ch = multiplier, cl=divider
cmp bx,0003h ; 8 bits on 8 bit channel?
jbe @F ; yes, continue on...
inc cx ; divide by 2
cmp bx,0007h ; 8 bits on 16 bit channel?
jbe @F ; yes, continue on...
xchg ch,cl ; multiply by 2
cmp bx,0203h ; 16 bits on 8 bit channel?
jbe @F ; yes, continue on...
sub cx,cx ; no multiply or divide
;
@@:
shr ax,cl ; if 8 on 16 divide by 2
xchg ch,cl
shl ax,cl ; if 16 on 8 multiply by 2
sub cx,cx ; The buffer size is # of bytes, so
neg bh ; we must convert it to the data size
adc cx,cx
shr ax,cl
call FFAR ptr _ASloadtimer1
;
; Setup the system interrupt mask (IRQ mask)
;
mov dx,IRQ1MASKREG
cmp TheIRQChannel,8 ; 2nd IRQ controller?
jl @F
mov dl,IRQ2MASKREG
;
@@:
in al,dx ; get the mask
mov ah,TheIRQMask
not ah
and al,ah ; unmask the correct IRQ
out dx,al ; then let the system know
;
; Setup the Interrupt Control Register
;
mov dx,INTRCTLRST ; flush any pending interrupts
xor dx,[_MVTranslateCode] ; xlate the board address
out dx,al ; of the PCM circuitry
mov dx,INTRCTLR
xor dx,[_MVTranslateCode] ; xlate the board address
in al,dx ; get the real mask
or al,bICsampbuff ; interrupt on sample buffer count
out dx,al ; send it..
mov es:[di._intrctlr],al ; save it..
;
; enable the 12/16 bit stuff
;
test [_MVHWVersionBits],bMV101 ; 101 chip?
jz sdhpas1_05 ; no, don't touch this...
mov cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
cmp [SampleSize],1 ; 12 bit?
jz @F
mov cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
cmp [SampleSize],2 ; 16 bit?
jz @F
mov cx,((NOT(bSC216bit+bSC212bit))*256) + 0
;
@@:
mov dx,SYSCONFIG2
xor dx,[_MVTranslateCode] ; xlate the board address
in al,dx
and al,ch ; clear the bits
or al,cl ; set the appropriate bits
out dx,al
;
sdhpas1_05:
;
; setup the direction, stereo/mono and DMA enable bits
;
mov al,bCCmono ; get the stereo/mono mask bit
and al,[StereoMono] ; al = bCCmono if in mono mode
or al,[PCMDirection] ; get the direction bit mask
or al,bCCenapcm ; enable the PCM state machine
mov dx,CROSSCHANNEL
xor dx,[_MVTranslateCode] ; xlate the board address
mov ah,0fh + bCCdrq ; get a mask to load non PCM bits
and ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
or al,ah ; merge the two states
xor al,bCCenapcm ; disable the PCM bit
out dx,al ; send to the hardware
xor al,bCCenapcm ; enable the PCM bit
out dx,al ; send to the hardware
mov es:[di._crosschannel],al; and save the new state
;
; Setup the audio filter sample bits
;
mov al,es:[di._audiofilt]
or al,(bFIsrate+bFIsbuff) ; enable the sample count/buff counters
mov dx,AUDIOFILT
xor dx,[_MVTranslateCode] ; xlate the board address
out dx,al
mov es:[di._audiofilt],al
mov NumberOfInterrupts,0
enable ; Fly, baby Fly!!!
pop di
pop es
ret
SetupPCMDMAIO endp
;
;
;---------------------------====< SetupPCMPolledIO >====-----------------------
;
; SetupPCMPolledIO -- Setup to read/write to the ADC/DAC in a polled fashion
;
public SetupPCMPolledIO
SetupPCMPolledIO proc
push es
push di
les di,[mvhwShadowPointer]
;
; Setup the Sample Timer (T0 & square wave output)
;
call _ASloadTimer0
;
; Setup the Sample Buffer Counter Timer (T1 & rate generator)
;
mov ax,1 ; get the count
call FFAR ptr _ASloadtimer1
;
; Setup the Interrupt Control Register
;
mov dx,INTRCTLR
xor dx,[_MVTranslateCode] ; xlate the board address
in al,dx ; get the real mask
or al,bICsampbuff+bICsamprate ; enable both sample timer ints
out dx,al ; send it...
mov es:[di._intrctlr],al ; save it...
;
; enable the 16 bit stuff
;
test [_MVHWVersionBits],bMV101 ; 101 chip?
jz sphpas1_05 ; no, don't touch this...
mov cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
cmp [SampleSize],1 ; 12 bit?
jz @F
mov cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
cmp [SampleSize],2 ; 16 bit?
jz @F
mov cx,((NOT(bSC216bit+bSC212bit))*256) + 0
;
@@:
mov dx,SYSCONFIG2
xor dx,[_MVTranslateCode] ; xlate the board address
in al,dx
and al,ch ; clear the bits
or al,cl ; set the appropriate bits
out dx,al
;
sphpas1_05:
;
; setup the direction, stereo/mono and DMA enable bits
;
mov al,bCCmono ; get the stereo/mono mask bit
and al,[StereoMono] ; al = bCCmono if in mono mode
or al,[PCMDirection] ; get the direction bit mask
or al,bCCenapcm + bCCdrq ; enable the PCM & set DRQ for NOT mask
mov dx,CROSSCHANNEL
xor dx,[_MVTranslateCode] ; xlate the board address
mov ah,0fh ; get a mask to load the non-PCM bits
and ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
or al,ah ; merge the two states
xor al,bCCenapcm + bCCdrq ; disable the PCM & DRQ
out dx,al ; send to the hardware
xor al,bCCenapcm ; enable the PCM
out dx,al
mov es:[di._crosschannel],al; and save the new state
;
; Setup the audio filter sample bits to enable sample timer/count
;
mov al,es:[di._audiofilt]
or al,(bFIsrate+bFIsbuff) ; enable the sample timer/counter
mov dx,AUDIOFILT
xor dx,[_MVTranslateCode] ; xlate the board address
out dx,al
mov es:[di._audiofilt],al
sub ax,ax
mov NumberOfInterrupts,ax
enable
pop di
pop es
ret
SetupPCMPolledIO endp
;
;
;----------------------------====< StartPlaying >====--------------------------
;
public StartPlaying
StartPlaying proc
;
; Save the type of setup. It contains the interrupt masks needed
;
mov [TypeOfSetup],DMAOUTPUT
mov [PCMDirection],bCCdac ; bit d6 of interrupt control register
;
; Select the DMA mode for playing
;
mov al,10h ; auto init bit on 8237 chip
and al,[DMAAutoInit] ; al may have the auto-init bit
or al,48h ; merge in the rest of the DMA bits
mov TheDMAMode,al ; save the mode
;
; Program the DMA, then our board circuitry to start the interrupts
;
call LoadDMA ; setup the DMA controller
call SetupPCMDMAIO ; Setup the MV Hardware
mov StatusWord,1 ; set the global status word
ret
StartPlaying endp
;
;
;---------------------------====< StartRecording >====-------------------------
;
public StartRecording
StartRecording proc
;
; Save the type of setup. It contains the interrupt masks needed
;
mov [TypeOfSetup],DMAINPUT
mov [PCMDirection],00h ; bit d6 of interrupt control register
;
; Select the DMA mode for recording
;
mov al,10h ; auto init bit on 8237 chip
and al,[DMAAutoInit] ; al may have the auto-init bit
or al,44h ; merge in the rest of the DMA bits
mov TheDMAMode,al ; save the mode
;
; Program the DMA, then our board circuitry to start the interrupts
;
call LoadDMA ; setup the DMA controller
call SetupPCMDMAIO ; Setup the MV Hardware
mov StatusWord,2 ; set the global status word
ret
StartRecording endp
;
endif ; PCMOBJ
if MISC2OBJ
;
;---------------------====< _unloadirqvector >====---------------
;
; Restore the original vector
;
; Entry Conditions:
; dParm1 points to the user routine
;
; Exit Conditions:
; Nothing
;
;
public _unloadirqvector
_unloadirqvector proc
push es
les ax,OldIRQRoutine
mov bx,es
or bx,ax
jz @F
mov bl,[TheIRQChannel]
call _getirqoffset
push ds
sub cx,cx
mov ds,cx
disable
mov ds:[bx+0],ax
mov ds:[bx+2],es
enable
pop ds
sub ax,ax
mov wptr [OldIRQRoutine+0],ax
mov wptr [OldIRQRoutine+2],ax
;
@@:
pop es
ret
_unloadirqvector endp
endif ; MISC2OBJ