⛏️ index : haiku.git

// ****************************************************************************
//
//  	CMonaDspCommObject.cpp
//
//		Implementation file for EchoGals generic driver Mona DSP
//		interface class.
//
// ----------------------------------------------------------------------------
//
// 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 "CEchoGals.h"
#include "CMonaDspCommObject.h"

#include "MonaDSP.c"
#include "Mona361DSP.c"

#include "Mona1ASIC48.c"
#include "Mona1ASIC96.c"
#include "Mona1ASIC48_361.c"
#include "Mona1ASIC96_361.c"
#include "Mona2ASIC.c"


/****************************************************************************

	Construction and destruction

 ****************************************************************************/

//===========================================================================
//
// Constructor
//
//===========================================================================

CMonaDspCommObject::CMonaDspCommObject
(
	PDWORD		pdwRegBase,				// Virtual ptr to DSP registers
	PCOsSupport	pOsSupport
) : CGMLDspCommObject( pdwRegBase, pOsSupport )
{
	strcpy( m_szCardName, "Mona" );
	m_pdwDspRegBase = pdwRegBase;		// Virtual addr DSP's register base

	m_wNumPipesOut = 14;
	m_wNumPipesIn = 12;
	m_wNumBussesOut = 14;
	m_wNumBussesIn = 12;
	m_wFirstDigitalBusOut = 6;
	m_wFirstDigitalBusIn = 4;
	
	m_bProfessionalSpdif = FALSE;

	m_fHasVmixer = FALSE;	

	m_wNumMidiOut = 0;					// # MIDI out channels
	m_wNumMidiIn = 0;						// # MIDI in  channels
	m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 44100 );
												// Need this in cse we start with ESYNC
	m_bHasASIC = TRUE;
	if ( DEVICE_ID_56361 == pOsSupport->GetDeviceId() )
		m_pwDspCodeToLoad = pwMona361DSP;
	else
		m_pwDspCodeToLoad = pwMonaDSP;

	m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA;
}	// CMonaDspCommObject::CMonaDspCommObject( DWORD dwPhysRegBase )


//===========================================================================
//
// Destructor
//
//===========================================================================

CMonaDspCommObject::~CMonaDspCommObject()
{
}	// CMonaDspCommObject::~CMonaDspCommObject()




/****************************************************************************

	Hardware setup and config

 ****************************************************************************/

//===========================================================================
//
// Mona has an ASIC on the PCI card and another ASIC in the external box; 
// both need to be loaded.
//
//===========================================================================

BOOL CMonaDspCommObject::LoadASIC()
{
	DWORD	dwControlReg;
	PBYTE	pbAsic1;
	DWORD	dwSize;

	if ( m_bASICLoaded )
		return TRUE;

	m_pOsSupport->OsSnooze( 10000 );

	if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
	{
		pbAsic1 = pbMona1ASIC48_361;
		dwSize = sizeof( pbMona1ASIC48_361 );
	}
	else
	{
		pbAsic1 = pbMona1ASIC48;
		dwSize = sizeof( pbMona1ASIC48 );
	}
	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
											  pbAsic1,
											  dwSize ) )
		return FALSE;

	m_pbyAsic = pbAsic1;	

	m_pOsSupport->OsSnooze( 10000 );

	// Do the external one
	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_EXTERNAL_ASIC,
											  pbMona2ASIC,
											  sizeof( pbMona2ASIC ) ) )
		return FALSE;

	m_pOsSupport->OsSnooze( 10000 );
		
	CheckAsicStatus();

	//
	// Set up the control register if the load succeeded -
	//
	// 48 kHz, internal clock, S/PDIF RCA mode
	//	
	if ( m_bASICLoaded )
	{
		dwControlReg = GML_CONVERTER_ENABLE | GML_48KHZ;
		ECHO_DEBUGPRINTF(("CMonaDspCommObject::LoadASIC - setting control reg for 0x%lx\n",
								dwControlReg));
		WriteControlReg( dwControlReg, TRUE );	
	}
		
	return m_bASICLoaded;
	
}	// BOOL CMonaDspCommObject::LoadASIC()


//===========================================================================
//
// Depending on what digital mode you want, Mona needs different ASICs 
//	loaded.  This function checks the ASIC needed for the new mode and sees 
// if it matches the one already loaded.
//
//===========================================================================

