// ****************************************************************************
//
//		C3g.cpp
//
//		Implementation file for the C3g driver class.
//		Set editor tabs to 3 for your viewing pleasure.
//
// ----------------------------------------------------------------------------
//
// This file is part of Echo Digital Audio's generic driver library.
// Copyright Echo Digital Audio Corporation (c) 1998 - 2005
// All rights reserved
// www.echoaudio.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// ****************************************************************************
 
#include "C3g.h"
 
#define ECHO3G_ANALOG_OUTPUT_LATENCY_1X		(1 + 32 + 12)		// ASIC + DSP + DAC
#define ECHO3G_ANALOG_OUTPUT_LATENCY_2X		(1 + 32 + 5)
#define ECHO3G_ANALOG_INPUT_LATENCY_1X			(1 + 32 + 12)
#define ECHO3G_ANALOG_INPUT_LATENCY_2X			(1 + 32 + 9)
 
#define ECHO3G_DIGITAL_OUTPUT_LATENCY			(1 + 32)
#define ECHO3G_DIGITAL_INPUT_LATENCY			(1 + 32)
 
 
 
/****************************************************************************
 
	Construction and destruction
 
 ****************************************************************************/
 
//===========================================================================
//
// Overload new & delete so memory for this object is allocated
//	from non-paged memory.
//
//===========================================================================
 
PVOID C3g::operator new( size_t Size )
{
	PVOID 		pMemory;
	ECHOSTATUS 	Status;
	
	Status = OsAllocateNonPaged(Size,&pMemory);
	
	if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory ))
	{
		ECHO_DEBUGPRINTF(("C3g::operator new - memory allocation failed\n"));
 
		pMemory = NULL;
	}
	else
	{
		memset( pMemory, 0, Size );
	}
 
	return pMemory;
	
}	// PVOID C3g::operator new( size_t Size )
 
 
VOID  C3g::operator delete( PVOID pVoid )
{
	if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) )
	{
		ECHO_DEBUGPRINTF(("C3g::operator delete memory free failed\n"));
	}
}	// VOID C3g::operator delete( PVOID pVoid )
 
 
//===========================================================================
//
// Constructor and destructor
//
//===========================================================================
 
C3g::C3g( PCOsSupport pOsSupport )
	  : CEchoGalsMTC( pOsSupport )
{
	ECHO_DEBUGPRINTF( ( "C3g::C3g() is born!\n" ) );
 
	m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
	m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
	m_wDigitalOutputLatency = ECHO3G_DIGITAL_OUTPUT_LATENCY;
	m_wDigitalInputLatency = ECHO3G_DIGITAL_INPUT_LATENCY;
}
 
 
C3g::~C3g()
{
	ECHO_DEBUGPRINTF( ( "C3g::~C3g() is toast!\n" ) );
}
 
 
 
 
/****************************************************************************
 
	Setup and hardware initialization
 
 ****************************************************************************/
 
//===========================================================================
//
// Every card has an InitHw method
//
//===========================================================================
 
ECHOSTATUS C3g::InitHw()
{
	ECHOSTATUS	Status;
	WORD			i;
 
	//
	// Call the base method
	//
	if ( ECHOSTATUS_OK != ( Status = CEchoGals::InitHw() ) )
		return Status;
 
	//
	// Create the DSP comm object
	//
	ECHO_ASSERT(NULL == m_pDspCommObject );
	m_pDspCommObject = new C3gDco( (PDWORD) m_pvSharedMemory, m_pOsSupport );
	if (NULL == m_pDspCommObject)
	{
		ECHO_DEBUGPRINTF(("C3g::InitHw - could not create DSP comm object\n"));
		return ECHOSTATUS_NO_MEM;
	}
 
	//
	// Load the DSP
	//
	DWORD dwBoxType;
	
	GetDspCommObject()->LoadFirmware();
	
	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
	if (NO3GBOX == dwBoxType)
		return ECHOSTATUS_NO_3G_BOX;
	
	if ( GetDspCommObject()->IsBoardBad() )
		return ECHOSTATUS_DSP_DEAD;
	
	//
	// Clear the "bad board" flag; set the flags to indicate that
	// 3G can handle super-interleave.
	//
	m_wFlags &= ~ECHOGALS_FLAG_BADBOARD;
	m_wFlags |= ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK;
	
	//
	//	Must call this here after DSP is init to 
	//	init gains and mutes
	//
	Status = InitLineLevels();
	if ( ECHOSTATUS_OK != Status )
		return Status;
		
	//
	// Initialize the MIDI input
	//	
	Status = m_MidiIn.Init( this );
	if ( ECHOSTATUS_OK != Status )
		return Status;
 
	//
	// Set defaults for +4/-10
	//
	for (i = 0; i < GetFirstDigitalBusOut(); i++ )
	{
		GetDspCommObject()->
			SetNominalLevel( i, FALSE );	// FALSE is +4 here
	}
	for ( i = 0; i < GetFirstDigitalBusIn(); i++ )
	{
		GetDspCommObject()->
			SetNominalLevel( GetNumBussesOut() + i, FALSE );
	}
 
	//
	// Set the digital mode to S/PDIF RCA
	//
	SetDigitalMode( DIGITAL_MODE_SPDIF_RCA );
	
	//
	//	Get default sample rate from DSP
	//
	m_dwSampleRate = GetDspCommObject()->GetSampleRate();
	
	ECHO_DEBUGPRINTF( ( "C3g::InitHw()\n" ) );
	return Status;
 
}	// ECHOSTATUS C3g::InitHw()
 
 
 
 
/****************************************************************************
 
	Informational methods
 
 ****************************************************************************/
 
