kolibrios/kernel/branches/drivers/sb16/SB16.INC

298 lines
7.9 KiB
Plaintext
Raw Normal View History

;--------------------------------
; program dma
;--------------------------------
sb_set_dma:
mov ebx,[sound_dma]
lea eax,[ebx+4] ;mask required channel
cmp bl,4
ja .use_second_dma_controller
jb @f
.dma_setup_error:
if DEBUG
mov esi,msgErrDMAsetup
call SysMsgBoardStr
end if
mov dword[esp],START.stop
ret
@@:
if use_cli_sti
cli ;here to minimize time with disabled ints
end if
out 0xA,al ;mask required channel
xor eax,eax
out 0xC,al ;clear byte pointer flip-flop register
lea eax,[ebx+0x58] ;auto-init mode for channel (ebx)
out 0xB,al ;DMA channel 0-3 mode register
movzx edx,byte[ebx+dma_table] ;page register
mov al,DMAPage
out dx,al
lea edx,[ebx*2] ;DMA channel 0-3 base address
mov al,0 ;LSB is 0
out dx,al
; mov al,0 ;MSB is 0 too
out dx,al
inc edx ;DMA channel 0-3 byte count
mov al,((sb_buffer_size-1) and 0xff)
out dx,al
mov al,((sb_buffer_size-1) shr 8) ;it is the same
out dx,al
mov eax,ebx ;unmask DMA channel
out 0xA,al
if use_cli_sti
sti
end if
ret
.use_second_dma_controller:
cmp bl,7
ja .dma_setup_error
sub bl,4
sub al,4
if use_cli_sti
cli ;here to minimize time with disabled ints
end if
out 0xD4,al ;mask required channel
xor eax,eax
out 0xD8,al ;clear byte pointer flip-flop register
lea eax,[ebx+0x58] ;auto-init mode for channel (ebx+4)
out 0xD6,al ;DMA channel 4-7 mode register
movzx edx,byte[ebx+dma_table+4] ;page register
mov al,DMAPage
out dx,al
lea edx,[ebx*4+0xC0] ;DMA channel 4-7 base address
mov al,0 ;LSB is 0 ;for 16bit DMA this contains
out dx,al ;A1-A8 lines of address bus, A0 is zero
; mov al,0 ;MSB is 0 too ;for 16bit DMA this contains
out dx,al ;A9-A16 lines of address bus
inc edx
inc edx ;DMA channel 4-7 16bit word count
mov al,(((sb_buffer_size/2)-1) and 0xff)
out dx,al
mov al,(((sb_buffer_size/2)-1) shr 8)
out dx,al
mov eax,ebx ;unmask DMA channel
out 0xD4,al
if use_cli_sti
sti
end if
ret
;-------------------------------------------------------------------------------
; out byte to SB DSP's write port
;-------------------------------------------------------------------------------
macro sb_out data_to_out {
@@:
in al,dx
test al,al ;is DSP busy?
js @b ;it's busy
mov al,data_to_out ;it's free
out dx,al
}
;-------------------------------------------------------------------------------
; stop playing
;-------------------------------------------------------------------------------
proc sb_stop
mov edx,[sb_base_port]
add dl,0xC
sb_out 0xD3 ;turn the speaker off
sb_out 0xDA ;exit 8bit DMA
sb_out 0xD9 ;exit 16bit DMA
ret
endp
;-------------------------------------------------------------------------------
; start playing
;-------------------------------------------------------------------------------
proc sb_play
and [int_flip_flop],0
mov edx,[sb_base_port]
add dl,0xC
sb_out 0xD1 ;turn speaker on
; sb_out 0x48 ;set DSP transfer size ;for older cards, not supported
; ;in this version
; mov ax,32767 ;(64k)/2-1
;@@: ;out the low byte...
; in al,dx
; test al,al ;is DSP busy?
; js @b ;it's busy
; out dx,al
; mov al,ah ;...then the high byte
;@@:
; in al,dx
; test al,al ;is DSP busy?
; js @b ;it's busy
; out dx,al
; sb_out 0x1C ;auto-init 8bit playback
; 0xBXh - 16 bit DMA mode
; ||||
sb_out 10110110b ;bCommand
; ||||
; |||+-reserved
; ||+--turn FIFO on (0 for off)
; |+---auto-init mode on (0 for off)
; +----A/D: 0-output, 1-input
; +------stereo on
; |+-----unsigned (1 for signed)
; ||
sb_out 00110000b ;bMode
; || ||||
; ---------reserved
;wSize is a number of 16bit samples less 1. For auto-init mode each half
;buffer is (64k)/2 bytes long and, obviously, contains ((64k)/2)/2 samples
sb_out (((sb_buffer_size/2/2)-1) and 0xFF) ;wSize.LowByte
sb_out (((sb_buffer_size/2/2)-1) shr 8) ;wSize.HighByte
ret
endp
;-------------------------------------------------------------------------------
; reset DSP
;-------------------------------------------------------------------------------
proc sb_reset
and [int_flip_flop],0
mov edx,[sb_base_port]
add dl,6
mov al,1 ;start DSP reset
if use_cli_sti
cli ;here to minimize time with disabled ints
end if
out dx,al
mov ecx,40 ;wait at least 3 microsec.
@@:
in al,dx
loop @b
xor eax,eax ;stop DSP reset
if use_cli_sti
sti
end if
out dx,al
ret
endp
;-------------------------------------------------------------------------------
; set the rate for playing, enable stereo
;-------------------------------------------------------------------------------
proc sb_setup
mov edx,[sb_base_port]
add dl,0xC
sb_out 40h ;set time constant, this is for old cards
sb_out sb_tc
sb_out 41h ;set sound rate, this can only SB16
sb_out (sb_out_rate shr 8) ;first high byte (MSB)
sb_out (sb_out_rate and 0xff) ;then low byte (LSB)
; mov al,0xE ;for older cards, not supported in this version
; sub dl,(0xC-4) ;talk to SB's mixer
; out dx,al ;select this register of the mixer
; mov ecx,6 ;wait for the chip
;@@:
; in al,dx
; loop @b
; inc edx ;now read the data port
; in al,dx
; or al,22h ;turn on stereo
; mov ah,al
; mov al,0xE
; dec edx ;talk to SB's mixer
; out dx,al ;select this register of the mixer
; mov ecx,6 ;wait for the chip
;@@:
; in al,dx
; loop @b
; inc edx ;now send data to the data port
; mov al,ah
; out dx,al
; dec edx
; mov ecx,35 ;wait for the chip
;@@:
; in al,dx
; loop @b
ret
endp
;-------------------------------------------------------------------------------
; set master volume of SB mixer, note, not only SB16 but SBPro and older
; this is the first step to more full support for hardware
;-------------------------------------------------------------------------------
;in: eax in range [-10000;0] - master volume for _both_ channels
;note that x*3*17/2000 and x*3/2000*17 are not the same numbers,
;because we count in integers
proc sb_set_master_vol
mov [sb_master_vol],eax
add eax,10000 ;SB sound level rise from 0 to MAX_LEVEL
lea eax,[eax+eax*2] ;*3
mov ebx,2000 ;divisor
xor edx,edx
cmp byte[sb_DSP_version_int],4
jae @f ;SBPro's MAX_LEVEL is 15, but we *11 because
;volume byte looks like that: 0xLR, where L - left
;channel volume, R - right, 0<=R,L<=15
div ebx
imul eax,17
mov edx,[sb_base_port]
push eax ;here for optimisation
add dl,4
mov al,0x22 ;write mixer register 0x22
out dx,al
in al,dx ;wait for the chip ;6
in al,dx ;wait for the chip ;5
in al,dx ;wait for the chip ;4
in al,dx ;wait for the chip ;3
in al,dx ;wait for the chip ;2
in al,dx ;wait for the chip ;1
pop eax ;go!
inc edx
out dx,al
ret
@@: ;SB16's MAX_LEVEL is 255
imul eax,17
div ebx
mov edx,[sb_base_port]
push eax ;here for optimisation
add dl,4
mov al,0x30 ;left speaker
out dx,al
pop eax ;<--+
inc edx ; \/
push eax ;here for optimisation
out dx,al ;write
dec edx
mov al,0x31 ;right speaker
out dx,al
pop eax
inc edx
out dx,al ;write
ret
endp
;-------------------------------------------------------------------------------