1// ****************************************************************************
2//
3//  	CMonaDspCommObject.cpp
4//
5//		Implementation file for EchoGals generic driver Mona DSP
6//		interface class.
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 "CEchoGals.h"
32#include "CMonaDspCommObject.h"
33
34#include "MonaDSP.c"
35#include "Mona361DSP.c"
36
37#include "Mona1ASIC48.c"
38#include "Mona1ASIC96.c"
39#include "Mona1ASIC48_361.c"
40#include "Mona1ASIC96_361.c"
41#include "Mona2ASIC.c"
42
43
44/****************************************************************************
45
46	Construction and destruction
47
48 ****************************************************************************/
49
50//===========================================================================
51//
52// Constructor
53//
54//===========================================================================
55
56CMonaDspCommObject::CMonaDspCommObject
57(
58	PDWORD		pdwRegBase,				// Virtual ptr to DSP registers
59	PCOsSupport	pOsSupport
60) : CGMLDspCommObject( pdwRegBase, pOsSupport )
61{
62	strcpy( m_szCardName, "Mona" );
63	m_pdwDspRegBase = pdwRegBase;		// Virtual addr DSP's register base
64
65	m_wNumPipesOut = 14;
66	m_wNumPipesIn = 12;
67	m_wNumBussesOut = 14;
68	m_wNumBussesIn = 12;
69	m_wFirstDigitalBusOut = 6;
70	m_wFirstDigitalBusIn = 4;
71
72	m_bProfessionalSpdif = FALSE;
73
74	m_fHasVmixer = FALSE;
75
76	m_wNumMidiOut = 0;					// # MIDI out channels
77	m_wNumMidiIn = 0;						// # MIDI in  channels
78	m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 44100 );
79												// Need this in cse we start with ESYNC
80	m_bHasASIC = TRUE;
81	if ( DEVICE_ID_56361 == pOsSupport->GetDeviceId() )
82		m_pwDspCodeToLoad = pwMona361DSP;
83	else
84		m_pwDspCodeToLoad = pwMonaDSP;
85
86	m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA;
87}	// CMonaDspCommObject::CMonaDspCommObject( DWORD dwPhysRegBase )
88
89
90//===========================================================================
91//
92// Destructor
93//
94//===========================================================================
95
96CMonaDspCommObject::~CMonaDspCommObject()
97{
98}	// CMonaDspCommObject::~CMonaDspCommObject()
99
100
101
102
103/****************************************************************************
104
105	Hardware setup and config
106
107 ****************************************************************************/
108
109//===========================================================================
110//
111// Mona has an ASIC on the PCI card and another ASIC in the external box;
112// both need to be loaded.
113//
114//===========================================================================
115
116BOOL CMonaDspCommObject::LoadASIC()
117{
118	DWORD	dwControlReg;
119	PBYTE	pbAsic1;
120	DWORD	dwSize;
121
122	if ( m_bASICLoaded )
123		return TRUE;
124
125	m_pOsSupport->OsSnooze( 10000 );
126
127	if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
128	{
129		pbAsic1 = pbMona1ASIC48_361;
130		dwSize = sizeof( pbMona1ASIC48_361 );
131	}
132	else
133	{
134		pbAsic1 = pbMona1ASIC48;
135		dwSize = sizeof( pbMona1ASIC48 );
136	}
137	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
138											  pbAsic1,
139											  dwSize ) )
140		return FALSE;
141
142	m_pbyAsic = pbAsic1;
143
144	m_pOsSupport->OsSnooze( 10000 );
145
146	// Do the external one
147	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_EXTERNAL_ASIC,
148											  pbMona2ASIC,
149											  sizeof( pbMona2ASIC ) ) )
150		return FALSE;
151
152	m_pOsSupport->OsSnooze( 10000 );
153
154	CheckAsicStatus();
155
156	//
157	// Set up the control register if the load succeeded -
158	//
159	// 48 kHz, internal clock, S/PDIF RCA mode
160	//
161	if ( m_bASICLoaded )
162	{
163		dwControlReg = GML_CONVERTER_ENABLE | GML_48KHZ;
164		ECHO_DEBUGPRINTF(("CMonaDspCommObject::LoadASIC - setting control reg for 0x%lx\n",
165								dwControlReg));
166		WriteControlReg( dwControlReg, TRUE );
167	}
168
169	return m_bASICLoaded;
170
171}	// BOOL CMonaDspCommObject::LoadASIC()
172
173
174//===========================================================================
175//
176// Depending on what digital mode you want, Mona needs different ASICs
177//	loaded.  This function checks the ASIC needed for the new mode and sees
178// if it matches the one already loaded.
179//
180//===========================================================================
181
182BOOL CMonaDspCommObject::SwitchAsic( DWORD dwMask96 )
183{
184	BYTE *	pbyAsicNeeded;
185	DWORD		dwAsicSize;
186
187	//
188	//	Check the clock detect bits to see if this is
189	// a single-speed clock or a double-speed clock; load
190	// a new ASIC if necessary.
191	//
192	if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
193	{
194		pbyAsicNeeded = pbMona1ASIC48_361;
195		dwAsicSize = sizeof( pbMona1ASIC48_361 );
196		if ( 0 != ( dwMask96 & GetInputClockDetect() ) )
197		{
198			pbyAsicNeeded = pbMona1ASIC96_361;
199			dwAsicSize = sizeof( pbMona1ASIC96_361 );
200		}
201	}
202	else
203	{
204		pbyAsicNeeded = pbMona1ASIC48;
205		dwAsicSize = sizeof( pbMona1ASIC48 );
206		if ( 0 != ( dwMask96 & GetInputClockDetect() ) )
207		{
208			pbyAsicNeeded = pbMona1ASIC96;
209			dwAsicSize = sizeof( pbMona1ASIC96 );
210		}
211	}
212
213	if ( pbyAsicNeeded != m_pbyAsic )
214	{
215		//
216		// Load the desired ASIC
217		//
218		if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
219												  pbyAsicNeeded,
220												  dwAsicSize ) )
221			return FALSE;
222
223		m_pbyAsic = pbyAsicNeeded;
224
225		m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
226	}
227
228	return TRUE;
229
230}	// BOOL CMonaDspCommObject::SwitchAsic( DWORD dwMask96 )
231
232
233//===========================================================================
234//
235// SetInputClock
236//
237//===========================================================================
238
239ECHOSTATUS CMonaDspCommObject::SetInputClock(WORD wClock)
240{
241	BOOL			bSetRate;
242	BOOL			bWriteControlReg;
243	DWORD			dwControlReg;
244
245	ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetInputClock: clock %d\n",wClock) );
246
247	dwControlReg = GetControlRegister();
248
249	//
250	// Mask off the clock select bits
251	//
252	dwControlReg &= GML_CLOCK_CLEAR_MASK;
253
254	bSetRate = FALSE;
255	bWriteControlReg = TRUE;
256	switch ( wClock )
257	{
258		case ECHO_CLOCK_INTERNAL :
259		{
260			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to INTERNAL\n" ) );
261
262			bSetRate = TRUE;
263			bWriteControlReg = FALSE;
264
265			break;
266		} // CLK_CLOCKININTERNAL
267
268		case ECHO_CLOCK_SPDIF :
269		{
270			if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
271			{
272				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
273			}
274
275			if ( FALSE == SwitchAsic( GML_CLOCK_DETECT_BIT_SPDIF96 ) )
276			{
277				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
278			}
279
280			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to SPDIF\n" ) );
281
282			dwControlReg |= GML_SPDIF_CLOCK;
283
284			if ( GML_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() )
285			{
286				dwControlReg |= GML_DOUBLE_SPEED_MODE;
287			}
288			else
289			{
290				dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
291			}
292			break;
293		} // CLK_CLOCKINSPDIF
294
295		case ECHO_CLOCK_WORD :
296		{
297			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to WORD\n" ) );
298
299			if ( FALSE == SwitchAsic( GML_CLOCK_DETECT_BIT_WORD96 ) )
300			{
301				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
302			}
303
304			dwControlReg |= GML_WORD_CLOCK;
305
306			if ( GML_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() )
307			{
308				dwControlReg |= GML_DOUBLE_SPEED_MODE;
309			}
310			else
311			{
312				dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
313			}
314			break;
315		} // CLK_CLOCKINWORD
316
317		case ECHO_CLOCK_ADAT :
318		{
319			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to ADAT\n" ) );
320
321			if ( DIGITAL_MODE_ADAT != GetDigitalMode() )
322			{
323				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
324			}
325
326			dwControlReg |= GML_ADAT_CLOCK;
327			dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
328			break;
329		} // CLK_CLOCKINADAT
330
331		default :
332			ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Mona\n",wClock));
333			ECHO_DEBUGBREAK();
334				return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
335	}	// switch (wClock)
336
337	//
338	// Winner! Save the new input clock.
339	//
340	m_wInputClock = wClock;
341
342	//
343	// Do things according to the flags
344	//
345	if ( bWriteControlReg )
346	{
347		WriteControlReg( dwControlReg, TRUE );
348	}
349
350	// Set Mona sample rate to something sane if word or superword is
351	// being turned off
352	if ( bSetRate )
353	{
354		SetSampleRate( GetSampleRate() );
355	}
356
357	return ECHOSTATUS_OK;
358
359}	// ECHOSTATUS CMonaDspCommObject::SetInputClock
360
361
362
363//===========================================================================
364//
365// SetSampleRate
366//
367// Set the audio sample rate for CMona
368//
369//===========================================================================
370
371DWORD CMonaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
372{
373	BYTE *pbyAsicNeeded;
374	DWORD	dwAsicSize, dwControlReg, dwNewClock;
375	BOOL	fForceControlReg;
376
377	ECHO_DEBUGPRINTF(("CMonaDspCommObject::SetSampleRate to %ld\n",dwNewSampleRate));
378
379	fForceControlReg = FALSE;
380
381	//
382	// Only set the clock for internal mode.  If the clock is not set to
383	// internal, try and re-set the input clock; this more transparently
384	// handles switching between single and double-speed mode
385	//
386	if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
387	{
388		ECHO_DEBUGPRINTF( ( "CMonaDspCommObject::SetSampleRate: Cannot set sample rate - "
389								  "clock not set to CLK_CLOCKININTERNAL\n" ) );
390
391		//
392		// Save the rate anyhow
393		//
394		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
395
396		//
397		// Set the input clock to the current value
398		//
399		SetInputClock( m_wInputClock );
400
401		return GetSampleRate();
402	}
403
404	//
405	// Now, check to see if the required ASIC is loaded
406	//
407	if ( dwNewSampleRate >= 88200 )
408	{
409		if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
410			return( GetSampleRate() );
411
412		if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
413		{
414			pbyAsicNeeded = pbMona1ASIC96_361;
415			dwAsicSize = sizeof(pbMona1ASIC96_361);
416		}
417		else
418		{
419			pbyAsicNeeded = pbMona1ASIC96;
420			dwAsicSize = sizeof(pbMona1ASIC96);
421		}
422	}
423	else
424	{
425		if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
426		{
427			pbyAsicNeeded = pbMona1ASIC48_361;
428			dwAsicSize = sizeof(pbMona1ASIC48_361);
429		}
430		else
431		{
432			pbyAsicNeeded = pbMona1ASIC48;
433			dwAsicSize = sizeof(pbMona1ASIC48);
434		}
435	}
436
437	if ( pbyAsicNeeded != m_pbyAsic )
438	{
439		ECHO_DEBUGPRINTF(("\tLoading a new ASIC\n"));
440		//
441		// Load the desired ASIC
442		//
443		if ( FALSE == CDspCommObject::LoadASIC
444													( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
445													  pbyAsicNeeded,
446													  dwAsicSize ) )
447			return( GetSampleRate() );
448
449		m_pbyAsic = pbyAsicNeeded;
450
451		fForceControlReg = TRUE;
452	}
453
454	//
455	// Get the new control register value
456	//
457	dwNewClock = 0;
458
459	dwControlReg = GetControlRegister();
460	dwControlReg &= GML_CLOCK_CLEAR_MASK;
461	dwControlReg &= GML_SPDIF_RATE_CLEAR_MASK;
462
463	switch ( dwNewSampleRate )
464	{
465		case 96000 :
466			dwNewClock = GML_96KHZ;
467			break;
468
469		case 88200 :
470			dwNewClock = GML_88KHZ;
471			break;
472
473		case 48000 :
474			dwNewClock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
475			break;
476
477		case 44100 :
478			dwNewClock = GML_44KHZ;
479			//
480			// Professional mode
481			//
482			if ( dwControlReg & GML_SPDIF_PRO_MODE )
483			{
484				dwNewClock |= GML_SPDIF_SAMPLE_RATE0;
485			}
486			break;
487
488		case 32000 :
489			dwNewClock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 | GML_SPDIF_SAMPLE_RATE1;
490			break;
491
492		case 22050 :
493			dwNewClock = GML_22KHZ;
494			break;
495
496		case 16000 :
497			dwNewClock = GML_16KHZ;
498			break;
499
500		case 11025 :
501			dwNewClock = GML_11KHZ;
502			break;
503
504		case 8000 :
505			dwNewClock = GML_8KHZ;
506			break;
507	}
508
509	dwControlReg |= dwNewClock;
510
511	//
512	// Send the new value to the card
513	//
514	if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg, fForceControlReg ) )
515	{
516		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
517
518		ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetSampleRate: %ld "
519								 "clock %ld\n", dwNewSampleRate, dwNewClock) );
520	}
521
522	return GetSampleRate();
523
524} // DWORD CMonaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
525
526
527//===========================================================================
528//
529//	Set digital mode
530//
531//===========================================================================
532
533ECHOSTATUS CMonaDspCommObject::SetDigitalMode
534(
535	BYTE	byNewMode
536)
537{
538	ECHO_DEBUGPRINTF(("CMonaDspCommObject::SetDigitalMode %d\n",byNewMode));
539
540	//
541	// If the new mode is ADAT mode, make sure that the single speed ASIC is loaded
542	//
543	BYTE *pbAsic96;
544
545	if (DIGITAL_MODE_ADAT == byNewMode)
546	{
547		switch (m_pOsSupport->GetDeviceId())
548		{
549			case DEVICE_ID_56301 :
550				pbAsic96 = pbMona1ASIC96;
551				break;
552
553			case DEVICE_ID_56361 :
554				pbAsic96 = pbMona1ASIC96_361;
555				break;
556
557			default :				// should never happen, but it's good to cover all the bases
558				return ECHOSTATUS_BAD_CARDID;
559		}
560		if (pbAsic96 == m_pbyAsic)
561			SetSampleRate( 48000 );
562	}
563
564	//
565	// Call the base class to tweak the input clock if necessary
566	//
567	return CGMLDspCommObject::SetDigitalMode(byNewMode);
568
569}	// ECHOSTATUS CMonaDspCommObject::SetDigitalMode
570
571
572// **** CMonaDspCommObject.cpp ****
573