kolibrios-fun/drivers/audio/sb16/SB16.INC

314 lines
9.6 KiB
Plaintext
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;--------------------------------
; 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
invoke 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
mov eax, [SB16Buffer]
invoke GetPhysAddr
mov ecx, eax
shr eax, 16
movzx edx, byte[ebx+dma_table];page register
out dx, al
lea edx, [ebx*2];DMA channel 0-3 base address
mov al, cl;LSB
out dx, al
mov al, ch;MSB
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
mov eax, [SB16Buffer]
invoke GetPhysAddr
mov ecx, eax
shr eax, 16
shr ecx, 1 ; 16-bit DMA takes offset in words
movzx edx, byte[ebx+dma_table+4];page register
out dx, al
lea edx, [ebx*4+0xC0];DMA channel 4-7 base address
mov al, cl;LSB;for 16bit DMA this contains
out dx, al;A1-A8 lines of address bus, A0 is zero
mov al, ch;MSB;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
;-------------------------------------------------------------------------------