build: add the SIBO SDK
This commit is contained in:
@@ -0,0 +1,521 @@
|
||||
title SNDFRC -- Epoc/Os Sound Device Driver Using FRC
|
||||
subttl Copyright (c) Psion PLC 1992
|
||||
name SNDFRC
|
||||
;
|
||||
; VER DATE BY DESCRIPTION
|
||||
; ----- -------- ---- -----------
|
||||
; 1.00A 21/04/92 JH Alpha release
|
||||
;
|
||||
TURBOC equ 1
|
||||
;
|
||||
include epocdef.inc
|
||||
include epocmac.inc
|
||||
include epocpan.inc
|
||||
include epoclib.inc
|
||||
include epocser.inc
|
||||
include ossibo.inc
|
||||
|
||||
HandlerDisable equ 000h ; the hnadler should not be called
|
||||
HandlerEnable equ 001h ; the handler should be called
|
||||
|
||||
MAX_NOTES equ 500
|
||||
|
||||
; This is allocated in the user space for the I/O channel
|
||||
SndFrcEnt struc
|
||||
SndFrcIo ChanEnt <> ; I/O channel hdr, MUST be first
|
||||
SndFrcWrite RqEnt <>
|
||||
SndFrcHandler dw ?
|
||||
SndFrcFlags dw ?
|
||||
SndFrcPstat dw ?
|
||||
SndFrcEnt ends
|
||||
|
||||
SndChannel struc
|
||||
Pid dw ? ; owning channel pid
|
||||
OpenFrcChan db ? ; channel open status (KEEP ORDER)
|
||||
WriteStat db ? ; write completion status (ORDER)
|
||||
DataPtr dw ? ; where we are in buffer
|
||||
DataLength dw ? ; number of notes to play
|
||||
DataPreBuffer dw ? ; First Frc timout ptr
|
||||
DataBuffer dw MAX_NOTES dup (?)
|
||||
SndChannel ends
|
||||
|
||||
CodeSeg
|
||||
|
||||
ProcBegin@ SndfrcLDD
|
||||
; ==========
|
||||
; The externally loadable device table
|
||||
dw LDDSignature
|
||||
db 'MUS',0,0,0,0,0
|
||||
dw (VectorEnd-Vector)/2
|
||||
Vector:
|
||||
dw SndfrcInstall
|
||||
dw SndfrcRemove
|
||||
dw SndfrcHold
|
||||
dw SndfrcResume
|
||||
dw SndfrcReset
|
||||
dw SndfrcUnits
|
||||
dw SndfrcOpen
|
||||
dw SndfrcStrategy
|
||||
VectorHandler:
|
||||
dw SndfrcHandler
|
||||
VectorEnd:
|
||||
ProcEnd noret
|
||||
|
||||
SoundChan SndChannel <>
|
||||
|
||||
ProcBegin@ disableFrcInt
|
||||
; =============
|
||||
; Disable the generation of Frc interrupts
|
||||
;
|
||||
pushf
|
||||
cli
|
||||
in al, A1InterruptMask
|
||||
and al, not (mask FrcExpired)
|
||||
out A1InterruptMask, al ; stop Interrupt controller from
|
||||
popf ; generating Frc interrupts
|
||||
ret
|
||||
ProcEnd
|
||||
;
|
||||
ProcBegin@ enableFrcInt
|
||||
; ============
|
||||
; Starts the free running counter.
|
||||
;
|
||||
pushf
|
||||
cli
|
||||
in al, A1Control
|
||||
or al, mask FrcSource or mask FrcMode
|
||||
out A1Control, al ; set 512khz and prescale mode
|
||||
mov ax, 5120 ; request a FrcInt every 10ms
|
||||
out A1FrcControl, ax
|
||||
out A1FrcEoi, al ; clear any junk Frc Interrupt
|
||||
in al, A1InterruptMask
|
||||
or al, mask FrcExpired ; allow interrupt controller to
|
||||
out A1InterruptMask, al ; generate a Frc Interrupt
|
||||
popf
|
||||
ret
|
||||
ProcEnd noret
|
||||
;
|
||||
|
||||
ProcBegin@ FrcInterrupt,far
|
||||
; ============
|
||||
; The Frc interrupt routine.
|
||||
; Although we could get addressability to the clients data space since it is
|
||||
; possible that the operating system is currently moving the
|
||||
; data space of the client in which case the data buffer to be played
|
||||
; may not be valid.
|
||||
; The ISR is called by the operating system after all registers have been
|
||||
; preserved.
|
||||
; We MUST NOT cause a reschedule directly since the ISR would take a long
|
||||
; time to complete if we did.
|
||||
;
|
||||
; Called in the context of whatever was running when the interrupt went off
|
||||
;
|
||||
out A1FrcEoi, al ; clear Frc Interrupt
|
||||
mov si, SoundChan.DataPtr
|
||||
cmp byte ptr cs:[si+1], 0 ; look at the duration byte
|
||||
je finishedThatNote ; if zero goto the next note
|
||||
dec byte ptr cs:[si+1] ; reduce timeout
|
||||
endFrcInterrupt:
|
||||
stc ; no potential reschedule required
|
||||
endFrcInterruptFlags:
|
||||
out A1NonSpecificEoi, al ; finish the ISR
|
||||
ret
|
||||
|
||||
finishedThatNote:
|
||||
cmp SoundChan.DataLength, 0
|
||||
je finishedAllNotes
|
||||
dec SoundChan.DataLength ; one less note to play
|
||||
inc si
|
||||
inc si ; find next note,volume and duration
|
||||
mov SoundChan.DataPtr, si ; updated ptr
|
||||
mov al, byte ptr cs:[si]
|
||||
push ax
|
||||
shr ax, 1 ; factor out the volume bits
|
||||
and al, 60h ; into bits 5+6 for the hardware
|
||||
mov ah, al
|
||||
mov al, A2IWrite
|
||||
out A2Index, al
|
||||
mov al, ah
|
||||
out A2Control, al ; set the volume for that note
|
||||
pop ax
|
||||
mov dx, PSoundControl
|
||||
and al, 3fh ; bottom 6 bits are note info
|
||||
out dx, al ; and play that note
|
||||
jmp short endFrcInterrupt
|
||||
finishedAllNotes:
|
||||
call StopSound
|
||||
mov SoundChan.WriteStat, 0 ; finished playing that lot
|
||||
mov bx, SoundChan.Pid ; get the channel owner
|
||||
IoSignalByPidNoReSched ; signal ourselves, causes handler
|
||||
clc ; reschedule if possible
|
||||
jmp short endFrcInterruptFlags
|
||||
ProcEnd noret
|
||||
;
|
||||
|
||||
ProcBegin@ setFrcIntVector
|
||||
; ===============
|
||||
; Set the ISR pointer to our FRC interrupt routine.
|
||||
; MUST be done with ints disabled so we cant be moved by the operating
|
||||
; system whilst setting the address.
|
||||
;
|
||||
pushf
|
||||
cli
|
||||
push bx
|
||||
mov al, HwIrq5Revector
|
||||
mov bx, offset FrcInterrupt
|
||||
mov cx, cs ; this ok as ints disabled.
|
||||
GenSetRevector
|
||||
pop bx
|
||||
popf
|
||||
ret
|
||||
ProcEnd noret
|
||||
;
|
||||
|
||||
ProcBegin@ StopSound
|
||||
; =========
|
||||
; Stop the sound generation.
|
||||
;
|
||||
call disableFrcInt ; Stop Frc interrupts
|
||||
mov dx, PSoundControl
|
||||
mov al, 1
|
||||
out dx, al ; stop sound chip
|
||||
HwComboOff ; stop amplifier
|
||||
ret
|
||||
ProcEnd noret
|
||||
|
||||
ProcBegin@ SndfrcInstall,far
|
||||
; =============
|
||||
; Install vector called when application calls p_loadldd()
|
||||
; Set OpenFrcChan to zero.
|
||||
; In:
|
||||
; NONE
|
||||
; Out:
|
||||
; Carry clear if installed ok
|
||||
; Carry set if failed to install
|
||||
;
|
||||
and SoundChan.OpenFrcChan, 0
|
||||
clc ; installed OK
|
||||
ret
|
||||
ProcEnd noret
|
||||
;
|
||||
|
||||
ProcBegin@ SndfrcRemove,far
|
||||
; ============
|
||||
; Remove vector called when application calls p_devdel()
|
||||
;
|
||||
cmp SoundChan.OpenFrcChan, 0
|
||||
je soundRemoved
|
||||
mov al, InUseErr
|
||||
stc ; channel open, fail to remove
|
||||
ret
|
||||
ProcEnd noret
|
||||
;
|
||||
|
||||
ProcBegin@ SndfrcReset,far
|
||||
; ===========
|
||||
; Reset vector called if the client terminated.
|
||||
; We can only get a reset if weve got channel open and client died
|
||||
; since we cancel the reset request when the channel is closed.
|
||||
; NOTE: The clients data space no longer exists thus all data required to
|
||||
; close down the channel must be avaliable in the drivers space.
|
||||
; In:
|
||||
; NONE
|
||||
; Out:
|
||||
; NONE
|
||||
;
|
||||
call StopSound ; disable Frc ints etc
|
||||
mov al, HwIrq5Revector
|
||||
GenResetRevector ; restore the default ROM ISR vector
|
||||
mov al, mask FrcExpired
|
||||
HwFreeChannel ; free Frc resource
|
||||
HwFreeCombo ; free up sound usage resource
|
||||
and word ptr SoundChan.OpenFrcChan, 0 ; all closed now
|
||||
soundRemoved:
|
||||
clc ; removed OK.
|
||||
ret
|
||||
ProcEnd noret
|
||||
|
||||
|
||||
ProcBegin@ SndfrcHold,far
|
||||
; ==========
|
||||
; Hold called when another driver loaded or switched off/power fail.
|
||||
; In:
|
||||
; AH - reason.
|
||||
; Out:
|
||||
; NONE
|
||||
|
||||
cmp SoundChan.OpenFrcChan, 0
|
||||
je soundHeld ; dont do anything if not open
|
||||
call StopSound ; shut down ints and sound
|
||||
soundHeld:
|
||||
ret
|
||||
ProcEnd noret
|
||||
|
||||
ProcBegin@ SndfrcResume,far
|
||||
; ============
|
||||
; Resume called after a Hold to allow the driver to continue.
|
||||
; If we were running enabling the Frc interrupt will cause the
|
||||
; FrcInt routine to be called thus allowing us to count down the current
|
||||
; duration as though nothing had happened before going to the next note.
|
||||
; In:
|
||||
; NONE
|
||||
; Out:
|
||||
; NONE
|
||||
;
|
||||
cmp SoundChan.OpenFrcChan, 0
|
||||
je soundResumed ; dont do anything if not open
|
||||
call setFrcIntVector ; we may have moved, set CS correctly
|
||||
cmp SoundChan.WriteStat, PendingErr
|
||||
jne soundResumed ; dont enable ints if no write queued
|
||||
HwComboOn ; switch amplifier on
|
||||
call enableFrcInt ; continue where we left off
|
||||
soundResumed:
|
||||
ret
|
||||
ProcEnd noret
|
||||
|
||||
ProcBegin@ SndfrcUnits,far
|
||||
; ===========
|
||||
; We can only handle 1 sound channel at a time.
|
||||
;
|
||||
mov ax, 1 ; support 1 unit at a time
|
||||
ret
|
||||
ProcEnd noret
|
||||
|
||||
ProcBegin@ SndfrcOpen,far
|
||||
; ==========
|
||||
; Open the sound device driver.
|
||||
; This runs is the context of the process that has called p_open("MUF:").
|
||||
;
|
||||
; In:
|
||||
; DS=ES=SS - Process data space.
|
||||
; DX - OS device handle
|
||||
; SI - ptr to OpenEnt struct
|
||||
; Out:
|
||||
; DX - OS device handle
|
||||
; Carry Clear
|
||||
; BX - channel, DX is as passed (device handle)
|
||||
; Carry Set
|
||||
; AL - error number
|
||||
;
|
||||
; All device drivers MUST have a ChanEnt as first item at returned BX
|
||||
;
|
||||
HwGetCombo ; see if snd already in use, if not grab it
|
||||
jc sndAlreadyInUse
|
||||
mov al, mask FrcExpired
|
||||
HwGetChannel ; see if FRC already in use, if not grab it
|
||||
jc endFrcInUse
|
||||
mov cx, (size SndFrcEnt)
|
||||
HeapAllocateCell
|
||||
jc endOpenNoMemory ; get users I/O channel
|
||||
mov bx, ax ; the allocated cell handle
|
||||
mov al, (VectorHandler-Vector)/2
|
||||
IoAddHandler ; handler handle in AX
|
||||
jc endOpenFreeMemory
|
||||
mov [bx].SndFrcHandler, ax
|
||||
xchg bx, dx
|
||||
xor cx, cx
|
||||
IoRequestReset ; call Reset if client terminates
|
||||
xchg bx, dx
|
||||
mov [bx].SndFrcIo.ChanNext, bx ; we are a root device
|
||||
mov [bx].SndFrcIo.ChanSignature, IoChanSignature
|
||||
mov [bx].SndFrcIo.ChanLibHandle, dx ; This is our device handle
|
||||
and [bx].SndFrcPstat, 0 ; no write pending yet
|
||||
and [bx].SndFrcFlags, 0
|
||||
ProcId
|
||||
mov SoundChan.Pid, ax ; remember client id for ISR
|
||||
mov SoundChan.OpenFrcChan, 1 ; now open
|
||||
call setFrcIntVector ; set up the ISR address ptr
|
||||
clc
|
||||
ret
|
||||
|
||||
endOpenFreeMemory:
|
||||
push ax
|
||||
HeapFreeCell
|
||||
pop ax
|
||||
endOpenNoMemory:
|
||||
push ax
|
||||
mov al, mask FrcExpired
|
||||
HwFreeChannel ; free Frc resource
|
||||
pop ax
|
||||
endFrcInUse:
|
||||
push ax
|
||||
HwFreeCombo ; free sound resource as failed somewhere
|
||||
pop ax
|
||||
stc
|
||||
sndAlreadyInUse:
|
||||
ret
|
||||
ProcEnd noret
|
||||
|
||||
ProcBegin@ SndfrcHandler,far
|
||||
; ==============
|
||||
; Called when an I/O signal is generated and were enabled. We should only
|
||||
; enabled when a write request is outstanding.
|
||||
; We need to check the LOW side drivers completion status to see if all the
|
||||
; notes have been played yet (SoundChan.WriteStat!=E_FILE_PENDING).
|
||||
; Typically write the handler defensivly since complex drivers may leave the
|
||||
; handler enabled other than when a request is outstanding.
|
||||
;
|
||||
; In:
|
||||
; DS,ES,SS == Process data space
|
||||
; BX == channel control block from open request
|
||||
; Out:
|
||||
; Carry clear
|
||||
; Did not consume signal
|
||||
; Carry set
|
||||
; al = 0 - Leave handler disabled
|
||||
; al = non 0 - Enable handler
|
||||
;
|
||||
test [bx].SndFrcFlags, RQ_DISABLE_HANDLER
|
||||
jnz signalNotForUs ; we are in StategyVector code
|
||||
cmp [bx].SndFrcPstat, 0
|
||||
je signalNotForUs ; no write request queued yet
|
||||
mov al, SoundChan.WriteStat
|
||||
cmp al, PendingErr
|
||||
je signalNotForUs ; pending write request not finished
|
||||
cbw
|
||||
xor si, si
|
||||
xchg si, [bx].SndFrcPstat ; no write queued if Pstat is zero
|
||||
mov [si], ax
|
||||
IoSignal ; complete the original write request
|
||||
xor ax, ax ; disable handler now
|
||||
stc
|
||||
ret
|
||||
signalNotForUs:
|
||||
clc
|
||||
ret
|
||||
ProcEnd noret
|
||||
|
||||
ProcBegin@ CancelWrite
|
||||
; ===========
|
||||
; Cancel any outstanding write request
|
||||
;
|
||||
xor di, di
|
||||
xchg di, [bx].SndFrcPstat
|
||||
or di, di ; see if any write is currently queued
|
||||
jz noWriteQueued
|
||||
push bx
|
||||
mov bx, [bx].SndFrcHandler
|
||||
mov cl, HandlerDisable
|
||||
IoEnableHandler ; make SndfrcHandler non callable
|
||||
pop bx
|
||||
call StopSound ; stops Frc ints
|
||||
mov word ptr [di], CancelErr ; set write completion stat
|
||||
IoSignal ; and signal write completion
|
||||
noWriteQueued:
|
||||
mov SoundChan.WriteStat, 0
|
||||
ret
|
||||
ProcEnd noret
|
||||
;
|
||||
|
||||
ProcBegin@ SndfrcStrategy,far
|
||||
; ==============
|
||||
; Strategy vector called by an I/O request on the opened sound device driver
|
||||
; channel.
|
||||
; The wait handler may be called (when enabled ) unless we block it when we
|
||||
; call a sync I/O request. Allowing the waithandler to run whilst in the
|
||||
; strategy vector is generally not a good thing to do.
|
||||
; In this particular example there are infact no sync calls to the I/O system
|
||||
; thus the wait handler cannot be run. In more complex drivers it may be
|
||||
; difficult to determine all possible paths through the code thus the driver
|
||||
; should be written defensivly (use RQ_DISABLE_HANDLER type mechanism).
|
||||
; In:
|
||||
; DS,ES,SS == Process data space
|
||||
; BX == channel control block from open request
|
||||
; DX == device handle
|
||||
; SI == RqEnt pointer
|
||||
; Out:
|
||||
; Carry clear
|
||||
; - request queued sucessfully (may have completed)
|
||||
; Carry set
|
||||
; - error queuing the I/O request
|
||||
;
|
||||
cld
|
||||
or [bx].SndFrcFlags, RQ_DISABLE_HANDLER
|
||||
mov al, byte ptr [si].RqFunction
|
||||
cmp al, IoFuncWrite
|
||||
jne tryCancel
|
||||
cmp [bx].SndFrcPstat, 0
|
||||
jne writeQueued ; panic if write already queued
|
||||
mov di, [si].RqA2Ptr
|
||||
mov cx, [di] ; length to write
|
||||
cmp cx, MAX_NOTES
|
||||
jae writeQueued ; length too much, panic dvr
|
||||
mov di, [si].RqStatusPtr
|
||||
mov word ptr [di], PendingErr
|
||||
mov [bx].SndFrcPstat, di ; write request now queued
|
||||
mov si, [si].RqA1Ptr ; ptr to data to write as sound
|
||||
mov di, offset SoundChan.DataPreBuffer
|
||||
and word ptr [di], 0 ; set pre buffer len to zero
|
||||
mov SoundChan.DataPtr, di
|
||||
inc di
|
||||
inc di
|
||||
mov SoundChan.DataLength, cx ; this many notes to play
|
||||
mov SoundChan.WriteStat, PendingErr
|
||||
pushf
|
||||
cli ; we can set ES when ints are off
|
||||
push cs
|
||||
pop es ; copy the notes+vol and duration
|
||||
popf ; into buf we can access in ISR
|
||||
rep movsw ; dont use CS override
|
||||
mov es, [bp].IntES
|
||||
push bx
|
||||
mov bx, [bx].SndFrcHandler
|
||||
mov cl, HandlerEnable
|
||||
IoEnableHandler ; allow waithandler to be called
|
||||
pop bx
|
||||
HwComboOn
|
||||
call enableFrcInt ; start the sound off
|
||||
and [bx].SndFrcFlags, NOT RQ_DISABLE_HANDLER
|
||||
xor ax, ax ; queued OK
|
||||
ret
|
||||
writeQueued:
|
||||
mov al, PanicIoPending
|
||||
ProcPanic ; stop bad applications
|
||||
|
||||
tryCancel:
|
||||
cmp al, IoFuncCancel
|
||||
jne tryClose
|
||||
call CancelWrite ; stop any queued write
|
||||
and [bx].IoRequestFlags, NOT RQ_DISABLE_HANDLER
|
||||
jmp short signalOk ; cancel completed ok.
|
||||
tryClose:
|
||||
cmp al, IoFuncClose
|
||||
jne notForUs
|
||||
call CancelWrite ; stop any queued writes
|
||||
push bx
|
||||
push [bx].SndFrcHandler
|
||||
push dx
|
||||
mov al, HwIrq5Revector
|
||||
GenResetRevector
|
||||
pop bx ; channel handle
|
||||
xor cx, cx
|
||||
IoRequestResetCancel ; dont call Reset vector now
|
||||
pop bx ; handler handle
|
||||
IoRemoveHandler
|
||||
pop bx ; alloc handle
|
||||
HeapFreeCell
|
||||
mov al, mask FrcExpired
|
||||
HwFreeChannel ; free Frc resource
|
||||
HwFreeCombo ; not in use any more
|
||||
and word ptr SoundChan.OpenFrcChan, 0 ; all closed now
|
||||
signalOk:
|
||||
xor ax, ax
|
||||
mov di, [si].RqStatusPtr
|
||||
stosw ; the I/O request completed OK
|
||||
IoSignal
|
||||
xor ax, ax ; also clears carry
|
||||
ret
|
||||
notForUs:
|
||||
and [bx].IoRequestFlags, NOT RQ_DISABLE_HANDLER
|
||||
IoRoot ; pass on request as not for us
|
||||
ret
|
||||
ProcEnd noret
|
||||
|
||||
EndCodeSeg
|
||||
;
|
||||
stack segment stack para 'data'
|
||||
;
|
||||
stack ends
|
||||
;
|
||||
end SndfrcLDD
|
||||
|
||||
Reference in New Issue
Block a user