
.MODEL MEDIUM
UGROUP0 GROUP CODE_SEG0
ASSUME CS:UGROUP0, DS:UGROUP0, SS:UGROUP0

.386
CODE_SEG0 SEGMENT PAGE USE16
LOCALS xx
;-----------------------------------------------------------------------------
; Main Routine and Interface
; IN:  ES:BX = Zeiger auf Struktur
; OUT: AX = SoundcardType	;0=NO,1=SB/SBPRO,2=SB16,3=PAS,4=GUS
;
;	meaning		offset	size
;	baseport	 0	dw 0
;	dma_number	 2	db 0
;	irq_number	 3	db 0
;	samplerate	 4	dw 0
;	intern_type	 6	db 0
;	irq_type	 7	db 0
;	start_pos	 8	db 0
;	loop_pos	 9	db 0
;	song_mod	10	db 0
;	char master_vol	11	db 0
;	char music_vol	12	db 0
;	char fx_vol	13	db 0
;-----------------------------------------------------------------------------

PUBLIC _MAIN0
_MAIN0 PROC FAR
	CALL	DetectSound
	SETC	DL
	XOR	DH,DH
	MOV	AX,CS:SoundPort
	MOV	ES:[BX],AX
	MOV	AL,CS:SoundDMA
	MOV	ES:[BX+2],AL
	MOV	AL,CS:SoundIRQ
	MOV	ES:[BX+3],AL
	MOV	AX,22222
	MOV	ES:[BX+4],AX		;DEFAULT SAMPLERATE = 22222
	XOR	AX,AX
	MOV	ES:[BX+6],AL		;DEFAULT INTERN TYPE =  0
	MOV	ES:[BX+8],AL		;START_POS = 0
	MOV	ES:[BX+9],AL		;LOOP_POS = 0 (ENDLESS LOOPING)
	MOV	ES:[BX+10],AL		;SONG_MOD = 0
	INC	AL
	MOV	ES:[BX+7],AL		;IRQ DEFAULT TO WINDOWS (TIMER)
	DEC	AL
	DEC	AL
	MOV	ES:[BX+11],AL		;VOLUMES TO MAX
	MOV	ES:[BX+12],AL
	MOV	ES:[BX+13],AL
	MOV	AL,CS:SoundType
	CMP	AL,2
	JB	SHORT MEND
	JA	SHORT MT1
	DEC	AL
	MOV	ES:[BX+6],AL
	JMP	SHORT MEND
MT1:	CMP	AL,3
	JNE	SHORT MT2
	INC	AL
	JMP	SHORT MEND
MT2:	CMP	AL,4
	JNE	SHORT MT3
	DEC	AL
	JMP	SHORT MEND
MT3:	CMP	AL,5
	JNE	SHORT MEND
	MOV	AL,2
MEND:	RETF

SoundType       db      0	;0=no,1=SB,2=SBPro,3=GUS,4=PAS16,5=SB16
SoundPort       dw      0
SoundDMA        db      0
SoundIRQ        db      0

_MAIN0 ENDP

;-----------------------------------------------------------------------------
;(Auto)detect Soundkarte: c=0 ok

DetectSound proc near
                pusha
                push    ds es cs
                pop     es
                mov     di,offset xxULTRASND
                call    GetEnv
                jnc     short xxGUSEnv
xxSBNoGUS:      mov     di,offset xxBLASTER
                call    GetEnv
                jnc     short xxSBEnv
                xor     dx,dx
                mov     cs:SoundType,3
                call    DetGUSHW
                mov     cs:SoundPort,dx
                jnc     xxEndDetect
                mov     cs:SoundType,4
		call	detectPAS
		jnc	xxEndDetect
                mov     cs:SoundType,1

xxSBHW:         call    detectSBProHW
                jnc     xxEndDetect
                call    detectSBHW
                jnc     xxEndDetect
                jmp     xxErrorDetect

xxGUSEnv:       mov     cs:SoundType,3
                call    GetValue
                mov     cs:SoundPort,ax
                jc      short xxSBNoGUS
                call    GetValue
                mov     cs:SoundDMA,al
                jc      short xxSBNoGUS
                call    GetValue
                jc      short xxSBNoGUS
                call    GetValue
                mov     cs:SoundIRQ,al
                jc      short xxSBNoGUS

                mov     dx,cs:SoundPort
                call    DetGUSHW
                jc      short xxSBNoGUS
                jmp     short xxEndDetect

