9ebd3255c3
git-svn-id: svn://kolibrios.org@2987 a494cfbc-eb01-0410-851d-a64ba20cac60
399 lines
11 KiB
NASM
399 lines
11 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2012. 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
|