;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; format PE DLL native 0.05 entry START include 'CONFIG.INC' section '.flat' code readable writable executable include '..\..\struct.inc' include '..\..\macros.inc' include '..\..\proc32.inc' include '..\..\peimport.inc' include 'SB16.INC' ;------------------------------------------------------------------------------- proc START c uses ebx esi edi, state:dword, cmdline:dword cmp [state], 1 jne .stop .entry: if DEBUG mov esi, msgInit invoke 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 invoke SysMsgBoardStr end if xor ebx, ebx mov ecx, [sb_base_port] lea edx, [ecx+0xF] invoke ReservePortArea ;these ports must be mine ! dec eax jnz @f if DEBUG mov esi, msgErrRsrvPorts invoke SysMsgBoardStr end if jmp .exit @@: invoke AllocDMA24, sb_buffer_size test eax, eax jz .exit mov [SB16Buffer], eax call sb_setup ;clock it, etc invoke AttachIntHandler, sb_irq_num, sb_irq, 0 if DEBUG test eax, eax jnz @f mov esi, msgErrAtchIRQ invoke SysMsgBoardStr ; stdcall GetIntHandler, sb_irq_num ; call SysMsgBoardNum jmp .stop @@: mov esi, msgSucAtchIRQ invoke SysMsgBoardStr end if invoke RegService, my_service, service_proc ret .stop: call sb_reset .exit: if DEBUG mov esi, msgExit invoke SysMsgBoardStr end if xor eax, eax ret endp ;------------------------------------------------------------------------------- proc service_proc stdcall uses ebx esi edi, ioctl:dword mov edi, [ioctl] mov eax, [edi+IOCTL.io_code] cmp eax, SRV_GETVERSION jne @F mov eax, [edi+IOCTL.output] cmp [edi+IOCTL.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 invoke 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 invoke SysMsgBoardStr end if mov edi, [edi+IOCTL.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 invoke SysMsgBoardStr end if mov eax, [edi+IOCTL.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 invoke SysMsgBoardStr end if mov eax, [edi+IOCTL.output] mov edx, [sb_master_vol] mov [eax], edx xor eax, eax ret .fail: or eax, -1 ret endp ;------------------------------------------------------------------------------- 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 mov eax, [SB16Buffer] stdcall [callback], eax ;for 32k buffer else if sb_buffer_size eq full_buffer mov eax, [SB16Buffer] push eax stdcall [callback], eax ;for 64k buffer pop eax add eax, 16384 stdcall [callback], eax ;for 64k buffer end if xor eax, eax not eax ret .fill_second_half: if sb_buffer_size eq small_buffer mov eax, [SB16Buffer] add eax, 16384 stdcall [callback], eax ;for 32k buffer else if sb_buffer_size eq full_buffer mov eax, [SB16Buffer] add eax, 32768 push eax stdcall [callback], eax ;for 64k buffer pop eax add eax, 16384 stdcall [callback], eax ;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 invoke SysMsgBoardStr ret endp end if ;all initialized data place here align 4 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,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 align 4 data fixups end data align 4 SB16Buffer rd 1 callback rd 1 int_flip_flop rd 1 sb_master_vol rd 1 sb_DSP_version_int rd 1