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