; Audiolib.asm
; Chris Evans feb 12 2007

Sndpnext      dd 0ffff0000h
Snddevattr    dw 1000000000000100b 
Sndstrategy   dw offset _snd_strategy
Sndinterrupt  dw offset _snd_interrupt
Snd_device    db 'ADLIB   ' ; Blank-padded device (or 10-byte block device sub-unit number)
; Jump table 
sndtable      db 9
              dw cs:snd_init    ; 0 - initialize driver
              dw cs:snd_err     ; 1 - media change check 
              dw cs:snd_err     ; 2 - build BPB
              dw cs:snd_err     ; 3 - IOCTL string output
              dw cs:snd_err     ; 4 - input
              dw cs:snd_err     ; 5 - nondestructive input
              dw cs:snd_err     ; 6 - input status
              dw cs:snd_err     ; 7 - input flush
              dw cs:snd_err     ; 8 - output
              dw cs:snd_err     ; 9 - output w/ verify
SbIOaddr      dw 210h
sbaddr        dw 220h
SbIRQ         dw 3
adlib         db 0

SND:


snd_init proc far
;         _output Snd_device, 8, 1
    call Is_HPDV5
    jc   no_adlib_init
         call cs:detect_adlib
         mov  cs:adlib, al
         ; Autodetects soundblaster
         ; BUG - 4/29/07 - Caused crap on screen on this HP pavilion dv5000 laptop
         call cs:get_sb_addr
no_adlib_init:
         ret
_snd_strategy:
        mov  word ptr [cs:reqpktptr], bx
        mov  word ptr [cs:reqpktptr+2], es
        retf
    ;    mov ds, ax
    ;    mov byte ptr ds:[417h], 0
    ;    int 20h
    ;    ret
_snd_interrupt:
        push es
        push bx
        les  bx, [cs:reqpktptr]
        or   word ptr es:[bx+3], 100h  ; set done flag
        pop  bx
        pop  es
        retf
snd_init endp

snd_err  proc far
        
         ret
snd_err  endp

audiolib_trapirq         Proc    Far
                push    dx                      ; General IRQ trapper
                push    ds                      ; used for IRQ autodetect.
                ;mov     dx,@Data
                ;mov ds, dx
                mov     [SbIrq],ax              ; save IRQ level.
                mov dx, cs:[SbioAddr]
                add     dx,0Eh
                in      al,dx                   ; SB acknowledge.
                mov     al,20h
                out     20h,al                  ; Hardware acknowledge.
                pop ds
                pop dx
                pop ax
                iret                            ; bye!

audiolib_trapirq2:
         push ax
         mov  ax, 2
         jmp audiolib_trapirq
audiolib_trapirq3:
         push ax
         mov  ax, 3
         jmp audiolib_trapirq
audiolib_trapirq5:
         push ax
         mov  ax, 5
         jmp audiolib_trapirq
audiolib_trapirq7:
         push ax
         mov  ax, 7
         jmp audiolib_trapirq
audiolib_trapirq EndP

get_sb_addr proc far
; begin at 210, 220, .. 260  
ScanPort:
        mov  bx, 210h                                               
Reset_SB_DSP:
        mov  dx, bx
        add  dx, 06h
        mov  al, 1
        OUT  dx, al            ; reset DSP
        in   al, dx
        in   al, dx
        in   al, dx
        in   al, dx
        xor  al, al
        OUT  dx, al
        add  dx, 08h
        mov  cx, 100
WaitID_SB:
        in   al, dx
        or   al, al
        js   GetID_SB
        loop WaitID_SB
        jmp  NPSB
GetID_SB:
        sub  dx, 04h
        in   al, dx
        cmp  al, 0AAh
        je   FoundSB
        add  dx, 04h
        loop WaitID_SB
NPSB:
        add  bx, 10h                  ; if not response,
        cmp  bx, 260h                 ; try the next port.
        jbe  Reset_SB_DSP
        jmp  FailSB
FailSB:
        mov  ax, 0
        mov  cs:[SbioAddr], ax
        jmp  AudioFail