xxSBEnv:        mov     cs:SoundType,1
xxNextSB:       lodsb
                cmp     al,0
                je      short xxSBEnd
                and     al,11011111b

                cmp     al,'A'
                jne     short xxNoA
                call    GetValue
                mov     cs:SoundPort,ax
                jnc     short xxNextSB
                jmp     short xxSBEnd

xxNoA:          cmp     al,'I'
                jne     short xxNoI
                call    GetValue
                mov     cs:SoundIRQ,al
                jnc     short xxNextSB
                jmp     short xxSBEnd

xxNoI:          cmp     al,'D'
                jne     short xxNoD
                call    GetValue
                mov     cs:SoundDMA,al
                jnc     short xxNextSB
                jmp     short xxSBEnd

xxNoD:          cmp     al,'T'
                jne     short xxNextSB
                call    GetValue
                pushf
                cmp     al,3
                jb      short xxSBOld
                mov     cs:SoundType,2
                cmp     al,4
                jb      short xxSBOld
                mov     cs:SoundType,5
xxSBOld:        popf
                jnc     short xxNextSB

xxSBEnd:        xor     ax,ax
                cmp     cs:SoundPort,ax
                je      xxSBHW
                cmp     cs:SoundIRQ,al
                je      xxSBHW
                cmp     cs:SoundDMA,al
                je      xxSBHW

xxEndDetect:	xor	ax,ax
		cmp     cs:SoundPort,ax
                je      short xxErrorDetect
                cmp     cs:SoundIRQ,al
                je      short xxErrorDetect
                cmp     cs:SoundDMA,al
                je      short xxErrorDetect
                clc
                pop     es ds
                popa
                ret

xxErrorDetect:  stc
                mov     cs:SoundType,0
                jmp     short xxEndDetect

xxBLASTER       db      "BLASTER",0
xxULTRASND      db      "ULTRASND",0

DetectSound endp

;------------------------------------------------------------------------------
;Liest Wert (hex) ab ds:si, zurck in ax, c=1 String mit 0 terminiert

GetValue proc near

                push    bx

                xor     ax,ax
                xor     bx,bx

xxNoStart:      lodsb
                cmp     al,' '
                je      short xxNoStart
                jmp     short xxEntry

xxNext:         lodsb
xxEntry:        cmp     al,' '
                je      short xxEnd2
                cmp     al,','
                je      short xxEnd2
                and     al,11011111b
                cmp     al,40h
                jb      short xxNoChar
                add     al,9
xxNoChar:       and     al,0fh
                shl     bx,4
                add     bx,ax
                jmp     short xxNext

xxEnd1:         stc
                mov     ax,bx
                pop     bx
                ret

xxEnd2:         clc
                mov     ax,bx
                pop     bx
                ret

GetValue endp

;------------------------------------------------------------------------------
;holt Umgebungsvariable es:di, ds:si zeigt auf erstes Zeichen, c=1 Fehler

GetEnv proc near

                push    bx
                push    di
                push    es

                mov     ah,62h          ;ds:si points at dos env.
                int     21h
                mov     ds,bx
                mov     ds,ds:2ch
                xor     si,si

xxLoop3:        xor     bx,bx
xxLoop:         lodsb
                cmp     al,0
                je      short xxError
                cmp     al,es:[di+bx]
                jne     short xxNextOne
                inc     bx
                jmp     short xxLoop
xxNextOne:      cmp     al,'='
                jne     short xxLoop2
                cmp     es:[di+bx],byte ptr 0
                je      short xxGotIt
xxLoop2:        lodsb
                cmp     al,0
                jne     short xxLoop2
                jmp     short xxLoop3

xxError:        stc
                jmp     short xxEnde

xxGotIt:        clc

xxEnde:         pop     es
                pop     di
                pop     bx
                ret
GetEnv endp

;------------------------------------------------------------------------------
;Autodetect/Check GUS
;dx = port, dx = 0 -> autodetect, else check port

DetGUSHW proc near

                pusha
                push    ds
                push    es

                mov     bp,1
                mov     si,dx
                xor     di,di
                cmp     dx,di
                jne     short xxnoAutodetect
                mov     si,210h
                mov     bp,6
                mov     di,-1

