1// ****************************************************************************
2//
3//		C3g.cpp
4//
5//		Implementation file for the C3g 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 "C3g.h"
32
33#define ECHO3G_ANALOG_OUTPUT_LATENCY_1X		(1 + 32 + 12)		// ASIC + DSP + DAC
34#define ECHO3G_ANALOG_OUTPUT_LATENCY_2X		(1 + 32 + 5)
35#define ECHO3G_ANALOG_INPUT_LATENCY_1X			(1 + 32 + 12)
36#define ECHO3G_ANALOG_INPUT_LATENCY_2X			(1 + 32 + 9)
37
38#define ECHO3G_DIGITAL_OUTPUT_LATENCY			(1 + 32)
39#define ECHO3G_DIGITAL_INPUT_LATENCY			(1 + 32)
40
41
42
43/****************************************************************************
44
45	Construction and destruction
46
47 ****************************************************************************/
48
49//===========================================================================
50//
51// Overload new & delete so memory for this object is allocated
52//	from non-paged memory.
53//
54//===========================================================================
55
56PVOID C3g::operator new( size_t Size )
57{
58	PVOID 		pMemory;
59	ECHOSTATUS 	Status;
60
61	Status = OsAllocateNonPaged(Size,&pMemory);
62
63	if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory ))
64	{
65		ECHO_DEBUGPRINTF(("C3g::operator new - memory allocation failed\n"));
66
67		pMemory = NULL;
68	}
69	else
70	{
71		memset( pMemory, 0, Size );
72	}
73
74	return pMemory;
75
76}	// PVOID C3g::operator new( size_t Size )
77
78
79VOID  C3g::operator delete( PVOID pVoid )
80{
81	if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) )
82	{
83		ECHO_DEBUGPRINTF(("C3g::operator delete memory free failed\n"));
84	}
85}	// VOID C3g::operator delete( PVOID pVoid )
86
87
88//===========================================================================
89//
90// Constructor and destructor
91//
92//===========================================================================
93
94C3g::C3g( PCOsSupport pOsSupport )
95	  : CEchoGalsMTC( pOsSupport )
96{
97	ECHO_DEBUGPRINTF( ( "C3g::C3g() is born!\n" ) );
98
99	m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
100	m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
101	m_wDigitalOutputLatency = ECHO3G_DIGITAL_OUTPUT_LATENCY;
102	m_wDigitalInputLatency = ECHO3G_DIGITAL_INPUT_LATENCY;
103}
104
105
106C3g::~C3g()
107{
108	ECHO_DEBUGPRINTF( ( "C3g::~C3g() is toast!\n" ) );
109}
110
111
112
113
114/****************************************************************************
115
116	Setup and hardware initialization
117
118 ****************************************************************************/
119
120//===========================================================================
121//
122// Every card has an InitHw method
123//
124//===========================================================================
125
126ECHOSTATUS C3g::InitHw()
127{
128	ECHOSTATUS	Status;
129	WORD			i;
130
131	//
132	// Call the base method
133	//
134	if ( ECHOSTATUS_OK != ( Status = CEchoGals::InitHw() ) )
135		return Status;
136
137	//
138	// Create the DSP comm object
139	//
140	ECHO_ASSERT(NULL == m_pDspCommObject );
141	m_pDspCommObject = new C3gDco( (PDWORD) m_pvSharedMemory, m_pOsSupport );
142	if (NULL == m_pDspCommObject)
143	{
144		ECHO_DEBUGPRINTF(("C3g::InitHw - could not create DSP comm object\n"));
145		return ECHOSTATUS_NO_MEM;
146	}
147
148	//
149	// Load the DSP
150	//
151	DWORD dwBoxType;
152
153	GetDspCommObject()->LoadFirmware();
154
155	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
156	if (NO3GBOX == dwBoxType)
157		return ECHOSTATUS_NO_3G_BOX;
158
159	if ( GetDspCommObject()->IsBoardBad() )
160		return ECHOSTATUS_DSP_DEAD;
161
162	//
163	// Clear the "bad board" flag; set the flags to indicate that
164	// 3G can handle super-interleave.
165	//
166	m_wFlags &= ~ECHOGALS_FLAG_BADBOARD;
167	m_wFlags |= ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK;
168
169	//
170	//	Must call this here after DSP is init to
171	//	init gains and mutes
172	//
173	Status = InitLineLevels();
174	if ( ECHOSTATUS_OK != Status )
175		return Status;
176
177	//
178	// Initialize the MIDI input
179	//
180	Status = m_MidiIn.Init( this );
181	if ( ECHOSTATUS_OK != Status )
182		return Status;
183
184	//
185	// Set defaults for +4/-10
186	//
187	for (i = 0; i < GetFirstDigitalBusOut(); i++ )
188	{
189		GetDspCommObject()->
190			SetNominalLevel( i, FALSE );	// FALSE is +4 here
191	}
192	for ( i = 0; i < GetFirstDigitalBusIn(); i++ )
193	{
194		GetDspCommObject()->
195			SetNominalLevel( GetNumBussesOut() + i, FALSE );
196	}
197
198	//
199	// Set the digital mode to S/PDIF RCA
200	//
201	SetDigitalMode( DIGITAL_MODE_SPDIF_RCA );
202
203	//
204	//	Get default sample rate from DSP
205	//
206	m_dwSampleRate = GetDspCommObject()->GetSampleRate();
207
208	ECHO_DEBUGPRINTF( ( "C3g::InitHw()\n" ) );
209	return Status;
210
211}	// ECHOSTATUS C3g::InitHw()
212
213
214
215
216/****************************************************************************
217
218	Informational methods
219
220 ****************************************************************************/
221
222//===========================================================================
223//
224// Override GetCapabilities to enumerate unique capabilties for this card
225//
226//===========================================================================
227
228ECHOSTATUS C3g::GetCapabilities
229(
230	PECHOGALS_CAPS	pCapabilities
231)
232{
233	ECHOSTATUS	Status;
234	WORD			i;
235
236	Status = GetBaseCapabilities(pCapabilities);
237	if ( ECHOSTATUS_OK != Status )
238		return Status;
239
240	//
241	// Add nominal level control to all ins & outs except the universal
242	//
243	for (i = 0 ; i < pCapabilities->wNumBussesOut; i++)
244	{
245		pCapabilities->dwBusOutCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
246	}
247
248	for (i = 2 ; i < pCapabilities->wNumBussesIn; i++)
249	{
250		pCapabilities->dwBusInCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
251	}
252
253	pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_SPDIF		|
254												ECHO_CLOCK_BIT_ADAT		|
255												ECHO_CLOCK_BIT_MTC;
256
257	//
258	// Box-specific capabilities
259	//
260	DWORD dwBoxType;
261
262	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
263	switch (dwBoxType)
264	{
265		case GINA3G :
266			pCapabilities->dwBusInCaps[0] |= ECHOCAPS_PHANTOM_POWER;
267			pCapabilities->dwBusInCaps[1] |= ECHOCAPS_PHANTOM_POWER;
268			break;
269
270		case LAYLA3G :
271			pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_WORD;
272			break;
273
274	}
275
276	pCapabilities->dwOutClockTypes = 0;
277
278	return Status;
279
280}	// ECHOSTATUS C3g::GetCapabilities
281
282
283//===========================================================================
284//
285// QueryAudioSampleRate is used to find out if this card can handle a
286// given sample rate.
287//
288//===========================================================================
289
290ECHOSTATUS C3g::QueryAudioSampleRate
291(
292	DWORD		dwSampleRate
293)
294{
295	//
296	// Check rates that are supported by continuous mode; only allow
297	// double-speed rates if not in ADAT mode
298	//
299	if ((dwSampleRate >= 32000) && (dwSampleRate <= 50000))
300		return ECHOSTATUS_OK;
301
302	if (	(DIGITAL_MODE_ADAT != GetDigitalMode()) &&
303			(dwSampleRate > 50000) &&
304			(dwSampleRate <= 100000))
305		return ECHOSTATUS_OK;
306
307	ECHO_DEBUGPRINTF(("C3g::QueryAudioSampleRate() - rate %ld invalid\n",dwSampleRate) );
308
309	return ECHOSTATUS_BAD_FORMAT;
310
311}	// ECHOSTATUS C3g::QueryAudioSampleRate
312
313
314void C3g::QuerySampleRateRange(DWORD &dwMinRate,DWORD &dwMaxRate)
315{
316	dwMinRate = 32000;
317	dwMaxRate = 96000;
318}
319
320
321
322//===========================================================================
323//
324// GetInputClockDetect returns a bitmask consisting of all the input
325// clocks currently connected to the hardware; this changes as the user
326// connects and disconnects clock inputs.
327//
328// You should use this information to determine which clocks the user is
329// allowed to select.
330//
331//===========================================================================
332
333ECHOSTATUS C3g::GetInputClockDetect(DWORD &dwClockDetectBits)
334{
335	if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
336	{
337		ECHO_DEBUGPRINTF( ("C3g::GetInputClockDetect: DSP Dead!\n") );
338		return ECHOSTATUS_DSP_DEAD;
339	}
340
341	//
342	// Map the DSP clock detect bits to the generic driver clock detect bits
343	//
344	DWORD dwClocksFromDsp = GetDspCommObject()->GetInputClockDetect();
345
346	dwClockDetectBits = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_MTC;
347
348	if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_WORD))
349		dwClockDetectBits |= ECHO_CLOCK_BIT_WORD;
350
351	switch (GetDigitalMode())
352	{
353		case DIGITAL_MODE_SPDIF_RCA :
354		case DIGITAL_MODE_SPDIF_OPTICAL :
355			if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_SPDIF))
356				dwClockDetectBits |= ECHO_CLOCK_BIT_SPDIF;
357			break;
358
359		case DIGITAL_MODE_ADAT :
360			if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_ADAT))
361				dwClockDetectBits |= ECHO_CLOCK_BIT_ADAT;
362			break;
363	}
364
365	return ECHOSTATUS_OK;
366
367}	// GetInputClockDetect
368
369
370//===========================================================================
371//
372// Get the external box type
373//
374//===========================================================================
375
376void C3g::Get3gBoxType(DWORD *pOriginalBoxType,DWORD *pCurrentBoxType)
377{
378	GetDspCommObject()->Get3gBoxType(pOriginalBoxType,pCurrentBoxType);
379}
380
381
382//===========================================================================
383//
384// Get the external box name
385//
386//===========================================================================
387
388char *C3g::Get3gBoxName()
389{
390	char *pszName;
391	DWORD dwBoxType;
392
393	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
394	switch (dwBoxType)
395	{
396		case GINA3G :
397			pszName = "Gina3G";
398			break;
399
400		case LAYLA3G :
401			pszName = "Layla3G";
402			break;
403
404		case NO3GBOX :
405		default :
406			pszName = "Echo3G";
407			break;
408	}
409
410	return pszName;
411}
412
413
414//===========================================================================
415//
416// Get phantom power state for Gina3G
417//
418//===========================================================================
419
420void C3g::GetPhantomPower(BOOL *pfPhantom)
421{
422	*pfPhantom = m_fPhantomPower;
423}
424
425
426//===========================================================================
427//
428// Set phantom power state for Gina3G
429//
430//===========================================================================
431
432void C3g::SetPhantomPower(BOOL fPhantom)
433{
434	DWORD dwBoxType;
435
436	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
437	if (GINA3G == dwBoxType)
438	{
439		GetDspCommObject()->SetPhantomPower( fPhantom );
440		m_fPhantomPower = fPhantom;
441	}
442}
443
444
445//===========================================================================
446//
447// GetAudioLatency - returns the latency for a single pipe
448//
449//===========================================================================
450
451void C3g::GetAudioLatency(ECHO_AUDIO_LATENCY *pLatency)
452{
453	DWORD dwSampleRate;
454
455	//
456	// Adjust the stored latency values based on the sample rate
457	//
458	dwSampleRate = GetDspCommObject()->GetSampleRate();
459	if (dwSampleRate <= 50000)
460	{
461		m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
462		m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
463	}
464	else
465	{
466		m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_2X;
467		m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_2X;
468	}
469
470	//
471	// Let the base class worry about analog vs. digital
472	//
473	CEchoGals::GetAudioLatency(pLatency);
474
475}	// GetAudioLatency
476
477
478
479//===========================================================================
480//
481//	Start transport for a group of pipes
482//
483// Use this to make sure no one tries to start digital channels 3-8
484// with the hardware in double speed mode.
485//
486//===========================================================================
487
488ECHOSTATUS C3g::Start
489(
490	PCChannelMask	pChannelMask
491)
492{
493	PC3gDco pDCO;
494
495	//
496	// Double speed mode?
497	//
498	pDCO = GetDspCommObject();
499	if (pDCO->DoubleSpeedMode())
500	{
501		BOOL intersect;
502
503		//
504		// See if ADAT in 3-8 or out 3-8 are being started
505		//
506		intersect = pChannelMask->IsIntersectionOf( pDCO->m_Adat38Mask );
507		if (intersect)
508		{
509			ECHO_DEBUGPRINTF(("Cannot start ADAT channels 3-8 in double speed mode\n"));
510			return ECHOSTATUS_INVALID_CHANNEL;
511		}
512	}
513
514	return CEchoGals::Start(pChannelMask);
515}
516
517// *** C3g.cpp ***
518