FoundSB:
        mov  cs:[SbioAddr], bx             ; SB Port Address Found!
ScanIRQ:
        cli
        in   al, 21h                  ; save the IMR.
        mov  bl, al
        mov  al, 11111111b            ; disable all the IRQs.
        out  21h, al
        xor  ax, ax                   ; trap the IRQs 2,3,5,7.
        mov  es, ax
SaveIrqs:
        mov  ax, es:[28h]             ; irq2
        mov  dx, es:[2Ah]
        push ax
        push dx
        mov  ax, es:[2Ch]             ; irq3
        mov  dx, es:[2Eh]
        push ax
        push dx
        mov  ax, es:[34h]             ; irq5
        mov  dx, es:[36h]
        push ax
        push dx
        mov  ax, es:[3Ch]             ; irq7
        mov  dx, es:[3Eh]
        push ax
        push dx
SetIrqs:
        mov  ax, offset audiolib_trapirq2      ; irq2
        mov  es:[28h], ax
        mov  es:[2Ah], cs
        mov  ax, offset audiolib_trapirq3      ; irq3
        mov  es:[2Ch], ax
        mov  es:[2Eh], cs
        mov  ax, offset audiolib_trapirq5      ; irq5
        mov  es:[34h], ax
        mov  es:[36h], cs
        mov  ax, offset audiolib_trapirq7      ; irq7
        mov  es:[3Ch], ax
        mov  es:[3Eh], cs
EnableIrqs:
        mov  al, bl                   ; enable IRQs 2,3,5,7.
        and  al, 01010011b
        out  21h, al
        sti
        mov  cs:[SbIrq], 0               ; clear the IRQ level.
        mov  dx, cs:[SbioAddr]             ; tells to the SB to
        add  dx, 0Ch                  ; generate a IRQ!
WaitSb:
        in   al, dx
        or   al, al
        js   WaitSb
        mov  al, 0F2h
        OUT  dx, al
        xor  cx, cx                   ; wait until IRQ level
WaitIRQ:
        cmp  cs:[SbIrq], 0               ; is changed or timeout.
        jne  IrqOk
        loop WaitIRQ
IrqOk:
        mov  al, bl                   ; restore IMR.
        out  21h, al
RestoreIrqs:
        cli                             ; restore IRQ vectors.
        xor  ax, ax
        mov  es, ax
        pop  dx                      ; irq7
        pop  ax
        mov  es:[3Ch], ax
        mov  es:[3Eh], dx
        pop  dx                      ; irq5
        pop  ax
        mov  es:[34h], ax
        mov  es:[36h], dx
        pop  dx                      ; irq3
        pop  ax
        mov  es:[2Ch], ax
        mov  es:[2Eh], dx
        pop  dx                      ; irq2
        pop  ax
        mov  es:[28h], ax
        mov  es:[2Ah], dx
        cli
        cmp  cs:[SbIrq], 0               ; IRQ level was changed?
        je   short AudioFail               ; no, fail.
SBSuccess:
        mov  dx, cs:[SbioAddr]
        mov  bx, cs:[SbIrq] 
AudioFail:
        ret
get_sb_addr endp

audioinfo proc far
        mov  al, cs:adlib
        or   al, al
        jz   _sh_nadlib
        _output Snd_device, 8, 1
_sh_nadlib:
        mov  ax, cs:sbioaddr
        cmp  ax, 0
        je   no_sblaster
        push ax
        _echo 'S'
        _echo 'B'
        pop  ax
        call put_hex
        _echo ' '
        _echo 'I'
        _echo 'R'
        _echo 'Q'
        mov  ax, cs:sbirq
        call puthex8
no_sblaster:
        _newline
        ret
audioinfo endp

audio_info proc far
      xor  ax, ax
      mov  ax, cs:sbioaddr
      add  al, cs:adlib
      or   ax, ax
      jz   no_ainfo4u
           call audioinfo
no_ainfo4u:
        ret
audio_info endp

