
        .386P

Segment                 DriverHeader PARA Public 'Code' Use16
                        Assume CS:Driver, DS:Nothing

;***** Driver Header *******

include drhead.inc

EndS

Segment                 Driver PARA Public 'Code' Use16
                        Assume CS:Driver, DS:Nothing

ORG 0
StartDriver:

include vtable.inc

;********  Required ProcedureTable *************

include reqproc.inc

;***********************************************

NUMMEMORYBLOCKS EQU     64

PNPSERIALID     EQU     0FFFFFFFFh
PNPVENDORID     EQU     80719304h

MMT_MAXENTRIES  EQU     64
MMT_MAXSIZE     EQU     3*MMT_MAXENTRIES


SAM_RD_MEM      EQU     2h
SAM_GET_MMT     EQU     3h
SAM_GEN_INT     EQU     48h
SAM_GET_VOI     EQU     51h
SAM_VOI_OPEN    EQU     52h
SAM_VOI_CLOSE   EQU     53h
SAM_VOI_START   EQU     54h
SAM_VOI_STOP    EQU     55h
SAM_VOI_VOL     EQU     56h
SAM_VOI_MAIN    EQU     57h
SAM_VOI_PITCH   EQU     58h
SAM_VOI_AUX     EQU     59h
SAM_VOI_FILT    EQU     5Ah
SAM_VOI_MEM     EQU     5Bh
SAM_GET_POS     EQU     5Ch
SAM_ADD_POS     EQU     5Dh

SAM9407Message  DB      "Dream SAM9407 Detected", 13
                DB      "Port ", 0FDh, "Xh, ", 0FDh, "Dk RAM", 0

StatusLine      DB      "FreeSAM ", 0FDh, "Dk", 0

SAMUpdateFlag   DB      0

ALIGN 4
OldIRQHandler           DD      0
SAMUpdateTimer          DW      0
SAMUpdateCount          DW      0

MMTData                 DW      MMT_MAXSIZE Dup (0)

MemoryBlocks            DD      NUMMEMORYBLOCKS*2 Dup (0)
    ; Memory blocks are offset/size pairs.

SampleInformation       DD      100*4 Dup (0)
                ; Sample data is a struct
                ; Offset 0: Starting address
                ; Offset 4: Loop start
                ; Offset 8: Loop end
                ; Offset 0Ch: ??

SlaveChannelOffset      DW      0

; ÄÄ EmptyFunction ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            EmptyFunction Far

                Xor     AX, AX
                StC
                Ret

EndP            EmptyFunction

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAM9407ReceiveByte      ; Returns AL = data
                                        ;         BL = status

                Push    DX
                Mov     DX, CS:BasePort
                Inc     DX

SAM9407ReceiveByte1:
                In      AL, DX
                Test    AL, AL
                JS      SAM9407ReceiveByte1

                Mov     BL, AL
                Dec     DX
                And     BL, 30h

                In      AL, DX
                Pop     DX

                Ret

EndP            SAM9407ReceiveByte

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAM9407ReceiveWord     ; Returns AX

                Call    SAM9407ReceiveByte
                Mov     AL, AH
                Call    SAM9407ReceiveByte
                XChg    AL, AH

                Ret

EndP            SAM9407ReceiveWord

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAM9407ReceiveDWord     ; Returns EAX

                Call    SAM9407ReceiveByte
                RoR     EAX, 8
                Call    SAM9407ReceiveByte
                RoR     EAX, 8
                Call    SAM9407ReceiveByte
                RoR     EAX, 8
                Call    SAM9407ReceiveByte
                RoR     EAX, 8

                Ret

EndP            SAM9407ReceiveDWord

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAM9407SendControlByte    ; BL = data

                Push    AX
                Push    DX

                Mov     DX, CS:BasePort
                Inc     DX

SAM9407SendControlByte1:
                In      AL, DX
                Test    AL, 40h
                JNZ     SAM9407SendControlByte1

                Mov     AL, BL
                Out     DX, AL

                Pop     DX
                Pop     AX

                Ret

EndP            SAM9407SendControlByte

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAM9407SendDataByte    ; AL = data

                Push    DX
                Push    AX

                Mov     DX, CS:BasePort
                Inc     DX

