.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