forked from KolibriOS/kolibrios
9022bde80a
git-svn-id: svn://kolibrios.org@1505 a494cfbc-eb01-0410-851d-a64ba20cac60
394 lines
9.2 KiB
NASM
394 lines
9.2 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; 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
|
|
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
|
|
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
|
|
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
|