SAM9407SendDataByte1:
                In      AL, DX
                Test    AL, 40h
                JNZ     SAM9407SendDataByte1

                Pop     AX
                Dec     DX

                Out     DX, AL

                Pop     DX

                Ret

EndP            SAM9407SendDataByte

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAM9407SendDataWord     ; AX = data

                Call    SAM9407SendDataByte
                Mov     AL, AH
                Call    SAM9407SendDataByte
                Ret

EndP            SAM9407SendDataWord

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAM9407SendDataDWord    ; EAX = data

                Call    SAM9407SendDataByte
                ShR     EAX, 8
                Call    SAM9407SendDataByte
                ShR     EAX, 8
                Call    SAM9407SendDataByte
                ShR     AX, 8
                Call    SAM9407SendDataByte
                Ret

EndP            SAM9407SendDataDWord

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAM9407ReceiveString    ; ES:DI points to deposit point.
                                        ; EAX = memory address
                                        ; CX = count

                Mov     BL, SAM_RD_MEM
                Call    SAM9407SendControlByte
                Call    SAM9407SendDataDWord
                Mov     AX, CX
                Call    SAM9407SendDataWord

SAM9407InString1:
                Call    SAM9407ReceiveByte
                Cmp     AL, 0ABh
                JE      SAM9407InStringError
                Cmp     AL, 0ACh
                JNE     SAM9407InString1

SAM9407InString2:
                Mov     DX, CS:BasePort
                Add     DX, 2

                Rep     InsW

                DB      85h

SAM9407InStringError:
                StC
                Ret

EndP            SAM9407ReceiveString

; ÄÄ DetectCard ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Returns carry set if error, else carry clear. Has to setup internal vars
; (eg. appropriate IRQ/DMA whatever).
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetWaitforSend     ; Given DX = control port

                Xor     CX, CX

ResetWaitforSend1:
                In      AL, DX
                Test    AL, 40h
                LoopNZ  ResetWaitforSend
                Ret

EndP            ResetWaitforSend

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetWaitforReceive

                Xor     CX, CX

ResetWaitforReceive1:
                In      AL, DX
                Test    AL, 80h
                JNZ     ResetWaitforReceive2

                Dec     DX
                In      AL, DX
                Inc     DX
                Cmp     AL, 0FEh
                JE      ResetWaitforReceive3

ResetWaitforReceive2:
                Loop    ResetWaitforReceive1

                StC
                Ret

ResetWaitforReceive3:
                ClC
                Ret

EndP            ResetWaitforReceive

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAMSendChannelNumber

                Mov     AX, SI
                Sub     AX, CS:SlaveChannelOffset
                ShR     AX, 7
                Call    SAM9407SendDataByte

                Ret

EndP            SAMSendChannelNumber

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAMOpenVoice

                Cmp     Byte Ptr [SI+2], 1
                JE      SAMOpenVoice1           ; Already opened!

                Mov     Byte Ptr [SI+2], 1

                Mov     BL, [SI+36h]    ; Sample number
                Xor     DH, DH
                And     BX, 0FFh
                ShL     BX, 4

                Mov     DL, [Byte Ptr CS:SampleInformation+BX+3]
                Sub     DL, [Byte Ptr CS:SampleInformation+BX+7]
                                ; Carry 0 if inbank
                                ; Carry 1 if crossbank

                SBB     DL, DL  ; DL = 0 inbank
                                ; DL = 0FFh crossbank

                ShL     DL, 7   ; DL = 0 inbank
                                ; DL = 80h crossbank

                Mov     BL, SAM_VOI_OPEN
                Call    SAM9407SendControlByte

                Mov     AX, SI
                Sub     AX, CS:SlaveChannelOffset
                ShR     AX, 7
                Or      AL, DL
                Call    SAM9407SendDataByte

SAMOpenVoice1:
                Ret

EndP            SAMOpenVoice

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAMStopNote     ; Closes the voice.

                Cmp     Byte Ptr [SI+2], 1
                JNE     SAMStopNote1

                Mov     Byte Ptr [SI+2], 0
                Mov     BL, SAM_VOI_CLOSE
                Call    SAM9407SendControlByte
                Call    SAMSendChannelNumber

