1 // ****************************************************************************
5 // Implementation file for EchoGals generic driver DSP interface class.
7 // ----------------------------------------------------------------------------
9 // This file is part of Echo Digital Audio's generic driver library.
10 // Copyright Echo Digital Audio Corporation (c) 1998 - 2005
11 // All rights reserved
14 // This library is free software; you can redistribute it and/or
15 // modify it under the terms of the GNU Lesser General Public
16 // License as published by the Free Software Foundation; either
17 // version 2.1 of the License, or (at your option) any later version.
19 // This library is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 // Lesser General Public License for more details.
24 // You should have received a copy of the GNU Lesser General Public
25 // License along with this library; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 // ****************************************************************************
30 #include "CEchoGals.h"
33 #include "LoaderDSP.c"
36 #define COMM_PAGE_PHYS_BYTES ((sizeof(DspCommPage)+PAGE_SIZE-1)/PAGE_SIZE)*PAGE_SIZE
39 /****************************************************************************
41 Construction and destruction
43 ****************************************************************************/
45 //===========================================================================
47 // Overload new & delete so memory for this object is allocated
48 // from non-paged memory.
50 //===========================================================================
52 PVOID
CDspCommObject::operator new( size_t Size
)
57 Status
= OsAllocateNonPaged(Size
,&pMemory
);
59 if ( (ECHOSTATUS_OK
!= Status
) || (NULL
== pMemory
))
61 ECHO_DEBUGPRINTF(("CDspCommObject::operator new - memory allocation failed\n"));
67 memset( pMemory
, 0, Size
);
72 } // PVOID CDspCommObject::operator new( size_t Size )
75 VOID
CDspCommObject::operator delete( PVOID pVoid
)
77 if ( ECHOSTATUS_OK
!= OsFreeNonPaged( pVoid
) )
79 ECHO_DEBUGPRINTF( ("CDspCommObject::operator delete memory free "
82 } // VOID CDspCommObject::operator delete( PVOID pVoid )
85 //===========================================================================
89 //===========================================================================
91 CDspCommObject::CDspCommObject
93 PDWORD pdwDspRegBase
, // Virtual ptr to DSP registers
94 PCOsSupport pOsSupport
99 ECHO_ASSERT(pOsSupport
);
102 // Init all the basic stuff
104 strcpy( m_szCardName
, "??????" );
105 m_pOsSupport
= pOsSupport
; // Ptr to OS Support methods & data
106 m_pdwDspRegBase
= pdwDspRegBase
; // Virtual addr DSP's register base
107 m_bBadBoard
= TRUE
; // Set TRUE until DSP loaded
108 m_pwDspCode
= NULL
; // Current DSP code not loaded
109 m_byDigitalMode
= DIGITAL_MODE_NONE
;
110 m_wInputClock
= ECHO_CLOCK_INTERNAL
;
111 m_wOutputClock
= ECHO_CLOCK_WORD
;
112 m_ullLastLoadAttemptTime
= (ULONGLONG
)(DWORD
)(0L - DSP_LOAD_ATTEMPT_PERIOD
); // force first load to go
115 m_ullNextMidiWriteTime
= 0;
119 // Create the DSP comm page - this is the area of memory read and written by
120 // the DSP via bus mastering
126 Status
= pOsSupport
->AllocPhysPageBlock( COMM_PAGE_PHYS_BYTES
,
127 m_pDspCommPageBlock
);
128 if (ECHOSTATUS_OK
!= Status
)
130 ECHO_DEBUGPRINTF( ("CDspCommObject::CDspCommObject DSP comm page "
131 "memory allocation failed\n") );
135 m_pDspCommPage
= (PDspCommPage
) pOsSupport
->
136 GetPageBlockVirtAddress( m_pDspCommPageBlock
);
138 pOsSupport
->GetPageBlockPhysSegment(m_pDspCommPageBlock
,
142 m_dwCommPagePhys
= PhysAddr
;
145 // Init the comm page
147 m_pDspCommPage
->dwCommSize
= SWAP( sizeof( DspCommPage
) );
148 // Size of DSP comm page
150 m_pDspCommPage
->dwHandshake
= 0xffffffff;
151 m_pDspCommPage
->dwMidiOutFreeCount
= SWAP( (DWORD
) DSP_MIDI_OUT_FIFO_SIZE
);
153 for ( i
= 0; i
< DSP_MAXAUDIOINPUTS
; i
++ )
154 m_pDspCommPage
->InLineLevel
[ i
] = 0x00;
155 // Set line levels so we don't blast
156 // any inputs on startup
157 memset( m_pDspCommPage
->byMonitors
,
158 GENERIC_TO_DSP(ECHOGAIN_MUTED
),
159 MONITOR_ARRAY_SIZE
); // Mute all monitors
161 memset( m_pDspCommPage
->byVmixerLevel
,
162 GENERIC_TO_DSP(ECHOGAIN_MUTED
),
163 VMIXER_ARRAY_SIZE
); // Mute all virtual mixer levels
165 #ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT
167 m_fDigitalInAutoMute
= TRUE
;
171 } // CDspCommObject::CDspCommObject
174 //===========================================================================
178 //===========================================================================
180 CDspCommObject::~CDspCommObject()
188 // Free the comm page
190 if ( NULL
!= m_pDspCommPageBlock
)
192 m_pOsSupport
->FreePhysPageBlock( COMM_PAGE_PHYS_BYTES
,
193 m_pDspCommPageBlock
);
196 ECHO_DEBUGPRINTF( ( "CDspCommObject::~CDspCommObject() is toast!\n" ) );
198 } // CDspCommObject::~CDspCommObject()
203 /****************************************************************************
205 Firmware loading functions
207 ****************************************************************************/
209 //===========================================================================
211 // ASIC status check - some cards have one or two ASICs that need to be
212 // loaded. Once that load is complete, this function is called to see if
213 // the load was successful.
215 // If this load fails, it does not necessarily mean that the hardware is
216 // defective - the external box may be disconnected or turned off.
218 //===========================================================================
220 BOOL
CDspCommObject::CheckAsicStatus()
226 // Always succeed if this card doesn't have an ASIC
230 m_bASICLoaded
= TRUE
;
234 // Send the vector command
235 m_bASICLoaded
= FALSE
;
236 SendVector( DSP_VC_TEST_ASIC
);
238 // The DSP will return a value to indicate whether or not the
239 // ASIC is currently loaded
240 dwReturn
= Read_DSP( &dwAsicStatus
);
241 if ( ECHOSTATUS_OK
!= dwReturn
)
243 ECHO_DEBUGPRINTF(("CDspCommObject::CheckAsicStatus - failed on Read_DSP\n"));
249 if ( (dwAsicStatus
!= ASIC_LOADED
) && (dwAsicStatus
!= ASIC_NOT_LOADED
) )
255 if ( dwAsicStatus
== ASIC_LOADED
)
256 m_bASICLoaded
= TRUE
;
258 return m_bASICLoaded
;
260 } // BOOL CDspCommObject::CheckAsicStatus()
263 //===========================================================================
265 // Load ASIC code - done after the DSP is loaded
267 //===========================================================================
269 BOOL
CDspCommObject::LoadASIC
278 DWORD dwChecksum
= 0;
281 ECHO_DEBUGPRINTF(("CDspCommObject::LoadASIC\n"));
287 ULONGLONG ullStartTime
, ullCurTime
;
288 m_pOsSupport
->OsGetSystemTime( &ullStartTime
);
291 // Send the "Here comes the ASIC" command
292 if ( ECHOSTATUS_OK
!= Write_DSP( dwCmd
) )
295 // Write length of ASIC file in bytes
296 if ( ECHOSTATUS_OK
!= Write_DSP( dwSize
) )
299 for ( i
= 0; i
< dwSize
; i
++ )
302 dwChecksum
+= pCode
[i
];
305 if ( ECHOSTATUS_OK
!= Write_DSP( pCode
[ i
] ) )
307 ECHO_DEBUGPRINTF(("\tfailed on Write_DSP\n"));
313 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
314 ECHO_DEBUGPRINTF( ("CDspCommObject::LoadASIC took %ld usec.\n",
315 (ULONG
) ( ullCurTime
- ullStartTime
) ) );
316 ECHO_DEBUGPRINTF(("ASIC load OK\n"));
319 #if defined(_WIN32) && (DBG)
320 DbgPrint("--- ASIC checksum is 0x%lx\n",dwChecksum
);
325 } // BOOL CDspCommObject::LoadASIC( DWORD dwCmd, PBYTE pCode, DWORD dwSize )
328 //===========================================================================
330 // InstallResidentLoader
332 // Install the resident loader for 56361 DSPs; The resident loader
333 // is on the EPROM on the board for 56301 DSP.
335 // The resident loader is a tiny little program that is used to load
336 // the real DSP code.
338 //===========================================================================
342 ECHOSTATUS
CDspCommObject::InstallResidentLoader()
351 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader\n") );
356 if (DEVICE_ID_56361
!= m_pOsSupport
->GetDeviceId() )
357 return ECHOSTATUS_OK
;
360 // Look to see if the resident loader is present. If the resident loader
361 // is already installed, host flag 5 will be on.
364 dwStatus
= GetDspRegister( CHI32_STATUS_REG
);
365 if ( 0 != (dwStatus
& CHI32_STATUS_REG_HF5
) )
367 ECHO_DEBUGPRINTF(("\tResident loader already installed; status is 0x%lx\n",
369 return ECHOSTATUS_OK
;
372 // Set DSP format bits for 24 bit mode
374 SetDspRegister( CHI32_CONTROL_REG
,
375 GetDspRegister( CHI32_CONTROL_REG
) | 0x900 );
377 //---------------------------------------------------------------------------
381 // The DSP code is an array of 16 bit words. The array is divided up into
382 // sections. The first word of each section is the size in words, followed
383 // by the section type.
385 // Since DSP addresses and data are 24 bits wide, they each take up two
386 // 16 bit words in the array.
388 // This is a lot like the other loader loop, but it's not a loop,
389 // you don't write the memory type, and you don't write a zero at the end.
391 //---------------------------------------------------------------------------
395 // Skip the header section; the first word in the array is the size of
396 // the first section, so the first real section of code is pointed to
399 dwIndex
= pCode
[ 0 ];
401 // Skip the section size, LRS block type, and DSP memory type
405 // Get the number of DSP words to write
407 iNum
= pCode
[ dwIndex
++ ];
409 // Get the DSP address for this block; 24 bits, so build from two words
411 dwAddress
= ( pCode
[ dwIndex
] << 16 ) + pCode
[ dwIndex
+ 1 ];
414 // Write the count to the DSP
416 dwReturn
= Write_DSP( (DWORD
) iNum
);
419 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader: Failed to "
420 "write word count!\n") );
421 return ECHOSTATUS_DSP_DEAD
;
424 // Write the DSP address
425 dwReturn
= Write_DSP( dwAddress
);
428 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader: Failed to "
429 "write DSP address!\n") );
430 return ECHOSTATUS_DSP_DEAD
;
434 // Write out this block of code to the DSP
435 for ( i
= 0; i
< iNum
; i
++) //
439 dwData
= ( pCode
[ dwIndex
] << 16 ) + pCode
[ dwIndex
+ 1 ];
440 dwReturn
= Write_DSP( dwData
);
443 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader: Failed to "
444 "write DSP code\n") );
445 return ECHOSTATUS_DSP_DEAD
;
452 // Wait for flag 5 to come up
455 ULONGLONG ullCurTime
,ullTimeout
;
457 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
458 ullTimeout
= ullCurTime
+ 10000L; // 10m.s.
462 m_pOsSupport
->OsSnooze(50); // Give the DSP some time;
463 // no need to hog the CPU
465 dwStatus
= GetDspRegister( CHI32_STATUS_REG
);
466 if (0 != (dwStatus
& CHI32_STATUS_REG_HF5
))
472 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
474 } while (ullCurTime
< ullTimeout
);
476 if (FALSE
== fSuccess
)
478 ECHO_DEBUGPRINTF(("\tResident loader failed to set HF5\n"));
479 return ECHOSTATUS_DSP_DEAD
;
482 ECHO_DEBUGPRINTF(("\tResident loader successfully installed\n"));
484 return ECHOSTATUS_OK
;
486 } // ECHOSTATUS CDspCommObject::InstallResidentLoader()
491 //===========================================================================
495 // This loads the DSP code.
497 //===========================================================================
499 ECHOSTATUS
CDspCommObject::LoadDSP
501 PWORD pCode
// Ptr to DSP object code
509 ULONGLONG ullTimeout
, ullCurTime
;
512 ECHO_DEBUGPRINTF(("CDspCommObject::LoadDSP\n"));
513 if ( m_pwDspCode
== pCode
)
515 ECHO_DEBUGPRINTF( ("\tDSP is already loaded!\n") );
516 return ECHOSTATUS_FIRMWARE_LOADED
;
518 m_bBadBoard
= TRUE
; // Set TRUE until DSP loaded
519 m_pwDspCode
= NULL
; // Current DSP code not loaded
520 m_bASICLoaded
= FALSE
; // Loading the DSP code will reset the ASIC
522 ECHO_DEBUGPRINTF(("CDspCommObject::LoadDSP Set m_bBadBoard to TRUE\n"));
525 // If this board requires a resident loader, install it.
528 InstallResidentLoader();
531 // Send software reset command
532 if ( ECHOSTATUS_OK
!= SendVector( DSP_VC_RESET
) )
534 m_pOsSupport
->EchoErrorMsg(
535 "CDspCommObject::LoadDsp SendVector DSP_VC_RESET failed",
536 "Critical Failure" );
537 return ECHOSTATUS_DSP_DEAD
;
541 m_pOsSupport
->OsSnooze( 10L );
543 // Wait 10ms for HF3 to indicate that software reset is complete
544 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
545 ullTimeout
= ullCurTime
+ 10000L; // 10m.s.
547 // wait for HF3 to be set
550 if ( GetDspRegister( CHI32_STATUS_REG
) & CHI32_STATUS_REG_HF3
)
551 goto set_dsp_format_bits
;
552 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
553 if ( ullCurTime
> ullTimeout
)
555 ECHO_DEBUGPRINTF( ("CDspCommObject::LoadDSP Timeout waiting for "
556 "CHI32_STATUS_REG_HF3\n") );
557 m_pOsSupport
->EchoErrorMsg(
558 "CDspCommObject::LoadDSP SendVector DSP_VC_RESET failed",
559 "Critical Failure" );
560 return ECHOSTATUS_DSP_TIMEOUT
;
565 // Set DSP format bits for 24 bit mode now that soft reset is done
567 SetDspRegister( CHI32_CONTROL_REG
,
568 GetDspRegister( CHI32_CONTROL_REG
) | (DWORD
) 0x900 );
570 //---------------------------------------------------------------------------
572 //---------------------------------------------------------------------------
574 dwIndex
= pCode
[ 0 ];
585 iBlockType
= pCode
[ dwIndex
];
586 if ( iBlockType
== 4 ) // We're finished
591 // Memory Type P=0,X=1,Y=2
592 iMemType
= pCode
[ dwIndex
];
596 iNum
= pCode
[ dwIndex
];
598 if ( iNum
== 0 ) // We're finished
602 dwAddress
= ( (DWORD
) pCode
[ dwIndex
] << 16 ) + pCode
[ dwIndex
+ 1 ];
603 // ECHO_DEBUGPRINTF( ("\tdwAddress %lX\n", dwAddress) );
606 dwReturn
= Write_DSP( (DWORD
)iNum
);
609 ECHO_DEBUGPRINTF(("LoadDSP - failed to write number of DSP words\n"));
610 return ECHOSTATUS_DSP_DEAD
;
613 dwReturn
= Write_DSP( dwAddress
);
616 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP address\n"));
617 return ECHOSTATUS_DSP_DEAD
;
620 dwReturn
= Write_DSP( (DWORD
)iMemType
);
623 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP memory type\n"));
624 return ECHOSTATUS_DSP_DEAD
;
628 for ( i
= 0; i
< iNum
; i
++ )
632 dwData
= ( (DWORD
) pCode
[ dwIndex
] << 16 ) + pCode
[ dwIndex
+ 1 ];
633 dwReturn
= Write_DSP( dwData
);
636 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP data\n"));
637 return ECHOSTATUS_DSP_DEAD
;
642 // ECHO_DEBUGPRINTF( ("\tEnd Code Block\n") );
644 dwReturn
= Write_DSP( 0 ); // We're done!!!
647 ECHO_DEBUGPRINTF(("LoadDSP: Failed to write final zero\n"));
648 return ECHOSTATUS_DSP_DEAD
;
653 m_pOsSupport
->OsSnooze( 10L );
655 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
656 ullTimeout
= ullCurTime
+ 500000L; // 1/2 sec. timeout
658 while ( ullCurTime
<= ullTimeout
)
661 // Wait for flag 4 - indicates that the DSP loaded OK
663 if ( GetDspRegister( CHI32_STATUS_REG
) & CHI32_STATUS_REG_HF4
)
665 SetDspRegister( CHI32_CONTROL_REG
,
666 GetDspRegister( CHI32_CONTROL_REG
) & ~0x1b00 );
668 dwReturn
= Write_DSP( DSP_FNC_SET_COMMPAGE_ADDR
);
671 ECHO_DEBUGPRINTF(("LoadDSP - Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n"));
672 return ECHOSTATUS_DSP_DEAD
;
675 dwReturn
= Write_DSP( m_dwCommPagePhys
);
678 ECHO_DEBUGPRINTF(("LoadDSP - Failed to write comm page address\n"));
679 return ECHOSTATUS_DSP_DEAD
;
683 // Get the serial number via slave mode.
684 // This is triggered by the SET_COMMPAGE_ADDR command.
685 // We don't actually use the serial number but we have to get
686 // it as part of the DSP init vodoo.
689 if ( ECHOSTATUS_OK
!= Status
)
691 ECHO_DEBUGPRINTF(("LoadDSP - Failed to read serial number\n"));
695 m_pwDspCode
= pCode
; // Show which DSP code loaded
696 m_bBadBoard
= FALSE
; // DSP OK
698 ECHO_DEBUGPRINTF(("CDspCommObject::LoadDSP Set m_bBadBoard to FALSE\n"));
700 return ECHOSTATUS_OK
;
703 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
706 ECHO_DEBUGPRINTF( ("LoadDSP: DSP load timed out waiting for HF4\n") );
708 return ECHOSTATUS_DSP_TIMEOUT
;
710 } // DWORD CDspCommObject::LoadDSP
715 //===========================================================================
717 // LoadFirmware takes care of loading the DSP and any ASIC code.
719 //===========================================================================
721 ECHOSTATUS
CDspCommObject::LoadFirmware()
724 ULONGLONG ullRightNow
;
727 if ( NULL
== m_pwDspCodeToLoad
|| NULL
== m_pDspCommPage
)
730 return ECHOSTATUS_NO_MEM
;
734 // Even if the external box is off, an application may still try
735 // to repeatedly open the driver, causing multiple load attempts and
736 // making the machine spend lots of time in the kernel. If the ASIC is not
737 // loaded, this code will gate the loading attempts so it doesn't happen
738 // more than once per second.
740 m_pOsSupport
->OsGetSystemTime(&ullRightNow
);
741 if ( (FALSE
== m_bASICLoaded
) &&
742 (DSP_LOAD_ATTEMPT_PERIOD
> (ullRightNow
- m_ullLastLoadAttemptTime
)) )
743 return ECHOSTATUS_ASIC_NOT_LOADED
;
746 // Update the timestamp
748 m_ullLastLoadAttemptTime
= ullRightNow
;
751 // See if the ASIC is present and working - only if the DSP is already loaded
753 if (NULL
!= m_pwDspCode
)
755 dwReturn
= CheckAsicStatus();
756 if (TRUE
== dwReturn
)
757 return ECHOSTATUS_OK
;
760 // ASIC check failed; force the DSP to reload
766 // Try and load the DSP
768 dwReturn
= LoadDSP( m_pwDspCodeToLoad
);
769 if ( (ECHOSTATUS_OK
!= dwReturn
) &&
770 (ECHOSTATUS_FIRMWARE_LOADED
!= dwReturn
) )
775 ECHO_DEBUGPRINTF(("DSP load OK\n"));
778 // Load the ASIC if the DSP load succeeded; LoadASIC will
779 // always return TRUE for cards that don't have an ASIC.
781 dwReturn
= LoadASIC();
782 if ( FALSE
== dwReturn
)
784 dwReturn
= ECHOSTATUS_ASIC_NOT_LOADED
;
789 // ASIC load was successful
791 RestoreDspSettings();
793 dwReturn
= ECHOSTATUS_OK
;
798 } // BOOL CDspCommObject::LoadFirmware()
801 //===========================================================================
803 // This function is used to read back the serial number from the DSP;
804 // this is triggered by the SET_COMMPAGE_ADDR command.
806 // Only some early Echogals products have serial numbers in the ROM;
807 // the serial number is not used, but you still need to do this as
808 // part of the DSP load process.
810 //===========================================================================
812 ECHOSTATUS
CDspCommObject::ReadSn()
818 ECHO_DEBUGPRINTF( ("CDspCommObject::ReadSn\n") );
819 for ( j
= 0; j
< 5; j
++ )
821 Status
= Read_DSP( &dwSn
[ j
] );
824 ECHO_DEBUGPRINTF( ("\tFailed to read serial number word %ld\n",
826 return ECHOSTATUS_DSP_DEAD
;
829 ECHO_DEBUGPRINTF( ("\tRead serial number %08lx %08lx %08lx %08lx %08lx\n",
830 dwSn
[0], dwSn
[1], dwSn
[2], dwSn
[3], dwSn
[4]) );
831 return ECHOSTATUS_OK
;
833 } // DWORD CDspCommObject::ReadSn
838 //===========================================================================
840 // This is called after LoadFirmware to restore old gains, meters on,
843 //===========================================================================
845 void CDspCommObject::RestoreDspSettings()
847 ECHO_DEBUGPRINTF(("RestoreDspSettings\n"));
848 ECHO_DEBUGPRINTF(("\tControl reg is 0x%lx\n",SWAP(m_pDspCommPage
->dwControlReg
) ));
850 if ( !CheckAsicStatus() )
853 m_pDspCommPage
->dwHandshake
= 0xffffffff;
856 m_ullNextMidiWriteTime
= 0;
860 if ( 0 != m_wMeterOnCount
)
862 SendVector( DSP_VC_METERS_ON
);
865 SetInputClock( m_wInputClock
);
866 SetOutputClock( m_wOutputClock
);
868 if ( !WaitForHandshake() )
872 UpdateAudioOutLineLevel();
874 if ( !WaitForHandshake() )
876 UpdateAudioInLineLevel();
880 if ( !WaitForHandshake() )
885 if ( !WaitForHandshake() )
889 SendVector( DSP_VC_UPDATE_FLAGS
);
891 ECHO_DEBUGPRINTF(("RestoreDspSettings done\n"));
893 } // void CDspCommObject::RestoreDspSettings()
898 /****************************************************************************
902 ****************************************************************************/
904 //===========================================================================
906 // Write_DSP writes a 32-bit value to the DSP; this is used almost
907 // exclusively for loading the DSP.
909 //===========================================================================
911 ECHOSTATUS
CDspCommObject::Write_DSP
913 DWORD dwData
// 32 bit value to write to DSP data register
917 ULONGLONG ullCurTime
, ullTimeout
;
919 // ECHO_DEBUGPRINTF(("Write_DSP\n"));
921 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
922 ullTimeout
= ullCurTime
+ 10000000L; // 10 sec.
923 while ( ullTimeout
>= ullCurTime
)
925 dwStatus
= GetDspRegister( CHI32_STATUS_REG
);
926 if ( ( dwStatus
& CHI32_STATUS_HOST_WRITE_EMPTY
) != 0 )
928 SetDspRegister( CHI32_DATA_REG
, dwData
);
929 // ECHO_DEBUGPRINTF(("Write DSP: 0x%x", dwData));
930 return ECHOSTATUS_OK
;
932 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
935 m_bBadBoard
= TRUE
; // Set TRUE until DSP re-loaded
937 ECHO_DEBUGPRINTF(("CDspCommObject::Write_DSP Set m_bBadBoard to TRUE\n"));
939 return ECHOSTATUS_DSP_TIMEOUT
;
941 } // ECHOSTATUS CDspCommObject::Write_DSP
946 //===========================================================================
948 // Read_DSP reads a 32-bit value from the DSP; this is used almost
949 // exclusively for loading the DSP and checking the status of the ASIC.
951 //===========================================================================
953 ECHOSTATUS
CDspCommObject::Read_DSP
955 DWORD
*pdwData
// Ptr to 32 bit value read from DSP data register
959 ULONGLONG ullCurTime
, ullTimeout
;
961 // ECHO_DEBUGPRINTF(("Read_DSP\n"));
962 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
964 ullTimeout
= ullCurTime
+ READ_DSP_TIMEOUT
;
965 while ( ullTimeout
>= ullCurTime
)
967 dwStatus
= GetDspRegister( CHI32_STATUS_REG
);
968 if ( ( dwStatus
& CHI32_STATUS_HOST_READ_FULL
) != 0 )
970 *pdwData
= GetDspRegister( CHI32_DATA_REG
);
971 // ECHO_DEBUGPRINTF(("Read DSP: 0x%x\n", *pdwData));
972 return ECHOSTATUS_OK
;
974 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
977 m_bBadBoard
= TRUE
; // Set TRUE until DSP re-loaded
979 ECHO_DEBUGPRINTF(("CDspCommObject::Read_DSP Set m_bBadBoard to TRUE\n"));
981 return ECHOSTATUS_DSP_TIMEOUT
;
982 } // ECHOSTATUS CDspCommObject::Read_DSP
986 //===========================================================================
988 // Much of the interaction between the DSP and the driver is done via vector
989 // commands; SendVector writes a vector command to the DSP. Typically,
990 // this causes the DSP to read or write fields in the comm page.
992 // Returns ECHOSTATUS_OK if sent OK.
994 //===========================================================================
996 ECHOSTATUS
CDspCommObject::SendVector
998 DWORD dwCommand
// 32 bit command to send to DSP vector register
1001 ULONGLONG ullTimeout
;
1002 ULONGLONG ullCurTime
;
1005 // Turn this on if you want to see debug prints for every vector command
1010 switch ( dwCommand
)
1012 case DSP_VC_ACK_INT
:
1013 pszCmd
= "DSP_VC_ACK_INT";
1015 case DSP_VC_SET_VMIXER_GAIN
:
1016 pszCmd
= "DSP_VC_SET_VMIXER_GAIN";
1018 case DSP_VC_START_TRANSFER
:
1019 pszCmd
= "DSP_VC_START_TRANSFER";
1021 case DSP_VC_METERS_ON
:
1022 pszCmd
= "DSP_VC_METERS_ON";
1024 case DSP_VC_METERS_OFF
:
1025 pszCmd
= "DSP_VC_METERS_OFF";
1027 case DSP_VC_UPDATE_OUTVOL
:
1028 pszCmd
= "DSP_VC_UPDATE_OUTVOL";
1030 case DSP_VC_UPDATE_INGAIN
:
1031 pszCmd
= "DSP_VC_UPDATE_INGAIN";
1033 case DSP_VC_ADD_AUDIO_BUFFER
:
1034 pszCmd
= "DSP_VC_ADD_AUDIO_BUFFER";
1036 case DSP_VC_TEST_ASIC
:
1037 pszCmd
= "DSP_VC_TEST_ASIC";
1039 case DSP_VC_UPDATE_CLOCKS
:
1040 pszCmd
= "DSP_VC_UPDATE_CLOCKS";
1042 case DSP_VC_SET_LAYLA_SAMPLE_RATE
:
1043 if ( GetCardType() == LAYLA
)
1044 pszCmd
= "DSP_VC_SET_LAYLA_RATE";
1045 else if ( GetCardType() == GINA
|| GetCardType() == DARLA
)
1046 pszCmd
= "DSP_VC_SET_GD_AUDIO_STATE";
1048 pszCmd
= "DSP_VC_WRITE_CONTROL_REG";
1050 case DSP_VC_MIDI_WRITE
:
1051 pszCmd
= "DSP_VC_MIDI_WRITE";
1053 case DSP_VC_STOP_TRANSFER
:
1054 pszCmd
= "DSP_VC_STOP_TRANSFER";
1056 case DSP_VC_UPDATE_FLAGS
:
1057 pszCmd
= "DSP_VC_UPDATE_FLAGS";
1060 pszCmd
= "DSP_VC_RESET";
1067 ECHO_DEBUGPRINTF( ("SendVector: %s dwCommand %s (0x%x)\n",
1073 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
1074 ullTimeout
= ullCurTime
+ 100000L; // 100m.s.
1077 // Wait for the "vector busy" bit to be off
1079 while ( ullCurTime
<= ullTimeout
)
1083 dwReg
= GetDspRegister( CHI32_VECTOR_REG
);
1084 if ( 0 == (dwReg
& CHI32_VECTOR_BUSY
) )
1086 SetDspRegister( CHI32_VECTOR_REG
, dwCommand
);
1088 return ECHOSTATUS_OK
;
1090 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
1093 ECHO_DEBUGPRINTF( ("\tPunked out on SendVector\n") );
1095 return ECHOSTATUS_DSP_TIMEOUT
;
1097 } // ECHOSTATUS CDspCommObject::SendVector
1101 //===========================================================================
1103 // Some vector commands involve the DSP reading or writing data to and
1104 // from the comm page; if you send one of these commands to the DSP,
1105 // it will complete the command and then write a non-zero value to
1106 // the dwHandshake field in the comm page. This function waits for the
1107 // handshake to show up.
1109 //===========================================================================
1111 BOOL
CDspCommObject::WaitForHandshake()
1114 ULONGLONG ullStartTime
,ullTime
;
1117 // Wait up to three milliseconds for the handshake from the DSP
1119 m_pOsSupport
->OsGetSystemTime( &ullStartTime
);
1122 // Look for the handshake value
1123 if ( 0 != GetHandshakeFlag() )
1128 // Give the DSP time to access the comm page
1129 m_pOsSupport
->OsSnooze( 2 );
1131 m_pOsSupport
->OsGetSystemTime(&ullTime
);
1132 ullDelta
= ullTime
- ullStartTime
;
1133 } while (ullDelta
< (ULONGLONG
) HANDSHAKE_TIMEOUT
);
1135 ECHO_DEBUGPRINTF( ("CDspCommObject::WaitForHandshake: Timeout waiting "
1140 } // DWORD CDspCommObject::WaitForHandshake()
1145 /****************************************************************************
1149 ****************************************************************************/
1151 //===========================================================================
1153 // StartTransport starts transport for a set of pipes
1155 //===========================================================================
1157 ECHOSTATUS
CDspCommObject::StartTransport
1159 PCChannelMask pChannelMask
// Pipes to start
1162 ECHO_DEBUGPRINTF( ("StartTransport\n") );
1165 // Wait for the previous command to complete
1167 if ( !WaitForHandshake() )
1168 return ECHOSTATUS_DSP_DEAD
;
1171 // Write the appropriate fields in the comm page
1173 m_pDspCommPage
->cmdStart
.Clear();
1174 m_pDspCommPage
->cmdStart
= *pChannelMask
;
1175 if ( !m_pDspCommPage
->cmdStart
.IsEmpty() )
1178 // Clear the handshake and send the vector command
1181 SendVector( DSP_VC_START_TRANSFER
);
1184 // Keep track of which pipes are transporting
1186 m_cmActive
+= *pChannelMask
;
1188 return ECHOSTATUS_OK
;
1189 } // if this monkey is being started
1191 ECHO_DEBUGPRINTF( ("CDspCommObject::StartTransport: No pipes to start!\n") );
1192 return ECHOSTATUS_INVALID_CHANNEL
;
1194 } // ECHOSTATUS CDspCommObject::StartTransport
1197 //===========================================================================
1199 // StopTransport pauses transport for a set of pipes
1201 //===========================================================================
1203 ECHOSTATUS
CDspCommObject::StopTransport
1205 PCChannelMask pChannelMask
1208 ECHO_DEBUGPRINTF(("StopTransport\n"));
1211 // Wait for the last command to finish
1213 if ( !WaitForHandshake() )
1214 return ECHOSTATUS_DSP_DEAD
;
1217 // Write to the comm page
1219 m_pDspCommPage
->cmdStop
.Clear();
1220 m_pDspCommPage
->cmdStop
= *pChannelMask
;
1221 m_pDspCommPage
->cmdReset
.Clear();
1222 if ( !m_pDspCommPage
->cmdStop
.IsEmpty() )
1225 // Clear the handshake and send the vector command
1228 SendVector( DSP_VC_STOP_TRANSFER
);
1231 // Keep track of which pipes are transporting
1233 m_cmActive
-= *pChannelMask
;
1235 return ECHOSTATUS_OK
;
1236 } // if this monkey is being started
1238 ECHO_DEBUGPRINTF( ("CDspCommObject::StopTransport: No pipes to stop!\n") );
1239 return ECHOSTATUS_OK
;
1241 } // ECHOSTATUS CDspCommObject::StopTransport
1244 //===========================================================================
1246 // ResetTransport resets transport for a set of pipes
1248 //===========================================================================
1250 ECHOSTATUS
CDspCommObject::ResetTransport
1252 PCChannelMask pChannelMask
1255 ECHO_DEBUGPRINTF(("ResetTransport\n"));
1258 // Wait for the last command to finish
1260 if ( !WaitForHandshake() )
1261 return ECHOSTATUS_DSP_DEAD
;
1264 // Write to the comm page
1266 m_pDspCommPage
->cmdStop
.Clear();
1267 m_pDspCommPage
->cmdReset
.Clear();
1268 m_pDspCommPage
->cmdStop
= *pChannelMask
;
1269 m_pDspCommPage
->cmdReset
= *pChannelMask
;
1270 if ( !m_pDspCommPage
->cmdReset
.IsEmpty() )
1273 // Clear the handshake and send the vector command
1276 SendVector( DSP_VC_STOP_TRANSFER
);
1279 // Keep track of which pipes are transporting
1281 m_cmActive
-= *pChannelMask
;
1283 return ECHOSTATUS_OK
;
1284 } // if this monkey is being started
1286 ECHO_DEBUGPRINTF( ("CDspCommObject::ResetTransport: No pipes to reset!\n") );
1287 return ECHOSTATUS_OK
;
1289 } // ECHOSTATUS CDspCommObject::ResetTransport
1292 //===========================================================================
1294 // This tells the DSP where to start reading the scatter-gather list
1295 // for a given pipe.
1297 //===========================================================================
1299 void CDspCommObject::SetAudioDuckListPhys
1301 WORD wPipeIndex
, // Pipe index
1302 DWORD dwNewPhysAdr
// Physical address asserted on the PCI bus
1305 if (wPipeIndex
< GetNumPipes() )
1307 m_pDspCommPage
->DuckListPhys
[ wPipeIndex
].PhysAddr
=
1308 SWAP( dwNewPhysAdr
);
1310 } // void CDspCommObject::SetAudioDuckListPhys
1314 //===========================================================================
1316 // Get a mask with active pipes
1318 //===========================================================================
1320 void CDspCommObject::GetActivePipes
1322 PCChannelMask pChannelMask
1325 pChannelMask
->Clear();
1326 *pChannelMask
+= m_cmActive
;
1327 } // void CDspCommObject::GetActivePipes()
1330 //===========================================================================
1332 // Set the audio format for a pipe
1334 //===========================================================================
1336 ECHOSTATUS
CDspCommObject::SetAudioFormat
1339 PECHOGALS_AUDIOFORMAT pFormat
1342 WORD wDspFormat
= DSP_AUDIOFORM_SS_16LE
;
1344 ECHO_DEBUGPRINTF(("CDspCommObject::SetAudioFormat - pipe %d bps %d channels %d\n",
1345 wPipeIndex
,pFormat
->wBitsPerSample
,pFormat
->wDataInterleave
));
1348 // Check the pipe number
1350 if (wPipeIndex
>= GetNumPipes() )
1352 ECHO_DEBUGPRINTF( ("CDspCommObject::SetAudioFormat: Invalid pipe"
1355 return ECHOSTATUS_INVALID_CHANNEL
;
1359 // Look for super-interleave
1361 if (pFormat
->wDataInterleave
> 2)
1363 switch (pFormat
->wBitsPerSample
)
1366 wDspFormat
= DSP_AUDIOFORM_SUPER_INTERLEAVE_16LE
;
1370 wDspFormat
= DSP_AUDIOFORM_SUPER_INTERLEAVE_24LE
;
1374 wDspFormat
= DSP_AUDIOFORM_SUPER_INTERLEAVE_32LE
;
1378 wDspFormat
|= pFormat
->wDataInterleave
;
1383 // For big-endian data, only 32 bit mono->mono samples and 32 bit stereo->stereo
1386 if (pFormat
->byDataAreBigEndian
)
1389 switch ( pFormat
->wDataInterleave
)
1392 wDspFormat
= DSP_AUDIOFORM_MM_32BE
;
1395 #ifdef STEREO_BIG_ENDIAN32_SUPPORT
1397 wDspFormat
= DSP_AUDIOFORM_SS_32BE
;
1406 // Check for 32 bit little-endian mono->mono case
1408 if ( (1 == pFormat
->wDataInterleave
) &&
1409 (32 == pFormat
->wBitsPerSample
) &&
1410 (0 == pFormat
->byMonoToStereo
) )
1412 wDspFormat
= DSP_AUDIOFORM_MM_32LE
;
1417 // Handle the other little-endian formats
1419 switch (pFormat
->wBitsPerSample
)
1422 if (2 == pFormat
->wDataInterleave
)
1423 wDspFormat
= DSP_AUDIOFORM_SS_8
;
1425 wDspFormat
= DSP_AUDIOFORM_MS_8
;
1431 if (2 == pFormat
->wDataInterleave
)
1432 wDspFormat
= DSP_AUDIOFORM_SS_16LE
;
1434 wDspFormat
= DSP_AUDIOFORM_MS_16LE
;
1438 if (2 == pFormat
->wDataInterleave
)
1439 wDspFormat
= DSP_AUDIOFORM_SS_24LE
;
1441 wDspFormat
= DSP_AUDIOFORM_MS_24LE
;
1445 if (2 == pFormat
->wDataInterleave
)
1446 wDspFormat
= DSP_AUDIOFORM_SS_32LE
;
1448 wDspFormat
= DSP_AUDIOFORM_MS_32LE
;
1452 } // check other little-endian formats
1454 } // not big endian data
1456 } // not super-interleave
1458 m_pDspCommPage
->wAudioFormat
[wPipeIndex
] = SWAP( wDspFormat
);
1460 return ECHOSTATUS_OK
;
1462 } // ECHOSTATUS CDspCommObject::SetAudioFormat
1465 //===========================================================================
1467 // Get the audio format for a pipe
1469 //===========================================================================
1471 ECHOSTATUS
CDspCommObject::GetAudioFormat
1474 PECHOGALS_AUDIOFORMAT pFormat
1477 if (wPipeIndex
>= GetNumPipes() )
1479 ECHO_DEBUGPRINTF( ("CDspCommObject::GetAudioFormat: Invalid pipe %d\n",
1482 return ECHOSTATUS_INVALID_CHANNEL
;
1485 pFormat
->byDataAreBigEndian
= 0; // true for most of the formats
1486 pFormat
->byMonoToStereo
= 0;
1488 switch (SWAP(m_pDspCommPage
->wAudioFormat
[wPipeIndex
]))
1490 case DSP_AUDIOFORM_MS_8
:
1491 pFormat
->wDataInterleave
= 1;
1492 pFormat
->wBitsPerSample
= 8;
1493 pFormat
->byMonoToStereo
= 1;
1496 case DSP_AUDIOFORM_MS_16LE
:
1497 pFormat
->wDataInterleave
= 1;
1498 pFormat
->wBitsPerSample
= 16;
1499 pFormat
->byMonoToStereo
= 1;
1502 case DSP_AUDIOFORM_SS_8
:
1503 pFormat
->wDataInterleave
= 2;
1504 pFormat
->wBitsPerSample
= 8;
1507 case DSP_AUDIOFORM_SS_16LE
:
1508 pFormat
->wDataInterleave
= 2;
1509 pFormat
->wBitsPerSample
= 16;
1512 case DSP_AUDIOFORM_SS_32LE
:
1513 pFormat
->wDataInterleave
= 2;
1514 pFormat
->wBitsPerSample
= 32;
1517 case DSP_AUDIOFORM_MS_32LE
:
1518 pFormat
->byMonoToStereo
= 1;
1521 case DSP_AUDIOFORM_MM_32LE
:
1522 pFormat
->wDataInterleave
= 1;
1523 pFormat
->wBitsPerSample
= 32;
1526 case DSP_AUDIOFORM_MM_32BE
:
1527 pFormat
->wDataInterleave
= 1;
1528 pFormat
->wBitsPerSample
= 32;
1529 pFormat
->byDataAreBigEndian
= 1;
1532 case DSP_AUDIOFORM_SS_32BE
:
1533 pFormat
->wDataInterleave
= 2;
1534 pFormat
->wBitsPerSample
= 32;
1535 pFormat
->byDataAreBigEndian
= 1;
1540 return ECHOSTATUS_OK
;
1542 } // void CDspCommObject::GetAudioFormat
1546 /****************************************************************************
1550 ****************************************************************************/
1552 //===========================================================================
1554 // SetPipeOutGain - set the gain for a single output pipe
1556 //===========================================================================
1558 ECHOSTATUS
CDspCommObject::SetPipeOutGain
1566 if ( wPipeOut
< m_wNumPipesOut
)
1569 // Wait for the handshake
1571 if ( !WaitForHandshake() )
1572 return ECHOSTATUS_DSP_DEAD
;
1575 // Save the new value
1577 iGain
= GENERIC_TO_DSP(iGain
);
1578 m_pDspCommPage
->OutLineLevel
[ wPipeOut
] = (BYTE
) iGain
;
1581 ECHO_DEBUGPRINTF( ("CDspCommObject::SetPipeOutGain: Out pipe %d "
1588 // If fImmediate is true, then do the gain setting right now.
1589 // If you want to do a batch of gain settings all at once, it's
1590 // more efficient to call this several times and then only set
1591 // fImmediate for the last one; then the DSP picks up all of
1596 return UpdateAudioOutLineLevel();
1599 return ECHOSTATUS_OK
;
1603 ECHO_DEBUGPRINTF( ("CDspCommObject::SetPipeOutGain: Invalid out pipe "
1608 return ECHOSTATUS_INVALID_CHANNEL
;
1613 //===========================================================================
1615 // GetPipeOutGain returns the current gain for an output pipe. This isn't
1616 // really used as the mixer code in CEchoGals stores logical values for
1617 // these, but it's here for completeness.
1619 //===========================================================================
1621 ECHOSTATUS
CDspCommObject::GetPipeOutGain
1628 if (wPipeOut
< m_wNumPipesOut
)
1630 iGain
= (INT32
) (char) m_pDspCommPage
->OutLineLevel
[ wPipeOut
];
1631 iGain
= DSP_TO_GENERIC(8);
1632 return ECHOSTATUS_OK
;
1635 ECHO_DEBUGPRINTF( ("CDspCommObject::GetPipeOutGain: Invalid out pipe "
1639 return ECHOSTATUS_INVALID_CHANNEL
;
1645 //===========================================================================
1647 // Set input bus gain - iGain is in units of 0.5 dB
1649 //===========================================================================
1651 ECHOSTATUS
CDspCommObject::SetBusInGain( WORD wBusIn
, INT32 iGain
)
1653 if (wBusIn
> m_wNumBussesIn
)
1654 return ECHOSTATUS_INVALID_CHANNEL
;
1657 // Wait for the handshake (OK even if ASIC is not loaded)
1659 if ( !WaitForHandshake() )
1660 return ECHOSTATUS_DSP_DEAD
;
1663 // Adjust the gain value
1665 iGain
+= GL20_INPUT_GAIN_MAGIC_NUMBER
;
1668 // Put it in the comm page
1670 m_pDspCommPage
->InLineLevel
[wBusIn
] = (BYTE
) iGain
;
1672 return UpdateAudioInLineLevel();
1676 //===========================================================================
1678 // Get the input bus gain in units of 0.5 dB
1680 //===========================================================================
1682 ECHOSTATUS
CDspCommObject::GetBusInGain( WORD wBusIn
, INT32
&iGain
)
1684 if (wBusIn
> m_wNumBussesIn
)
1685 return ECHOSTATUS_INVALID_CHANNEL
;
1687 iGain
= m_pDspCommPage
->InLineLevel
[wBusIn
];
1688 iGain
-= GL20_INPUT_GAIN_MAGIC_NUMBER
;
1690 return ECHOSTATUS_OK
;
1694 //===========================================================================
1696 // Set the nominal level for an input or output bus
1698 // bState TRUE -10 nominal level
1699 // bState FALSE +4 nominal level
1701 //===========================================================================
1703 ECHOSTATUS
CDspCommObject::SetNominalLevel
1710 // Check the pipe index
1712 if (wBus
< (m_wNumBussesOut
+ m_wNumBussesIn
))
1715 // Wait for the handshake (OK even if ASIC is not loaded)
1717 if ( !WaitForHandshake() )
1718 return ECHOSTATUS_DSP_DEAD
;
1721 // Set the nominal bit
1724 m_pDspCommPage
->cmdNominalLevel
.SetIndexInMask( wBus
);
1726 m_pDspCommPage
->cmdNominalLevel
.ClearIndexInMask( wBus
);
1728 return UpdateAudioOutLineLevel();
1731 ECHO_DEBUGPRINTF( ("CDspCommObject::SetNominalOutLineLevel Invalid "
1734 return ECHOSTATUS_INVALID_CHANNEL
;
1736 } // ECHOSTATUS CDspCommObject::SetNominalLevel
1739 //===========================================================================
1741 // Get the nominal level for an input or output bus
1743 // bState TRUE -10 nominal level
1744 // bState FALSE +4 nominal level
1746 //===========================================================================
1748 ECHOSTATUS
CDspCommObject::GetNominalLevel
1755 if (wBus
< (m_wNumBussesOut
+ m_wNumBussesIn
))
1758 m_pDspCommPage
->cmdNominalLevel
.TestIndexInMask( wBus
);
1759 return ECHOSTATUS_OK
;
1762 ECHO_DEBUGPRINTF( ("CDspCommObject::GetNominalLevel Invalid "
1765 return ECHOSTATUS_INVALID_CHANNEL
;
1766 } // ECHOSTATUS CDspCommObject::GetNominalLevel
1769 //===========================================================================
1771 // Set the monitor level from an input bus to an output bus.
1773 //===========================================================================
1775 ECHOSTATUS
CDspCommObject::SetAudioMonitor
1777 WORD wBusOut
, // output bus
1778 WORD wBusIn
, // input bus
1784 ECHO_DEBUGPRINTF( ("CDspCommObject::SetAudioMonitor: "
1785 "Out %d in %d Gain %d (0x%x)\n",
1786 wBusOut, wBusIn, iGain, iGain) );
1790 // The monitor array is a one-dimensional array;
1791 // compute the offset into the array
1793 WORD wOffset
= ComputeAudioMonitorIndex( wBusOut
, wBusIn
);
1796 // Wait for the offset
1798 if ( !WaitForHandshake() )
1799 return ECHOSTATUS_DSP_DEAD
;
1802 // Write the gain value to the comm page
1804 iGain
= GENERIC_TO_DSP(iGain
);
1805 m_pDspCommPage
->byMonitors
[ wOffset
] = (BYTE
) (iGain
);
1808 // If fImmediate is set, do the command right now
1812 return UpdateAudioOutLineLevel();
1815 return ECHOSTATUS_OK
;
1817 } // ECHOSTATUS CDspCommObject::SetAudioMonitor
1820 //===========================================================================
1822 // SetMetersOn turns the meters on or off. If meters are turned on, the
1823 // DSP will write the meter and clock detect values to the comm page
1826 //===========================================================================
1828 ECHOSTATUS
CDspCommObject::SetMetersOn
1835 if ( 0 == m_wMeterOnCount
)
1837 SendVector( DSP_VC_METERS_ON
);
1845 if ( m_wMeterOnCount
== 0 )
1846 return ECHOSTATUS_OK
;
1848 if ( 0 == --m_wMeterOnCount
)
1850 SendVector( DSP_VC_METERS_OFF
);
1852 for ( iDevice
= 0; iDevice
< DSP_MAXPIPES
; iDevice
++ )
1856 muted
= (BYTE
) GENERIC_TO_DSP(ECHOGAIN_MUTED
);
1857 m_pDspCommPage
->VUMeter
[ iDevice
] = muted
;
1858 m_pDspCommPage
->PeakMeter
[ iDevice
] = muted
;
1862 return ECHOSTATUS_OK
;
1864 } // ECHOSTATUS CDspCommObject::SetMetersOn
1867 //===========================================================================
1869 // Tell the DSP to read and update output, nominal & monitor levels
1872 //===========================================================================
1874 ECHOSTATUS
CDspCommObject::UpdateAudioOutLineLevel()
1876 //ECHO_DEBUGPRINTF( ( "CDspCommObject::UpdateAudioOutLineLevel:\n" ) );
1878 if (FALSE
== m_bASICLoaded
)
1879 return ECHOSTATUS_ASIC_NOT_LOADED
;
1882 return( SendVector( DSP_VC_UPDATE_OUTVOL
) );
1884 } // ECHOSTATUS CDspCommObject::UpdateAudioOutLineLevel()
1887 //===========================================================================
1889 // Tell the DSP to read and update input levels in comm page
1891 //===========================================================================
1893 ECHOSTATUS
CDspCommObject::UpdateAudioInLineLevel()
1895 //ECHO_DEBUGPRINTF( ( "CDspCommObject::UpdateAudioInLineLevel:\n" ) );
1897 if (FALSE
== m_bASICLoaded
)
1898 return ECHOSTATUS_ASIC_NOT_LOADED
;
1901 return( SendVector( DSP_VC_UPDATE_INGAIN
) );
1902 } // ECHOSTATUS CDspCommObject::UpdateAudioInLineLevel()
1905 //===========================================================================
1907 // Tell the DSP to read and update virtual mixer levels
1908 // in comm page. This method is overridden by cards that actually
1909 // support a vmixer.
1911 //===========================================================================
1913 ECHOSTATUS
CDspCommObject::UpdateVmixerLevel()
1915 ECHO_DEBUGPRINTF(("CDspCommObject::UpdateVmixerLevel\n"));
1916 return ECHOSTATUS_NOT_SUPPORTED
;
1917 } // ECHOSTATUS CDspCommObject::UpdateVmixerLevel()
1920 //===========================================================================
1922 // Tell the DSP to change the input clock
1924 //===========================================================================
1926 ECHOSTATUS
CDspCommObject::SetInputClock(WORD wClock
)
1929 // Wait for the last command
1931 if (!WaitForHandshake())
1932 return ECHOSTATUS_DSP_DEAD
;
1934 ECHO_DEBUGPRINTF( ("CDspCommObject::SetInputClock:\n") );
1937 // Write to the comm page
1939 m_pDspCommPage
->wInputClock
= SWAP(wClock
);
1942 // Clear the handshake and send the command
1945 ECHOSTATUS Status
= SendVector(DSP_VC_UPDATE_CLOCKS
);
1949 } // ECHOSTATUS CDspCommObject::SetInputClock
1952 //===========================================================================
1954 // Tell the DSP to change the output clock - Layla20 only
1956 //===========================================================================
1958 ECHOSTATUS
CDspCommObject::SetOutputClock(WORD wClock
)
1961 return ECHOSTATUS_CLOCK_NOT_SUPPORTED
;
1963 } // ECHOSTATUS CDspCommObject::SetOutputClock
1966 //===========================================================================
1968 // Fill out an ECHOGALS_METERS struct using the current values in the
1969 // comm page. This method is overridden for vmixer cards.
1971 //===========================================================================
1973 ECHOSTATUS
CDspCommObject::GetAudioMeters
1975 PECHOGALS_METERS pMeters
1978 pMeters
->iNumPipesOut
= 0;
1979 pMeters
->iNumPipesIn
= 0;
1987 pMeters
->iNumBussesOut
= (INT32
) m_wNumBussesOut
;
1988 for (i
= 0; i
< m_wNumBussesOut
; i
++)
1990 pMeters
->iBusOutVU
[i
] =
1991 DSP_TO_GENERIC( ((INT32
) (INT8
) m_pDspCommPage
->VUMeter
[ dwCh
]) );
1993 pMeters
->iBusOutPeak
[i
] =
1994 DSP_TO_GENERIC( ((INT32
) (INT8
) m_pDspCommPage
->PeakMeter
[ dwCh
]) );
1999 pMeters
->iNumBussesIn
= (INT32
) m_wNumBussesIn
;
2000 for (i
= 0; i
< m_wNumBussesIn
; i
++)
2002 pMeters
->iBusInVU
[i
] =
2003 DSP_TO_GENERIC( ((INT32
) (INT8
) m_pDspCommPage
->VUMeter
[ dwCh
]) );
2004 pMeters
->iBusInPeak
[i
] =
2005 DSP_TO_GENERIC( ((INT32
) (INT8
) m_pDspCommPage
->PeakMeter
[ dwCh
]) );
2010 return ECHOSTATUS_OK
;
2015 #ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT
2017 //===========================================================================
2019 // Digital input auto-mute - Gina24, Layla24, and Mona only
2021 //===========================================================================
2023 ECHOSTATUS
CDspCommObject::GetDigitalInputAutoMute(BOOL
&fAutoMute
)
2025 fAutoMute
= m_fDigitalInAutoMute
;
2027 ECHO_DEBUGPRINTF(("CDspCommObject::GetDigitalInputAutoMute %d\n",fAutoMute
));
2029 return ECHOSTATUS_OK
;
2032 ECHOSTATUS
CDspCommObject::SetDigitalInputAutoMute(BOOL fAutoMute
)
2034 ECHO_DEBUGPRINTF(("CDspCommObject::SetDigitalInputAutoMute %d\n",fAutoMute
));
2039 m_fDigitalInAutoMute
= fAutoMute
;
2042 // Re-set the input clock to the current value - indirectly causes the
2043 // auto-mute flag to be sent to the DSP
2045 SetInputClock(m_wInputClock
);
2047 return ECHOSTATUS_OK
;
2050 #endif // DIGITAL_INPUT_AUTO_MUTE_SUPPORT
2055 /****************************************************************************
2059 ****************************************************************************/
2061 //===========================================================================
2063 // Tell the DSP to go into low-power mode
2065 //===========================================================================
2067 ECHOSTATUS
CDspCommObject::GoComatose()
2069 ECHO_DEBUGPRINTF(("CDspCommObject::GoComatose\n"));
2071 if (NULL
!= m_pwDspCode
)
2074 // Make LoadFirmware do a complete reload
2079 // Make sure that the sample rate get re-set on wakeup
2080 // (really only for Indigo and Mia)
2082 m_pDspCommPage
->dwControlReg
= 0;
2085 // Put the DSP to sleep
2087 return SendVector(DSP_VC_GO_COMATOSE
);
2090 return ECHOSTATUS_OK
;
2092 } // end of GoComatose
2098 /****************************************************************************
2102 ****************************************************************************/
2104 //===========================================================================
2106 // Send a buffer full of MIDI data to the DSP
2108 //===========================================================================
2110 ECHOSTATUS
CDspCommObject::WriteMidi
2112 PBYTE pData
, // Ptr to data buffer
2113 DWORD dwLength
, // How many bytes to write
2114 PDWORD pdwActualCt
// Return how many actually written
2117 DWORD dwWriteCount
,dwHandshake
,dwStatus
;
2122 // Return immediately if the handshake flag is clar
2124 dwHandshake
= GetHandshakeFlag();
2125 if (0 == dwHandshake
)
2127 ECHO_DEBUGPRINTF(("CDCO::WriteMidi - can't write - handshake %ld\n",dwHandshake
));
2130 return ECHOSTATUS_BUSY
;
2134 // Return immediately if HF4 is clear - HF4 indicates that it is safe
2135 // to write MIDI output data
2137 dwStatus
= GetDspRegister( CHI32_STATUS_REG
);
2138 if ( 0 == (dwStatus
& CHI32_STATUS_REG_HF4
) )
2140 ECHO_DEBUGPRINTF(("CDCO::WriteMidi - can't write - dwStatus 0x%lx\n",dwStatus
));
2143 return ECHOSTATUS_BUSY
;
2148 // Copy data to the comm page; limit to the amount of space in the DSP output
2149 // FIFO and in the comm page
2151 dwWriteCount
= dwLength
;
2152 if (dwWriteCount
> (CP_MIDI_OUT_BUFFER_SIZE
- 1))
2154 dwWriteCount
= CP_MIDI_OUT_BUFFER_SIZE
- 1;
2157 ECHO_DEBUGPRINTF(("WriteMidi - dwWriteCount %ld\n",dwWriteCount
));
2159 *pdwActualCt
= dwWriteCount
; // Save the # of bytes written for the caller
2161 pOutBuffer
= m_pDspCommPage
->byMidiOutData
;
2162 *pOutBuffer
= (BYTE
) dwWriteCount
;
2166 OsCopyMemory(pOutBuffer
,pData
,dwWriteCount
);
2169 // Send the command to the DSP
2172 m_pDspCommPage
->dwMidiOutFreeCount
= 0;
2173 SendVector( DSP_VC_MIDI_WRITE
);
2176 // Save the current time - used to detect if MIDI out is currently busy
2180 m_pOsSupport
->OsGetSystemTime( &ullTime
);
2181 m_ullMidiOutTime
= ullTime
;
2183 return ECHOSTATUS_OK
;
2185 } // ECHOSTATUS CDspCommObject::WriteMidi
2188 //===========================================================================
2190 // Called from the interrupt handler - get a MIDI input byte
2192 //===========================================================================
2194 ECHOSTATUS
CDspCommObject::ReadMidi
2196 WORD wIndex
, // Buffer index
2197 DWORD
& dwData
// Return data
2200 if ( wIndex
>= CP_MIDI_IN_BUFFER_SIZE
)
2201 return ECHOSTATUS_INVALID_INDEX
;
2206 dwData
= SWAP( m_pDspCommPage
->wMidiInData
[ wIndex
] );
2209 // Timestamp for the MIDI input activity indicator
2213 m_pOsSupport
->OsGetSystemTime( &ullTime
);
2214 m_ullMidiInTime
= ullTime
;
2216 return ECHOSTATUS_OK
;
2218 } // ECHOSTATUS CDspCommObject::ReadMidi
2221 ECHOSTATUS
CDspCommObject::SetMidiOn( BOOL bOn
)
2225 if ( 0 == m_wMidiOnCount
)
2227 if ( !WaitForHandshake() )
2228 return ECHOSTATUS_DSP_DEAD
;
2230 m_pDspCommPage
->dwFlags
|= SWAP( (DWORD
) DSP_FLAG_MIDI_INPUT
);
2233 SendVector( DSP_VC_UPDATE_FLAGS
);
2239 if ( m_wMidiOnCount
== 0 )
2240 return ECHOSTATUS_OK
;
2242 if ( 0 == --m_wMidiOnCount
)
2244 if ( !WaitForHandshake() )
2245 return ECHOSTATUS_DSP_DEAD
;
2247 m_pDspCommPage
->dwFlags
&= SWAP( (DWORD
) ~DSP_FLAG_MIDI_INPUT
);
2250 SendVector( DSP_VC_UPDATE_FLAGS
);
2254 return ECHOSTATUS_OK
;
2256 } // ECHOSTATUS CDspCommObject::SetMidiOn
2259 //===========================================================================
2261 // Detect MIDI output activity
2263 //===========================================================================
2265 BOOL
CDspCommObject::IsMidiOutActive()
2267 ULONGLONG ullCurTime
;
2269 m_pOsSupport
->OsGetSystemTime( &ullCurTime
);
2270 return( ( ( ullCurTime
- m_ullMidiOutTime
) > MIDI_ACTIVITY_TIMEOUT_USEC
) ? FALSE
: TRUE
);
2272 } // BOOL CDspCommObject::IsMidiOutActive()
2275 #endif // MIDI_SUPPORT
2279 // **** CDspCommObject.cpp ****