xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/C3gDco.cpp (revision be188ae133da3258026dc1f9c1330f0d27e53494)
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 
49 C3gDco::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 
89 C3gDco::~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 
101 DWORD 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 
125 BOOL 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 few milliseconds to set up
149 	//
150 	m_pOsSupport->OsSnooze( 2000 );
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 
182 ECHOSTATUS 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 // fixme - it's pointless to return the sample rate back?
286 //
287 //===========================================================================
288 
289 DWORD C3gDco::SetSampleRate( DWORD dwNewSampleRate )
290 {
291 	DWORD dwControlReg,dwNewClock,dwBaseRate,dwFreqReg;
292 
293 	ECHO_DEBUGPRINTF(("3G set sample rate to %ld\n",dwNewSampleRate));
294 
295 	//
296 	// Only set the clock for internal mode.  If the clock is not set to
297 	// internal, try and re-set the input clock; this more transparently
298 	// handles switching between single and double-speed mode
299 	//
300 	if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
301 	{
302 		ECHO_DEBUGPRINTF( ( "C3gDco::SetSampleRate: Cannot set sample rate - "
303 								  "clock not set to ECHO_CLOCK_INTERNAL\n" ) );
304 
305 		//
306 		// Save the rate anyhow
307 		//
308 		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
309 
310 		//
311 		// Set the input clock to the current value
312 		//
313 		SetInputClock( m_wInputClock );
314 
315 		return dwNewSampleRate;
316 	}
317 
318 	//
319 	// Get the control register & clear the appropriate bits
320 	//
321 	dwControlReg = GetControlRegister();
322 	dwControlReg &= E3G_CLOCK_CLEAR_MASK;
323 
324 	//
325 	// Set the sample rate
326 	//
327 	switch ( dwNewSampleRate )
328 	{
329 		case 96000 :
330 			dwNewClock = E3G_96KHZ;
331 			break;
332 
333 		case 88200 :
334 			dwNewClock = E3G_88KHZ;
335 			break;
336 
337 		case 48000 :
338 			dwNewClock = E3G_48KHZ;
339 			break;
340 
341 		case 44100 :
342 			dwNewClock = E3G_44KHZ;
343 			break;
344 
345 		case 32000 :
346 			dwNewClock = E3G_32KHZ;
347 			break;
348 
349 		default :
350 			dwNewClock = E3G_CONTINUOUS_CLOCK;
351 			if (dwNewSampleRate > 50000)
352 				dwNewClock |= E3G_DOUBLE_SPEED_MODE;
353 			break;
354 	}
355 
356 	dwControlReg |= dwNewClock;
357 	SetSpdifBits(&dwControlReg,dwNewSampleRate);
358 
359 	ECHO_DEBUGPRINTF(("\tdwNewClock 0x%lx  dwControlReg 0x%lx\n",dwNewClock,dwControlReg));
360 
361 	//
362 	// Set up the frequency reg
363 	//
364 	dwBaseRate = dwNewSampleRate;
365 	if (dwBaseRate > 50000)
366 		dwBaseRate /= 2;
367 
368 	if (dwBaseRate < 32000)
369 		dwBaseRate = 32000;
370 
371 	dwFreqReg = E3G_MAGIC_NUMBER / dwBaseRate - 2;
372 	if (dwFreqReg > E3G_FREQ_REG_MAX)
373 		dwFreqReg = E3G_FREQ_REG_MAX;
374 
375 	//
376 	// Tell the DSP about it - DSP reads both control reg & freq reg
377 	//
378 	if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg, dwFreqReg) )
379 	{
380 		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
381 
382 		ECHO_DEBUGPRINTF( ("C3gDco::SetSampleRate: %ld  clock %lx\n", dwNewSampleRate, dwControlReg) );
383 	}
384 
385 	return dwNewSampleRate;
386 
387 } // DWORD C3gDco::SetSampleRate( DWORD dwNewSampleRate )
388 
389 
390 
391 //===========================================================================
392 //
393 // SetDigitalMode
394 //
395 //===========================================================================
396 
397 ECHOSTATUS C3gDco::SetDigitalMode
398 (
399 	BYTE	byNewMode
400 )
401 {
402 	DWORD		dwControlReg;
403 	WORD		wInvalidClock;
404 
405 	//
406 	// See if the current input clock doesn't match the new digital mode
407 	//
408 	switch (byNewMode)
409 	{
410 		case DIGITAL_MODE_SPDIF_RCA :
411 		case DIGITAL_MODE_SPDIF_OPTICAL :
412 			wInvalidClock = ECHO_CLOCK_ADAT;
413 			break;
414 
415 		case DIGITAL_MODE_ADAT :
416 			wInvalidClock = ECHO_CLOCK_SPDIF;
417 			break;
418 
419 		default :
420 			wInvalidClock = 0xffff;
421 			break;
422 	}
423 
424 	if (wInvalidClock == GetInputClock())
425 	{
426 		SetInputClock( ECHO_CLOCK_INTERNAL );
427 		SetSampleRate( 48000 );
428 	}
429 
430 
431 	//
432 	// Clear the current digital mode
433 	//
434 	dwControlReg = GetControlRegister();
435 	dwControlReg &= E3G_DIGITAL_MODE_CLEAR_MASK;
436 
437 	//
438 	// Tweak the control reg
439 	//
440 	switch ( byNewMode )
441 	{
442 		default :
443 			return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED;
444 
445 		case DIGITAL_MODE_SPDIF_OPTICAL :
446 			dwControlReg |= E3G_SPDIF_OPTICAL_MODE;
447 			// fall through
448 
449 		case DIGITAL_MODE_SPDIF_RCA :
450 			break;
451 
452 		case DIGITAL_MODE_ADAT :
453 			dwControlReg |= E3G_ADAT_MODE;
454 			dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
455 			break;
456 	}
457 
458 	//
459 	// Write the control reg
460 	//
461 	WriteControlReg( dwControlReg, Get3gFreqReg(), TRUE );
462 
463 	m_byDigitalMode = byNewMode;
464 
465 	ECHO_DEBUGPRINTF( ("C3gDco::SetDigitalMode to %ld\n",
466 							(DWORD) m_byDigitalMode) );
467 
468 	return ECHOSTATUS_OK;
469 
470 }	// ECHOSTATUS C3gDco::SetDigitalMode
471 
472 
473 
474 //===========================================================================
475 //
476 // WriteControlReg
477 //
478 //===========================================================================
479 
480 ECHOSTATUS C3gDco::WriteControlReg
481 (
482 	DWORD dwControlReg,
483 	DWORD	dwFreqReg,
484 	BOOL 	fForceWrite
485 )
486 {
487 	ECHOSTATUS Status;
488 
489 	ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg 0x%lx 0x%lx\n",dwControlReg,dwFreqReg));
490 
491 	//
492 	// New value OK?
493 	//
494 	Status = ValidateCtrlReg(dwControlReg);
495 	if (ECHOSTATUS_OK != Status)
496 		return Status;
497 
498 	//
499 	// Ready to go?
500 	//
501 	if ( !m_bASICLoaded )
502 	{
503 		ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg - ASIC not loaded\n"));
504 		return( ECHOSTATUS_ASIC_NOT_LOADED );
505 	}
506 
507 	if ( !WaitForHandshake() )
508 	{
509 		ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg - no handshake\n"));
510 		return ECHOSTATUS_DSP_DEAD;
511 	}
512 
513 	//
514 	// Write the control register
515 	//
516 	if (	fForceWrite ||
517 			(dwControlReg != GetControlRegister()) ||
518 			(dwFreqReg != Get3gFreqReg())
519 		)
520 	{
521 		m_pDspCommPage->dw3gFreqReg = SWAP( dwFreqReg );
522 		SetControlRegister( dwControlReg );
523 
524 		ECHO_DEBUGPRINTF( ("C3gDco::WriteControlReg: Setting 0x%lx, 0x%lx\n",
525 								 dwControlReg,dwFreqReg) );
526 
527 		ClearHandshake();
528 		return SendVector( DSP_VC_WRITE_CONTROL_REG );
529 	}
530 	else
531 	{
532 		ECHO_DEBUGPRINTF( ("C3gDco::WriteControlReg: not written, no change\n") );
533 	}
534 
535 	return ECHOSTATUS_OK;
536 
537 } // ECHOSTATUS C3gDco::WriteControlReg
538 
539 
540 //===========================================================================
541 //
542 // SetSpdifBits
543 //
544 //===========================================================================
545 
546 void C3gDco::SetSpdifBits(DWORD *pdwCtrlReg,DWORD dwSampleRate)
547 {
548 	DWORD dwCtrlReg;
549 
550 	dwCtrlReg = *pdwCtrlReg;
551 
552 	//
553 	// Clean out the old status bits
554 	//
555 	dwCtrlReg &= E3G_SPDIF_FORMAT_CLEAR_MASK;
556 
557 	//
558 	// Sample rate
559 	//
560 	switch (dwSampleRate)
561 	{
562 		case 32000 :
563 			dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE0 |
564 							 E3G_SPDIF_SAMPLE_RATE1;
565 			break;
566 
567 		case 44100 :
568 			if (m_bProfessionalSpdif)
569 				dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE0;
570 			break;
571 
572 		case 48000 :
573 			dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE1;
574 			break;
575 	}
576 
577 	//
578 	// Professional mode?
579 	//
580 	if (m_bProfessionalSpdif)
581 		dwCtrlReg |= E3G_SPDIF_PRO_MODE;
582 
583 	//
584 	// Non-audio data?
585 	//
586 	if (m_bNonAudio)
587 		dwCtrlReg |= E3G_SPDIF_NOT_AUDIO;
588 
589 	//
590 	// Always stereo, 24 bit, copy permit
591 	//
592 	dwCtrlReg |= E3G_SPDIF_24_BIT | E3G_SPDIF_TWO_CHANNEL | E3G_SPDIF_COPY_PERMIT;
593 
594 	*pdwCtrlReg = dwCtrlReg;
595 
596 } // SetSpdifBits
597 
598 
599 //===========================================================================
600 //
601 // SetSpdifOutNonAudio
602 //
603 // Set the state of the non-audio status bit in the S/PDIF out status bits
604 //
605 //===========================================================================
606 
607 void C3gDco::SetSpdifOutNonAudio(BOOL bNonAudio)
608 {
609 	DWORD		dwControlReg;
610 
611 	m_bNonAudio = bNonAudio;
612 
613 	dwControlReg = GetControlRegister();
614 	SetSpdifBits( &dwControlReg, SWAP(	m_pDspCommPage->dwSampleRate ));
615 	WriteControlReg( dwControlReg, Get3gFreqReg() );
616 }
617 
618 
619 //===========================================================================
620 //
621 // Set the S/PDIF output format
622 //
623 //===========================================================================
624 
625 void C3gDco::SetProfessionalSpdif
626 (
627 	BOOL bNewStatus
628 )
629 {
630 	DWORD		dwControlReg;
631 
632 	m_bProfessionalSpdif = bNewStatus;
633 
634 	dwControlReg = GetControlRegister();
635 	SetSpdifBits( &dwControlReg, SWAP(	m_pDspCommPage->dwSampleRate ));
636 	WriteControlReg( dwControlReg, Get3gFreqReg() );
637 
638 }	// void C3gDco::SetProfessionalSpdif( ... )
639 
640 
641 //===========================================================================
642 //
643 // ASIC status check
644 //
645 // 3G ASIC status check returns different values depending on what kind of box
646 // is hooked up
647 //
648 //===========================================================================
649 
650 BOOL C3gDco::CheckAsicStatus()
651 {
652 	DWORD	dwBoxStatus,dwBoxType;
653 
654 	if ( !WaitForHandshake() )
655 		return FALSE;
656 
657 	//
658 	// Send the vector command
659 	//
660 	m_pDspCommPage->dwExtBoxStatus = SWAP( (DWORD) E3G_ASIC_NOT_LOADED);
661 	m_bASICLoaded = FALSE;
662 	ClearHandshake();
663 	SendVector( DSP_VC_TEST_ASIC );
664 
665 	//
666 	// Wait for return from DSP
667 	//
668 	if ( !WaitForHandshake() )
669 	{
670 		m_pwDspCode = NULL;
671 		m_ullLastLoadAttemptTime = 0;	// so LoadFirmware will try again right away
672 		return FALSE;
673 	}
674 
675 	//
676 	// What box type was set?
677 	//
678 	dwBoxStatus = SWAP(m_pDspCommPage->dwExtBoxStatus);
679 	if (E3G_ASIC_NOT_LOADED == dwBoxStatus)
680 	{
681 		dwBoxType = NO3GBOX;
682 	}
683 	else
684 	{
685 		dwBoxType = dwBoxStatus & E3G_BOX_TYPE_MASK;
686 		m_bASICLoaded = TRUE;
687 	}
688 
689 	m_dwCurrentBoxType = dwBoxType;
690 
691 	//
692 	// Has the box type already been set?
693 	//
694 	if (m_bBoxTypeSet)
695 	{
696 		//
697 		// Did the ASIC load?
698 		// Was the box type correct?
699 		//
700 		if (	(NO3GBOX == dwBoxType) ||
701 				(dwBoxType != m_dwOriginalBoxType) )
702 		{
703 			//GoComatose();
704 			return FALSE;
705 		}
706 
707 		m_bASICLoaded = TRUE;
708 		return TRUE;
709 	}
710 
711 	//
712 	// First ASIC load - determine the box type and set up for that kind of box
713 	//
714 	m_dwOriginalBoxType = dwBoxType;
715 	m_bBoxTypeSet = TRUE;
716 
717 	SetChannelCounts();
718 
719 	//
720 	// Set the bad board flag if no external box
721 	//
722 	if (NO3GBOX == dwBoxType)
723 		m_bBadBoard = TRUE;
724 
725 	return m_bASICLoaded;
726 
727 }	// BOOL C3gDco::CheckAsicStatus()
728 
729 
730 //===========================================================================
731 //
732 // SetPhantomPower
733 //
734 //===========================================================================
735 
736 void C3gDco::SetPhantomPower(BOOL fPhantom)
737 {
738 	DWORD		dwControlReg;
739 
740 	dwControlReg = GetControlRegister();
741 	if (fPhantom)
742 	{
743 		dwControlReg |= E3G_PHANTOM_POWER;
744 	}
745 	else
746 	{
747 		dwControlReg &= ~E3G_PHANTOM_POWER;
748 	}
749 
750 	WriteControlReg( dwControlReg, Get3gFreqReg() );
751 }
752 
753 
754 //===========================================================================
755 //
756 // Set channel counts for the current box type
757 //
758 //===========================================================================
759 
760 void C3gDco::SetChannelCounts()
761 {
762 	char *pszName;
763 	WORD ch,i;
764 
765 	switch (m_dwOriginalBoxType)
766 	{
767 		case GINA3G :
768 			m_wNumPipesOut = 14;
769 			m_wNumPipesIn = 10;
770 			m_wFirstDigitalBusOut = 6;
771 			m_wFirstDigitalBusIn = 2;
772 
773 			pszName = "Gina3G";
774 			break;
775 
776 
777 		case NO3GBOX :
778 		case LAYLA3G :
779 		default :
780 			m_wNumPipesOut = 16;
781 			m_wNumPipesIn = 16;
782 			m_wFirstDigitalBusOut = 8;
783 			m_wFirstDigitalBusIn = 8;
784 
785 			pszName = "Layla3G";
786 			break;
787 	}
788 
789 	m_wNumBussesOut = m_wNumPipesOut;
790 	m_wNumBussesIn = m_wNumPipesIn;
791 	strcpy( m_szCardName, pszName);
792 
793 	//
794 	// Build a channel mask for ADAT inputs & outputs 3-8
795 	// OK to use bus # here since this hardware has no virtual outputs
796 	//
797 	m_Adat38Mask.Clear();
798 	ch = m_wFirstDigitalBusOut + 2;
799 	for (i = 0; i < 6; i++)
800 	{
801 		m_Adat38Mask.SetIndexInMask(ch);
802 		ch++;
803 	}
804 
805 	ch += m_wFirstDigitalBusIn + 2;
806 	for (i = 0; i < 6; i++)
807 	{
808 		m_Adat38Mask.SetIndexInMask(ch);
809 		ch++;
810 	}
811 }
812 
813 
814 //===========================================================================
815 //
816 // Return the 3G box type
817 //
818 //===========================================================================
819 
820 void C3gDco::Get3gBoxType(DWORD *pOriginalBoxType,DWORD *pCurrentBoxType)
821 {
822 	if (NULL != pOriginalBoxType)
823 		*pOriginalBoxType = m_dwOriginalBoxType;
824 
825 	if (NULL != pCurrentBoxType)
826 	{
827 		CheckAsicStatus();
828 
829 		*pCurrentBoxType = m_dwCurrentBoxType;
830 	}
831 
832 } // Get3gBoxType
833 
834 
835 
836 //===========================================================================
837 //
838 // Fill out an ECHOGALS_METERS struct using the current values in the
839 // comm page.  This method is overridden for vmixer cards.
840 //
841 //===========================================================================
842 
843 ECHOSTATUS C3gDco::GetAudioMeters
844 (
845 	PECHOGALS_METERS	pMeters
846 )
847 {
848 	pMeters->iNumPipesOut = 0;
849 	pMeters->iNumPipesIn = 0;
850 
851 	//
852 	//	Output
853 	//
854 	DWORD dwCh = 0;
855 	WORD 	i;
856 
857 	pMeters->iNumBussesOut = (INT32) m_wNumBussesOut;
858 	for (i = 0; i < m_wNumBussesOut; i++)
859 	{
860 		pMeters->iBusOutVU[i] =
861 			DSP_TO_GENERIC( ((INT32) (INT8) m_pDspCommPage->VUMeter[ dwCh ]) );
862 
863 		pMeters->iBusOutPeak[i] =
864 			DSP_TO_GENERIC( ((INT32) (INT8) m_pDspCommPage->PeakMeter[ dwCh ]) );
865 
866 		dwCh++;
867 	}
868 
869 	pMeters->iNumBussesIn = (INT32) m_wNumBussesIn;
870 	dwCh = E3G_MAX_OUTPUTS;
871 	for (i = 0; i < m_wNumBussesIn; i++)
872 	{
873 		pMeters->iBusInVU[i] =
874 			DSP_TO_GENERIC( ((INT32) (INT8) m_pDspCommPage->VUMeter[ dwCh ]) );
875 		pMeters->iBusInPeak[i] =
876 			DSP_TO_GENERIC( ((INT32) (INT8) m_pDspCommPage->PeakMeter[ dwCh ]) );
877 
878 		dwCh++;
879 	}
880 
881 	return ECHOSTATUS_OK;
882 
883 } // GetAudioMeters
884 
885 
886 
887 //===========================================================================
888 //
889 // Utility function; returns TRUE if double speed mode is set
890 //
891 //===========================================================================
892 
893 BOOL C3gDco::DoubleSpeedMode(DWORD *pdwNewCtrlReg)
894 {
895 	DWORD dwControlReg;
896 
897 	if (NULL == pdwNewCtrlReg)
898 		dwControlReg = GetControlRegister();
899 	else
900 		dwControlReg = *pdwNewCtrlReg;
901 
902 	if (0 != (dwControlReg & E3G_DOUBLE_SPEED_MODE))
903 		return TRUE;
904 
905 	return FALSE;
906 }
907 
908 
909 //===========================================================================
910 //
911 // Utility function; validates a new control register value.  Prevents
912 // speed change while transport is running
913 //
914 //===========================================================================
915 
916 ECHOSTATUS C3gDco::ValidateCtrlReg(DWORD dwNewControlReg)
917 {
918 	BOOL fCurrDoubleSpeed,fNewDoubleSpeed;
919 
920 	//
921 	// Return OK if transport is off
922 	//
923 	if (m_cmActive.IsEmpty())
924 		return ECHOSTATUS_OK;
925 
926 	//
927 	// Get the new and current state of things
928 	//
929 	fNewDoubleSpeed = DoubleSpeedMode(&dwNewControlReg);
930 	fCurrDoubleSpeed = DoubleSpeedMode(NULL);
931 
932 	//
933 	// OK to change?
934 	//
935 	if (fCurrDoubleSpeed != fNewDoubleSpeed)
936 	{
937 		ECHO_DEBUGPRINTF(("Can't switch to speeds with transport active\n"));
938 		return ECHOSTATUS_INVALID_CHANNEL;
939 	}
940 
941 	return ECHOSTATUS_OK;
942 }
943 
944 // **** C3gDco.cpp ****
945