SAMStopNote1:
                Ret


EndP            SAMStopNote

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAMSetVolume

                Cmp     Byte Ptr [SI+2], 1
                JNE     SAMSetVolume1

                Mov     BL, SAM_VOI_VOL
                Call    SAM9407SendControlByte
                Call    SAMSendChannelNumber
                Mov     AL, [SI+20h]
                Call    SAM9407SendDataByte

SAMSetVolume1:
                Ret

EndP            SAMSetVolume

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAMSetPan

                Cmp     Byte Ptr [SI+2], 1
                JNE     SAMSetPan1

Comment ~
                Mov     BL, SAM_VOI_PAN
                Call    SAM9407SendControlByte
                Call    SAMSendChannelNumber
                Mov     AL, [SI+37h]
                Call    SAM9407SendDataByte
~
SAMSetPan1:
                Ret

EndP            SAMSetPan

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAMSetPitch

; Pitch value sent is 400h for nominal frequency of 37.5khz, linear scale
; -> Value sent = Frequency*400h / 37500
;               = Frequency * 0.02730666
;               = Frequency * 117281240 / 2^32

                Cmp     Byte Ptr [SI+2], 1
                JNE     SAMSetPitch3

                Mov     EAX, 117281240
                Mul     DWord Ptr [SI+10h]

                Cmp     EDX, 0FFFFh
                JA      SAMSetPitch1

                Mov     BL, SAM_VOI_PITCH
                Call    SAM9407SendControlByte
                Call    SAMSendChannelNumber
                Mov     AX, DX
                Call    SAM9407SendDataWord

SAMSetPitch3:
                Ret

SAMSetPitch1:
                Call    SAMStopNote

                Mov     Word Ptr [SI], 200h
                Test    Byte Ptr [SI+3Ah], 80h
                JNZ     SAMSetPitch2

                Mov     BX, [SI+38h]
                And     Byte Ptr [BX], Not 4    ; Signify channel off

SAMSetPitch2:
                Ret

EndP            SAMSetPitch

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAMSetRegisters

; First get offset of currently playing notes

; Update Registers to play notes

; Flow is as follows:
;  If new note, open voice
;
;  If pitch change, set pitch
;  If volume change, set volume + filters
;
PlayNote:

                Ret

EndP            SAMSetRegisters

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SAMIRQHandler                   ; IRQ Handler has to
                                                ; 1) Update GUS registers
                                                ; 2) Update song position
                Push    AX
                Push    DS

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     AX, SAMUpdateTimer
                Add     SAMUpdateCount, AX
                JC      SAMIRQHandler1

                Mov     AL, 20h
                Out     20h, AL
                Jmp     SAMIRQHandler2

SAMIRQHandler1:
                PushF
                Call    [OldIRQHandler]

SAMIRQHandler2:
                Xor     SAMUpdateFlag, 1
                JZ      SAMIRQHandlerEnd

                PushAD
                Push    ES

                ClD

                Call    SaveEMSPageFrame
                Call    Update          ; Returns DS:SI, CX
                        Assume DS:Nothing

                Mov     SlaveChannelOffset, SI

                Call    SAMSetRegisters
                Call    RestoreEMSPageFrame

                Pop     ES
                PopAD

SAMIRQHandlerEnd:
                Pop     DS
                Pop     AX
                IRet

EndP            SAMIRQHandler

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetUART              ; Given DX = Port

                Inc     DX

                Mov     AL, 0FFh        ; Reset!
                Out     DX, AL
                Out     DX, AL          ; Two resets required to ensure it'll work

                Call    ResetWaitforReceive
                JNC     ResetUART1

ResetUARTError:
                StC
                Ret

ResetUART1:                    ; Now to shove it into 'intelligent' mode.
                Call    ResetWaitforSend
                JNZ     ResetUARTError

                Mov     AL, 3Fh         ; Intelligent mode!
                Out     DX, AL

                Call    ResetWaitforReceive
                JC      ResetUARTError

                Call    ResetWaitforSend
                JNZ     ResetUARTError

                Mov     AL, SAM_GEN_INT
                Out     DX, AL

                Call    ResetWaitforSend
                JNZ     ResetUARTError

                Dec     DX
                Xor     AL, AL
                Out     DX, AL
                Inc     DX

                Xor     CX, CX

