1 // ****************************************************************************
5 // Implementation file for EchoGals generic driver 3G DSP
8 // ----------------------------------------------------------------------------
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
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.
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.
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
29 // ****************************************************************************
31 #include "CEchoGals.h"
34 #include "Echo3gDSP.c"
37 /****************************************************************************
39 Construction and destruction
41 ****************************************************************************/
43 //===========================================================================
47 //===========================================================================
51 PDWORD pdwRegBase
, // Virtual ptr to DSP registers
52 PCOsSupport pOsSupport
53 ) : CDspCommObject( pdwRegBase
, pOsSupport
)
55 m_pdwDspRegBase
= pdwRegBase
; // Virtual addr DSP's register base fixme put this in base class
57 m_dwOriginalBoxType
= NO3GBOX
;
58 m_dwCurrentBoxType
= m_dwOriginalBoxType
;
60 m_bBoxTypeSet
= FALSE
;
64 m_wNumMidiOut
= 1; // # MIDI out channels
65 m_wNumMidiIn
= 1; // # MIDI in channels
67 m_pDspCommPage
->dwSampleRate
= SWAP( (DWORD
) 48000 );
68 m_pDspCommPage
->dw3gFreqReg
= SWAP( (DWORD
) (E3G_MAGIC_NUMBER
/ 48000) - 2);
72 m_pwDspCodeToLoad
= pwEcho3gDSP
;
74 m_byDigitalMode
= DIGITAL_MODE_SPDIF_RCA
;
76 m_bProfessionalSpdif
= FALSE
;
79 } // C3gDco::C3gDco( DWORD dwPhysRegBase )
83 //===========================================================================
87 //===========================================================================
91 } // C3gDco::~C3gDco()
95 //===========================================================================
97 // Supported digital modes depend on what kind of box you have
99 //===========================================================================
101 DWORD
C3gDco::GetDigitalModes()
105 dwModes
= ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA
|
106 ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL
|
107 ECHOCAPS_HAS_DIGITAL_MODE_ADAT
;
113 /****************************************************************************
115 Hardware setup and config
117 ****************************************************************************/
119 //===========================================================================
121 // 3G has an ASIC in the external box
123 //===========================================================================
125 BOOL
C3gDco::LoadASIC()
129 if ( m_bASICLoaded
== TRUE
)
132 ECHO_DEBUGPRINTF(("C3gDco::LoadASIC\n"));
135 // Give the DSP a few milliseconds to settle down
137 m_pOsSupport
->OsSnooze( 2000 );
142 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_3G_ASIC
,
144 sizeof(pb3g_asic
) ) )
148 // Give the ASIC a whole second to set up
150 m_pOsSupport
->OsSnooze( 1000000 );
158 // Set up the control register if the load succeeded -
160 // 48 kHz, internal clock, S/PDIF RCA mode
164 dwControlReg
= E3G_48KHZ
;
165 WriteControlReg( dwControlReg
, E3G_FREQ_REG_DEFAULT
, TRUE
); // TRUE == force write
168 ECHO_DEBUGPRINTF(("\t3G ASIC loader finished\n"));
170 return m_bASICLoaded
;
172 } // BOOL C3gDco::LoadASIC()
176 //===========================================================================
178 // Set the input clock
180 //===========================================================================
182 ECHOSTATUS
C3gDco::SetInputClock(WORD wClock
)
184 DWORD dwControlReg
,dwSampleRate
;
187 ECHO_DEBUGPRINTF( ("C3gDco::SetInputClock:\n") );
190 // Mask off the clock select bits
192 dwControlReg
= GetControlRegister();
193 dwControlReg
&= E3G_CLOCK_CLEAR_MASK
;
200 case ECHO_CLOCK_INTERNAL
:
201 ECHO_DEBUGPRINTF(("\tsetting internal clock\n"));
203 m_wInputClock
= ECHO_CLOCK_INTERNAL
; // prevent recursion
205 dwSampleRate
= GetSampleRate();
206 if ((dwSampleRate
< 32000) || (dwSampleRate
> 100000))
207 dwSampleRate
= 48000;
209 SetSampleRate(dwSampleRate
);
210 return ECHOSTATUS_OK
;
213 case ECHO_CLOCK_WORD
:
214 dwControlReg
|= E3G_WORD_CLOCK
;
216 if ( E3G_CLOCK_DETECT_BIT_WORD96
& GetInputClockDetect() )
218 dwControlReg
|= E3G_DOUBLE_SPEED_MODE
;
222 dwControlReg
&= ~E3G_DOUBLE_SPEED_MODE
;
224 ECHO_DEBUGPRINTF( ( "\tSet 3G clock to WORD\n" ) );
228 case ECHO_CLOCK_SPDIF
:
229 if ( DIGITAL_MODE_ADAT
== GetDigitalMode() )
231 return ECHOSTATUS_CLOCK_NOT_AVAILABLE
;
234 dwControlReg
|= E3G_SPDIF_CLOCK
;
235 if ( E3G_CLOCK_DETECT_BIT_SPDIF96
& GetInputClockDetect() )
237 dwControlReg
|= E3G_DOUBLE_SPEED_MODE
;
241 dwControlReg
&= ~E3G_DOUBLE_SPEED_MODE
;
244 ECHO_DEBUGPRINTF( ( "\tSet 3G clock to SPDIF\n" ) );
248 case ECHO_CLOCK_ADAT
:
249 if ( DIGITAL_MODE_ADAT
!= GetDigitalMode() )
251 return ECHOSTATUS_CLOCK_NOT_AVAILABLE
;
254 dwControlReg
|= E3G_ADAT_CLOCK
;
255 dwControlReg
&= ~E3G_DOUBLE_SPEED_MODE
;
256 ECHO_DEBUGPRINTF( ( "\tSet 3G clock to ADAT\n" ) );
261 ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for 3G\n",wClock
));
263 return ECHOSTATUS_CLOCK_NOT_SUPPORTED
;
267 // Winner! Try to write the hardware
269 Status
= WriteControlReg( dwControlReg
, Get3gFreqReg(), TRUE
);
270 if (ECHOSTATUS_OK
== Status
)
271 m_wInputClock
= wClock
;
275 } // ECHOSTATUS C3gDco::SetInputClock
279 //===========================================================================
283 // Set the audio sample rate for 3G
285 //===========================================================================
287 DWORD
C3gDco::SetSampleRate( DWORD dwNewSampleRate
)
289 DWORD dwControlReg
,dwNewClock
,dwBaseRate
,dwFreqReg
;
291 ECHO_DEBUGPRINTF(("3G set sample rate to %ld\n",dwNewSampleRate
));
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
298 if ( GetInputClock() != ECHO_CLOCK_INTERNAL
)
300 ECHO_DEBUGPRINTF( ( "C3gDco::SetSampleRate: Cannot set sample rate - "
301 "clock not set to ECHO_CLOCK_INTERNAL\n" ) );
304 // Save the rate anyhow
306 m_pDspCommPage
->dwSampleRate
= SWAP( dwNewSampleRate
);
309 // Set the input clock to the current value
311 SetInputClock( m_wInputClock
);
313 return dwNewSampleRate
;
317 // Get the control register & clear the appropriate bits
319 dwControlReg
= GetControlRegister();
320 dwControlReg
&= E3G_CLOCK_CLEAR_MASK
;
323 // Set the sample rate
325 switch ( dwNewSampleRate
)
328 dwNewClock
= E3G_96KHZ
;
332 dwNewClock
= E3G_88KHZ
;
336 dwNewClock
= E3G_48KHZ
;
340 dwNewClock
= E3G_44KHZ
;
344 dwNewClock
= E3G_32KHZ
;
348 dwNewClock
= E3G_CONTINUOUS_CLOCK
;
349 if (dwNewSampleRate
> 50000)
350 dwNewClock
|= E3G_DOUBLE_SPEED_MODE
;
354 dwControlReg
|= dwNewClock
;
355 SetSpdifBits(&dwControlReg
,dwNewSampleRate
);
357 ECHO_DEBUGPRINTF(("\tdwNewClock 0x%lx dwControlReg 0x%lx\n",dwNewClock
,dwControlReg
));
360 // Set up the frequency reg
362 dwBaseRate
= dwNewSampleRate
;
363 if (dwBaseRate
> 50000)
366 if (dwBaseRate
< 32000)
369 dwFreqReg
= E3G_MAGIC_NUMBER
/ dwBaseRate
- 2;
370 if (dwFreqReg
> E3G_FREQ_REG_MAX
)
371 dwFreqReg
= E3G_FREQ_REG_MAX
;
374 // Tell the DSP about it - DSP reads both control reg & freq reg
376 if ( ECHOSTATUS_OK
== WriteControlReg( dwControlReg
, dwFreqReg
) )
378 m_pDspCommPage
->dwSampleRate
= SWAP( dwNewSampleRate
);
380 ECHO_DEBUGPRINTF( ("C3gDco::SetSampleRate: %ld clock %lx\n", dwNewSampleRate
, dwControlReg
) );
384 ECHO_DEBUGPRINTF( ("C3gDco::SetSampleRate: could not set sample rate %ld\n", dwNewSampleRate
) );
386 dwNewSampleRate
= SWAP( m_pDspCommPage
->dwSampleRate
);
389 return dwNewSampleRate
;
391 } // DWORD C3gDco::SetSampleRate( DWORD dwNewSampleRate )
395 //===========================================================================
399 //===========================================================================
401 ECHOSTATUS
C3gDco::SetDigitalMode
410 // See if the current input clock doesn't match the new digital mode
414 case DIGITAL_MODE_SPDIF_RCA
:
415 case DIGITAL_MODE_SPDIF_OPTICAL
:
416 wInvalidClock
= ECHO_CLOCK_ADAT
;
419 case DIGITAL_MODE_ADAT
:
420 wInvalidClock
= ECHO_CLOCK_SPDIF
;
424 wInvalidClock
= 0xffff;
428 if (wInvalidClock
== GetInputClock())
430 SetInputClock( ECHO_CLOCK_INTERNAL
);
431 SetSampleRate( 48000 );
436 // Clear the current digital mode
438 dwControlReg
= GetControlRegister();
439 dwControlReg
&= E3G_DIGITAL_MODE_CLEAR_MASK
;
442 // Tweak the control reg
447 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED
;
449 case DIGITAL_MODE_SPDIF_OPTICAL
:
450 dwControlReg
|= E3G_SPDIF_OPTICAL_MODE
;
453 case DIGITAL_MODE_SPDIF_RCA
:
456 case DIGITAL_MODE_ADAT
:
457 dwControlReg
|= E3G_ADAT_MODE
;
458 dwControlReg
&= ~E3G_DOUBLE_SPEED_MODE
;
463 // Write the control reg
465 WriteControlReg( dwControlReg
, Get3gFreqReg(), TRUE
);
467 m_byDigitalMode
= byNewMode
;
469 ECHO_DEBUGPRINTF( ("C3gDco::SetDigitalMode to %ld\n",
470 (DWORD
) m_byDigitalMode
) );
472 return ECHOSTATUS_OK
;
474 } // ECHOSTATUS C3gDco::SetDigitalMode
478 //===========================================================================
482 //===========================================================================
484 ECHOSTATUS
C3gDco::WriteControlReg
493 ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg 0x%lx 0x%lx\n",dwControlReg
,dwFreqReg
));
498 Status
= ValidateCtrlReg(dwControlReg
);
499 if (ECHOSTATUS_OK
!= Status
)
505 if ( !m_bASICLoaded
)
507 ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg - ASIC not loaded\n"));
508 return( ECHOSTATUS_ASIC_NOT_LOADED
);
511 if ( !WaitForHandshake() )
513 ECHO_DEBUGPRINTF(("C3gDco::WriteControlReg - no handshake\n"));
514 return ECHOSTATUS_DSP_DEAD
;
518 // Write the control register
521 (dwControlReg
!= GetControlRegister()) ||
522 (dwFreqReg
!= Get3gFreqReg())
525 m_pDspCommPage
->dw3gFreqReg
= SWAP( dwFreqReg
);
526 SetControlRegister( dwControlReg
);
528 ECHO_DEBUGPRINTF( ("C3gDco::WriteControlReg: Setting 0x%lx, 0x%lx\n",
529 dwControlReg
,dwFreqReg
) );
532 return SendVector( DSP_VC_WRITE_CONTROL_REG
);
536 ECHO_DEBUGPRINTF( ("C3gDco::WriteControlReg: not written, no change\n") );
539 return ECHOSTATUS_OK
;
541 } // ECHOSTATUS C3gDco::WriteControlReg
544 //===========================================================================
548 //===========================================================================
550 void C3gDco::SetSpdifBits(DWORD
*pdwCtrlReg
,DWORD dwSampleRate
)
554 dwCtrlReg
= *pdwCtrlReg
;
557 // Clean out the old status bits
559 dwCtrlReg
&= E3G_SPDIF_FORMAT_CLEAR_MASK
;
564 switch (dwSampleRate
)
567 dwCtrlReg
|= E3G_SPDIF_SAMPLE_RATE0
|
568 E3G_SPDIF_SAMPLE_RATE1
;
572 if (m_bProfessionalSpdif
)
573 dwCtrlReg
|= E3G_SPDIF_SAMPLE_RATE0
;
577 dwCtrlReg
|= E3G_SPDIF_SAMPLE_RATE1
;
582 // Professional mode?
584 if (m_bProfessionalSpdif
)
585 dwCtrlReg
|= E3G_SPDIF_PRO_MODE
;
591 dwCtrlReg
|= E3G_SPDIF_NOT_AUDIO
;
594 // Always stereo, 24 bit, copy permit
596 dwCtrlReg
|= E3G_SPDIF_24_BIT
| E3G_SPDIF_TWO_CHANNEL
| E3G_SPDIF_COPY_PERMIT
;
598 *pdwCtrlReg
= dwCtrlReg
;
603 //===========================================================================
605 // SetSpdifOutNonAudio
607 // Set the state of the non-audio status bit in the S/PDIF out status bits
609 //===========================================================================
611 void C3gDco::SetSpdifOutNonAudio(BOOL bNonAudio
)
615 m_bNonAudio
= bNonAudio
;
617 dwControlReg
= GetControlRegister();
618 SetSpdifBits( &dwControlReg
, SWAP( m_pDspCommPage
->dwSampleRate
));
619 WriteControlReg( dwControlReg
, Get3gFreqReg() );
623 //===========================================================================
625 // Set the S/PDIF output format
627 //===========================================================================
629 void C3gDco::SetProfessionalSpdif
636 m_bProfessionalSpdif
= bNewStatus
;
638 dwControlReg
= GetControlRegister();
639 SetSpdifBits( &dwControlReg
, SWAP( m_pDspCommPage
->dwSampleRate
));
640 WriteControlReg( dwControlReg
, Get3gFreqReg() );
642 } // void C3gDco::SetProfessionalSpdif( ... )
645 //===========================================================================
649 // 3G ASIC status check returns different values depending on what kind of box
652 //===========================================================================
654 BOOL
C3gDco::CheckAsicStatus()
656 DWORD dwBoxStatus
,dwBoxType
;
658 if ( !WaitForHandshake() )
660 ECHO_DEBUGPRINTF(("CheckAsicStatus - no handshake!\n"));
665 // Send the vector command
667 m_pDspCommPage
->dwExtBoxStatus
= SWAP( (DWORD
) E3G_ASIC_NOT_LOADED
);
668 m_bASICLoaded
= FALSE
;
670 SendVector( DSP_VC_TEST_ASIC
);
673 // Wait for return from DSP
675 if ( !WaitForHandshake() )
677 ECHO_DEBUGPRINTF(("CheckAsicStatus - no handshake after VC\n"));
679 m_ullLastLoadAttemptTime
= 0; // so LoadFirmware will try again right away
684 // What box type was set?
686 dwBoxStatus
= SWAP(m_pDspCommPage
->dwExtBoxStatus
);
687 if (E3G_ASIC_NOT_LOADED
== dwBoxStatus
)
689 ECHO_DEBUGPRINTF(("CheckAsicStatus - ASIC not loaded\n"));
694 dwBoxType
= dwBoxStatus
& E3G_BOX_TYPE_MASK
;
695 m_bASICLoaded
= TRUE
;
696 ECHO_DEBUGPRINTF(("CheckAsicStatus - read box type %x\n",dwBoxType
));
699 m_dwCurrentBoxType
= dwBoxType
;
702 // Has the box type already been set?
707 // Did the ASIC load?
708 // Was the box type correct?
710 if ( (NO3GBOX
== dwBoxType
) ||
711 (dwBoxType
!= m_dwOriginalBoxType
) )
713 ECHO_DEBUGPRINTF(("CheckAsicStatus - box type mismatch - original %x, got %x\n",m_dwOriginalBoxType
,dwBoxType
));
717 ECHO_DEBUGPRINTF(("CheckAsicStatus - ASIC ok\n"));
718 m_bASICLoaded
= TRUE
;
723 // First ASIC load - determine the box type and set up for that kind of box
725 m_dwOriginalBoxType
= dwBoxType
;
726 m_bBoxTypeSet
= TRUE
;
731 // Set the bad board flag if no external box
733 if (NO3GBOX
== dwBoxType
)
735 ECHO_DEBUGPRINTF(("CheckAsicStatus - no external box\n"));
739 return m_bASICLoaded
;
741 } // BOOL C3gDco::CheckAsicStatus()
744 //===========================================================================
748 //===========================================================================
750 void C3gDco::SetPhantomPower(BOOL fPhantom
)
754 dwControlReg
= GetControlRegister();
757 dwControlReg
|= E3G_PHANTOM_POWER
;
761 dwControlReg
&= ~E3G_PHANTOM_POWER
;
764 WriteControlReg( dwControlReg
, Get3gFreqReg() );
768 //===========================================================================
770 // Set channel counts for the current box type
772 //===========================================================================
774 void C3gDco::SetChannelCounts()
779 switch (m_dwOriginalBoxType
)
784 m_wFirstDigitalBusOut
= 6;
785 m_wFirstDigitalBusIn
= 2;
796 m_wFirstDigitalBusOut
= 8;
797 m_wFirstDigitalBusIn
= 8;
803 m_wNumBussesOut
= m_wNumPipesOut
;
804 m_wNumBussesIn
= m_wNumPipesIn
;
805 strcpy( m_szCardName
, pszName
);
808 // Build a channel mask for ADAT inputs & outputs 3-8
809 // OK to use bus # here since this hardware has no virtual outputs
811 m_Adat38Mask
.Clear();
812 ch
= m_wFirstDigitalBusOut
+ 2;
813 for (i
= 0; i
< 6; i
++)
815 m_Adat38Mask
.SetIndexInMask(ch
);
819 ch
+= m_wFirstDigitalBusIn
+ 2;
820 for (i
= 0; i
< 6; i
++)
822 m_Adat38Mask
.SetIndexInMask(ch
);
828 //===========================================================================
830 // Return the 3G box type
832 //===========================================================================
834 void C3gDco::Get3gBoxType(DWORD
*pOriginalBoxType
,DWORD
*pCurrentBoxType
)
836 if (NULL
!= pOriginalBoxType
)
837 *pOriginalBoxType
= m_dwOriginalBoxType
;
839 if (NULL
!= pCurrentBoxType
)
843 *pCurrentBoxType
= m_dwCurrentBoxType
;
850 //===========================================================================
852 // Fill out an ECHOGALS_METERS struct using the current values in the
853 // comm page. This method is overridden for vmixer cards.
855 //===========================================================================
857 ECHOSTATUS
C3gDco::GetAudioMeters
859 PECHOGALS_METERS pMeters
862 pMeters
->iNumPipesOut
= 0;
863 pMeters
->iNumPipesIn
= 0;
871 pMeters
->iNumBussesOut
= (INT32
) m_wNumBussesOut
;
872 for (i
= 0; i
< m_wNumBussesOut
; i
++)
874 pMeters
->iBusOutVU
[i
] =
875 DSP_TO_GENERIC( ((INT32
) (INT8
) m_pDspCommPage
->VUMeter
[ dwCh
]) );
877 pMeters
->iBusOutPeak
[i
] =
878 DSP_TO_GENERIC( ((INT32
) (INT8
) m_pDspCommPage
->PeakMeter
[ dwCh
]) );
883 pMeters
->iNumBussesIn
= (INT32
) m_wNumBussesIn
;
884 dwCh
= E3G_MAX_OUTPUTS
;
885 for (i
= 0; i
< m_wNumBussesIn
; i
++)
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
]) );
895 return ECHOSTATUS_OK
;
901 //===========================================================================
903 // Utility function; returns TRUE if double speed mode is set
905 //===========================================================================
907 BOOL
C3gDco::DoubleSpeedMode(DWORD
*pdwNewCtrlReg
)
911 if (NULL
== pdwNewCtrlReg
)
912 dwControlReg
= GetControlRegister();
914 dwControlReg
= *pdwNewCtrlReg
;
916 if (0 != (dwControlReg
& E3G_DOUBLE_SPEED_MODE
))
923 //===========================================================================
925 // Utility function; validates a new control register value. Prevents
926 // speed change while transport is running
928 //===========================================================================
930 ECHOSTATUS
C3gDco::ValidateCtrlReg(DWORD dwNewControlReg
)
932 BOOL fCurrDoubleSpeed
,fNewDoubleSpeed
;
935 // Return OK if transport is off
937 if (m_cmActive
.IsEmpty())
938 return ECHOSTATUS_OK
;
941 // Get the new and current state of things
943 fNewDoubleSpeed
= DoubleSpeedMode(&dwNewControlReg
);
944 fCurrDoubleSpeed
= DoubleSpeedMode(NULL
);
949 if (fCurrDoubleSpeed
!= fNewDoubleSpeed
)
951 ECHO_DEBUGPRINTF(("Can't switch to speeds with transport active\n"));
952 return ECHOSTATUS_INVALID_CHANNEL
;
955 return ECHOSTATUS_OK
;
958 // **** C3gDco.cpp ****