xxnoAutodetect: mov bx,si

                mov cs:xxBasePort,bx
                add bx,6h
                mov cs:xxStatusPort,bx
                add bx,2+1+100h-9h+3
                mov cs:xxCommandPort,bx
                inc bx
                mov cs:xxDataLowPort,bx
                inc bx
                mov cs:xxDataHighPort,bx
                add bx,2
                mov cs:xxDRAMIOPort,bx

                mov bx,cs:xxCommandPort
                mov cx,cs:xxDataHighPort
                mov dx,bx
                mov al,4ch      ;Initialize
                out dx,al
                mov dx,cx
                mov al,0
                out dx,al
                mov dx,cs:xxBasePort
                REPT 8
                in al,dx
                ENDM

                mov dx,bx
                mov al,4Ch
                out dx,al
                mov dx,cx
                mov al,1
                out dx,al
                mov dx,cs:xxBasePort
                REPT 8
                in al,dx
                ENDM

                mov dx,bx
                mov al,41h      ;DMACtrl
                out dx,al
                mov dx,cx
                mov al,0
                out dx,al
                mov dx,bx
                mov al,45h
                out dx,al
                mov dx,cx
                mov al,0
                out dx,al
                mov dx,bx
                mov al,49h
                out dx,al
                mov dx,cx
                mov al,0
                out dx,al

                mov dx,bx
                mov al,0eh      ;VoicesActive
                out dx,al
                mov dx,cx
                mov al,20       ;NumVoices
                dec al
                or  al,0C0h
                out dx,al

                mov dx,cs:xxStatusPort
                in  al,dx
                mov dx,bx
                mov al,41h      ;DMACtrl
                out dx,al
                mov dx,cx
                in  al,dx
                mov dx,bx
                mov al,49h
                out dx,al
                mov dx,cx
                in  al,dx
                mov dx,bx
                mov al,8Fh
                out dx,al
                mov dx,cx
                in  al,dx

                mov dx,bx
                mov al,4ch
                out dx,al
                mov dx,cx
                mov al,7
                out dx,al

                mov dx,cs:xxCommandPort
                mov al,43h      ;DRAMAddrLo
                out dx,al
                mov dx,cs:xxDataLowPort
                mov ax,113h
                out dx,ax

                mov dx,cs:xxCommandPort
                mov al,44h      ;DRAMAddrHi
                out dx,al
                mov dx,cs:xxDataHighPort
                xor al,al
                out dx,al

                mov dx,cs:xxDRAMIOPort
                mov al,0d4h                             ;testwert 1 d4h
                out dx,al

                mov dx,cs:xxCommandPort
                mov al,43h      ;DRAMAddrLo
                out dx,al
                mov dx,cs:xxDataLowPort
                mov ax,12h                              ;testweise mal 12h beschreiben
                out dx,ax

                mov dx,cs:xxCommandPort
                mov al,44h      ;DRAMAddrHi
                out dx,al
                mov dx,cs:xxDataHighPort
                xor al,al
                out dx,al

                mov dx,cs:xxDRAMIOPort
                mov al,53h                              ;testwert 2 53h
                out dx,al


                mov dx,cs:xxCommandPort
                mov al,43h      ;DRAMAddrLo
                out dx,al
                mov dx,cs:xxDataLowPort
                mov ax,113h                             ;also testwert 1 lesen
                out dx,ax

                mov dx,cs:xxCommandPort
                mov al,44h      ;DRAMAddrHi
                out dx,al
                mov dx,cs:xxDataHighPort
                xor al,al
                out dx,al

                mov dx,cs:xxDRAMIOPort
                in  al,dx                               ;speicher lesen
                cmp al,0d4h                             ;testwert Ok ?
                jne short xxnotfound

                mov dx,cs:xxCommandPort
                mov al,43h      ;DRAMAddrLo
                out dx,al
                mov dx,cs:xxDataLowPort
                mov ax,12h                              ;testoffset 2
                out dx,ax

                mov dx,cs:xxCommandPort
                mov al,44h      ;DRAMAddrHi
                out dx,al
                mov dx,cs:xxDataHighPort
                xor al,al
                out dx,al

                mov dx,cs:xxDRAMIOPort
                in  al,dx
                cmp al,53h                              ;wert = testwert 2 ?
                jne short xxnotfound                    ;n, nicht gefunden
                jmp short xxfoundGUS
xxnotfound:
                cmp di,0ffffh
                jne short xxno
                add si,10h
                dec bp
                jnz xxnoAutodetect
xxno:
                pop es
                pop ds
                popa
                xor dx,dx
                stc                                     ;Carry setzen
                ret

xxfoundGUS:     pop     es
                pop     ds
                popa
                mov dx,cs:xxBasePort
                clc
                ret

xxBasePort      dw      0
xxStatusPort    dw      0
xxCommandPort   dw      0
xxDataLowPort   dw      0
xxDataHighPort  dw      0
xxDRAMIOPort    dw      0

DetGUSHW endp