ResetUART2:
                In      AL, DX
                Test    AL, 80h
                JNZ     ResetUART3

                Mov     AH, AL
                Dec     DX
                In      AL, DX
                Inc     DX
                And     AH, 30h
                Cmp     AX, 3088h
                JE      ResetUART4

ResetUART3:
                Loop    ResetUART2
                Jmp     ResetUARTError

ResetUART4:
                Call    ResetWaitforReceive
                JC      ResetUARTError

                Dec     DX

                ClC
                Ret

EndP            ResetUART

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            DetectCard Far          ; returns carry clear if succesful

                Push    CS
                Pop     DS

; Check whether the MPU can be reset
                Mov     DX, BasePort
                Cmp     DX, 0FFFFh
                JE      DetectCard1

                Call    ResetUART
                JNC     DetectCardFound

DetectCardExit:
                Ret

DetectCard1:
                Mov     DX, 330h
                Call    ResetUART
                JNC     DetectCard2

                Mov     DX, 300h
                Call    ResetUART
                JC      DetectCardExit

DetectCard2:
                Mov     BasePort, DX

DetectCardFound:
; Find memory mapping table,
                Mov     BL, SAM_GET_MMT
                Xor     AL, AL
                Call    SAM9407SendControlByte
                Call    SAM9407SendDataByte
                Call    SAM9407ReceiveDWord

                Push    CS
                Pop     ES
                Mov     CX, MMT_MAXSIZE
                Mov     DI, Offset MMTData
                Call    SAM9407ReceiveString

                Mov     EAX, 'Jeff'
                Ret

EndP            DetectCard
                Assume DS:Nothing

;ÄÄ InitSound ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Sets up any memory required for output
; Initiates output
;
; Parameters: AX = Number of Channels
;
; If sucessful, returns:
;   Carry flag clear
;   DS:SI = pointer to text to display
;      AX = parameter 1 in text
;      BX = parameter 2 in text
;      CX = parameter 3 in text
;      DX = parameter 4 in text
;      DI = parameter 5 in text
;
; If unsucessful, returns:
;   Carry flag set
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            InitSound Far

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     AL, 34h         ; Program IRQ 0. LSB&MSB, Rate gen
                Out     43h, AL

                Call    GetTempo
                Call    SetTempo
                Call    ResetMemory

                Xor     AX, AX
                Mov     ES, AX          ; ES = 0

                Mov     AX, CS
                ShL     EAX, 16
                Mov     AX, Offset SAMIRQHandler

                ClI

                XChg    DWord Ptr [ES:20h], EAX         ; Clock tick
                Mov     OldIRQHandler, EAX

                StI

                Mov     SI, Offset SAM9407Message
                Xor     BX, BX

Comment ~
                Mov     BL, SAM_GET_VOI
                Xor     AL, AL
                Call    SAM9407SendControlByte
                Call    SAM9407SendDataByte
                Call    SAM9407ReceiveByte
                Mov     BL, AL
~
                Mov     AX, BasePort
                Mov     EBX, DWord Ptr [MMTData+2]
                ShR     EBX, 9

                ClC
                Ret

EndP            InitSound
                Assume DS:Nothing

;ÄÄ ReInitSound ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Reinitialises sound output
; Initiates sound output
;
; Parameters: AX = number of channels.
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ReInitSound Far

                Ret

EndP            ReInitSound

;ÄÄ UnInitSound ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Stops sound output, releases any memory used by driver
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            UnInitSound Far

                Mov     BL, 0FFh
                Call    SAM9407SendControlByte

                Mov     AL, 34h
                Out     43h, AL

                Xor     AX, AX
                Out     40h, AL
                Out     40h, AL

                Mov     ES, AX
                Mov     EAX, OldIRQHandler
                Mov     [ES:20h], EAX

                Ret

EndP            UnInitSound

;ÄÄ Poll ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; This procedure is called as often as possible by IT.EXE
; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song)
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            Poll Far

                Ret

EndP            Poll