BOOL CMonaDspCommObject::SwitchAsic( DWORD dwMask96 )
{
	BYTE *	pbyAsicNeeded;
	DWORD		dwAsicSize;
	
	//
	//	Check the clock detect bits to see if this is
	// a single-speed clock or a double-speed clock; load
	// a new ASIC if necessary.
	// 
	if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
	{
		pbyAsicNeeded = pbMona1ASIC48_361;
		dwAsicSize = sizeof( pbMona1ASIC48_361 );
		if ( 0 != ( dwMask96 & GetInputClockDetect() ) )
		{
			pbyAsicNeeded = pbMona1ASIC96_361;
			dwAsicSize = sizeof( pbMona1ASIC96_361 );
		}
	}
	else
	{
		pbyAsicNeeded = pbMona1ASIC48;
		dwAsicSize = sizeof( pbMona1ASIC48 );
		if ( 0 != ( dwMask96 & GetInputClockDetect() ) )
		{
			pbyAsicNeeded = pbMona1ASIC96;
			dwAsicSize = sizeof( pbMona1ASIC96 );
		}
	}

	if ( pbyAsicNeeded != m_pbyAsic )
	{
		//
		// Load the desired ASIC
		//
		if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
												  pbyAsicNeeded,
												  dwAsicSize ) )
			return FALSE;

		m_pbyAsic = pbyAsicNeeded;	
		
		m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
	}
	
	return TRUE;

}	// BOOL CMonaDspCommObject::SwitchAsic( DWORD dwMask96 )


//===========================================================================
//
// SetInputClock
//
//===========================================================================

ECHOSTATUS CMonaDspCommObject::SetInputClock(WORD wClock)
{
	BOOL			bSetRate;
	BOOL			bWriteControlReg;
	DWORD			dwControlReg;

	ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetInputClock: clock %d\n",wClock) );

	dwControlReg = GetControlRegister();

	//
	// Mask off the clock select bits
	//
	dwControlReg &= GML_CLOCK_CLEAR_MASK;
	
	bSetRate = FALSE;
	bWriteControlReg = TRUE;
	switch ( wClock )
	{
		case ECHO_CLOCK_INTERNAL : 
		{
			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to INTERNAL\n" ) );
	
			bSetRate = TRUE;
			bWriteControlReg = FALSE;

			break;
		} // CLK_CLOCKININTERNAL

		case ECHO_CLOCK_SPDIF :
		{
			if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
			{
				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
			}

			if ( FALSE == SwitchAsic( GML_CLOCK_DETECT_BIT_SPDIF96 ) )
			{
				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
			}
			
			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to SPDIF\n" ) );
	
			dwControlReg |= GML_SPDIF_CLOCK;

			if ( GML_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() )
			{
				dwControlReg |= GML_DOUBLE_SPEED_MODE;
			}
			else
			{
				dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
			}
			break;
		} // CLK_CLOCKINSPDIF

		case ECHO_CLOCK_WORD : 
		{
			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to WORD\n" ) );

			if ( FALSE == SwitchAsic( GML_CLOCK_DETECT_BIT_WORD96 ) )
			{
				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
			}
		
			dwControlReg |= GML_WORD_CLOCK;
			
			if ( GML_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() )
			{
				dwControlReg |= GML_DOUBLE_SPEED_MODE;
			}
			else
			{
				dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
			}
			break;
		} // CLK_CLOCKINWORD

		case ECHO_CLOCK_ADAT :
		{
			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to ADAT\n" ) );
			
			if ( DIGITAL_MODE_ADAT != GetDigitalMode() )
			{
				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
			}
			
			dwControlReg |= GML_ADAT_CLOCK;
			dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
			break;
		} // CLK_CLOCKINADAT

		default :
			ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Mona\n",wClock));
			ECHO_DEBUGBREAK();
				return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
	}	// switch (wClock)

	//
	// Winner! Save the new input clock.
	//
	m_wInputClock = wClock;

	//
	// Do things according to the flags
	//
	if ( bWriteControlReg )
	{
		WriteControlReg( dwControlReg, TRUE );
	}

	// Set Mona sample rate to something sane if word or superword is
	// being turned off
	if ( bSetRate )
	{
		SetSampleRate( GetSampleRate() );
	}
		
	return ECHOSTATUS_OK;
	
}	// ECHOSTATUS CMonaDspCommObject::SetInputClock



//===========================================================================
//
// SetSampleRate
// 
// Set the audio sample rate for CMona
//
//===========================================================================