; /***********************************************************************
; *
; *     File        : DETSBHW.ASM
; *
; *     Description : Sound Blaster hardware detection routines
; *
; ************************************************************************

waitSB MACRO
	local	l1
l1:
	in	al,dx
	or	al,al
        js      short l1
ENDM

waitSBport MACRO
	local	l1

        mov     dx,cs:SoundPort
	add	dx,0Ch
l1:
	in	al,dx
	or	al,al
        js      short l1
ENDM

waitSBPROport MACRO
	local	l1

        mov     dx,cs:SoundPort
	add	dx,0Ch
l1:
	in	al,dx
	or	al,al
        js      short l1
ENDM

;/*************************************************************************
; *
; *	Function    : 	checkPort_SB
; *
; *	Description :   Checks if given address is SB's I/O address
; *
; *	Input       : 	DX = port to check
; *
; *	Returns     :	AX = 0	successful
; *		      	AX = 1	unsuccessful
; *
; ************************************************************************/

checkPort_SB proc near

	push	dx
	add	dl,6			; Init Sound Blaster
	mov	al,1
	out	dx,al
	in	al,dx			; Wait for awhile
	in	al,dx
	in	al,dx
	in	al,dx
	in	al,dx
	mov	al,0
	out	dx,al
	sub	dl,6

	add	dl,0Eh          	; DSP data available status
	mov	cx,1000
xxloop:
	in	al,dx			; port 22Eh
	or	al,al
        js      short xx10
        loop    short xxloop

	mov	ax,1
        jmp     short xxexit
xx10:
	sub	dl,4
	in	al,dx			; port 22Ah
	cmp	al,0AAh			; Is ID 0AAh?
	mov	ax,0
        je      short xxexit
	mov	ax,1
xxexit:
	pop	dx
	or	ax,ax			; Set zero-flag accordingly
	ret

checkPort_SB endp

;/*************************************************************************
; *
; *	Function    : 	findDMAIRQ_SB
; *
; *	Description :	Finds SB's DMA interrupt number
; *
; *	Returns     :	AX = 0	error
; *			AX = port number (2,3,5,7)
; *
; ************************************************************************/

findDMAIRQ_SB proc near

        push    ds
        push    es

	mov	ah,35h
	mov	al,8+2
	int	21h
        mov     cs:xxsaveVect+2,es
        mov     cs:xxsaveVect,bx
	mov	al,8+3
	int	21h
        mov     cs:xxsaveVect+6,es
        mov     cs:xxsaveVect+4,bx
	mov	al,8+5
	int	21h
        mov     cs:xxsaveVect+10,es
        mov     cs:xxsaveVect+8,bx
	mov	al,8+7
	int	21h
        mov     cs:xxsaveVect+14,es
        mov     cs:xxsaveVect+12,bx

	mov	ah,25h
	mov	dx,offset DMA2		; Set vectors
	mov	al,8+2
	int	21h
	mov	dx,offset DMA3
	mov	al,8+3
	int	21h
	mov	dx,offset DMA5
	mov	al,8+5
	int	21h
	mov	dx,offset DMA7
	mov	al,8+7
	int	21h

	in	al,21h
        mov     cs:xxintMask,al            ; Save interrupt mask
	mov	al,0FFh
	out	21h,al			; Mask out all interrupts
	cli				; Disable interrupts

        mov     al,cs:xxintMask
	and	al,01010011b		; Allow DMA interrupts (2,3,5 & 7)
	out	21h,al
	sti				; Set DMA up

	mov	al,5
	out	0Ah,al			; Break on
	mov	al,0
	out	0Ch,al			; Reset counter
	mov	al,49h
	out	0Bh,al			; DMA -> DSP (output)
	mov	al,0
	out	83h,al			; page 0
	mov	al,0
	out	2,al			; offset 0
	mov	al,0
	out	2,al			; whole address is 0000:0000
	mov	al,1
	out	3,al			; count = 1
	mov	al,0
	out	3,al
	mov	al,1
	out	0Ah,al			; Break off

        mov     dx,cs:SoundPort
	add	dx,0Ch
	waitSB
	mov	al,40h                  ; Set DSP speed
	out	dx,al
	waitSB
	mov	al,0D3h			; 22222 Hz
	out	dx,al
	waitSB
	mov	al,14h			; 14h = output command
	out	dx,al
	waitSB
	mov	al,1			; digitize 1 byte
	out	dx,al
	waitSB
	mov	al,0
	out	dx,al
	mov	cx,0FFFFh		; Big loop
        mov     cs:SoundIRQ,byte ptr 0  ; Clear interrupt value