;ÄÄ SetTempo ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: BX = tempo
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetTempo Far    ; BX = tempo...

                Push    AX
                Push    BX
                Push    DX

                                        ; Frames per second = 2 * (0.4*Tempo)
                Mov     AX, 0C214h
                Mov     DX, 16h         ; Ticks = (1193181/(2*0.4))/Tempo
                Div     BX

                                        ; AX contains counter.
                Mov     CS:SAMUpdateTimer, AX

                Out     40h, AL         ; Timer IRQ.
                Mov     AL, AH
                Out     40h, AL

                Pop     DX
                Pop     BX
                Pop     AX
                Ret

EndP            SetTempo

;ÄÄ SetMixVolume ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AX = MixVolume
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetMixVolume Far

                Ret

EndP            SetMixVolume

;ÄÄ SetStereo ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AL = Stereo on/off, 0 = off.
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetStereo Far

                Ret

EndP            SetStereo

;ÄÄ LoadSample ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AX = sample to load (0 based)
;             DS:SI points to sample header
;             ES:0 points to first sample
;
; Returns: **Carry set if NO error**
;          **Carry clear if error**
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            LoadSample Far

                StC
                Ret

EndP            LoadSample

;ÄÄ ReleaseSample ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AX = sample to release (1 based)
;             DS:SI points to sample header
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ReleaseSample Far

                Ret

EndP            ReleaseSample

;ÄÄ ResetMemory ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  Frees all on-board memory
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetMemory Far

                PushA
                Push    DS
                Push    ES

                Push    CS
                Pop     DS
                Push    CS
                Pop     ES

                Mov     SI, Offset MMTData+6
                Mov     DI, Offset MemoryBlocks

ResetMemory1:
                Mov     AX, [SI]
                Add     SI, 6

                Cmp     AX, -1
                JE      ResetMemory2

                Cmp     AX, 1
                JNE     ResetMemory1

                Mov     EAX, [SI-4]
                StosD
                Neg     EAX
                Add     EAX, [SI+2]
                StosD
                Jmp     ResetMemory1

ResetMemory2:
                Mov     CX, Offset MemoryBlocks+NUMMEMORYBLOCKS*2*4
                Sub     CX, DI
                Xor     AX, AX
                ShR     CX, 1
                Rep     StosW

                Pop     ES
                Pop     DS
                PopA
                Ret

EndP            ResetMemory

;ÄÄ GetStatus ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  Returns text to show on status line, AX = display parameter
;  Carry set if not to show anything.
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetStatus Far

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     SI, Offset MemoryBlocks+4
                Mov     CX, NUMMEMORYBLOCKS
                Xor     EAX, EAX

GetStatus1:
                Add     EAX, [SI]
                Add     SI, 8
                Loop    GetStatus1

                Mov     SI, Offset StatusLine
                ShR     EAX, 9

                ClC
                Ret

EndP            GetStatus
                Assume DS:Nothing

;ÄÄ SoundCardScreen ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  Function to have driver interactive part of program
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SoundCardScreen Far

                Xor     AX, AX
                StC
                Ret

EndP            SoundCardScreen

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetVariable Far

                Ret

EndP            GetVariable

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetVariable Far

                Ret

EndP            SetVariable

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

EndDriver:

;********  Provided Variable Table *************

MaxNumberOfChannels     DW      64      ; Maximum number of channels the
                                        ; driver can handle.
StopAfterPlay           DW      0
DefaultChannels         DW      64

                        DW      5 Dup (0)

;********  Provided Procedure Table *************

ProvidedTableStart:

        DW      Offset DetectCard

        DW      Offset InitSound        ; Playing related
        DW      Offset ReinitSound
        DW      Offset UninitSound

        DW      Offset Poll

        DW      Offset SetTempo         ; Sound variable related
        DW      Offset SetMixVolume
        DW      Offset SetStereo

        DW      Offset LoadSample       ; Sample related
        DW      Offset ReleaseSample
        DW      Offset ResetMemory
        DW      Offset GetStatus        ; Returns string to show on status line

        DW      Offset SoundCardScreen  ; Sound card 'screen'

        DW      Offset GetVariable      ; For interface
        DW      Offset SetVariable

ProvidedTableEnd:
        DW      32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0)

EndS

End
