kolibrios/kernel/branches/Kolibri-acpi/drivers/sb16/sb16.asm

399 lines
11 KiB
NASM
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2011. 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
mov esi, sb_DSP_description
dec eax
jz .sb_say_about_found_dsp
mov dword[esi], '2.x '
dec eax
jz .sb_say_about_found_dsp
mov dword[esi], 'Pro '
dec eax
jz .sb_say_about_found_dsp
mov dword[esi], '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]
xor ebx, ebx
mov ecx, [sb_base_port]
lea edx, [ebx+0xF]
call ReservePortArea ;these ports must be my!
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 ;set maximum volume
call sb_set_master_vol
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
xor eax, eax
ret
@@:
cmp eax, DEV_SET_MASTERVOL;Serge asked me to unlock
jne @F ;DEV_SET(GET)_MASTERVOL, although mixer doesn't use it.
;It doesn't use it _in current version_ - but in the future...
if DEBUG
mov esi, msgSetVol
call SysMsgBoardStr
end if
mov eax, [edi+input]
mov eax, [eax]
call sb_set_master_vol
xor eax, 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
xor eax, eax
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
if sb_buffer_size eq small_buffer
stdcall [callback], SB16Buffer0 ;for 32k buffer
else if sb_buffer_size eq full_buffer
stdcall [callback], SB16Buffer0 ;for 64k buffer
stdcall [callback], SB16Buffer1 ;for 64k buffer
end if
xor eax, eax
not eax
ret
.fill_second_half:
if sb_buffer_size eq small_buffer
stdcall [callback], SB16Buffer1 ;for 32k buffer
else if sb_buffer_size eq full_buffer
stdcall [callback], SB16Buffer2 ;for 64k buffer
stdcall [callback], SB16Buffer3 ;for 64k buffer
end if
xor eax, eax
not 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
mov [sb_DSP_version_int], eax;for internal usage
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 ;warning: destroys eax,ebx,ecx,esi
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 ;don't ask me why - see the code&docs
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
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
;pTempBuf rd 1
callback rd 1
int_flip_flop rd 1
sb_master_vol rd 1
sb_DSP_version_int rd 1