xxloop:
        cmp     cs:SoundIRQ,byte ptr 0  ; Wait dmaIRQ to change
        loope   short xxloop            ; loop if it doesn't
        mov     dx,cs:SoundPort
	add	dl,0Eh
	in	al,dx			; Reset SB

        mov     al,cs:xxintMask
	out	21h,al			; Restore interrupt mask
	sti				; Allow interrupts

        push    ds
	mov	ah,25h
        lds     dx,dword ptr cs:xxsaveVect
	mov	al,8+2
	int	21h
        lds     dx,dword ptr cs:xxsaveVect+4
	mov	al,8+3
	int	21h
        lds     dx,dword ptr cs:xxsaveVect+8
	mov	al,8+5
	int	21h
        lds     dx,dword ptr cs:xxsaveVect+12
	mov	al,8+7
	int	21h
        pop     ds

        pop     es
        pop     ds

	sub	ax,ax
        mov     al,cs:SoundIRQ             ; Return with interrupt number
        ret

xxsaveVect      dw      8 dup(0)
xxintMask       db      0

findDMAIRQ_SB endp

;/*************************************************************************
; *
; *	Function    : 	findDMAIRQ_SBpro
; *
; *	Description :	Finds SBpro's DMA interrupt number
; *
; *	Returns     :	AX = 0	error
; *                     AX = IRQ number (2,3,5,7,10)
; *
; ************************************************************************/

findDMAIRQ_SBpro proc near

        push    ds
        push    es

	mov	ah,35h
	mov	al,8+2
	int	21h
        mov     cs:xxsaveVect+2,es
        mov     cs:xxsaveVect,bx
	mov	al,8+5
	int	21h
        mov     cs:xxsaveVect+6,es
        mov     cs:xxsaveVect+4,bx
	mov	al,8+7
	int	21h
        mov     cs:xxsaveVect+10,es
        mov     cs:xxsaveVect+8,bx
	mov	al,72h
	int	21h
        mov     cs:xxsaveVect+14,es
        mov     cs:xxsaveVect+12,bx

	in	al,21h
        mov     cs:xxintMask1,al           ; Save interrupt mask
	mov	al,0FFh
	out	21h,al			; Mask out all interrupts
	in	al,0A1h
        mov     cs:xxintMask2,al           ; Save interrupt mask
	mov	al,0FFh
	out	0A1h,al			; Mask out all interrupts
	cli				; Disable interrupts

        push    cs
        pop     ds
	mov	ah,25h
	mov	dx,offset DMA2		; Set vectors
	mov	al,8+2
	int	21h
	mov	dx,offset DMA5
	mov	al,8+5
	int	21h
	mov	dx,offset DMA7
	mov	al,8+7
	int	21h
	mov	dx,offset DMA10
	mov	al,72h
	int	21h

        mov     al,cs:xxintMask1
	and	al,01010011b		; Allow DMA interrupts (2,3,5 & 7)
	out	21h,al
        mov     al,cs:xxintMask2
	and	al,11111011b		; Allow DMA interrupt 10
	out	0A1h,al
	sti

	mov	cx,1000
xxwaitloop:
	in	al,21h
        loop    short xxwaitloop

	mov	al,4
	out	0Ah,al			; Break on
	mov	al,5
	out	0Ah,al			; Break on
	mov	al,7
	out	0Ah,al			; Break on

        mov     dx,cs:SoundPort
	add	dx,0Ch
	waitSB
	mov	al,40h                  ; Set DSP speed
	out	dx,al
	waitSB
	mov	al,0D3h			; 22222 Hz
	out	dx,al
	waitSB
	mov	al,14h			; 14h = output command
	out	dx,al
	waitSB
	mov	al,10			; digitize 1 byte
	out	dx,al
	waitSB
	mov	al,0
	out	dx,al
	sti

	mov	ax,1			; Check for DMA channel 1
        call    findDMAchannel_SBpro
	or	ax,ax
        jnz     short xxchannelFound
	mov	ax,0			; Channel 0
        call    findDMAchannel_SBpro
	or	ax,ax
        jnz     short xxchannelFound
	mov	ax,3			; Channel 3
        call    findDMAchannel_SBpro
	or	ax,ax
        jnz     short xxchannelFound
        mov     cs:SoundIRQ,0
