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 |