Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Ignore whitespace Rev 2287 → Rev 2288

/kernel/trunk/drivers/sb16/SB16.INC
1,297 → 1,297
;--------------------------------
; 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
;-------------------------------------------------------------------------------
;--------------------------------
; 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
;-------------------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property