1// ****************************************************************************
2//
3//  	C3gDco.cpp
4//
5//		Implementation file for EchoGals generic driver 3G 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 "C3gDco.h"
33
34#include "Echo3gDSP.c"
35#include "3G_ASIC.c"
36
37/****************************************************************************
38
39	Construction and destruction
40
41 ****************************************************************************/
42
43//===========================================================================
44//
45// Constructor
46//
47//===========================================================================
48
49C3gDco::C3gDco
50(
51	PDWORD		pdwRegBase,				// Virtual ptr to DSP registers
52	PCOsSupport	pOsSupport
53) : CDspCommObject( pdwRegBase, pOsSupport )
54{
55	m_pdwDspRegBase = pdwRegBase;		// Virtual addr DSP's register base  fixme put this in base class
56
57	m_dwOriginalBoxType = NO3GBOX;
58	m_dwCurrentBoxType = m_dwOriginalBoxType;
59	SetChannelCounts();
60	m_bBoxTypeSet = FALSE;
61
62	m_fHasVmixer = FALSE;
63
64	m_wNumMidiOut = 1;					// # MIDI out channels
65	m_wNumMidiIn = 1;						// # MIDI in  channels
66
67	m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
68	m_pDspCommPage->dw3gFreqReg = SWAP( (DWORD) (E3G_MAGIC_NUMBER / 48000) - 2);
69
70	m_bHasASIC = TRUE;
71
72	m_pwDspCodeToLoad = pwEcho3gDSP;
73
74	m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA;
75
76	m_bProfessionalSpdif = FALSE;
77	m_bNonAudio = FALSE;
78
79}	// C3gDco::C3gDco( DWORD dwPhysRegBase )
80
81
82
83//===========================================================================
84//
85// Destructor
86//
87//===========================================================================
88
89C3gDco::~C3gDco()
90{
91}	// C3gDco::~C3gDco()
92
93
94
95//===========================================================================
96//
97// Supported digital modes depend on what kind of box you have
98//
99//===========================================================================
100
101DWORD C3gDco::GetDigitalModes()
102{
103	DWORD dwModes;
104
105	dwModes =	ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
106					ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
107					ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
108
109	return dwModes;
110}
111
112
113/****************************************************************************
114
115	Hardware setup and config
116
117 ****************************************************************************/
118
119//===========================================================================
120//
121// 3G has an ASIC in the external box
122//
123//===========================================================================
124
125BOOL C3gDco::LoadASIC()
126{
127	DWORD	dwControlReg;
128
129	if ( m_bASICLoaded == TRUE )
130		return TRUE;
131
132	ECHO_DEBUGPRINTF(("C3gDco::LoadASIC\n"));
133
134	//
135	// Give the DSP a few milliseconds to settle down
136	//
137	m_pOsSupport->OsSnooze( 2000 );
138
139	//
140	// Load the ASIC
141	//
142	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_3G_ASIC,
143											  pb3g_asic,
144											  sizeof(pb3g_asic) ) )
145		return FALSE;
146
147	//
148	// Give the ASIC a whole second to set up
149	//
150	m_pOsSupport->OsSnooze( 1000000 );
151
152	//
153	// See if it worked
154	//
155	CheckAsicStatus();
156
157	//
158	// Set up the control register if the load succeeded -
159	//
160	// 48 kHz, internal clock, S/PDIF RCA mode
161	//
162	if ( m_bASICLoaded )
163	{
164		dwControlReg = E3G_48KHZ;
165		WriteControlReg( dwControlReg, E3G_FREQ_REG_DEFAULT, TRUE);	// TRUE == force write
166	}
167
168	ECHO_DEBUGPRINTF(("\t3G ASIC loader finished\n"));
169
170	return m_bASICLoaded;
171
172}	// BOOL C3gDco::LoadASIC()
173
174
175
176//===========================================================================
177//
178//	Set the input clock
179//
180//===========================================================================
181
182ECHOSTATUS C3gDco::SetInputClock(WORD wClock)
183{
184	DWORD dwControlReg,dwSampleRate;
185	ECHOSTATUS Status;
186
187	ECHO_DEBUGPRINTF( ("C3gDco::SetInputClock:\n") );
188
189	//
190	// Mask off the clock select bits
191	//
192	dwControlReg = GetControlRegister();
193	dwControlReg &= E3G_CLOCK_CLEAR_MASK;
194
195	//
196	// New clock
197	//
198	switch (wClock)
199	{
200		case ECHO_CLOCK_INTERNAL :
201			ECHO_DEBUGPRINTF(("\tsetting internal clock\n"));
202
203			m_wInputClock = ECHO_CLOCK_INTERNAL;	// prevent recursion
204
205			dwSampleRate = GetSampleRate();
206			if ((dwSampleRate < 32000) || (dwSampleRate > 100000))
207				dwSampleRate = 48000;
208
209			SetSampleRate(dwSampleRate);
210			return ECHOSTATUS_OK;
211
212
213		case ECHO_CLOCK_WORD:
214			dwControlReg |= E3G_WORD_CLOCK;
215
216			if ( E3G_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() )
217			{
218				dwControlReg |= E3G_DOUBLE_SPEED_MODE;
219			}
220			else
221			{
222				dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
223			}
224			ECHO_DEBUGPRINTF( ( "\tSet 3G clock to WORD\n" ) );
225			break;
226
227
228		case ECHO_CLOCK_SPDIF :
229			if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
230			{
231				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
232			}
233
234			dwControlReg |= E3G_SPDIF_CLOCK;
235			if ( E3G_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() )
236			{
237				dwControlReg |= E3G_DOUBLE_SPEED_MODE;
238			}
239			else
240			{
241				dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
242			}
243
244			ECHO_DEBUGPRINTF( ( "\tSet 3G clock to SPDIF\n" ) );
245			break;
246
247
248		case ECHO_CLOCK_ADAT :
249			if ( DIGITAL_MODE_ADAT != GetDigitalMode() )
250			{
251				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
252			}
253
254			dwControlReg |= E3G_ADAT_CLOCK;
255			dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
256			ECHO_DEBUGPRINTF( ( "\tSet 3G clock to ADAT\n" ) );
257			break;
258
259
260		default :
261			ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for 3G\n",wClock));
262			ECHO_DEBUGBREAK();
263				return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
264	}
265
266	//
267	// Winner! Try to write the hardware
268	//
269	Status = WriteControlReg( dwControlReg, Get3gFreqReg(), TRUE );
270	if (ECHOSTATUS_OK == Status)
271		m_wInputClock = wClock;
272
273	return Status;
274
275}	// ECHOSTATUS C3gDco::SetInputClock
276
277
278
279//===========================================================================
280//
281// SetSampleRate
282//
283// Set the audio sample rate for 3G
284//
285//===========================================================================
286
287DWORD C3gDco::SetSampleRate( DWORD dwNewSampleRate )
288{
289	DWORD dwControlReg,dwNewClock,dwBaseRate,dwFreqReg;
290
291	ECHO_DEBUGPRINTF(("3G set sample rate to %ld\n",dwNewSampleRate));
292
293	//
294	// Only set the clock for internal mode.  If the clock is not set to
295	// internal, try and re-set the input clock; this more transparently
296	// handles switching between single and double-speed mode
297	//
298	if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
299	{
300		ECHO_DEBUGPRINTF( ( "C3gDco::SetSampleRate: Cannot set sample rate - "
301								  "clock not set to ECHO_CLOCK_INTERNAL\n" ) );
302
303		//
304		// Save the rate anyhow
305		//
306		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
307
308		//
309		// Set the input clock to the current value
310		//
311		SetInputClock( m_wInputClock );
312
313		return dwNewSampleRate;
314	}
315
316	//
317	// Get the control register & clear the appropriate bits
318	//
319	dwControlReg = GetControlRegister();
320	dwControlReg &= E3G_CLOCK_CLEAR_MASK;
321
322	//
323	// Set the sample rate
324	//
325	switch ( dwNewSampleRate )
326	{
327		case 96000 :
328			dwNewClock = E3G_96KHZ;
329			break;
330
331		case 88200 :
332			dwNewClock = E3G_88KHZ;
333			break;
334
335		case 48000 :
336			dwNewClock = E3G_48KHZ;
337			break;
338
339		case 44100 :
340			dwNewClock = E3G_44KHZ;
341			break;
342
343		case 32000 :
344			dwNewClock = E3G_32KHZ;
345			break;
346
347		default :
348			dwNewClock = E3G_CONTINUOUS_CLOCK;
349			if (dwNewSampleRate > 50000)
350				dwNewClock |= E3G_DOUBLE_SPEED_MODE;
351			break;
352	}
353
354	dwControlReg |= dwNewClock;
355	SetSpdifBits(&dwControlReg,dwNewSampleRate);
356
357	ECHO_DEBUGPRINTF(("\tdwNewClock 0x%lx  dwControlReg 0x%lx\n",dwNewClock,dwControlReg));
358
359	//
360	// Set up the frequency reg
361	//
362	dwBaseRate = dwNewSampleRate;
363	if (dwBaseRate > 50000)
364		dwBaseRate /= 2;
365
366	if (dwBaseRate < 32000)
367		dwBaseRate = 32000;
368
369	dwFreqReg = E3G_MAGIC_NUMBER / dwBaseRate - 2;
370	if (dwFreqReg > E3G_FREQ_REG_MAX)
371		dwFreqReg = E3G_FREQ_REG_MAX;
372
373	//
374	// Tell the DSP about it - DSP reads both control reg & freq reg
375	//
376	if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg, dwFreqReg) )
377	{
378		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
379
380		ECHO_DEBUGPRINTF( ("C3gDco::SetSampleRate: %ld  clock %lx\n", dwNewSampleRate, dwControlReg) );
381	}
382	else
383	{
384		ECHO_DEBUGPRINTF( ("C3gDco::SetSampleRate: could not set sample rate %ld\n", dwNewSampleRate) );
385
386		dwNewSampleRate = SWAP( m_pDspCommPage->dwSampleRate );
387	}
388
389	return dwNewSampleRate;
390
391} // DWORD C3gDco::SetSampleRate( DWORD dwNewSampleRate )
392
393
394
395//===========================================================================
396//
397// SetDigitalMode
398//
399//===========================================================================
400
401ECHOSTATUS C3gDco::SetDigitalMode
402(
403	BYTE	byNewMode
404)
405{
406	DWORD		dwControlReg;
407	WORD		wInvalidClock;
408
409	//
410	// See if the current input clock doesn't match the new digital mode
411	//
412	switch (byNewMode)
413	{
414		case DIGITAL_MODE_SPDIF_RCA :
415		case DIGITAL_MODE_SPDIF_OPTICAL :
416			wInvalidClock = ECHO_CLOCK_ADAT;
417			break;
418
419		case DIGITAL_MODE_ADAT :
420			wInvalidClock = ECHO_CLOCK_SPDIF;
421			break;
422
423		default :
424			wInvalidClock = 0xffff;
425			break;
426	}
427
428	if (wInvalidClock == GetInputClock())
429	{
430		SetInputClock( ECHO_CLOCK_INTERNAL );
431		SetSampleRate( 48000 );
432	}
433
434
435	//
436	// Clear the current digital mode
437	//
438	dwControlReg = GetControlRegister();
439	dwControlReg &= E3G_DIGITAL_MODE_CLEAR_MASK;
440
441	//
442	// Tweak the control reg
443	//
444	switch ( byNewMode )
445	{
446		default :
447			return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED;
448
449		case DIGITAL_MODE_SPDIF_OPTICAL :
450			dwControlReg |= E3G_SPDIF_OPTICAL_MODE;
451			// fall through
452
453		case DIGITAL_MODE_SPDIF_RCA :
454			break;
455
456		case DIGITAL_MODE_ADAT :
457			dwControlReg |= E3G_ADAT_MODE;
458			dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
459			break;
460	}
461
462	//
463	// Write the control reg
464	//
465	WriteControlReg( dwControlReg, Get3gFreqReg(), TRUE );
466
467	m_byDigitalMode = byNewMode;
468
469	ECHO_DEBUGPRINTF( ("C3gDco::SetDigitalMode to %ld\n",
470							(DWORD) m_byDigitalMode) );
471
472	return ECHOSTATUS_OK;
473
474}	// ECHOSTATUS C3gDco::SetDigitalMode
475
476
477
478//===========================================================================
479//
480// WriteControlReg
481//
482//===========================================================================
483
484ECHOSTATUS C3gDco::WriteControlReg
485(
486	DWORD dwControlReg,
487	DWORD	dwFreqReg,
488	BOOL 	fForceWrite
489)
490{
491	ECHOSTATUS Status;
492
493	ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg 0x%lx 0x%lx\n",dwControlReg,dwFreqReg));
494
495	//
496	// New value OK?
497	//
498	Status = ValidateCtrlReg(dwControlReg);
499	if (ECHOSTATUS_OK != Status)
500		return Status;
501
502	//
503	// Ready to go?
504	//
505	if ( !m_bASICLoaded )
506	{
507		ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg - ASIC not loaded\n"));
508		return( ECHOSTATUS_ASIC_NOT_LOADED );
509	}
510
511	if ( !WaitForHandshake() )
512	{
513		ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg - no handshake\n"));
514		return ECHOSTATUS_DSP_DEAD;
515	}
516
517	//
518	// Write the control register
519	//
520	if (	fForceWrite ||
521			(dwControlReg != GetControlRegister()) ||
522			(dwFreqReg != Get3gFreqReg())
523		)
524	{
525		m_pDspCommPage->dw3gFreqReg = SWAP( dwFreqReg );
526		SetControlRegister( dwControlReg );
527
528		ECHO_DEBUGPRINTF( ("C3gDco::WriteControlReg: Setting 0x%lx, 0x%lx\n",
529								 dwControlReg,dwFreqReg) );
530
531		ClearHandshake();
532		return SendVector( DSP_VC_WRITE_CONTROL_REG );
533	}
534	else
535	{
536		ECHO_DEBUGPRINTF( ("C3gDco::WriteControlReg: not written, no change\n") );
537	}
538
539	return ECHOSTATUS_OK;
540
541} // ECHOSTATUS C3gDco::WriteControlReg
542
543
544//===========================================================================
545//
546// SetSpdifBits
547//
548//===========================================================================
549
550void C3gDco::SetSpdifBits(DWORD *pdwCtrlReg,DWORD dwSampleRate)
551{
552	DWORD dwCtrlReg;
553
554	dwCtrlReg = *pdwCtrlReg;
555
556	//
557	// Clean out the old status bits
558	//
559	dwCtrlReg &= E3G_SPDIF_FORMAT_CLEAR_MASK;
560
561	//
562	// Sample rate
563	//
564	switch (dwSampleRate)
565	{
566		case 32000 :
567			dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE0 |
568							 E3G_SPDIF_SAMPLE_RATE1;
569			break;
570
571		case 44100 :
572			if (m_bProfessionalSpdif)
573				dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE0;
574			break;
575
576		case 48000 :
577			dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE1;
578			break;
579	}
580
581	//
582	// Professional mode?
583	//
584	if (m_bProfessionalSpdif)
585		dwCtrlReg |= E3G_SPDIF_PRO_MODE;
586
587	//
588	// Non-audio data?
589	//
590	if (m_bNonAudio)
591		dwCtrlReg |= E3G_SPDIF_NOT_AUDIO;
592
593	//
594	// Always stereo, 24 bit, copy permit
595	//
596	dwCtrlReg |= E3G_SPDIF_24_BIT | E3G_SPDIF_TWO_CHANNEL | E3G_SPDIF_COPY_PERMIT;
597
598	*pdwCtrlReg = dwCtrlReg;
599
600} // SetSpdifBits
601
602
603//===========================================================================
604//
605// SetSpdifOutNonAudio
606//
607// Set the state of the non-audio status bit in the S/PDIF out status bits
608//
609//===========================================================================
610
611void C3gDco::SetSpdifOutNonAudio(BOOL bNonAudio)
612{
613	DWORD		dwControlReg;
614
615	m_bNonAudio = bNonAudio;
616
617	dwControlReg = GetControlRegister();
618	SetSpdifBits( &dwControlReg, SWAP(	m_pDspCommPage->dwSampleRate ));
619	WriteControlReg( dwControlReg, Get3gFreqReg() );
620}
621
622
623//===========================================================================
624//
625// Set the S/PDIF output format
626//
627//===========================================================================
628
629void C3gDco::SetProfessionalSpdif
630(
631	BOOL bNewStatus
632)
633{
634	DWORD		dwControlReg;
635
636	m_bProfessionalSpdif = bNewStatus;
637
638	dwControlReg = GetControlRegister();
639	SetSpdifBits( &dwControlReg, SWAP(	m_pDspCommPage->dwSampleRate ));
640	WriteControlReg( dwControlReg, Get3gFreqReg() );
641
642}	// void C3gDco::SetProfessionalSpdif( ... )
643
644
645//===========================================================================
646//
647// ASIC status check
648//
649// 3G ASIC status check returns different values depending on what kind of box
650// is hooked up
651//
652//===========================================================================
653
654BOOL C3gDco::CheckAsicStatus()
655{
656	DWORD	dwBoxStatus,dwBoxType;
657
658	if ( !WaitForHandshake() )
659	{
660		ECHO_DEBUGPRINTF(("CheckAsicStatus - no handshake!\n"));
661		return FALSE;
662	}
663
664	//
665	// Send the vector command
666	//
667	m_pDspCommPage->dwExtBoxStatus = SWAP( (DWORD) E3G_ASIC_NOT_LOADED);
668	m_bASICLoaded = FALSE;
669	ClearHandshake();
670	SendVector( DSP_VC_TEST_ASIC );
671
672	//
673	// Wait for return from DSP
674	//
675	if ( !WaitForHandshake() )
676	{
677		ECHO_DEBUGPRINTF(("CheckAsicStatus - no handshake after VC\n"));
678		m_pwDspCode = NULL;
679		m_ullLastLoadAttemptTime = 0;	// so LoadFirmware will try again right away
680		return FALSE;
681	}
682
683	//
684	// What box type was set?
685	//
686	dwBoxStatus = SWAP(m_pDspCommPage->dwExtBoxStatus);
687	if (E3G_ASIC_NOT_LOADED == dwBoxStatus)
688	{
689		ECHO_DEBUGPRINTF(("CheckAsicStatus - ASIC not loaded\n"));
690		dwBoxType = NO3GBOX;
691	}
692	else
693	{
694		dwBoxType = dwBoxStatus & E3G_BOX_TYPE_MASK;
695		m_bASICLoaded = TRUE;
696		ECHO_DEBUGPRINTF(("CheckAsicStatus - read box type %x\n",dwBoxType));
697	}
698
699	m_dwCurrentBoxType = dwBoxType;
700
701	//
702	// Has the box type already been set?
703	//
704	if (m_bBoxTypeSet)
705	{
706		//
707		// Did the ASIC load?
708		// Was the box type correct?
709		//
710		if (	(NO3GBOX == dwBoxType) ||
711				(dwBoxType != m_dwOriginalBoxType) )
712		{
713			ECHO_DEBUGPRINTF(("CheckAsicStatus - box type mismatch - original %x, got %x\n",m_dwOriginalBoxType,dwBoxType));
714			return FALSE;
715		}
716
717		ECHO_DEBUGPRINTF(("CheckAsicStatus - ASIC ok\n"));
718		m_bASICLoaded = TRUE;
719		return TRUE;
720	}
721
722	//
723	// First ASIC load - determine the box type and set up for that kind of box
724	//
725	m_dwOriginalBoxType = dwBoxType;
726	m_bBoxTypeSet = TRUE;
727
728	SetChannelCounts();
729
730	//
731	// Set the bad board flag if no external box
732	//
733	if (NO3GBOX == dwBoxType)
734	{
735		ECHO_DEBUGPRINTF(("CheckAsicStatus - no external box\n"));
736		m_bBadBoard = TRUE;
737	}
738
739	return m_bASICLoaded;
740
741}	// BOOL C3gDco::CheckAsicStatus()
742
743
744//===========================================================================
745//
746// SetPhantomPower
747//
748//===========================================================================
749
750void C3gDco::SetPhantomPower(BOOL fPhantom)
751{
752	DWORD		dwControlReg;
753
754	dwControlReg = GetControlRegister();
755	if (fPhantom)
756	{
757		dwControlReg |= E3G_PHANTOM_POWER;
758	}
759	else
760	{
761		dwControlReg &= ~E3G_PHANTOM_POWER;
762	}
763
764	WriteControlReg( dwControlReg, Get3gFreqReg() );
765}
766
767
768//===========================================================================
769//
770// Set channel counts for the current box type
771//
772//===========================================================================
773
774void C3gDco::SetChannelCounts()
775{
776	char *pszName;
777	WORD ch,i;
778
779	switch (m_dwOriginalBoxType)
780	{
781		case GINA3G :
782			m_wNumPipesOut = 14;
783			m_wNumPipesIn = 10;
784			m_wFirstDigitalBusOut = 6;
785			m_wFirstDigitalBusIn = 2;
786
787			pszName = "Gina3G";
788			break;
789
790
791		case NO3GBOX :
792		case LAYLA3G :
793		default :
794			m_wNumPipesOut = 16;
795			m_wNumPipesIn = 16;
796			m_wFirstDigitalBusOut = 8;
797			m_wFirstDigitalBusIn = 8;
798
799			pszName = "Layla3G";
800			break;
801	}
802
803	m_wNumBussesOut = m_wNumPipesOut;
804	m_wNumBussesIn = m_wNumPipesIn;
805	strcpy( m_szCardName, pszName);
806
807	//
808	// Build a channel mask for ADAT inputs & outputs 3-8
809	// OK to use bus # here since this hardware has no virtual outputs
810	//
811	m_Adat38Mask.Clear();
812	ch = m_wFirstDigitalBusOut + 2;
813	for (i = 0; i < 6; i++)
814	{
815		m_Adat38Mask.SetIndexInMask(ch);
816		ch++;
817	}
818
819	ch += m_wFirstDigitalBusIn + 2;
820	for (i = 0; i < 6; i++)
821	{
822		m_Adat38Mask.SetIndexInMask(ch);
823		ch++;
824	}
825}
826
827
828//===========================================================================
829//
830// Return the 3G box type
831//
832//===========================================================================
833
834void C3gDco::Get3gBoxType(DWORD *pOriginalBoxType,DWORD *pCurrentBoxType)
835{
836	if (NULL != pOriginalBoxType)
837		*pOriginalBoxType = m_dwOriginalBoxType;
838
839	if (NULL != pCurrentBoxType)
840	{
841		CheckAsicStatus();
842
843		*pCurrentBoxType = m_dwCurrentBoxType;
844	}
845
846} // Get3gBoxType
847
848
849
850//===========================================================================
851//
852// Fill out an ECHOGALS_METERS struct using the current values in the
853// comm page.  This method is overridden for vmixer cards.
854//
855//===========================================================================
856
857ECHOSTATUS C3gDco::GetAudioMeters
858(
859	PECHOGALS_METERS	pMeters
860)
861{
862	pMeters->iNumPipesOut = 0;
863	pMeters->iNumPipesIn = 0;
864
865	//
866	//	Output
867	//
868	DWORD dwCh = 0;
869	WORD 	i;
870
871	pMeters->iNumBussesOut = (INT32) m_wNumBussesOut;
872	for (i = 0; i < m_wNumBussesOut; i++)
873	{
874		pMeters->iBusOutVU[i] =
875			DSP_TO_GENERIC( ((INT32) (INT8) m_pDspCommPage->VUMeter[ dwCh ]) );
876
877		pMeters->iBusOutPeak[i] =
878			DSP_TO_GENERIC( ((INT32) (INT8) m_pDspCommPage->PeakMeter[ dwCh ]) );
879
880		dwCh++;
881	}
882
883	pMeters->iNumBussesIn = (INT32) m_wNumBussesIn;
884	dwCh = E3G_MAX_OUTPUTS;
885	for (i = 0; i < m_wNumBussesIn; i++)
886	{
887		pMeters->iBusInVU[i] =
888			DSP_TO_GENERIC( ((INT32) (INT8) m_pDspCommPage->VUMeter[ dwCh ]) );
889		pMeters->iBusInPeak[i] =
890			DSP_TO_GENERIC( ((INT32) (INT8) m_pDspCommPage->PeakMeter[ dwCh ]) );
891
892		dwCh++;
893	}
894
895	return ECHOSTATUS_OK;
896
897} // GetAudioMeters
898
899
900
901//===========================================================================
902//
903// Utility function; returns TRUE if double speed mode is set
904//
905//===========================================================================
906
907BOOL C3gDco::DoubleSpeedMode(DWORD *pdwNewCtrlReg)
908{
909	DWORD dwControlReg;
910
911	if (NULL == pdwNewCtrlReg)
912		dwControlReg = GetControlRegister();
913	else
914		dwControlReg = *pdwNewCtrlReg;
915
916	if (0 != (dwControlReg & E3G_DOUBLE_SPEED_MODE))
917		return TRUE;
918
919	return FALSE;
920}
921
922
923//===========================================================================
924//
925// Utility function; validates a new control register value.  Prevents
926// speed change while transport is running
927//
928//===========================================================================
929
930ECHOSTATUS C3gDco::ValidateCtrlReg(DWORD dwNewControlReg)
931{
932	BOOL fCurrDoubleSpeed,fNewDoubleSpeed;
933
934	//
935	// Return OK if transport is off
936	//
937	if (m_cmActive.IsEmpty())
938		return ECHOSTATUS_OK;
939
940	//
941	// Get the new and current state of things
942	//
943	fNewDoubleSpeed = DoubleSpeedMode(&dwNewControlReg);
944	fCurrDoubleSpeed = DoubleSpeedMode(NULL);
945
946	//
947	// OK to change?
948	//
949	if (fCurrDoubleSpeed != fNewDoubleSpeed)
950	{
951		ECHO_DEBUGPRINTF(("Can't switch to speeds with transport active\n"));
952		return ECHOSTATUS_INVALID_CHANNEL;
953	}
954
955	return ECHOSTATUS_OK;
956}
957
958// **** C3gDco.cpp ****
959