xxchannelFound:
        mov     cs:SoundDMA,al

        mov     dx,cs:SoundPort
	add	dl,6			; Init Sound Blaster
	mov	al,1
	out	dx,al
	in	al,dx			; Wait for awhile
	in	al,dx
	in	al,dx
	in	al,dx
	in	al,dx
	mov	al,0
	out	dx,al
	sub	dl,6

	add	dx,0Eh			; Reset SB
	in	al,dx

        push    ds
	mov	ah,25h
        lds     dx,dword ptr cs:xxsaveVect
	mov	al,8+2
	int	21h
        lds     dx,dword ptr cs:xxsaveVect+4
	mov	al,8+5
	int	21h
        lds     dx,dword ptr cs:xxsaveVect+8
	mov	al,8+7
	int	21h
        lds     dx,dword ptr cs:xxsaveVect+12
	mov	al,72h
	int	21h
        pop     ds

        mov     al,cs:xxintMask1
	out	21h,al			; Restore interrupt mask
        mov     al,cs:xxintMask2
	out	0A1h,al			; Restore interrupt mask
        sti                             ; Allow interrupts

        pop     es
        pop     ds

	sub	ax,ax
        mov     al,cs:SoundIRQ        ; Return with interrupt number
        ret

xxsaveVect      dw      8 dup(0)
xxintMask1      db      0
xxintMask2      db      0

findDMAIRQ_SBpro endp

;/*************************************************************************
; *
; *	Function    :	findDMAchannel_SBpro
; *
; *	Description :	Checks if given channel is the channel SBPro uses
; *
; *	Input       :	AX = Channel to test
; *
; *	Returns     :	AX = 0 if error
; *			AX = channel if OK
; *
; ************************************************************************/

findDMAchannel_SBpro proc near

        mov     cs:xxchannel,al
	add	al,4
	out	0Ah,al			; Break on
	mov	al,0
	out	0Ch,al			; Reset counter
	mov	al,48h
        add     al,cs:xxchannel
	out	0Bh,al			; DMA -> DSP (output)
	mov	dx,87h
        cmp     cs:xxchannel,byte ptr 0
        je      short xx10
	mov	dx,83h
        cmp     cs:xxchannel,byte ptr 1
        je      short xx10
	mov	dx,82h			; Channel is 3
xx10:
	mov	al,0
	out	dx,al			; page 0
        mov     dl,cs:xxchannel
	shl	dx,1
	mov	al,0
	out	dx,al			; offset 0
	mov	al,0
	out	dx,al			; whole address is 0000:0000
	inc	dx
	mov	al,10
	out	dx,al			; count = 10
	mov	al,0
	out	dx,al
        mov     al,cs:xxchannel
	out	0Ah,al			; Break off

	mov	cx,0FFFFh		; Big loop
        mov     cs:SoundIRQ,byte ptr 0  ; Clear interrupt value
xxloop:
        cmp     cs:SoundIRQ,byte ptr 0  ; Wait dmaIRQ to change
        loope   short xxloop            ; loop if it doesn't

        mov     al,cs:xxchannel
	add	al,4
	out	0Ah,al			; Break on
	mov	al,0
	out	0Ch,al			; Reset counter
        mov     al,cs:xxchannel
	out	0Ah,al			; Break off

	sub	ax,ax
        cmp     cs:SoundIRQ,byte ptr 0
        je      short xxexit
	inc	ah			; Indicate success
        mov     al,cs:xxchannel
xxexit:
	ret

xxchannel       db      0

findDMAchannel_SBpro endp

;/*************************************************************************
; *
; *	Function    : 	DMAint_SB
; *
; *	Description :	Interrupt function that determines SB's interrupt
; *
; ************************************************************************/

DMAint_SB proc near

DMA2:
        push    ds
	push	ax
        mov     cs:SoundIRQ,byte ptr 2               ; Set interrupt number
        jmp     short xxDMAdone
DMA3:
        push    ds
	push	ax
        mov     cs:SoundIRQ,byte ptr 3
        jmp     short xxDMAdone
DMA5:
        push    ds
	push	ax
        mov     cs:SoundIRQ,byte ptr 5
        jmp     short xxDMAdone
DMA7:
        push    ds
	push	ax
        mov     cs:SoundIRQ,byte ptr 7
        jmp     short xxDMAdone
DMA10:
        push    ds
	push	ax
        mov     cs:SoundIRQ,byte ptr 10
	mov	al,20h
	out	0A0h,al
xxDMAdone:
	mov	al,20h
	out	20h,al			; EOI (end of interrupt)
	pop	ax
        pop     ds
	iret

DMAint_SB endp

;/*************************************************************************
; *
; *	Function    :	detectSB
; *
; *	Description :	Checks for presence of SB.
; *
; *	Returns     :	c=0  if succesful
; *			c=1  on error (no card found)
; *
; ************************************************************************/

