1// ****************************************************************************
2//
3//		CLayla24.cpp
4//
5//		Implementation file for the CLayla24 driver class.
6//		Set editor tabs to 3 for your viewing pleasure.
7//
8// ----------------------------------------------------------------------------
9//
10// This file is part of Echo Digital Audio's generic driver library.
11// Copyright Echo Digital Audio Corporation (c) 1998 - 2005
12// All rights reserved
13// www.echoaudio.com
14//
15// This library is free software; you can redistribute it and/or
16// modify it under the terms of the GNU Lesser General Public
17// License as published by the Free Software Foundation; either
18// version 2.1 of the License, or (at your option) any later version.
19//
20// This library is distributed in the hope that it will be useful,
21// but WITHOUT ANY WARRANTY; without even the implied warranty of
22// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23// Lesser General Public License for more details.
24//
25// You should have received a copy of the GNU Lesser General Public
26// License along with this library; if not, write to the Free Software
27// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28//
29// ****************************************************************************
30
31#include "CLayla24.h"
32
33#define LAYLA24_ANALOG_OUTPUT_LATENCY		59
34#define LAYLA24_ANALOG_INPUT_LATENCY		71
35#define LAYLA24_DIGITAL_OUTPUT_LATENCY		32
36#define LAYLA24_DIGITAL_INPUT_LATENCY		32
37
38
39
40/****************************************************************************
41
42	Construction and destruction
43
44 ****************************************************************************/
45
46//===========================================================================
47//
48// Overload new & delete so memory for this object is allocated
49//	from non-paged memory.
50//
51//===========================================================================
52
53PVOID CLayla24::operator new( size_t Size )
54{
55	PVOID 		pMemory;
56	ECHOSTATUS 	Status;
57
58	Status = OsAllocateNonPaged(Size,&pMemory);
59
60	if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory ))
61	{
62		ECHO_DEBUGPRINTF(("CLayla24::operator new - memory allocation failed\n"));
63
64		pMemory = NULL;
65	}
66	else
67	{
68		memset( pMemory, 0, Size );
69	}
70
71	return pMemory;
72
73}	// PVOID CLayla24::operator new( size_t Size )
74
75
76VOID  CLayla24::operator delete( PVOID pVoid )
77{
78	if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) )
79	{
80		ECHO_DEBUGPRINTF( ("CLayla24::operator delete memory free failed\n") );
81	}
82}	// VOID  CLayla24::operator delete( PVOID pVoid )
83
84
85//===========================================================================
86//
87// Constructor and destructor
88//
89//===========================================================================
90
91CLayla24::CLayla24( PCOsSupport pOsSupport )
92		  : CEchoGalsMTC( pOsSupport )
93{
94	ECHO_DEBUGPRINTF( ( "CLayla24::CLayla24() is born!\n" ) );
95
96	m_wAnalogOutputLatency = LAYLA24_ANALOG_OUTPUT_LATENCY;
97	m_wAnalogInputLatency = LAYLA24_ANALOG_INPUT_LATENCY;
98	m_wDigitalOutputLatency = LAYLA24_DIGITAL_OUTPUT_LATENCY;
99	m_wDigitalInputLatency = LAYLA24_DIGITAL_INPUT_LATENCY;
100
101}	// CLayla24::CLayla24()
102
103
104CLayla24::~CLayla24()
105{
106	ECHO_DEBUGPRINTF( ( "CLayla24::~CLayla24() is toast!\n" ) );
107}	// CLayla24::~CLayla24()
108
109
110
111
112/****************************************************************************
113
114	Setup and hardware initialization
115
116 ****************************************************************************/
117
118//===========================================================================
119//
120// Every card has an InitHw method
121//
122//===========================================================================
123
124ECHOSTATUS CLayla24::InitHw()
125{
126	ECHOSTATUS	Status;
127	WORD			i;
128
129	//
130	// Call the base method
131	//
132	if ( ECHOSTATUS_OK != ( Status = CEchoGals::InitHw() ) )
133		return Status;
134
135	//
136	// Create the DSP comm object
137	//
138	ECHO_ASSERT(NULL == m_pDspCommObject );
139	m_pDspCommObject = new CLayla24DspCommObject( (PDWORD) m_pvSharedMemory,
140																 m_pOsSupport );
141	if (NULL == m_pDspCommObject)
142	{
143		ECHO_DEBUGPRINTF(("CLayla24::InitHw - could not create DSP comm object\n"));
144		return ECHOSTATUS_NO_MEM;
145	}
146
147	//
148	// Load the DSP, the PCI card ASIC, and the external box ASIC
149	//
150	GetDspCommObject()->LoadFirmware();
151	if ( GetDspCommObject()->IsBoardBad() )
152		return ECHOSTATUS_DSP_DEAD;
153
154	//
155	// Clear the "bad board" flag; set the flags to indicate that
156	// Layla24 can handle super-interleave and supports the digital
157	// input auto-mute.
158	//
159	m_wFlags &= ~ECHOGALS_FLAG_BADBOARD;
160	m_wFlags |= ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK |
161					ECHOGALS_ROFLAG_DIGITAL_IN_AUTOMUTE;
162
163	//
164	//	Must call this here after DSP is init to
165	//	init gains and mutes
166	//
167	Status = InitLineLevels();
168	if ( ECHOSTATUS_OK != Status )
169		return Status;
170
171	//
172	// Initialize the MIDI input
173	//
174	Status = m_MidiIn.Init( this );
175	if ( ECHOSTATUS_OK != Status )
176		return Status;
177
178
179	//
180	// Set defaults for +4/-10
181	//
182	for (i = 0; i < GetFirstDigitalBusOut(); i++ )
183	{
184		GetDspCommObject()->
185			SetNominalLevel( i, FALSE );	// FALSE is +4 here
186	}
187
188	for ( i = 0; i < GetNumBussesIn(); i++ )
189	{
190		GetDspCommObject()->
191			SetNominalLevel( GetNumBussesOut() + i, FALSE );
192	}
193
194	//
195	// Set the digital mode to S/PDIF RCA
196	//
197	SetDigitalMode( DIGITAL_MODE_SPDIF_RCA );
198
199	//
200	// Set the S/PDIF output format to "professional"
201	//
202	SetProfessionalSpdif( TRUE );
203
204	//
205	//	Get default sample rate from DSP
206	//
207	m_dwSampleRate = GetDspCommObject()->GetSampleRate();
208
209	ECHO_DEBUGPRINTF( ( "CLayla24::InitHw()\n" ) );
210	return Status;
211
212}	// ECHOSTATUS CLayla24::InitHw()
213
214
215
216
217/****************************************************************************
218
219	Informational methods
220
221 ****************************************************************************/
222
223//===========================================================================
224//
225// Override GetCapabilities to enumerate unique capabilties for this card
226//
227//===========================================================================
228
229ECHOSTATUS CLayla24::GetCapabilities
230(
231	PECHOGALS_CAPS	pCapabilities
232)
233{
234	ECHOSTATUS	Status;
235	WORD			i;
236
237	Status = GetBaseCapabilities(pCapabilities);
238
239	if ( ECHOSTATUS_OK != Status )
240		return Status;
241
242	//
243	// Add nominal level control to analog ins & outs
244	//
245	for (i = 0 ; i < GetFirstDigitalBusOut(); i++)
246	{
247		pCapabilities->dwBusOutCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
248	}
249
250	for (i = 0 ; i < GetNumBussesIn(); i++)
251	{
252		pCapabilities->dwBusInCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
253	}
254
255	pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_WORD		|
256												ECHO_CLOCK_BIT_SPDIF		|
257												ECHO_CLOCK_BIT_ADAT		|
258												ECHO_CLOCK_BIT_MTC;
259
260	return Status;
261
262}	// ECHOSTATUS CLayla24::GetCapabilities
263
264
265//===========================================================================
266//
267// QueryAudioSampleRate is used to find out if this card can handle a
268// given sample rate.
269//
270//===========================================================================
271
272ECHOSTATUS CLayla24::QueryAudioSampleRate
273(
274	DWORD		dwSampleRate
275)
276{
277	//
278	// Standard sample rates are allowed (like Mona & Layla24)
279	//
280	switch ( dwSampleRate )
281	{
282		case 8000 :
283		case 11025 :
284		case 16000 :
285		case 22050 :
286		case 32000 :
287		case 44100 :
288		case 48000 :
289			goto qasr_ex;
290
291		case 88200 :
292		case 96000 :
293
294			//
295			// Double speed sample rates not allowed in ADAT mode
296			//
297			if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
298			{
299				ECHO_DEBUGPRINTF(
300					("CLayla24::QueryAudioSampleRate() Sample rate must be < "
301					 "50,000 Hz in ADAT mode\n") );
302				return ECHOSTATUS_BAD_FORMAT;
303			}
304			goto qasr_ex;
305	}
306
307	//
308	// Any rate from 25000 to 50000 is allowed
309	//
310	if ( ( dwSampleRate >= 25000 ) &&
311	  	  ( dwSampleRate <= 50000 ) )
312		goto qasr_ex;
313
314	//
315	//	If not in ADAT mode, any rate from 50,000 to 100,000 is allowed
316	//
317	if ( DIGITAL_MODE_ADAT != GetDigitalMode() &&
318		  ( dwSampleRate >= 50000 ) &&
319		  ( dwSampleRate <= 100000 ) )
320		goto qasr_ex;
321
322	ECHO_DEBUGPRINTF(
323		("CLayla24::QueryAudioSampleRate() - rate %ld invalid\n",dwSampleRate) );
324	return ECHOSTATUS_BAD_FORMAT;
325
326qasr_ex:
327	ECHO_DEBUGPRINTF( ( "CLayla24::QueryAudioSampleRate() %ld Hz OK\n",
328							  dwSampleRate ) );
329	return ECHOSTATUS_OK;
330}	// ECHOSTATUS CLayla24::QueryAudioSampleRate
331
332
333void CLayla24::QuerySampleRateRange(DWORD &dwMinRate,DWORD &dwMaxRate)
334{
335	dwMinRate = 8000;
336	dwMaxRate = 96000;
337}
338
339
340
341//===========================================================================
342//
343// GetInputClockDetect returns a bitmask consisting of all the input
344// clocks currently connected to the hardware; this changes as the user
345// connects and disconnects clock inputs.
346//
347// You should use this information to determine which clocks the user is
348// allowed to select.
349//
350// Layla24 supports S/PDIF, word, and ADAT input clocks.
351//
352//===========================================================================
353
354ECHOSTATUS CLayla24::GetInputClockDetect(DWORD &dwClockDetectBits)
355{
356	if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
357	{
358		ECHO_DEBUGPRINTF( ("CLayla24::GetInputClockDetect: DSP Dead!\n") );
359		return ECHOSTATUS_DSP_DEAD;
360	}
361
362	//
363	// Map the DSP clock detect bits to the generic driver clock detect bits
364	//
365	DWORD dwClocksFromDsp = GetDspCommObject()->GetInputClockDetect();
366
367	dwClockDetectBits = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_MTC;
368
369	if (0 != (dwClocksFromDsp & GML_CLOCK_DETECT_BIT_SPDIF))
370		dwClockDetectBits |= ECHO_CLOCK_BIT_SPDIF;
371
372	if (0 != (dwClocksFromDsp & GML_CLOCK_DETECT_BIT_ADAT))
373		dwClockDetectBits |= ECHO_CLOCK_BIT_ADAT;
374
375	if (0 != (dwClocksFromDsp & GML_CLOCK_DETECT_BIT_WORD))
376		dwClockDetectBits |= ECHO_CLOCK_BIT_WORD;
377
378	return ECHOSTATUS_OK;
379
380}	// GetInputClockDetect
381
382
383// *** Layla24.cpp ***
384