DWORD CMonaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
{
	BYTE *pbyAsicNeeded;
	DWORD	dwAsicSize, dwControlReg, dwNewClock;
	BOOL	fForceControlReg;
	
	ECHO_DEBUGPRINTF(("CMonaDspCommObject::SetSampleRate to %ld\n",dwNewSampleRate));
	
	fForceControlReg = FALSE;
	
	//
	// Only set the clock for internal mode.  If the clock is not set to
	// internal, try and re-set the input clock; this more transparently
	// handles switching between single and double-speed mode
	//
	if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
	{
		ECHO_DEBUGPRINTF( ( "CMonaDspCommObject::SetSampleRate: Cannot set sample rate - "
								  "clock not set to CLK_CLOCKININTERNAL\n" ) );
		
		//
		// Save the rate anyhow
		//
		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
		
		//
		// Set the input clock to the current value
		//
		SetInputClock( m_wInputClock );
		
		return GetSampleRate();
	}
	
	//
	// Now, check to see if the required ASIC is loaded
	//
	if ( dwNewSampleRate >= 88200 )
	{
		if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
			return( GetSampleRate() );

		if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
		{
			pbyAsicNeeded = pbMona1ASIC96_361;
			dwAsicSize = sizeof(pbMona1ASIC96_361);
		}
		else
		{
			pbyAsicNeeded = pbMona1ASIC96;
			dwAsicSize = sizeof(pbMona1ASIC96);
		}
	}
	else
	{
		if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
		{
			pbyAsicNeeded = pbMona1ASIC48_361;
			dwAsicSize = sizeof(pbMona1ASIC48_361);
		}
		else
		{
			pbyAsicNeeded = pbMona1ASIC48;
			dwAsicSize = sizeof(pbMona1ASIC48);
		}
	}

	if ( pbyAsicNeeded != m_pbyAsic )
	{
		ECHO_DEBUGPRINTF(("\tLoading a new ASIC\n"));
		//
		// Load the desired ASIC
		//
		if ( FALSE == CDspCommObject::LoadASIC
													( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
													  pbyAsicNeeded,
													  dwAsicSize ) )
			return( GetSampleRate() );

		m_pbyAsic = pbyAsicNeeded;	
		
		fForceControlReg = TRUE;
	}

	//
	// Get the new control register value
	//
	dwNewClock = 0;

	dwControlReg = GetControlRegister();
	dwControlReg &= GML_CLOCK_CLEAR_MASK;
	dwControlReg &= GML_SPDIF_RATE_CLEAR_MASK;

	switch ( dwNewSampleRate )
	{
		case 96000 :
			dwNewClock = GML_96KHZ;
			break;
		
		case 88200 :
			dwNewClock = GML_88KHZ;
			break;
		
		case 48000 : 
			dwNewClock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
			break;
		
		case 44100 : 
			dwNewClock = GML_44KHZ;
			//
			// Professional mode
			//
			if ( dwControlReg & GML_SPDIF_PRO_MODE )
			{
				dwNewClock |= GML_SPDIF_SAMPLE_RATE0;
			}
			break;
		
		case 32000 :
			dwNewClock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 | GML_SPDIF_SAMPLE_RATE1;
			break;
		
		case 22050 :
			dwNewClock = GML_22KHZ;
			break;
		
		case 16000 :
			dwNewClock = GML_16KHZ;
			break;
		
		case 11025 :
			dwNewClock = GML_11KHZ;
			break;
		
		case 8000 :
			dwNewClock = GML_8KHZ;
			break;
	}

	dwControlReg |= dwNewClock;

	//
	// Send the new value to the card
	//
	if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg, fForceControlReg ) )
	{
		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );

		ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetSampleRate: %ld "
								 "clock %ld\n", dwNewSampleRate, dwNewClock) );
	}

	return GetSampleRate();

} // DWORD CMonaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )


//===========================================================================
//
//	Set digital mode
//
//===========================================================================

ECHOSTATUS CMonaDspCommObject::SetDigitalMode
(
	BYTE	byNewMode
)
{
	ECHO_DEBUGPRINTF(("CMonaDspCommObject::SetDigitalMode %d\n",byNewMode));

	//
	// If the new mode is ADAT mode, make sure that the single speed ASIC is loaded
	//
	BYTE *pbAsic96;
	
	if (DIGITAL_MODE_ADAT == byNewMode)
	{
		switch (m_pOsSupport->GetDeviceId())
		{
			case DEVICE_ID_56301 :
				pbAsic96 = pbMona1ASIC96;
				break;
				
			case DEVICE_ID_56361 :
				pbAsic96 = pbMona1ASIC96_361;
				break;
				
			default :				// should never happen, but it's good to cover all the bases
				return ECHOSTATUS_BAD_CARDID;
		}
		if (pbAsic96 == m_pbyAsic)
			SetSampleRate( 48000 );	
	}
	
	//
	// Call the base class to tweak the input clock if necessary
	//
	return CGMLDspCommObject::SetDigitalMode(byNewMode);
	
}	// ECHOSTATUS CMonaDspCommObject::SetDigitalMode


// **** CMonaDspCommObject.cpp ****