Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 801 → Rev 802

/kernel/trunk/drivers/sb16/CONFIG.INC
0,0 → 1,41
;flags------------------------------------------------------------
DEBUG equ 1 ;show messages at debug board
use_cli_sti equ 1 ;driver come more stable (theoretically)
 
;constants--------------------------------------------------------
API_VERSION equ 0 ;debug
 
OS_BASE equ 0x80000000
new_app_base equ 0x0
PROC_BASE equ (OS_BASE+0x080000)
SB16Buffer equ (OS_BASE+0x2A0000)
SB16_Status equ (OS_BASE+0x2B0000)
DMAPage equ ((SB16Buffer-OS_BASE) shr 16)
 
SB16Buffer0 equ SB16Buffer
SB16Buffer1 equ (SB16Buffer+16384)
SB16Buffer2 equ (SB16Buffer+(2*16384))
SB16Buffer3 equ (SB16Buffer+(3*16384))
 
sb_irq_num equ 5
sb_dma_num equ 5
sb_buffer_size equ 32768 ;really it needs code modifications to change
;buffer size
sb_out_rate equ 44100
;time constant for cards older than SB16
 
sb_tc equ (256-(1000000/(sb_out_rate*2)))
 
SRV_GETVERSION equ 0
DEV_PLAY equ 1
DEV_STOP equ 2
DEV_CALLBACK equ 3
DEV_SET_BUFF equ 4
DEV_NOTIFY equ 5
DEV_SET_MASTERVOL equ 6
DEV_GET_MASTERVOL equ 7
DEV_GET_INFO equ 8
 
DRV_ENTRY equ 1
DRV_EXIT equ -1
 
/kernel/trunk/drivers/sb16/SB16.INC
0,0 → 1,239
;--------------------------------
; 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
 
; 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 bytes
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
; 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
/kernel/trunk/drivers/sb16/sb16.asm
0,0 → 1,375
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
format MS COFF
 
include 'config.inc'
 
;structs----------------------------------------------------------
struc IOCTL
{ .handle dd ?
.io_code dd ?
.input dd ?
.inp_size dd ?
.output dd ?
.out_size dd ?
}
 
virtual at 0
IOCTL IOCTL
end virtual
 
;something--------------------------------------------------------
public START
public service_proc
public version
 
include '..\proc32.inc'
include '..\imports.inc'
 
section '.flat' code readable align 16
 
include 'sb16.inc'
 
;-------------------------------------------------------------------------------
proc START stdcall, state:dword
 
cmp [state], 1
jne .stop
.entry:
 
if DEBUG
mov esi, msgInit
call SysMsgBoardStr
end if
 
call detect ;returns DSP version or zero if
test eax,eax ;SB card not found
jz .exit
 
if DEBUG
movzx eax,al ;major version
dec eax
jz .sb_say_about_found_dsp
mov dword[sb_DSP_description],'2.x '
dec eax
jz .sb_say_about_found_dsp
mov dword[sb_DSP_description],'Pro '
dec eax
jz .sb_say_about_found_dsp
mov dword[sb_DSP_description],'16 '
.sb_say_about_found_dsp:
mov esi,msgDSPFound
call SysMsgBoardStr
end if
xor eax,eax
mov ebx,[sb_base_port]
lea ecx,[ebx+0xF]
call ReservePortArea ;these ports must be mine!
if DEBUG
dec eax
jnz @f
mov esi,msgErrRsrvPorts
call SysMsgBoardStr
@@:
end if
 
call sb_setup ;clock it, etc
 
stdcall AttachIntHandler, sb_irq_num, sb_irq, 0
 
if DEBUG
test eax,eax
jnz @f
 
mov esi,msgErrAtchIRQ
call SysMsgBoardStr
 
stdcall GetIntHandler, sb_irq_num
call SysMsgBoardNum
 
jmp .stop
@@:
mov esi,msgSucAtchIRQ
call SysMsgBoardStr
end if
stdcall RegService, my_service, service_proc
ret
.stop:
call sb_reset
.exit:
 
if DEBUG
mov esi,msgExit
call SysMsgBoardStr
end if
 
xor eax, eax
ret
endp
;-------------------------------------------------------------------------------
 
handle equ IOCTL.handle
io_code equ IOCTL.io_code
input equ IOCTL.input
inp_size equ IOCTL.inp_size
output equ IOCTL.output
out_size equ IOCTL.out_size
 
align 4
proc service_proc stdcall, ioctl:dword
mov edi,[ioctl]
mov eax,[edi+io_code]
cmp eax,SRV_GETVERSION
jne @F
 
mov eax,[edi+output]
cmp [edi+out_size],4
jne .fail
mov [eax],dword API_VERSION
xor eax,eax
ret
@@:
cmp eax,DEV_PLAY
jne @f
if DEBUG
mov esi,msgPlay
call SysMsgBoardStr
end if
call sb_stop ;to play smth new we must stop smth old
 
call pre_fill_data ;fill first and second half of the buffer
call pre_fill_data ;
 
