home *** CD-ROM | disk | FTP | other *** search
- ;$Author: DCODY $
- ;$Date: 24 Mar 1993 10:19:32 $
- ;$Header: X:/sccs/pcm/pcmioa.asv 1.11 24 Mar 1993 10:19:32 DCODY $
- ;$Log: X:/sccs/pcm/pcmioa.asv $
- ;
- ; Rev 1.11 24 Mar 1993 10:19:32 DCODY
- ; removed common.inc as an include
- ;
- ; Rev 1.10 10 Feb 1993 10:21:48 DCODY
- ; added "FFAR ptr" to a couple calls to internal routines.
- ;
- ; Rev 1.9 09 Feb 1993 08:29:52 DCODY
- ; removed the compile switches that creates separate .OBJs from this source.
- ; This file is now compiled just once.
- ;
- ; Rev 1.8 03 Feb 1993 12:10:30 DCODY
- ; No change.
- ;
- ; Rev 1.7 08 Dec 1992 17:15:00 DCODY
- ; moved externADDR macro for Borland link.
- ;
- ; Rev 1.6 20 Oct 1992 10:09:08 DCODY
- ; adjusted tiny model .data declaration and segment use. removed binary.inc
- ; as an include file.
- ;
- ; Rev 1.5 06 Oct 1992 16:00:44 DCODY
- ; added direct dos read/write file routines.
- ;
- ; Rev 1.4 23 Sep 1992 10:57:04 DCODY
- ; more work on playthisblock, continuethisblock...
- ;
- ; Rev 1.3 26 Aug 1992 10:58:26 DCODY
- ; added Playthisblock and RecordthisBlock support routines
- ;
- ; Rev 1.2 12 Aug 1992 17:10:56 DCODY
- ; major change to eliminate the foreground buffers and background
- ; processing responsibilities.
- ;
- ; Rev 1.1 23 Jun 1992 17:11:34 DCODY
- ; PAS2 update
- ;
- ; Rev 1.0 15 Jun 1992 09:44:36 BCRANE
- ; Initial revision.
- ;$Logfile: X:/sccs/pcm/pcmioa.asv $
- ;$Modtimes$
- ;$Revision: 1.11 $
- ;$Workfile: pcmioa.asm $
-
-
- page 64,131
- Title PCMIOA -- Background Task for PCM I/O
-
- ; /*\
- ;---|*|------------====< PCMIOA.ASM >====------------
- ;---|*|
- ;---|*| Copyright (c) 1991, Media Vision, Inc. All rights reserved
- ;---|*|
- ; \*/
-
- .xlist
- include model.inc
- include masm.inc
- .list
-
- ;
- ;-----------------------================================-----------------------
- ;-----------------------====< Code/Data Generation >====-----------------------
- ;-----------------------================================-----------------------
- ;
-
- externADDR InitPCM ; initialize the PCM low level code
- externADDR StopPCM ; Kill the PCM hardware
- externADDR PCMPlay ; start the PCM output
- externADDR PCMRecord ; start the PCM input
- externADDR UserFunc ; sets up the call-back routine
-
- ;
- ;---------------------------========================---------------------------
- ;---------------------------====< DATA SECTION >====---------------------------
- ;---------------------------========================---------------------------
- ;
- if MODELSIZE eq 0
- .code
- else
- .data
- endif
-
- ;
- ; Code Model Dependencies
- ;
- if @datasize
- cptr equ <dword> ; C pointer is FAR
- else
- cptr equ <word> ; C pointer is NEAR
- endif
-
- NODIRECTION equ 0
- DMAINPUT equ 1
- DMAOUTPUT equ 2
-
- PCMFILEINPUT equ DMAINPUT
- PCMFILEOUTPUT equ DMAOUTPUT
- PCMBLOCKINPUT equ DMAINPUT+80h
- PCMBLOCKOUTPUT equ DMAOUTPUT+80h
-
- ;
- ; Structure Definitions
- ;
- buffptr struc
-
- BPstatus dw 0 ; 0=empty, 1=full
- BPcount dw 0 ; # of bytes in the buffer
- BPsize dw 0 ; total size of allocated buff
- BPbuffer dd 0 ; pointer to buffer data
-
- if @datasize
- BPnextptr dd 0 ; pointer to buffer data
- else
- BPnextptr dw 0 ; pointer to buffer data
- endif
-
- buffptr ends
-
- ;
- ;--------------====< code generation dependent declarations >====------------
- ;
-
- ;
- ; Local data declarations
- ;
- public CountdownBuffers
- CountdownBuffers db 00 ; countdown value
- public NextDMAPtr
- NextDMAPtr dd 00 ; our pointer to the DMA's buffer
- public DMAUnitSize
- DMAUnitSize dw 00 ; size of DMA buffer divisions
-
- public __callersroutine
- if @codesize
- __callersroutine dd 00
- else
- __callersroutine dw 00
- endif
-
- externPTR HeadOfBuffers ; pointer to buffer linked list
- extrn BufferDataCount :word ; # of full buffers (0=done)
- extrn DMARunning :word ; DMA status (0=off,1=running)
- extrn StartOfDMABuffer :dword ; always a far * to start of DMA buffer
- extrn __pcmdatasize :byte ; default to 8 bit pcm
- extrn MaxBuffCount :word ; count of DMA blocks
- extrn ProcessedBlockCount:word; # of full buffers (0=done)
- extrn __synccallback :dword ; callback to application at int
- extrn __fptrpos :dword ; file position byte count pointer
-
- ;
- ;---------------------------========================---------------------------
- ;---------------------------====< CODE SECTION >====---------------------------
- ;---------------------------========================---------------------------
- ;
- .code
-
-
- ; /*\
- ;---|*|------------====< BackgroundInit( int, int ) >====------------
- ;---|*|
- ;---|*| Initialize our internal variables, etc...
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| wParm1 - Size of DMA buffer
- ;---|*| wParm2 - # of DMA buffer divisions
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| No return value
- ;---|*|
- ;---|*| Functionality:
- ;---|*|
- ;---|*| Clear interrupt mechanisms.
- ;---|*| Disable DMA channel.
- ;---|*| Set DMARunning to 0;
- ;---|*|
- ; \*/
-
- public BackgroundInit
- BackgroundInit proc
- push bp
- mov bp,sp
- push es
- ;
- ; get the # of buffers in the linked list
- ;
- mov ax,wParm1
- mov [DMAUnitSize],ax ; max size of each DMA division
- ;
- ; flush any prior low-level setup
- ;
- call InitPCM
- mov DMARunning,0 ; signal it dead
- ;
- ; all done, return home
- ;
- pop es
- pop bp
- ret
-
- BackgroundInit endp
-
-
- ; /*\
- ;---|*|------------====< _dofread ( char far *, int, int ) >====------------
- ;---|*|
- ;---|*| Replacement code for the fread C library function. This will also
- ;---|*| keep track of the file position.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| char far * is a pointer to the buffer
- ;---|*| int - Length of the buffer
- ;---|*| int - file handle
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX holds the length read from disk
- ;---|*|
- ; \*/
-
- public _dofread
- _dofread proc
- push bp
- mov bp,sp
- push ds
-
- lds dx,wParm1 ; get the buffer
- mov cx,wParm3 ; get the length
- mov bx,wParm4 ; get the handle
- mov ah,3fh ; read command
-
- int 21h
-
- pop ds
-
- cmc ; set carry if good read
- sbb bx,bx
- and ax,bx
- add wptr [__fptrpos+0],ax
- adc wptr [__fptrpos+2],0
-
- pop bp
- ret
-
- _dofread endp
-
-
- ; /*\
- ;---|*|--------------====< FlushBuffer >====-----------------
- ;---|*|
- ;---|*| Flush the buffer by filling it with silence (value of 0x80)
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| dParm1 is the far pointer to the block
- ;---|*| wParm2 is an unsigned integer which is the block length
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| DX:AX hold the ending pointer
- ;---|*|
- ;---|*| Prototype:
- ;---|*|
- ;---|*| char far * FlushBuffer (char far *, int)
- ;---|*|
- ;---|*|
- ; \*/
-
- public FlushBuffer
- FlushBuffer proc
- push bp
- mov bp,sp
-
- push es
- push di
-
- pushf
- cld
-
- les di,dParm1 ; grab 2 words off the stack
- mov cx,wParm3 ; wParm3 is used to skip the 2nd word
-
- cmp [__pcmdatasize],9 ; 8 bit sets the carry
- sbb al,al ; al = ff if 8 bit PCM
- and al,80h ; al = 80 if 8 bit, 00 if 16 bit
-
- jcxz @F
- rep stosb
- @@:
-
- mov dx,es ; return the ending ptr
- mov ax,di
-
- popf
-
- pop di
- pop es
- pop bp
- ret
-
- FlushBuffer endp
-
-
- ; /*\
- ;---|*|------------====< _dofwrite ( char far *, int, int ) >====------------
- ;---|*|
- ;---|*| Replacement code for the fwrite C library function. This will also
- ;---|*| keep track of the file position.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| char far * is a pointer to the buffer
- ;---|*| int - Length of the buffer
- ;---|*| int - file handle
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX holds the length writtent to disk
- ;---|*|
- ; \*/
- public _dofwrite
- _dofwrite proc
- push bp
- mov bp,sp
- push ds
-
- lds dx,wParm1 ; get the buffer
- mov cx,wParm3 ; get the length
- mov bx,wParm4 ; get the handle
- mov ah,40h ; write command
-
- int 21h
-
- pop ds
-
- cmc ; set carry if good read
- sbb bx,bx
- and ax,bx
- add wptr [__fptrpos+0],ax
- adc wptr [__fptrpos+2],0
-
- pop bp
- ret
-
- _dofwrite endp
-
-
- ; /*\
- ;---|*|------------====< StartTheDMAInput() >====------------
- ;---|*|
- ;---|*| Calculate the H/W timer value (internal routine)
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| pointer to a routine
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0 indicates DMA running
- ;---|*| AX = -1 indicates a failure
- ;---|*|
- ;---|*| Functionality:
- ;---|*|
- ;---|*| Reset input pointer to the DMA buffer.
- ;---|*| Load next buffer of data into the DMA buffer.
- ;---|*| Enable DMA & interrupts.
- ;---|*| Set DMARunning to 1;
- ;---|*|
- ; \*/
-
- public StartTheDMAInput
- StartTheDMAInput proc
- push bp
- mov bp,sp
-
- push es
- ;
- ; Reset the DMA's internal buffer pointer & counter
- ;
- call FFAR ptr _resetdmaptrs ; reset the criticals
- ;
- ; Validate some critical data
- ;
- mov ax,-1 ; setup for bad return
-
- cmp DMAUnitSize,0 ; we must have a valid size of units
- jz stdmaout_bad
-
- les bx,[NextDMAPtr] ; we must have a valid DMA buffer
- mov cx,es
- or bx,cx
- jz stdmaout_bad
- ;
- ; setup the callers callback
- ;
- if @codesize
- mov ax,wParm1+0
- mov dx,wParm1+2
- mov wptr [__callersroutine+0],ax
- mov wptr [__callersroutine+2],dx
- else
- mov ax,wParm1+0
- mov [__callersroutine],ax
- endif
- ;
- ; setup our call-back routine
- ;
- lea ax,InputBackgroundTask
- push cs
- push ax
- call UserFunc
- add sp,4
- ;
- ; The DMA is loaded, let'er rip!!!
- ;
- call PCMRecord
- mov DMARunning,1
-
- sub ax,ax
- ;
- stdmaout_bad:
- pop es
- pop bp
- ret
-
- StartTheDMAInput endp
-
-
- ; /*\
- ;---|*|------------====< StartTheDMAOutput() >====------------
- ;---|*|
- ;---|*| Calculate the H/W timer value (internal routine)
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0 indicates DMA running
- ;---|*| AX = -1 indicates a failure
- ;---|*|
- ;---|*| Functionality:
- ;---|*|
- ;---|*| Reset input pointer to the DMA buffer.
- ;---|*| Load next buffer of data into the DMA buffer.
- ;---|*| Enable DMA & interrupts.
- ;---|*| Set DMARunning to 1;
- ;---|*|
- ; \*/
-
- public StartTheDMAOutput
- StartTheDMAOutput proc
- push bp
- mov bp,sp
- push es
- ;
- ; Reset the DMA's internal buffer pointer & counter
- ;
- call FFAR ptr _resetdmaptrs ; reset the criticals
- ;
- ; Validate some critical data
- ;
- mov ax,-1 ; setup for bad return
-
- cmp DMAUnitSize,0 ; we must have a valid size of units
- jz stdmaout_bad
-
- les bx,[NextDMAPtr] ; we must have a valid DMA buffer
- mov cx,es
- or bx,cx
- jz stdmaout_bad
- ;
- ; setup the callers callback
- ;
- if @codesize
- mov ax,wParm1+0
- mov dx,wParm1+2
- mov wptr [__callersroutine+0],ax
- mov wptr [__callersroutine+2],dx
- else
- mov ax,wParm1+0
- mov [__callersroutine],ax
- endif
- ;
- ; setup our call-back routine
- ;
- lea ax,OutputBackgroundTask
- push cs
- push ax
- call UserFunc
- add sp,4
- ;
- ; The DMA is loaded, let'er rip!!!
- ;
- call PCMPlay
- mov DMARunning,1
-
- sub ax,ax
- ;
- stdmaout_bad:
- pop es
- pop bp
- ret
-
- StartTheDMAOutput endp
-
-
- ;
- ;--------------------------=============================-----------------------
- ;--------------------------====< Internal Routines >====-----------------------
- ;--------------------------=============================-----------------------
- ;
-
- ; /*\
- ;---|*|------------====< InputBackgroundTask() >====------------
- ;---|*|
- ;---|*| This is the interrupt code for processing DMA-buffer-has-data interrupts
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Interrupt handling:
- ;---|*|
- ;---|*| if Next Buffer has data,
- ;---|*| Kill-the-DMA;
- ;---|*| set DMARunning to 0;
- ;---|*| exit interrupt.
- ;---|*| else
- ;---|*| Load DMA into Next buffer.
- ;---|*|
- ;---|*| Increment BufferDataCount.
- ;---|*|
- ; \*/
-
- InputBackgroundTask proc
- push ax ; save the entire state
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- ;
- ; initialize the segment registers to point to our local static segment
- ;
- if MODELSIZE eq 0
- mov ax,cs ; load our data segment
- mov ds,ax ; DS too in case of failure
- else
- mov ax,@data ; load our data segment
- mov ds,ax ; DS too in case of failure
- endif
-
- ;
- ; Save the next DMA pointer, increment our internal buffer-loaded count
- ;
- inc ProcessedBlockCount ; total block count the DMA has seen
- inc BufferDataCount ; tell the world, we have new data
- mov ax,BufferDataCount
- cmp ax,MaxBuffCount
- jb inbkgrtsk_exit
- ;
- ; Yuck! We just ran out of buffer space, we must kill the DMA
- ;
- call StopPCM ; kill the interrupts...
- mov DMARunning,0
- ;
- inbkgrtsk_exit:
- if @codesize
- cmp wptr [__callersroutine+2],0 ; if there is no vector, just exit
- jz @F
- call dptr [__callersroutine] ; call the user routine
- @@:
- else
- cmp wptr [__callersroutine],0 ; if there is no vector, just exit
- jz @F
- call wptr [__callersroutine] ; call the user routine
- @@:
- endif
- ;
- ; Call the application level it it wants a slice of time...
- ;
- cmp wptr [__synccallback+2],0 ; if no App. vector, just exit
- jz @F
- call dptr [__synccallback] ; if no App. vector, just exit
- @@:
- ;
- ; finally, all done.
- ;
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- retf
-
- InputBackgroundTask endp
-
-
- ; /*\
- ;---|*|------------====< OutputBackgroundTask() >====------------
- ;---|*|
- ;---|*| This is the interrupt code for processing DMA buffer
- ;---|*| empty interrupts for the file output routines.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Interrupt handling:
- ;---|*|
- ;---|*| If BufferDataCount is zero,
- ;---|*| Kill-the-DMA;
- ;---|*| set DMARunning to 0;
- ;---|*|
- ;---|*| Attempt to load as many blocks as possible into the DMA buffer.
- ;---|*|
- ;---|*| If data is loaded and DMARunning = 0,
- ;---|*| restart the DMA;
- ;---|*| set DMARunning to -1;
- ;---|*|
- ;---|*| Exit interrupt.
- ;---|*|
- ; \*/
-
- OutputBackgroundTask proc
- push ax ; save the entire state
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- ;
- ; initialize the data segment to point to our local static segment
- ;
- if MODELSIZE eq 0
- mov ax,cs ; load our data segment
- mov ds,ax ; DS too in case of failure
- else
- mov ax,@data ; load our data segment
- mov ds,ax
- endif
- ;
- ; We just finished a block. If done (0), stop the DMA, else go load another
- ;
- inc ProcessedBlockCount ; total block count the DMA has seen
- sub BufferDataCount,1 ; decrement the internal buffered data
- adc BufferDataCount,0 ; count down to zero
- jnz bkgrtsk_05 ; more data, go load it...
- ;
- ; Yuck! We just ran out of data, we must silence the DMA
- ;
- call StopPCM ; kill the interrupts...
- mov DMARunning,0
- ;
- bkgrtsk_05:
- if @codesize
- cmp wptr [__callersroutine+2],0 ; if there is no vector, just exit
- jz @F
- call dptr [__callersroutine] ; call the user routine
- @@:
- else
- cmp wptr [__callersroutine],0 ; if there is no vector, just exit
- jz @F
- call wptr [__callersroutine] ; call the user routine
- @@:
- endif
- ;
- ; Call the application level it it wants a slice of time...
- ;
- cmp wptr [__synccallback+2],0 ; if no App. vector, just exit
- jz @F
- call dptr [__synccallback] ; if no App. vector, just exit
- @@:
- ;
- ; finally, all done.
- ;
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- retf
-
- OutputBackgroundTask endp
-
-
- ;
- ; /*\
- ;---|*|------------====< _resetdmaptrs >====----------------
- ;---|*|
- ;---|*| Reset the DMA starting point
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| DS points to the default data segment
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| None
- ;---|*|
- ; \*/
-
- _resetdmaptrs proc
- push es
- ;
- ; load the number of buffer divisions. this tells us when to wrap the DMA buff
- ;
- mov al,byte ptr [MaxBuffCount]
- mov [CountdownBuffers],al
- ;
- ; reset the DMA buffer offset
- ;
- les ax,[StartOfDMABuffer]
- mov wptr [NextDMAPtr+0],ax
- mov wptr [NextDMAPtr+2],es
-
- pop es
- ret
-
- _resetdmaptrs endp
-
-
- ; /*\
- ;---|*| end of PCMIOA.ASM
- ; \*/
-
- end
-
-