detectSBHW proc near

        mov     cs:xxretvalue,word ptr -1           ; Assume failure
	mov	dx,220h
	call	checkPort_SB
        jz      short xxOK
	mov	dx,210h
	call	checkPort_SB		; Check for every possible I/O value
        jz      short xxOK
	mov	dx,230h
	call	checkPort_SB
        jz      short xxOK
	mov	dx,240h
	call	checkPort_SB
        jz      short xxOK
	mov	dx,250h
	call	checkPort_SB
        jz      short xxOK
	mov	dx,260h
	call	checkPort_SB
        jnz     short xxexit                  ; No match found, error exit
xxOK:
        mov     cs:SoundPort,dx       ; ioPort is for internal use only

        push    es
	push	di
        call    findDMAIRQ_SB           ; Find DMA interrupt number
	pop	di
        pop     es
	or	ax,ax			; 0 = error
        jz      short xxexit
        mov     cs:SoundIRQ,al
        mov     cs:SoundDMA,1

        mov     cs:xxretrycount,word ptr 10
xxretry:
        dec     word ptr cs:xxretrycount
        jnz     short xxcontinue
	mov	ax,0			; not found
        jmp     short xxdone
xxcontinue:
        mov     dx,cs:SoundPort
	add	dx,0Ch
	waitSB
	mov	al,0E1h			; Read version number
	out	dx,al

	add	dl,2			; DX = 22Eh
	sub	al,al
	mov	cx,1000
xx10:
        in      al,dx                   ; Read version high
	or	al,al
        js      short xx10ok
        loop    short xx10
        jmp     short xxretry
xx10ok:
	mov	cx,1000
	sub	dl,4
	in	al,dx
	mov	ah,al

	add	dl,4
	sub	al,al
xx20:
	in	al,dx			; Read version low
	or	al,al
        js      short xx20ok
        loop    short xx20
        jmp     short xxretry
xx20ok:
	sub	dl,4
	in	al,dx
xxdone:
        mov     cs:xxretvalue,word ptr 0
xxexit:
        mov     ax,cs:xxretvalue
        or      ax,ax
        jne     short xxexiterror
        clc
	ret
xxexiterror:
        stc
        ret

xxretvalue      dw      0
xxretrycount    dw      0

detectSBHW endp

;/*************************************************************************
; *
; *     Function    :   detectSBProHW
; *
; *	Description :	Checks for presence of SB Pro.
; *
; *	Returns     :	c=0  if succesful
; *			c=1  on error (no card found)
; *
; ************************************************************************/

detectSBProHW proc near

        mov     cs:xxretvalue,word ptr -1           ; Assume failure
	mov	dx,220h
	call	checkPort_SB
        jz      short xxOK
	mov	dx,210h
	call	checkPort_SB		; Check for every possible I/O value
        jz      short xxOK
	mov	dx,230h
	call	checkPort_SB
        jz      short xxOK
	mov	dx,240h
	call	checkPort_SB
        jz      short xxOK
	mov	dx,250h
	call	checkPort_SB
        jz      short xxOK
	mov	dx,260h
	call	checkPort_SB
        jnz     xxexit                  ; No match found, error exit
xxOK:
        mov     cs:SoundPort,dx       ; ioPort is for internal use only

        mov     cs:xxretrycount,word ptr 10
xxretry:
        dec     word ptr cs:xxretrycount
        jnz     short xxcontinue
	mov	ax,0			; not found
        jmp     short xxdone
xxcontinue:
        mov     dx,cs:SoundPort
	add	dx,0Ch
	waitSB
	mov	al,0E1h			; Read version number
	out	dx,al

	add	dl,2			; DX = 22Eh
	sub	al,al
	mov	cx,1000
xx10:
	in	al,dx			; Read version high
	or	al,al
        js      short xx10ok
        loop    short xx10
        jmp     short xxretry
xx10ok:
	mov	cx,1000
	sub	dl,4
	in	al,dx
	mov	ah,al

	add	dl,4
	sub	al,al
xx20:
	in	al,dx			; Read version low
	or	al,al
        js      short xx20ok
        loop    short xx20
        jmp     short xxretry
xx20ok:
	sub	dl,4
	in	al,dx
xxdone:
	cmp	ax,0300h
        jl      short xxexit            ; Not SBpro
	mov	cs:SoundType,2		;is sb16
	cmp	ax,0400h
	jl	short xxpro
	mov	cs:SoundType,5		;is sb16
xxpro:
        push    es
        push    di
        call    findDMAIRQ_SBpro        ; Find DMA interrupt number
	pop	di
        pop     es
	or	ax,ax			; 0 = error
        jz      short xxexit
        mov     cs:SoundIRQ,al

        mov     cs:xxretvalue,word ptr 0
