Metropoli BBS
VIEWER: sb_xsd.asm MODE: TEXT (ASCII)
.386P
; DO NOT USE IT, I JUST STARTED CODING, LOTS OF THINGS ARE MISSING!!

code32  segment para public use32
        assume cs:code32, ds:code32

include 386power.inc
include vdma.inc
include 386timer.inc

; XVD SOUNDBLASTER DRIVER
sb_base dd 0
sb_irqn dd 7
sb_dmac dd 1
sb_type dd 0

; some useful i/o port offsets from sb_base
dsp_reset dd  6
sb_fm     dd  8
sb_fmdata dd  9
dsp_read  dd 0ah
dsp_write dd 0ch
dsp_avail dd 0eh

; dsp commands
dma8_dac      =  14h
time_constant =  40h
halt_dma      = 0d0h
cont_dma      = 0d4h
speaker_on    = 0d1h
speaker_off   = 0d3h
dsp_id        = 0e0h
dsp_ver       = 0e1h

; sb_types
sb_1_5 =1
sbpro  =2
sb_2_0 =3

sbwrite: ; in: ah = byte to write to dsp   , out: eax,edx modified
        mov edx,dsp_write
sbw:    in al,dx
        test al,080h
        jnz sbw
        mov al,ah
        out dx,ax
        ret

sbread: ; edx modified   out: al = byte read from dsp
        mov edx,dsp_avail
sbr:    in al,dx
        test al,80h
        jz sbr
        sub dl,4
        in al,dx
        ret

; DAC 8bit mono DMA allowed frequencies for a plain soundblaster
; 4khz ... 23khz
; you set the playback frequency sending a time_constant command
; and then sending the t_c byte equivalent to the requested frequency
;
; t_c = 256 - (1000000/frequency)
;
; then you need to calculate the actual playback frequency you set
; (there are rounding errors)
;
; actual_frequency = 1000000/(256 - t_c)
;

setfreq: ; in:  eax= requested frequency
         ; out: eax= nearest supported frequency
         push edx
         push ebx
         cmp eax,4000
         jg goodlow
         mov eax,4000
goodlow: cmp eax,23000
         jl goodhi
         mov eax,23000
goodhi:  xor edx,edx
         mov ebx,eax
         mov eax,1000000
         div ebx
         sub eax,256
         neg eax
         shl eax,16 ; save t_c into upper word
         mov ah,time_constant
         call sbwrite
         shr eax,8 ; t_c into ah
         call sbwrite
         ; now get back the actual playback frequency
         shr eax,8 ; eax == t_c
         mov ebx,256
         xor edx,edx
         sub ebx,eax
         mov eax,1000000
         div ebx
         ; eax = actual frequency
         pop ebx
         pop edx
         ret

sbirq_ack macro
          mov edx,dsp_avail
          in al,dx
          ; sb irq acknowledged , now notify the eoi to the P.I.C.
          endm

sbsound   macro
          mov ah,speaker_on
          call sbwrite
          endm

nosbsound macro
          mov ah,speaker_off
          call sbwrite
          endm

no_blast db 'SoundBlaster XSD DRIVER: DSP timeout or 386Timer too fast',CR,LF
         db '     Maybe soundblaster not present or wrong base address',CR,LF,'$'

error_no_blaster:
        mov 386Return,offset no_blast
        jmp _Exit
; reset sound blaster dsp

dspreset:
         pushad
         mov edx,dsp_reset
         mov al,01
         out dx,al
recaliber:
         call _ReadTimer
         lea ebx,[eax+10]
         cmp eax,ebx
         jnb  recaliber
skid3:   call _ReadTimer
         cmp eax,ebx
         jb skid3
         mov edx,dsp_reset
         xor al,al
         out dx,al
xrecaliber:
         call _ReadTimer
         lea ebx,[eax+400]
         cmp eax,ebx
         jnb  xrecaliber
skid100: mov edx,dsp_read
         in al,dx
         cmp al,0AAh
         je gotcha
         call _ReadTimer
         cmp eax,ebx
         jb skid100
         jmp error_no_blaster
gotcha:  popad
         ret

; ENVIRONMENT SCANNER
;
; The environment segment is a sequence of ASCIIZ strings
; following the format "var=value",0
; and terminated by a null string (a single code 0 character)

ENV_SEG= 2ch
SPACE=32
TAB=9

envfind: ; in:  esi = ptr to ASCIIZ string containing the invironment var. name
         ; out: esi = ptr to ASCIIZ string (by way of the 4GW wraparound)
         ;            containing the environment var. "value"
         ;            n.b. read it but do not modify it!!!!!!

        push edx
        push ebx
        push eax
        mov edx,_PSPBase
        add edx,ENV_SEG
        movzx edx,word ptr gs:[edx]
        shl edx,4
        sub edx,_Code32Base
estring:
        mov ebx,esi
eqchar: mov al,[edx]
        cmp al,SPACE
        je skiip
        cmp al,TAB
        je skiip
        cmp al,[ebx]
        jne naah
        inc ebx
skiip:
        inc edx
        jmp short eqchar

naah:   cmp al,'='
        jne findend
        cmp byte ptr [ebx],0
        je cuccato
findend:
        cmp ebx,esi
        je lafine
z_end:  inc edx
        test al,al
        jz estring
        mov al,[edx]
        jmp short z_end

lafine: test al,al
        jne z_end
byenv:  mov esi,edx
        pop eax
        pop ebx
        pop edx
cuccato:
        inc edx
        jmp short byenv

; get BLASTER environment var. settings

sb db 'BLASTER',0   ; ASCIIZ BLASTER

sbenv:  pushad
        cmp sb_base,0
        jne env_set
        mov esi, offset sb
        call envfind
nextc:  lodsb
        test al,al
        jz settato
        cmp al,SPACE
        je nextc
        cmp al,TAB
        je nextc
        cmp al,'I'
        jne newa
        lodsb
        sub al,'0'
        mov  byte ptr sb_irqn,al
        jmp short nextc
newa:
        cmp al,'D'
        jne newb
        lodsb
        sub al,'0'
        mov  byte ptr sb_dmac,al
        jmp short nextc
newb:
        cmp al,'T'
        jne newc
        lodsb
        sub al,'0'
        mov  byte ptr sb_type,al
        jmp short nextc
newc:
        cmp al,'A'
        jne nextc  ; try to ignore unknown switches
        xor eax,eax
sboing: lodsb
        cmp al,'0'
        jb sguuk
        cmp al,'9'
        ja sguuk
        sub al,'0'
skud:   shl al,4
        shl eax,4
        jmp short sboing
sguuk:
        cmp al,'a'
        jb sgook
        cmp al,'f'
        ja sgook
        sub al,'a'
        jmp short skud
sgook:
        cmp al,'A'
        jb sgok
        cmp al,'F'
        ja sgok
        sub al,'A'
        jmp short skud
sgok:   shr eax,8
        mov sb_base,eax
        jmp short nextc

settato:
        mov eax,sb_base
        test eax,eax
        jz wrong_set



env_set:
        popad
        ret

[ RETURN TO DIRECTORY ]