//===========================================================================
//
// Override GetCapabilities to enumerate unique capabilties for this card
//
//===========================================================================
 
ECHOSTATUS C3g::GetCapabilities
(
	PECHOGALS_CAPS	pCapabilities
)
{
	ECHOSTATUS	Status;
	WORD			i;
 
	Status = GetBaseCapabilities(pCapabilities);
	if ( ECHOSTATUS_OK != Status )
		return Status;
		
	//
	// Add nominal level control to all ins & outs except the universal
	//
	for (i = 0 ; i < pCapabilities->wNumBussesOut; i++)
	{
		pCapabilities->dwBusOutCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
	}
 
	for (i = 2 ; i < pCapabilities->wNumBussesIn; i++)
	{
		pCapabilities->dwBusInCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
	}
 
	pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_SPDIF		|
												ECHO_CLOCK_BIT_ADAT		|
												ECHO_CLOCK_BIT_MTC;
												
	//
	// Box-specific capabilities
	//
	DWORD dwBoxType;
	
	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
	switch (dwBoxType)
	{
		case GINA3G :
			pCapabilities->dwBusInCaps[0] |= ECHOCAPS_PHANTOM_POWER;
			pCapabilities->dwBusInCaps[1] |= ECHOCAPS_PHANTOM_POWER;
			break;
			
		case LAYLA3G :
			pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_WORD;
			break;
	
	}
 
	pCapabilities->dwOutClockTypes = 0;
	
	return Status;
 
}	// ECHOSTATUS C3g::GetCapabilities
 
 
//===========================================================================
//
// QueryAudioSampleRate is used to find out if this card can handle a 
// given sample rate.
//
//===========================================================================
 
ECHOSTATUS C3g::QueryAudioSampleRate
(
	DWORD		dwSampleRate
)
{
	//
	// Check rates that are supported by continuous mode; only allow
	// double-speed rates if not in ADAT mode
	//
	if ((dwSampleRate >= 32000) && (dwSampleRate <= 50000))
		return ECHOSTATUS_OK;
 
	if (	(DIGITAL_MODE_ADAT != GetDigitalMode()) && 
			(dwSampleRate > 50000) && 
			(dwSampleRate <= 100000))
		return ECHOSTATUS_OK;
 
	ECHO_DEBUGPRINTF(("C3g::QueryAudioSampleRate() - rate %ld invalid\n",dwSampleRate) );
 
	return ECHOSTATUS_BAD_FORMAT;
 
}	// ECHOSTATUS C3g::QueryAudioSampleRate
 
 
void C3g::QuerySampleRateRange(DWORD &dwMinRate,DWORD &dwMaxRate)
{
	dwMinRate = 32000;
	dwMaxRate = 96000;
}
 
 
 
//===========================================================================
//
// GetInputClockDetect returns a bitmask consisting of all the input
// clocks currently connected to the hardware; this changes as the user
// connects and disconnects clock inputs.  
//
// You should use this information to determine which clocks the user is
// allowed to select.
//
//===========================================================================
 
