BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / audio / echo / generic / CDspCommObject.cpp
blob908e0b49a78031ddd9a02c3277e23fce11125380
1 // ****************************************************************************
2 //
3 // CDspCommObject.cpp
4 //
5 // Implementation file for EchoGals generic driver DSP interface class.
6 //
7 // ----------------------------------------------------------------------------
8 //
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
12 // www.echoaudio.com
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"
32 #ifdef DSP_56361
33 #include "LoaderDSP.c"
34 #endif
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 )
54 PVOID pMemory;
55 ECHOSTATUS Status;
57 Status = OsAllocateNonPaged(Size,&pMemory);
59 if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory ))
61 ECHO_DEBUGPRINTF(("CDspCommObject::operator new - memory allocation failed\n"));
63 pMemory = NULL;
65 else
67 memset( pMemory, 0, Size );
70 return pMemory;
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 "
80 "failed\n") );
82 } // VOID CDspCommObject::operator delete( PVOID pVoid )
85 //===========================================================================
87 // Constructor
89 //===========================================================================
91 CDspCommObject::CDspCommObject
93 PDWORD pdwDspRegBase, // Virtual ptr to DSP registers
94 PCOsSupport pOsSupport
97 INT32 i;
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
114 #ifdef MIDI_SUPPORT
115 m_ullNextMidiWriteTime = 0;
116 #endif
119 // Create the DSP comm page - this is the area of memory read and written by
120 // the DSP via bus mastering
122 ECHOSTATUS Status;
123 DWORD dwSegmentSize;
124 PHYS_ADDR PhysAddr;
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") );
132 return;
135 m_pDspCommPage = (PDspCommPage) pOsSupport->
136 GetPageBlockVirtAddress( m_pDspCommPageBlock );
138 pOsSupport->GetPageBlockPhysSegment(m_pDspCommPageBlock,
140 PhysAddr,
141 dwSegmentSize);
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;
169 #endif
171 } // CDspCommObject::CDspCommObject
174 //===========================================================================
176 // Destructor
178 //===========================================================================
180 CDspCommObject::~CDspCommObject()
183 // Go to sleep
185 GoComatose();
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()
222 DWORD dwAsicStatus;
223 DWORD dwReturn;
226 // Always succeed if this card doesn't have an ASIC
228 if ( !m_bHasASIC )
230 m_bASICLoaded = TRUE;
231 return 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"));
244 ECHO_DEBUGBREAK();
245 return FALSE;
248 #ifdef ECHO_DEBUG
249 if ( (dwAsicStatus != ASIC_LOADED) && (dwAsicStatus != ASIC_NOT_LOADED) )
251 ECHO_DEBUGBREAK();
253 #endif
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
271 DWORD dwCmd,
272 PBYTE pCode,
273 DWORD dwSize
276 DWORD i;
277 #ifdef _WIN32
278 DWORD dwChecksum = 0;
279 #endif
281 ECHO_DEBUGPRINTF(("CDspCommObject::LoadASIC\n"));
283 if ( !m_bHasASIC )
284 return TRUE;
286 #ifdef _DEBUG
287 ULONGLONG ullStartTime, ullCurTime;
288 m_pOsSupport->OsGetSystemTime( &ullStartTime );
289 #endif
291 // Send the "Here comes the ASIC" command
292 if ( ECHOSTATUS_OK != Write_DSP( dwCmd ) )
293 return FALSE;
295 // Write length of ASIC file in bytes
296 if ( ECHOSTATUS_OK != Write_DSP( dwSize ) )
297 return FALSE;
299 for ( i = 0; i < dwSize; i++ )
301 #ifdef _WIN32
302 dwChecksum += pCode[i];
303 #endif
305 if ( ECHOSTATUS_OK != Write_DSP( pCode[ i ] ) )
307 ECHO_DEBUGPRINTF(("\tfailed on Write_DSP\n"));
308 return FALSE;
312 #ifdef _DEBUG
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"));
317 #endif
319 #if defined(_WIN32) && (DBG)
320 DbgPrint("--- ASIC checksum is 0x%lx\n",dwChecksum);
321 #endif
323 return TRUE;
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 //===========================================================================
340 #ifdef DSP_56361
342 ECHOSTATUS CDspCommObject::InstallResidentLoader()
344 DWORD dwAddress;
345 DWORD dwIndex;
346 INT32 iNum;
347 INT32 i;
348 DWORD dwReturn;
349 PWORD pCode;
351 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader\n") );
354 // 56361 cards only!
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.
363 DWORD dwStatus;
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",
368 dwStatus));
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 //---------------------------------------------------------------------------
379 // Loader
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 //---------------------------------------------------------------------------
393 pCode = pwLoaderDSP;
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
397 // by pCode[0].
399 dwIndex = pCode[ 0 ];
401 // Skip the section size, LRS block type, and DSP memory type
403 dwIndex += 3;
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 ];
412 dwIndex += 2;
414 // Write the count to the DSP
416 dwReturn = Write_DSP( (DWORD) iNum );
417 if ( dwReturn != 0 )
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 );
426 if ( dwReturn != 0 )
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++) //
437 DWORD dwData;
439 dwData = ( pCode[ dwIndex ] << 16 ) + pCode[ dwIndex + 1 ];
440 dwReturn = Write_DSP( dwData );
441 if ( dwReturn != 0 )
443 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader: Failed to "
444 "write DSP code\n") );
445 return ECHOSTATUS_DSP_DEAD;
448 dwIndex+=2;
452 // Wait for flag 5 to come up
454 BOOL fSuccess;
455 ULONGLONG ullCurTime,ullTimeout;
457 m_pOsSupport->OsGetSystemTime( &ullCurTime );
458 ullTimeout = ullCurTime + 10000L; // 10m.s.
459 fSuccess = FALSE;
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))
468 fSuccess = TRUE;
469 break;
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()
488 #endif // DSP_56361
491 //===========================================================================
493 // LoadDSP
495 // This loads the DSP code.
497 //===========================================================================
499 ECHOSTATUS CDspCommObject::LoadDSP
501 PWORD pCode // Ptr to DSP object code
504 DWORD dwAddress;
505 DWORD dwIndex;
506 INT32 iNum;
507 INT32 i;
508 DWORD dwReturn;
509 ULONGLONG ullTimeout, ullCurTime;
510 ECHOSTATUS Status;
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.
527 #ifdef DSP_56361
528 InstallResidentLoader();
529 #endif
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;
540 // Delay 10us
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
548 wait_for_hf3:
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;
562 goto wait_for_hf3;
565 // Set DSP format bits for 24 bit mode now that soft reset is done
566 set_dsp_format_bits:
567 SetDspRegister( CHI32_CONTROL_REG,
568 GetDspRegister( CHI32_CONTROL_REG ) | (DWORD) 0x900 );
570 //---------------------------------------------------------------------------
571 // Main loader loop
572 //---------------------------------------------------------------------------
574 dwIndex = pCode[ 0 ];
576 for (;;)
578 INT32 iBlockType;
579 INT32 iMemType;
581 // Total Block Size
582 dwIndex++;
584 // Block Type
585 iBlockType = pCode[ dwIndex ];
586 if ( iBlockType == 4 ) // We're finished
587 break;
589 dwIndex++;
591 // Memory Type P=0,X=1,Y=2
592 iMemType = pCode[ dwIndex ];
593 dwIndex++;
595 // Block Code Size
596 iNum = pCode[ dwIndex ];
597 dwIndex++;
598 if ( iNum == 0 ) // We're finished
599 break;
601 // Start Address
602 dwAddress = ( (DWORD) pCode[ dwIndex ] << 16 ) + pCode[ dwIndex + 1 ];
603 // ECHO_DEBUGPRINTF( ("\tdwAddress %lX\n", dwAddress) );
604 dwIndex += 2;
606 dwReturn = Write_DSP( (DWORD)iNum );
607 if ( dwReturn != 0 )
609 ECHO_DEBUGPRINTF(("LoadDSP - failed to write number of DSP words\n"));
610 return ECHOSTATUS_DSP_DEAD;
613 dwReturn = Write_DSP( dwAddress );
614 if ( dwReturn != 0 )
616 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP address\n"));
617 return ECHOSTATUS_DSP_DEAD;
620 dwReturn = Write_DSP( (DWORD)iMemType );
621 if ( dwReturn != 0 )
623 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP memory type\n"));
624 return ECHOSTATUS_DSP_DEAD;
627 // Code
628 for ( i = 0; i < iNum; i++ )
630 DWORD dwData;
632 dwData = ( (DWORD) pCode[ dwIndex ] << 16 ) + pCode[ dwIndex + 1 ];
633 dwReturn = Write_DSP( dwData );
634 if ( dwReturn != 0 )
636 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP data\n"));
637 return ECHOSTATUS_DSP_DEAD;
640 dwIndex += 2;
642 // ECHO_DEBUGPRINTF( ("\tEnd Code Block\n") );
644 dwReturn = Write_DSP( 0 ); // We're done!!!
645 if ( dwReturn != 0 )
647 ECHO_DEBUGPRINTF(("LoadDSP: Failed to write final zero\n"));
648 return ECHOSTATUS_DSP_DEAD;
652 // Delay 10us
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 );
669 if ( dwReturn != 0 )
671 ECHO_DEBUGPRINTF(("LoadDSP - Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n"));
672 return ECHOSTATUS_DSP_DEAD;
675 dwReturn = Write_DSP( m_dwCommPagePhys );
676 if ( dwReturn != 0 )
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.
688 Status = ReadSn();
689 if ( ECHOSTATUS_OK != Status )
691 ECHO_DEBUGPRINTF(("LoadDSP - Failed to read serial number\n"));
692 return Status;
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()
723 ECHOSTATUS dwReturn;
724 ULONGLONG ullRightNow;
726 // Sanity check
727 if ( NULL == m_pwDspCodeToLoad || NULL == m_pDspCommPage )
729 ECHO_DEBUGBREAK();
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
762 m_pwDspCode = NULL;
766 // Try and load the DSP
768 dwReturn = LoadDSP( m_pwDspCodeToLoad );
769 if ( (ECHOSTATUS_OK != dwReturn) &&
770 (ECHOSTATUS_FIRMWARE_LOADED != dwReturn) )
772 return 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;
786 else
789 // ASIC load was successful
791 RestoreDspSettings();
793 dwReturn = ECHOSTATUS_OK;
796 return dwReturn;
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()
814 INT32 j;
815 DWORD dwSn[ 6 ];
816 ECHOSTATUS Status;
818 ECHO_DEBUGPRINTF( ("CDspCommObject::ReadSn\n") );
819 for ( j = 0; j < 5; j++ )
821 Status = Read_DSP( &dwSn[ j ] );
822 if ( Status != 0 )
824 ECHO_DEBUGPRINTF( ("\tFailed to read serial number word %ld\n",
825 j) );
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,
841 // monitors, etc.
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() )
851 return;
853 m_pDspCommPage->dwHandshake = 0xffffffff;
855 #ifdef MIDI_SUPPORT
856 m_ullNextMidiWriteTime = 0;
857 #endif
859 SetSampleRate();
860 if ( 0 != m_wMeterOnCount )
862 SendVector( DSP_VC_METERS_ON );
865 SetInputClock( m_wInputClock );
866 SetOutputClock( m_wOutputClock );
868 if ( !WaitForHandshake() )
870 return;
872 UpdateAudioOutLineLevel();
874 if ( !WaitForHandshake() )
875 return;
876 UpdateAudioInLineLevel();
878 if ( HasVmixer() )
880 if ( !WaitForHandshake() )
881 return;
882 UpdateVmixerLevel();
885 if ( !WaitForHandshake() )
886 return;
888 ClearHandshake();
889 SendVector( DSP_VC_UPDATE_FLAGS );
891 ECHO_DEBUGPRINTF(("RestoreDspSettings done\n"));
893 } // void CDspCommObject::RestoreDspSettings()
898 /****************************************************************************
900 DSP utilities
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
916 DWORD dwStatus;
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
958 DWORD dwStatus;
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
1007 #if 0
1008 //#ifdef ECHO_DEBUG
1009 char * pszCmd;
1010 switch ( dwCommand )
1012 case DSP_VC_ACK_INT :
1013 pszCmd = "DSP_VC_ACK_INT";
1014 break;
1015 case DSP_VC_SET_VMIXER_GAIN :
1016 pszCmd = "DSP_VC_SET_VMIXER_GAIN";
1017 break;
1018 case DSP_VC_START_TRANSFER :
1019 pszCmd = "DSP_VC_START_TRANSFER";
1020 break;
1021 case DSP_VC_METERS_ON :
1022 pszCmd = "DSP_VC_METERS_ON";
1023 break;
1024 case DSP_VC_METERS_OFF :
1025 pszCmd = "DSP_VC_METERS_OFF";
1026 break;
1027 case DSP_VC_UPDATE_OUTVOL :
1028 pszCmd = "DSP_VC_UPDATE_OUTVOL";
1029 break;
1030 case DSP_VC_UPDATE_INGAIN :
1031 pszCmd = "DSP_VC_UPDATE_INGAIN";
1032 break;
1033 case DSP_VC_ADD_AUDIO_BUFFER :
1034 pszCmd = "DSP_VC_ADD_AUDIO_BUFFER";
1035 break;
1036 case DSP_VC_TEST_ASIC :
1037 pszCmd = "DSP_VC_TEST_ASIC";
1038 break;
1039 case DSP_VC_UPDATE_CLOCKS :
1040 pszCmd = "DSP_VC_UPDATE_CLOCKS";
1041 break;
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";
1047 else
1048 pszCmd = "DSP_VC_WRITE_CONTROL_REG";
1049 break;
1050 case DSP_VC_MIDI_WRITE :
1051 pszCmd = "DSP_VC_MIDI_WRITE";
1052 break;
1053 case DSP_VC_STOP_TRANSFER :
1054 pszCmd = "DSP_VC_STOP_TRANSFER";
1055 break;
1056 case DSP_VC_UPDATE_FLAGS :
1057 pszCmd = "DSP_VC_UPDATE_FLAGS";
1058 break;
1059 case DSP_VC_RESET :
1060 pszCmd = "DSP_VC_RESET";
1061 break;
1062 default :
1063 pszCmd = "?????";
1064 break;
1067 ECHO_DEBUGPRINTF( ("SendVector: %s dwCommand %s (0x%x)\n",
1068 GetCardName(),
1069 pszCmd,
1070 dwCommand) );
1071 #endif
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)
1081 DWORD dwReg;
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") );
1094 ECHO_DEBUGBREAK();
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()
1113 ULONGLONG ullDelta;
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() )
1125 return TRUE;
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 "
1136 "for DSP\n") );
1137 ECHO_DEBUGBREAK();
1138 return FALSE;
1140 } // DWORD CDspCommObject::WaitForHandshake()
1145 /****************************************************************************
1147 Transport methods
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
1180 ClearHandshake();
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
1227 ClearHandshake();
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
1275 ClearHandshake();
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
1338 WORD wPipeIndex,
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"
1353 "%d\n",
1354 wPipeIndex) );
1355 return ECHOSTATUS_INVALID_CHANNEL;
1359 // Look for super-interleave
1361 if (pFormat->wDataInterleave > 2)
1363 switch (pFormat->wBitsPerSample)
1365 case 16 :
1366 wDspFormat = DSP_AUDIOFORM_SUPER_INTERLEAVE_16LE;
1367 break;
1369 case 24 :
1370 wDspFormat = DSP_AUDIOFORM_SUPER_INTERLEAVE_24LE;
1371 break;
1373 case 32 :
1374 wDspFormat = DSP_AUDIOFORM_SUPER_INTERLEAVE_32LE;
1375 break;
1378 wDspFormat |= pFormat->wDataInterleave;
1380 else
1383 // For big-endian data, only 32 bit mono->mono samples and 32 bit stereo->stereo
1384 // are supported
1386 if (pFormat->byDataAreBigEndian)
1389 switch ( pFormat->wDataInterleave )
1391 case 1 :
1392 wDspFormat = DSP_AUDIOFORM_MM_32BE;
1393 break;
1395 #ifdef STEREO_BIG_ENDIAN32_SUPPORT
1396 case 2 :
1397 wDspFormat = DSP_AUDIOFORM_SS_32BE;
1398 break;
1399 #endif
1403 else
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;
1414 else
1417 // Handle the other little-endian formats
1419 switch (pFormat->wBitsPerSample)
1421 case 8 :
1422 if (2 == pFormat->wDataInterleave)
1423 wDspFormat = DSP_AUDIOFORM_SS_8;
1424 else
1425 wDspFormat = DSP_AUDIOFORM_MS_8;
1427 break;
1429 default :
1430 case 16 :
1431 if (2 == pFormat->wDataInterleave)
1432 wDspFormat = DSP_AUDIOFORM_SS_16LE;
1433 else
1434 wDspFormat = DSP_AUDIOFORM_MS_16LE;
1435 break;
1437 case 24 :
1438 if (2 == pFormat->wDataInterleave)
1439 wDspFormat = DSP_AUDIOFORM_SS_24LE;
1440 else
1441 wDspFormat = DSP_AUDIOFORM_MS_24LE;
1442 break;
1444 case 32 :
1445 if (2 == pFormat->wDataInterleave)
1446 wDspFormat = DSP_AUDIOFORM_SS_32LE;
1447 else
1448 wDspFormat = DSP_AUDIOFORM_MS_32LE;
1449 break;
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
1473 WORD wPipeIndex,
1474 PECHOGALS_AUDIOFORMAT pFormat
1477 if (wPipeIndex >= GetNumPipes() )
1479 ECHO_DEBUGPRINTF( ("CDspCommObject::GetAudioFormat: Invalid pipe %d\n",
1480 wPipeIndex) );
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;
1494 break;
1496 case DSP_AUDIOFORM_MS_16LE :
1497 pFormat->wDataInterleave = 1;
1498 pFormat->wBitsPerSample = 16;
1499 pFormat->byMonoToStereo = 1;
1500 break;
1502 case DSP_AUDIOFORM_SS_8 :
1503 pFormat->wDataInterleave = 2;
1504 pFormat->wBitsPerSample = 8;
1505 break;
1507 case DSP_AUDIOFORM_SS_16LE :
1508 pFormat->wDataInterleave = 2;
1509 pFormat->wBitsPerSample = 16;
1510 break;
1512 case DSP_AUDIOFORM_SS_32LE :
1513 pFormat->wDataInterleave = 2;
1514 pFormat->wBitsPerSample = 32;
1515 break;
1517 case DSP_AUDIOFORM_MS_32LE :
1518 pFormat->byMonoToStereo = 1;
1519 // fall through
1521 case DSP_AUDIOFORM_MM_32LE :
1522 pFormat->wDataInterleave = 1;
1523 pFormat->wBitsPerSample = 32;
1524 break;
1526 case DSP_AUDIOFORM_MM_32BE :
1527 pFormat->wDataInterleave = 1;
1528 pFormat->wBitsPerSample = 32;
1529 pFormat->byDataAreBigEndian = 1;
1530 break;
1532 case DSP_AUDIOFORM_SS_32BE :
1533 pFormat->wDataInterleave = 2;
1534 pFormat->wBitsPerSample = 32;
1535 pFormat->byDataAreBigEndian = 1;
1536 break;
1540 return ECHOSTATUS_OK;
1542 } // void CDspCommObject::GetAudioFormat
1546 /****************************************************************************
1548 Mixer methods
1550 ****************************************************************************/
1552 //===========================================================================
1554 // SetPipeOutGain - set the gain for a single output pipe
1556 //===========================================================================
1558 ECHOSTATUS CDspCommObject::SetPipeOutGain
1560 WORD wPipeOut,
1561 WORD wBusOut,
1562 INT32 iGain,
1563 BOOL fImmediate
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 "
1582 "= 0x%lx\n",
1583 wPipeOut,
1584 iGain) );
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
1592 // them at once.
1594 if (fImmediate)
1596 return UpdateAudioOutLineLevel();
1599 return ECHOSTATUS_OK;
1603 ECHO_DEBUGPRINTF( ("CDspCommObject::SetPipeOutGain: Invalid out pipe "
1604 "%d\n",
1605 wPipeOut) );
1606 ECHO_DEBUGBREAK();
1608 return ECHOSTATUS_INVALID_CHANNEL;
1610 } // SetPipeOutGain
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
1623 WORD wPipeOut,
1624 WORD wBusOut,
1625 INT32 &iGain
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 "
1636 "%d\n",
1637 wPipeOut) );
1639 return ECHOSTATUS_INVALID_CHANNEL;
1641 } // GetPipeOutGain
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
1705 WORD wBus,
1706 BOOL bState
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
1723 if ( bState )
1724 m_pDspCommPage->cmdNominalLevel.SetIndexInMask( wBus );
1725 else
1726 m_pDspCommPage->cmdNominalLevel.ClearIndexInMask( wBus );
1728 return UpdateAudioOutLineLevel();
1731 ECHO_DEBUGPRINTF( ("CDspCommObject::SetNominalOutLineLevel Invalid "
1732 "index %d\n",
1733 wBus ) );
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
1750 WORD wBus,
1751 PBYTE pbyState
1755 if (wBus < (m_wNumBussesOut + m_wNumBussesIn))
1757 *pbyState = (BYTE)
1758 m_pDspCommPage->cmdNominalLevel.TestIndexInMask( wBus );
1759 return ECHOSTATUS_OK;
1762 ECHO_DEBUGPRINTF( ("CDspCommObject::GetNominalLevel Invalid "
1763 "index %d\n",
1764 wBus ) );
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
1779 INT32 iGain,
1780 BOOL fImmediate
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
1810 if (fImmediate)
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
1824 // at about 30 Hz.
1826 //===========================================================================
1828 ECHOSTATUS CDspCommObject::SetMetersOn
1830 BOOL bOn
1833 if ( bOn )
1835 if ( 0 == m_wMeterOnCount )
1837 SendVector( DSP_VC_METERS_ON );
1839 m_wMeterOnCount++;
1841 else
1843 INT32 iDevice;
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++ )
1854 BYTE muted;
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
1870 // in comm page.
1872 //===========================================================================
1874 ECHOSTATUS CDspCommObject::UpdateAudioOutLineLevel()
1876 //ECHO_DEBUGPRINTF( ( "CDspCommObject::UpdateAudioOutLineLevel:\n" ) );
1878 if (FALSE == m_bASICLoaded)
1879 return ECHOSTATUS_ASIC_NOT_LOADED;
1881 ClearHandshake();
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;
1900 ClearHandshake();
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
1944 ClearHandshake();
1945 ECHOSTATUS Status = SendVector(DSP_VC_UPDATE_CLOCKS);
1947 return Status;
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;
1982 // Output
1984 DWORD dwCh = 0;
1985 WORD i;
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 ]) );
1996 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 ]) );
2007 dwCh++;
2010 return ECHOSTATUS_OK;
2012 } // GetAudioMeters
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));
2037 // Store the flag
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 /****************************************************************************
2057 Power management
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
2076 m_pwDspCode = NULL;
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
2096 #ifdef MIDI_SUPPORT
2098 /****************************************************************************
2100 MIDI
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;
2118 BYTE *pOutBuffer;
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));
2129 *pdwActualCt = 0;
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));
2142 *pdwActualCt = 0;
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;
2164 pOutBuffer++;
2166 OsCopyMemory(pOutBuffer,pData,dwWriteCount);
2169 // Send the command to the DSP
2171 ClearHandshake();
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
2178 ULONGLONG ullTime;
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;
2204 // Get the data
2206 dwData = SWAP( m_pDspCommPage->wMidiInData[ wIndex ] );
2209 // Timestamp for the MIDI input activity indicator
2211 ULONGLONG ullTime;
2213 m_pOsSupport->OsGetSystemTime( &ullTime );
2214 m_ullMidiInTime = ullTime;
2216 return ECHOSTATUS_OK;
2218 } // ECHOSTATUS CDspCommObject::ReadMidi
2221 ECHOSTATUS CDspCommObject::SetMidiOn( BOOL bOn )
2223 if ( bOn )
2225 if ( 0 == m_wMidiOnCount )
2227 if ( !WaitForHandshake() )
2228 return ECHOSTATUS_DSP_DEAD;
2230 m_pDspCommPage->dwFlags |= SWAP( (DWORD) DSP_FLAG_MIDI_INPUT );
2232 ClearHandshake();
2233 SendVector( DSP_VC_UPDATE_FLAGS );
2235 m_wMidiOnCount++;
2237 else
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 );
2249 ClearHandshake();
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 ****