xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/C3gDco.cpp (revision c2ddc71cc54397447f60bda00ea1ceca5c80bead)
1 // ****************************************************************************
2 //
3 //  	C3gDco.cpp
4 //
5 //		Implementation file for EchoGals generic driver 3G DSP
6 //		interface class.
7 //
8 // ----------------------------------------------------------------------------
9 //
10 //   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
11 //   All rights reserved
12 //   www.echoaudio.com
13 //
14 //   This file is part of Echo Digital Audio's generic driver library.
15 //
16 //   Echo Digital Audio's generic driver library is free software;
17 //   you can redistribute it and/or modify it under the terms of
18 //   the GNU General Public License as published by the Free Software Foundation.
19 //
20 //   This program 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
23 //   GNU General Public License for more details.
24 //
25 //   You should have received a copy of the GNU General Public License
26 //   along with this program; if not, write to the Free Software
27 //   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 //   MA  02111-1307, USA.
29 //
30 // ****************************************************************************
31 
32 #include "CEchoGals.h"
33 #include "C3gDco.h"
34 
35 #include "Echo3gDSP.c"
36 #include "Gina3gDSP.c"
37 #include "3G_ASIC.c"
38 
39 /****************************************************************************
40 
41 	Construction and destruction
42 
43  ****************************************************************************/
44 
45 //===========================================================================
46 //
47 // Constructor
48 //
49 //===========================================================================
50 
51 C3gDco::C3gDco
52 (
53 	PDWORD		pdwRegBase,				// Virtual ptr to DSP registers
54 	PCOsSupport	pOsSupport
55 ) : CDspCommObject( pdwRegBase, pOsSupport )
56 {
57 	m_pdwDspRegBase = pdwRegBase;		// Virtual addr DSP's register base  fixme put this in base class
58 
59 	m_dwOriginalBoxType = NO3GBOX;
60 	m_dwCurrentBoxType = m_dwOriginalBoxType;
61 	SetChannelCounts();
62 	m_bBoxTypeSet = FALSE;
63 
64 	m_fHasVmixer = FALSE;
65 
66 	m_wNumMidiOut = 1;					// # MIDI out channels
67 	m_wNumMidiIn = 1;						// # MIDI in  channels
68 
69 	m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
70 	m_pDspCommPage->dw3gFreqReg = SWAP( (DWORD) (E3G_MAGIC_NUMBER / 48000) - 2);
71 
72 	m_bHasASIC = TRUE;
73 
74 	m_pwDspCodeToLoad = pwEcho3gDSP;
75 
76 	m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA;
77 
78 	m_bProfessionalSpdif = FALSE;
79 	m_bNonAudio = FALSE;
80 
81 }	// C3gDco::C3gDco( DWORD dwPhysRegBase )
82 
83 
84 
85 //===========================================================================
86 //
87 // Destructor
88 //
89 //===========================================================================
90 
91 C3gDco::~C3gDco()
92 {
93 }	// C3gDco::~C3gDco()
94 
95 
96 
97 //===========================================================================
98 //
99 // Supported digital modes depend on what kind of box you have
100 //
101 //===========================================================================
102 
103 DWORD C3gDco::GetDigitalModes()
104 {
105 	DWORD dwModes;
106 
107 	dwModes =	ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
108 					ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
109 					ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
110 
111 	return dwModes;
112 }
113 
114 
115 /****************************************************************************
116 
117 	Hardware setup and config
118 
119  ****************************************************************************/
120 
121 //===========================================================================
122 //
123 // 3G has an ASIC in the external box
124 //
125 //===========================================================================
126 
127 BOOL C3gDco::LoadASIC()
128 {
129 	DWORD	dwControlReg;
130 
131 	if ( m_bASICLoaded == TRUE )
132 		return TRUE;
133 
134 	ECHO_DEBUGPRINTF(("C3gDco::LoadASIC\n"));
135 
136 	//
137 	// Give the DSP a few milliseconds to settle down
138 	//
139 	m_pOsSupport->OsSnooze( 2000 );
140 
141 	//
142 	// Load the ASIC
143 	//
144 	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_3G_ASIC,
145 											  pb3g_asic,
146 											  sizeof(pb3g_asic) ) )
147 		return FALSE;
148 
149 	//
150 	// Give the ASIC a few milliseconds to set up
151 	//
152 	m_pOsSupport->OsSnooze( 2000 );
153 
154 	//
155 	// See if it worked
156 	//
157 	CheckAsicStatus();
158 
159 	//
160 	// Set up the control register if the load succeeded -
161 	//
162 	// 48 kHz, internal clock, S/PDIF RCA mode
163 	//
164 	if ( m_bASICLoaded )
165 	{
166 		dwControlReg = E3G_48KHZ;
167 		WriteControlReg( dwControlReg, E3G_FREQ_REG_DEFAULT, TRUE);	// TRUE == force write
168 	}
169 
170 	ECHO_DEBUGPRINTF(("\t3G ASIC loader finished\n"));
171 
172 	return m_bASICLoaded;
173 
174 }	// BOOL C3gDco::LoadASIC()
175 
176 
177 
178 //===========================================================================
179 //
180 //	Set the input clock
181 //
182 //===========================================================================
183 
184 ECHOSTATUS C3gDco::SetInputClock(WORD wClock)
185 {
186 	DWORD dwControlReg,dwSampleRate;
187 
188 	ECHO_DEBUGPRINTF( ("C3gDco::SetInputClock:\n") );
189 
190 	//
191 	// Mask off the clock select bits
192 	//
193 	dwControlReg = GetControlRegister();
194 	dwControlReg &= E3G_CLOCK_CLEAR_MASK;
195 
196 	//
197 	// New clock
198 	//
199 	switch (wClock)
200 	{
201 		case ECHO_CLOCK_INTERNAL :
202 			ECHO_DEBUGPRINTF(("\tsetting internal clock\n"));
203 
204 			m_wInputClock = ECHO_CLOCK_INTERNAL;	// prevent recursion
205 
206 			dwSampleRate = GetSampleRate();
207 			if ((dwSampleRate < 32000) || (dwSampleRate > 100000))
208 				dwSampleRate = 48000;
209 
210 			SetSampleRate(dwSampleRate);
211 			return ECHOSTATUS_OK;
212 
213 
214 		case ECHO_CLOCK_WORD:
215 			dwControlReg |= E3G_WORD_CLOCK;
216 
217 			if ( E3G_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() )
218 			{
219 				dwControlReg |= E3G_DOUBLE_SPEED_MODE;
220 			}
221 			else
222 			{
223 				dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
224 			}
225 			ECHO_DEBUGPRINTF( ( "\tSet 3G clock to WORD\n" ) );
226 			break;
227 
228 
229 		case ECHO_CLOCK_SPDIF :
230 			if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
231 			{
232 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
233 			}
234 
235 			dwControlReg |= E3G_SPDIF_CLOCK;
236 			if ( E3G_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() )
237 			{
238 				dwControlReg |= E3G_DOUBLE_SPEED_MODE;
239 			}
240 			else
241 			{
242 				dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
243 			}
244 
245 			ECHO_DEBUGPRINTF( ( "\tSet 3G clock to SPDIF\n" ) );
246 			break;
247 
248 
249 		case ECHO_CLOCK_ADAT :
250 			if ( DIGITAL_MODE_ADAT != GetDigitalMode() )
251 			{
252 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
253 			}
254 
255 			dwControlReg |= E3G_ADAT_CLOCK;
256 			dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
257 			ECHO_DEBUGPRINTF( ( "\tSet 3G clock to ADAT\n" ) );
258 			break;
259 
260 
261 		default :
262 			ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for 3G\n",wClock));
263 			ECHO_DEBUGBREAK();
264 				return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
265 	}
266 
267 	//
268 	// Winner! Set the new input clock.
269 	//
270 	m_wInputClock = wClock;
271 	WriteControlReg( dwControlReg, Get3gFreqReg(), TRUE );
272 
273 	return ECHOSTATUS_OK;
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 	//
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 	//
358 	// Set up the frequency reg
359 	//
360 	dwBaseRate = dwNewSampleRate;
361 	if (dwBaseRate > 50000)
362 		dwBaseRate /= 2;
363 
364 	if (dwBaseRate < 32000)
365 		dwBaseRate = 32000;
366 
367 	dwFreqReg = E3G_MAGIC_NUMBER / dwBaseRate - 2;
368 	if (dwFreqReg > E3G_FREQ_REG_MAX)
369 		dwFreqReg = E3G_FREQ_REG_MAX;
370 
371 	//
372 	// Tell the DSP about it - DSP reads both control reg & freq reg
373 	//
374 	if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg, dwFreqReg) )
375 	{
376 		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
377 
378 		ECHO_DEBUGPRINTF( ("C3gDco::SetSampleRate: %ld  clock %lx\n", dwNewSampleRate, dwControlReg) );
379 	}
380 
381 	return dwNewSampleRate;
382 
383 } // DWORD C3gDco::SetSampleRate( DWORD dwNewSampleRate )
384 
385 
386 
387 //===========================================================================
388 //
389 // SetDigitalMode
390 //
391 //===========================================================================
392 
393 ECHOSTATUS C3gDco::SetDigitalMode
394 (
395 	BYTE	byNewMode
396 )
397 {
398 	DWORD		dwControlReg;
399 	WORD		wInvalidClock;
400 
401 	//
402 	// See if the current input clock doesn't match the new digital mode
403 	//
404 	switch (byNewMode)
405 	{
406 		case DIGITAL_MODE_SPDIF_RCA :
407 		case DIGITAL_MODE_SPDIF_OPTICAL :
408 			wInvalidClock = ECHO_CLOCK_ADAT;
409 			break;
410 
411 		case DIGITAL_MODE_ADAT :
412 			wInvalidClock = ECHO_CLOCK_SPDIF;
413 			break;
414 
415 		default :
416 			wInvalidClock = 0xffff;
417 			break;
418 	}
419 
420 	if (wInvalidClock == GetInputClock())
421 	{
422 		SetInputClock( ECHO_CLOCK_INTERNAL );
423 		SetSampleRate( 48000 );
424 	}
425 
426 
427 	//
428 	// Clear the current digital mode
429 	//
430 	dwControlReg = GetControlRegister();
431 	dwControlReg &= E3G_DIGITAL_MODE_CLEAR_MASK;
432 
433 	//
434 	// Tweak the control reg
435 	//
436 	switch ( byNewMode )
437 	{
438 		default :
439 			return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED;
440 
441 		case DIGITAL_MODE_SPDIF_OPTICAL :
442 			dwControlReg |= E3G_SPDIF_OPTICAL_MODE;
443 			// fall through
444 
445 		case DIGITAL_MODE_SPDIF_RCA :
446 			break;
447 
448 		case DIGITAL_MODE_ADAT :
449 			dwControlReg |= E3G_ADAT_MODE;
450 			dwControlReg &= ~E3G_DOUBLE_SPEED_MODE;
451 			break;
452 	}
453 
454 	//
455 	// Write the control reg
456 	//
457 	WriteControlReg( dwControlReg, Get3gFreqReg(), TRUE );
458 
459 	m_byDigitalMode = byNewMode;
460 
461 	ECHO_DEBUGPRINTF( ("C3gDco::SetDigitalMode to %ld\n",
462 							(DWORD) m_byDigitalMode) );
463 
464 	return ECHOSTATUS_OK;
465 
466 }	// ECHOSTATUS C3gDco::SetDigitalMode
467 
468 
469 
470 //===========================================================================
471 //
472 // WriteControlReg
473 //
474 //===========================================================================
475 
476 ECHOSTATUS C3gDco::WriteControlReg
477 (
478 	DWORD dwControlReg,
479 	DWORD	dwFreqReg,
480 	BOOL 	fForceWrite
481 )
482 {
483 	ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg 0x%lx 0x%lx\n",dwControlReg,dwFreqReg));
484 
485 	//
486 	// Ready to go?
487 	//
488 	if ( !m_bASICLoaded )
489 	{
490 		ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg - ASIC not loaded\n"));
491 		return( ECHOSTATUS_ASIC_NOT_LOADED );
492 	}
493 
494 	if ( !WaitForHandshake() )
495 	{
496 		ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg - no handshake\n"));
497 		return ECHOSTATUS_DSP_DEAD;
498 	}
499 
500 	//
501 	// Write the control register
502 	//
503 	if (	fForceWrite ||
504 			(dwControlReg != GetControlRegister()) ||
505 			(dwFreqReg != Get3gFreqReg())
506 		)
507 	{
508 		m_pDspCommPage->dw3gFreqReg = SWAP( dwFreqReg );
509 		SetControlRegister( dwControlReg );
510 
511 		ECHO_DEBUGPRINTF( ("C3gDco::WriteControlReg: Setting 0x%lx, 0x%lx\n",
512 								 dwControlReg,dwFreqReg) );
513 
514 		ClearHandshake();
515 		return SendVector( DSP_VC_WRITE_CONTROL_REG );
516 	}
517 	else
518 	{
519 		ECHO_DEBUGPRINTF( ("C3gDco::WriteControlReg: not written, no change\n") );
520 	}
521 
522 	return ECHOSTATUS_OK;
523 
524 } // ECHOSTATUS C3gDco::WriteControlReg
525 
526 
527 //===========================================================================
528 //
529 // SetSpdifBits
530 //
531 //===========================================================================
532 
533 void C3gDco::SetSpdifBits(DWORD *pdwCtrlReg,DWORD dwSampleRate)
534 {
535 	DWORD dwCtrlReg;
536 
537 	dwCtrlReg = *pdwCtrlReg;
538 
539 	//
540 	// Clean out the old status bits
541 	//
542 	dwCtrlReg &= E3G_SPDIF_FORMAT_CLEAR_MASK;
543 
544 	//
545 	// Sample rate
546 	//
547 	switch (dwSampleRate)
548 	{
549 		case 32000 :
550 			dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE0 |
551 							 E3G_SPDIF_SAMPLE_RATE1;
552 			break;
553 
554 		case 44100 :
555 			if (m_bProfessionalSpdif)
556 				dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE0;
557 			break;
558 
559 		case 48000 :
560 			dwCtrlReg |= E3G_SPDIF_SAMPLE_RATE1;
561 			break;
562 	}
563 
564 	//
565 	// Professional mode?
566 	//
567 	if (m_bProfessionalSpdif)
568 		dwCtrlReg |= E3G_SPDIF_PRO_MODE;
569 
570 	//
571 	// Non-audio data?
572 	//
573 	if (m_bNonAudio)
574 		dwCtrlReg |= E3G_SPDIF_NOT_AUDIO;
575 
576 	//
577 	// Always stereo, 24 bit, copy permit
578 	//
579 	dwCtrlReg |= E3G_SPDIF_24_BIT | E3G_SPDIF_TWO_CHANNEL | E3G_SPDIF_COPY_PERMIT;
580 
581 	*pdwCtrlReg = dwCtrlReg;
582 
583 } // SetSpdifBits
584 
585 
586 //===========================================================================
587 //
588 // SetSpdifOutNonAudio
589 //
590 // Set the state of the non-audio status bit in the S/PDIF out status bits
591 //
592 //===========================================================================
593 
594 void C3gDco::SetSpdifOutNonAudio(BOOL bNonAudio)
595 {
596 	DWORD		dwControlReg;
597 
598 	m_bNonAudio = bNonAudio;
599 
600 	dwControlReg = GetControlRegister();
601 	SetSpdifBits( &dwControlReg, SWAP(	m_pDspCommPage->dwSampleRate ));
602 	WriteControlReg( dwControlReg, Get3gFreqReg() );
603 }
604 
605 
606 //===========================================================================
607 //
608 // Set the S/PDIF output format
609 //
610 //===========================================================================
611 
612 void C3gDco::SetProfessionalSpdif
613 (
614 	BOOL bNewStatus
615 )
616 {
617 	DWORD		dwControlReg;
618 
619 	m_bProfessionalSpdif = bNewStatus;
620 
621 	dwControlReg = GetControlRegister();
622 	SetSpdifBits( &dwControlReg, SWAP(	m_pDspCommPage->dwSampleRate ));
623 	WriteControlReg( dwControlReg, Get3gFreqReg() );
624 
625 }	// void C3gDco::SetProfessionalSpdif( ... )
626 
627 
628 //===========================================================================
629 //
630 // ASIC status check
631 //
632 // 3G ASIC status check returns different values depending on what kind of box
633 // is hooked up
634 //
635 //===========================================================================
636 
637 BOOL C3gDco::CheckAsicStatus()
638 {
639 	DWORD	dwBoxStatus,dwBoxType;
640 
641 	m_bReloadFirmware = FALSE;
642 
643 	if ( !WaitForHandshake() )
644 		return FALSE;
645 
646 	//
647 	// Send the vector command
648 	//
649 	m_pDspCommPage->dwExtBoxStatus = SWAP( (DWORD) E3G_ASIC_NOT_LOADED);
650 	m_bASICLoaded = FALSE;
651 	ClearHandshake();
652 	SendVector( DSP_VC_TEST_ASIC );
653 
654 	//
655 	// Wait for return from DSP
656 	//
657 	if ( !WaitForHandshake() )
658 	{
659 		m_pwDspCode = NULL;
660 		m_ullLastLoadAttemptTime = 0;	// so LoadFirmware will try again right away
661 		return FALSE;
662 	}
663 
664 	//
665 	// What box type was set?
666 	//
667 	dwBoxStatus = SWAP(m_pDspCommPage->dwExtBoxStatus);
668 	if (E3G_ASIC_NOT_LOADED == dwBoxStatus)
669 		dwBoxType = NO3GBOX;
670 	else
671 		dwBoxType = dwBoxStatus & E3G_BOX_TYPE_MASK;
672 
673 	m_dwCurrentBoxType = dwBoxType;
674 
675 	//
676 	// Has the box type already been set?
677 	//
678 	if (m_bBoxTypeSet)
679 	{
680 		//
681 		// Did the ASIC load?
682 		// Was the box type correct?
683 		//
684 		if (	(NO3GBOX == dwBoxType) ||
685 				(dwBoxType != m_dwOriginalBoxType) )
686 		{
687 			//GoComatose();
688 			return FALSE;
689 		}
690 
691 		m_bASICLoaded = TRUE;
692 		return TRUE;
693 	}
694 
695 	//
696 	// First ASIC load - determine the box type and set up for that kind of box
697 	//
698 	m_dwOriginalBoxType = dwBoxType;
699 	m_bBoxTypeSet = TRUE;
700 
701 	SetChannelCounts();
702 
703 	//
704 	// Set the bad board flag if no external box
705 	//
706 	if (NO3GBOX == dwBoxType)
707 		m_bBadBoard = TRUE;
708 
709 	//
710 	// OK if correct DSP code is loaded for this box type
711 	//
712 	if (m_pwDspCode == m_pwDspCodeToLoad)
713 	{
714 		m_bASICLoaded = TRUE;
715 	}
716 	else
717 	{
718 		m_pwDspCode = NULL;
719 		m_ullLastLoadAttemptTime = 0;	// so LoadFirmware will try again right away
720 		m_bReloadFirmware = TRUE;
721 	}
722 
723 	return m_bASICLoaded;
724 
725 }	// BOOL C3gDco::CheckAsicStatus()
726 
727 
728 //===========================================================================
729 //
730 // SetPhantomPower
731 //
732 //===========================================================================
733 
734 void C3gDco::SetPhantomPower(BOOL fPhantom)
735 {
736 	DWORD		dwControlReg;
737 
738 	dwControlReg = GetControlRegister();
739 	if (fPhantom)
740 	{
741 		dwControlReg |= E3G_PHANTOM_POWER;
742 	}
743 	else
744 	{
745 		dwControlReg &= ~E3G_PHANTOM_POWER;
746 	}
747 
748 	WriteControlReg( dwControlReg, Get3gFreqReg() );
749 }
750 
751 
752 //===========================================================================
753 //
754 // Set channel counts for the current box type
755 //
756 //===========================================================================
757 
758 void C3gDco::SetChannelCounts()
759 {
760 	char *pszName;
761 
762 	switch (m_dwOriginalBoxType)
763 	{
764 		case GINA3G :
765 			m_wNumPipesOut = 14;
766 			m_wNumPipesIn = 10;
767 			m_wFirstDigitalBusOut = 6;
768 			m_wFirstDigitalBusIn = 2;
769 
770 			pszName = "Gina3G";
771 
772 			m_pwDspCodeToLoad = pwGina3gDSP;
773 			break;
774 
775 
776 		case NO3GBOX :
777 		case LAYLA3G :
778 		default :
779 			m_wNumPipesOut = 16;
780 			m_wNumPipesIn = 16;
781 			m_wFirstDigitalBusOut = 8;
782 			m_wFirstDigitalBusIn = 8;
783 
784 			pszName = "Layla3G";
785 
786 			m_pwDspCodeToLoad = pwEcho3gDSP;
787 			break;
788 	}
789 
790 	m_wNumBussesOut = m_wNumPipesOut;
791 	m_wNumBussesIn = m_wNumPipesIn;
792 	strcpy( m_szCardName, pszName);
793 }
794 
795 
796 //===========================================================================
797 //
798 // Override LoadFirmware to try again in case the box type doesn't match
799 //
800 //===========================================================================
801 
802 ECHOSTATUS C3gDco::LoadFirmware()
803 {
804 	ECHOSTATUS status;
805 
806 	m_bReloadFirmware = FALSE;
807 	do
808 	{
809 		status = CDspCommObject::LoadFirmware();
810 	} while ( m_bReloadFirmware );
811 
812 	return status;
813 
814 } // LoadFirmware
815 
816 
817 //===========================================================================
818 //
819 // Return the 3G box type
820 //
821 //===========================================================================
822 
823 void C3gDco::Get3gBoxType(DWORD *pOriginalBoxType,DWORD *pCurrentBoxType)
824 {
825 	if (NULL != pOriginalBoxType)
826 		*pOriginalBoxType = m_dwOriginalBoxType;
827 
828 	if (NULL != pCurrentBoxType)
829 	{
830 		CheckAsicStatus();
831 
832 		*pCurrentBoxType = m_dwCurrentBoxType;
833 	}
834 
835 } // Get3gBoxType
836 
837 
838 // **** C3gDco.cpp ****
839