xxexit:
        mov     ax,cs:xxretvalue
        or      ax,ax
        jne     short xxexiterror
        clc
	ret
xxexiterror:
        stc
        ret

xxretvalue      dw      0
xxretrycount    dw      0

detectSBProHW endp

;/*************************************************************************
; *
; *     Function    :   detectPAS
; *
; *	Description :	Checks for presence of PAS16.
; *
; *	Returns     :	c=0  if successful
; *			c=1  on error (no card found)
; *
; ************************************************************************/

DEFAULT_BASE	EQU	00388h		;; default base I/O address
ALT_BASE_1	EQU	00384h		;; first alternate address
ALT_BASE_2	EQU	0038Ch		;; second alternate address
ALT_BASE_3	EQU	00288h		;; third alternate address
ALT_BASE_4	EQU	00280h		;; 4th alternate address
ALT_BASE_5	EQU	00284h		;; 5th alternate address
ALT_BASE_6	EQU	0028Ch		;; 6th alternate address
INTRCTLR	EQU	00B8Bh		;; Interrupt Control Register write
fICrevbits	EQU	11100000B	;; revision mask field bits

detectPAS proc near
        mov     di,DEFAULT_BASE         ; try the first address
	mov	SoundPort,di
	call	SearchHWVersion
	jnc	xxpas_ok

	mov	di,ALT_BASE_1		; try the first alternate
	mov	SoundPort,di
	call	SearchHWVersion
	jnc	xxpas_ok

	mov	di,ALT_BASE_2		; try the second alternate
	mov	SoundPort,di
	call	SearchHWVersion
	jnc	xxpas_ok

	mov	di,ALT_BASE_3		; try the third alternate
	mov	SoundPort,di
	call	SearchHWVersion
	jnc	xxpas_ok

	mov	di,ALT_BASE_4		; try the 4th alternate
	mov	SoundPort,di
	call	SearchHWVersion
	jnc	xxpas_ok

	mov	di,ALT_BASE_5		; try the 5th alternate
	mov	SoundPort,di
	call	SearchHWVersion
	jnc	xxpas_ok

	mov	di,ALT_BASE_6		; try the 6th alternate
	mov	SoundPort,di
	call	SearchHWVersion
xxpas_ok:
	ret
detectPAS endp

;   /*\
;---|*|----====< SearchHWVersion >====----
;---|*|
;---|*| Given a specific I/O address, this routine will see if the
;---|*| hardware exists at this address.
;---|*|
;---|*| Entry Conditions:
;---|*|     DI holds the I/O address to test
;---|*|
;---|*| Exit Conditions:
;---|*|     c=0 ok
;---|*|     c=1 no card found
;   \*/

SearchHWVersion proc near
;
; calculate the translation code
;
	xor	di,DEFAULT_BASE 	; di holds the translation code
	mov	ax,0BC00H		; make sure MVSOUND.SYS is loaded
	mov	bx,'??'                 ; this is our way of knowing if the
	xor	cx,cx			; hardware is actually present.
	xor	dx,dx
	int	2fh			; get the ID pattern
	xor	bx,cx			; build the result
	xor	bx,dx
	cmp	bx,'MV'                 ; if not here, exit...
	jnz	xxbad
;
; get the MVSOUND.SYS specified DMA and IRQ channel
;
        mov     ax,0bc04h               ; get the DMA and IRQ numbers
	int	2fh
	mov	cs:SoundDMA,bl		; save the correct DMA & IRQ
	mov	cs:SoundIRQ,cl
;
; grab the version # in the interrupt mask. The top few bits hold the version #
;
        mov     dx,INTRCTLR             ; board ID is in MSB 3 bits
	xor	dx,di			; adjust to other address
	in	al,dx
	cmp	al,-1			; bus float meaning not present?
	je	xxbad			; yes, there is no card here
	mov	ah,al			; save an original copy
	xor	al,fICrevbits		; the top bits wont change
	out	dx,al			; send out the inverted bits
	jmp	xxl1
xxl1:	jmp	xxl2
xxl2:	in	al,dx			; get it back...
	cmp	al,ah			; both should match now...
	xchg	al,ah			; (restore without touching the flags)
	out	dx,al
	jnz	xxbad			; we have a bad board
;
; We do have hardware! Load the product bit definitions
;
	clc
	ret
xxbad:	stc
	ret
SearchHWVersion endp

CODE_SEG0 ENDS

END _MAIN0