ECHOSTATUS C3g::GetInputClockDetect(DWORD &dwClockDetectBits)
{
	if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
	{
		ECHO_DEBUGPRINTF( ("C3g::GetInputClockDetect: DSP Dead!\n") );
		return ECHOSTATUS_DSP_DEAD;
	}
					 
	//
	// Map the DSP clock detect bits to the generic driver clock detect bits
	//
	DWORD dwClocksFromDsp = GetDspCommObject()->GetInputClockDetect();	
 
	dwClockDetectBits = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_MTC;
	
	if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_WORD))
		dwClockDetectBits |= ECHO_CLOCK_BIT_WORD;
 
	switch (GetDigitalMode())
	{
		case DIGITAL_MODE_SPDIF_RCA :
		case DIGITAL_MODE_SPDIF_OPTICAL :
			if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_SPDIF))
				dwClockDetectBits |= ECHO_CLOCK_BIT_SPDIF;
			break;
 
		case DIGITAL_MODE_ADAT :	
			if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_ADAT))
				dwClockDetectBits |= ECHO_CLOCK_BIT_ADAT;
			break;
	}	
		
	return ECHOSTATUS_OK;
	
}	// GetInputClockDetect
 
 
//===========================================================================
//
// Get the external box type
//
//===========================================================================
 
void C3g::Get3gBoxType(DWORD *pOriginalBoxType,DWORD *pCurrentBoxType)
{
	GetDspCommObject()->Get3gBoxType(pOriginalBoxType,pCurrentBoxType);
}
 
 
//===========================================================================
//
// Get the external box name
//
//===========================================================================
 
char *C3g::Get3gBoxName()
{
	char *pszName;
	DWORD dwBoxType;
	
	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
	switch (dwBoxType)
	{
		case GINA3G :
			pszName = "Gina3G";
			break;
		
		case LAYLA3G :
			pszName = "Layla3G";
			break;
			
		case NO3GBOX :
		default :
			pszName = "Echo3G";
			break;
	}
	
	return pszName;
}
 
 
//===========================================================================
//
// Get phantom power state for Gina3G
//
//===========================================================================
 
void C3g::GetPhantomPower(BOOL *pfPhantom)
{
	*pfPhantom = m_fPhantomPower;
}
 
 
//===========================================================================
//
// Set phantom power state for Gina3G
//
//===========================================================================
 
void C3g::SetPhantomPower(BOOL fPhantom)
{
	DWORD dwBoxType;
	
	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
	if (GINA3G == dwBoxType)
	{
		GetDspCommObject()->SetPhantomPower( fPhantom );
		m_fPhantomPower = fPhantom;
	}
}
 
 
//===========================================================================
//
// GetAudioLatency - returns the latency for a single pipe
//
//===========================================================================
 
void C3g::GetAudioLatency(ECHO_AUDIO_LATENCY *pLatency)
{
	DWORD dwSampleRate;
 
	//
	// Adjust the stored latency values based on the sample rate
	//
	dwSampleRate = GetDspCommObject()->GetSampleRate();
	if (dwSampleRate <= 50000)
	{
		m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
		m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
	}
	else
	{
		m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_2X;
		m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_2X;
	}
 
	//
	// Let the base class worry about analog vs. digital
	//
	CEchoGals::GetAudioLatency(pLatency);
	
}	// GetAudioLatency
 
 
 
//===========================================================================
//
//	Start transport for a group of pipes
//
// Use this to make sure no one tries to start digital channels 3-8 
// with the hardware in double speed mode.
//
//===========================================================================
 
ECHOSTATUS C3g::Start
(
	PCChannelMask	pChannelMask
)
{
	PC3gDco pDCO;
 
	//
	// Double speed mode?
	//
	pDCO = GetDspCommObject();
	if (pDCO->DoubleSpeedMode())
	{
		BOOL intersect;
		
		//
		// See if ADAT in 3-8 or out 3-8 are being started
		//		
		intersect = pChannelMask->IsIntersectionOf( pDCO->m_Adat38Mask );
		if (intersect)
		{
			ECHO_DEBUGPRINTF(("Cannot start ADAT channels 3-8 in double speed mode\n"));
			return ECHOSTATUS_INVALID_CHANNEL;
		}
	}
 
	return CEchoGals::Start(pChannelMask);
}
 
// *** C3g.cpp ***

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: m_fPhantomPower.