call sb_set_dma ;is it really needed here? Paranoia.
call sb_play
xor eax,eax
ret
;@@: ;all this commented stuff in service proc
; cmp eax,DEV_STOP ;is never used. Mixer do this virtually,
; jne @f ;e.g. instead of stopping driver it
;if DEBUG ;outputs silence
; mov esi,msgStop
; call SysMsgBoardStr
;end if
; call sb_stop
; xor eax,eax
; ret
@@:
cmp eax,DEV_CALLBACK
jne @f
if DEBUG
mov esi,msgCallback
call SysMsgBoardStr
end if
mov edi,[edi+input]
mov eax,[edi]
mov [callback],eax
if DEBUG
call SysMsgBoardNum
end if
ret
@@:
; cmp eax,DEV_SET_MASTERVOL
; jne @F
;if DEBUG
; mov esi,msgSetVol
; call SysMsgBoardStr
;end if
; mov eax,[edi+input]
; mov eax,[eax]
; mov [sb_master_vol],eax
; ret
;@@:
; cmp eax,DEV_GET_MASTERVOL
; jne @F
;if DEBUG
; mov esi,msgGetVol
; call SysMsgBoardStr
;end if
; mov eax,[edi+output]
; mov edx,[sb_master_vol]
; mov [eax],edx
; ret
 
.fail:
or eax, -1
ret
endp
 
restore handle
restore io_code
restore input
restore inp_size
restore output
restore out_size
 
;-------------------------------------------------------------------------------
align 4
proc sb_irq
mov edx,[sb_base_port] ;tell the DSP that we have processed IRQ
add dl,0xF ;0xF for 16 bit sound, 0xE for 8 bit sound
in al,dx ;for non-stop sound
 
pre_fill_data:
mov eax,int_flip_flop
not dword[eax]
mov eax,[eax]
test eax,eax
jns .fill_second_half
 
stdcall [callback],SB16Buffer0 ;for 32k buffer
; stdcall [callback],SB16Buffer0 ;for 64k buffer
; stdcall [callback],SB16Buffer1 ;for 64k buffer
 
xor eax,eax
ret
 
.fill_second_half:
stdcall [callback],SB16Buffer1 ;for 32k buffer
; stdcall [callback],SB16Buffer2 ;for 64k buffer
; stdcall [callback],SB16Buffer3 ;for 64k buffer
 
xor eax,eax
ret
endp
;-------------------------------------------------------------------------------
align 4
proc detect
.sb_detect_next_port:
if DEBUG
inc dword[port_second_digit_num]
end if
mov edx,sb_base_port
add byte[edx],10h
cmp byte[edx],80h
jbe .sb_try_to_detect_at_specified_port
;error - no SB card detected
.sb_not_found_err:
xor eax, eax
ret
 
.sb_try_to_detect_at_specified_port:
call sb_reset
add dl,8
mov ecx,100
.sb_check_port:
in al,dx
test al,al ;is DSP port ready to be read?
jns .sb_port_not_ready
 
sub dl,4
in al,dx ;check for AAh response
add dl,4
cmp al,0xAA
jne .sb_port_not_ready
.sb_card_found:
and dl,0xF0
add dl,0xC
sb_out 0xE1 ;get DSP version
add dl,2
@@:
in al,dx
test al,al ;is DSP port ready to be read?
jns @b
sub dl,4
in al,dx ;get major version
ror eax,16
add dl,4
@@:
in al,dx
test al,al ;is DSP port ready to be read?
jns @b
sub dl,4
in al,dx ;get minor version
xor edx,edx
mov dl,10
div dl
ror eax,16
xor ah,ah
if DEBUG
add [sb_DSP_version],eax
end if
ret
 
.sb_port_not_ready:
loop .sb_check_port ;100 retries (~100 microsec.)
jmp .sb_detect_next_port
endp
;-------------------------------------------------------------------------------
if DEBUG
proc SysMsgBoardNum
mov ebx,eax
mov ecx,8
mov esi,(number_to_out+1)
.1:
mov eax,ebx
and eax,0xF
add al,'0'
cmp al,(10+'0')
jb @f
add al,('A'-'0'-10)
@@:
mov [esi+ecx],al
shr ebx,4
loop .1
dec esi
call SysMsgBoardStr
ret
endp
end if
;all initialized data place here
 
align 4
version dd (5 shl 16) or (API_VERSION and 0xFFFF)
 
sb_base_port: dd 200h
 
;pTempBuf dd 0
 
callback dd 0
 
int_flip_flop dd 0
 
sound_dma dd sb_dma_num
 
;note that 4th DMA channel doesn't exist, it is used for cascade
;plugging the first DMA controler to the second
dma_table db 0x87,0x83,0x81,0x82,0xFF,0x8B,0x89,0x8A
 
;sb_master_vol dd 0
 
my_service db 'SOUND',0 ;max 16 chars include zero
 
if DEBUG
number_to_out db '0x00000000',13,10,0
 
msgInit db 'detecting hardware...',13,10,0
msgExit db 'exiting... May be some problems found?',13,10,0
msgPlay db 'start play',13,10,0
;msgStop db 'stop play',13,10,0
msgCallback db 'set_callback received from the mixer!',13,10
db 'callback handler is: ',0
msgErrAtchIRQ db 'failed to attach IRQ',(sb_irq_num+'0'),13,10
db 'owner',39,'s handler: ',0
msgSucAtchIRQ db 'succesfully attached IRQ',(sb_irq_num+'0')
db ' as hardcoded',13,10,0
msgErrRsrvPorts db 'failed to reserve needed ports.',13,10
db 'Driver may work unstable',13,10,0
;msgSetVol db 'DEV_SET_MASTERVOL call came',13,10,0
;msgGetVol db 'DEV_GET_MASTERVOL call came',13,10,0
msgErrDMAsetup db 'failed to setup DMA - bad channel',13,10,0
;-------------------------------------------------------------------------------
msgDSPFound db 'DSP found at port 2'
label port_second_digit_num dword at $
db '00h',13,10,'DSP version '
sb_DSP_version: db '0.00 - SB'
sb_DSP_description: db 32,32,32,32,13,10,0
;-------------------------------------------------------------------------------
end if
;section '.data' data readable writable align 16
;all uninitialized data place here