1 // ****************************************************************************
3 // CLayla24DspCommObject.cpp
5 // Implementation file for EchoGals generic driver Layla24 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"
32 #include "CLayla24DspCommObject.h"
34 #include LAYLA24_DSP_FILENAME
35 #include "Layla24_1ASIC.c"
36 #include "Layla24_2A_ASIC.c"
37 #include LAYLA24_2ASIC_FILENAME
40 // The ASIC files for Layla24 are always this size
42 #define LAYLA24_ASIC_SIZE 31146
45 /****************************************************************************
47 Construction and destruction
49 ****************************************************************************/
51 //===========================================================================
55 //===========================================================================
57 CLayla24DspCommObject::CLayla24DspCommObject
59 PDWORD pdwRegBase
, // Virtual ptr to DSP registers
60 PCOsSupport pOsSupport
61 ) : CGMLDspCommObject( pdwRegBase
, pOsSupport
)
64 strcpy( m_szCardName
, LAYLA24_CARD_NAME
);
66 m_pdwDspRegBase
= pdwRegBase
; // Virtual addr DSP's register base
72 m_wFirstDigitalBusOut
= 8;
73 m_wFirstDigitalBusIn
= 8;
75 m_fHasVmixer
= LAYLA24_HAS_VMIXER
;
77 m_wNumMidiOut
= 1; // # MIDI out channels
78 m_wNumMidiIn
= 1; // # MIDI in channels
81 m_pwDspCodeToLoad
= LAYLA24_DSP_CODE
;
83 m_byDigitalMode
= DIGITAL_MODE_SPDIF_RCA
;
84 m_bProfessionalSpdif
= FALSE
;
85 m_wMtcState
= MIDI_IN_STATE_NORMAL
;
87 m_dwSampleRate
= 48000;
89 } // CLayla24DspCommObject::CLayla24DspCommObject( DWORD dwPhysRegBase )
92 //===========================================================================
96 //===========================================================================
98 CLayla24DspCommObject::~CLayla24DspCommObject()
100 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::~CLayla24DspCommObject() "
102 } // CLayla24DspCommObject::~CLayla24DspCommObject()
107 /****************************************************************************
109 Hardware setup and config
111 ****************************************************************************/
113 //===========================================================================
115 // Layla24 has an ASIC on the PCI card and another ASIC in the external box;
116 // both need to be loaded.
118 //===========================================================================
120 BOOL
CLayla24DspCommObject::LoadASIC()
124 if ( m_bASICLoaded
== TRUE
)
127 ECHO_DEBUGPRINTF(("CLayla24DspCommObject::LoadASIC\n"));
130 // Give the DSP a few milliseconds to settle down
132 m_pOsSupport
->OsSnooze( 10000 );
135 // Load the ASIC for the PCI card
137 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC
,
139 sizeof( pbLayla24_1ASIC
) ) )
142 m_pbyAsic
= pbLayla24_2S_ASIC
;
145 // Now give the new ASIC a little time to set up
147 m_pOsSupport
->OsSnooze( 10000 );
150 // Do the external one
152 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC
,
154 sizeof( pbLayla24_2S_ASIC
) ) )
158 // Now give the external ASIC a little time to set up
160 m_pOsSupport
->OsSnooze( 10000 );
168 // Set up the control register if the load succeeded -
170 // 48 kHz, internal clock, S/PDIF RCA mode
174 dwControlReg
= GML_CONVERTER_ENABLE
| GML_48KHZ
;
175 WriteControlReg( dwControlReg
, TRUE
);
177 m_dwSampleRate
= 48000;
180 ECHO_DEBUGPRINTF(("\tFinished\n"));
182 return m_bASICLoaded
;
183 } // BOOL CLayla24DspCommObject::LoadASIC()
187 //===========================================================================
191 // Set the sample rate for Layla24
193 // Layla24 is simple; just send it the sampling rate (assuming that the clock
196 //===========================================================================
198 DWORD
CLayla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate
)
200 DWORD dwControlReg
, dwNewClock
, dwBaseRate
;
201 BOOL bSetFreqReg
= FALSE
;
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
208 if ( GetInputClock() != ECHO_CLOCK_INTERNAL
)
210 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::SetSampleRate: Cannot set sample rate - "
211 "clock not set to CLK_CLOCKININTERNAL\n" ) );
214 // Save the rate anyhow
216 m_dwSampleRate
= SWAP( dwNewSampleRate
);
219 // Set the input clock to the current value
221 SetInputClock( m_wInputClock
);
223 return dwNewSampleRate
;
227 // Get the control register & clear the appropriate bits
229 dwControlReg
= GetControlRegister();
230 dwControlReg
&= GML_CLOCK_CLEAR_MASK
;
231 dwControlReg
&= GML_SPDIF_RATE_CLEAR_MASK
;
234 // Set the sample rate
238 switch ( dwNewSampleRate
)
241 dwNewClock
= GML_96KHZ
;
245 dwNewClock
= GML_88KHZ
;
249 dwNewClock
= GML_48KHZ
| GML_SPDIF_SAMPLE_RATE1
;
253 dwNewClock
= GML_44KHZ
;
258 if ( dwControlReg
& GML_SPDIF_PRO_MODE
)
260 dwNewClock
|= GML_SPDIF_SAMPLE_RATE0
;
265 dwNewClock
= GML_32KHZ
|
266 GML_SPDIF_SAMPLE_RATE0
|
267 GML_SPDIF_SAMPLE_RATE1
;
271 dwNewClock
= GML_22KHZ
;
275 dwNewClock
= GML_16KHZ
;
279 dwNewClock
= GML_11KHZ
;
283 dwNewClock
= GML_8KHZ
;
288 // Set flag to write the frequency register
293 // Set for continuous mode
295 dwNewClock
= LAYLA24_CONTINUOUS_CLOCK
;
298 dwControlReg
|= dwNewClock
;
301 // If this is a non-standard rate, then the driver
302 // needs to use Layla24's special "continuous frequency" mode
306 if ( dwNewSampleRate
> 50000 )
308 dwBaseRate
= dwNewSampleRate
>> 1;
309 dwControlReg
|= GML_DOUBLE_SPEED_MODE
;
313 dwBaseRate
= dwNewSampleRate
;
316 if ( dwBaseRate
< 25000 )
319 if ( !WaitForHandshake() )
322 m_pDspCommPage
->dwSampleRate
=
323 SWAP( LAYLA24_MAGIC_NUMBER
/ dwBaseRate
- 2 );
326 SendVector( DSP_VC_SET_LAYLA24_FREQUENCY_REG
);
330 // Tell the DSP about it
332 if ( ECHOSTATUS_OK
== WriteControlReg( dwControlReg
) )
334 m_pDspCommPage
->dwSampleRate
= SWAP( dwNewSampleRate
);
336 ECHO_DEBUGPRINTF( ("CLayla24DspCommObject::SetSampleRate: %ld "
337 "clock %lx\n", dwNewSampleRate
, dwControlReg
) );
340 m_dwSampleRate
= dwNewSampleRate
;
342 return dwNewSampleRate
;
344 } // DWORD CLayla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate )
347 //===========================================================================
351 //===========================================================================
353 ECHOSTATUS
CLayla24DspCommObject::SetDigitalMode
365 case DIGITAL_MODE_SPDIF_RCA
:
366 case DIGITAL_MODE_SPDIF_OPTICAL
:
368 // If the currently loaded ASIC is the S/PDIF ASIC, switch
371 AsicOk
= SwitchAsic( pbLayla24_2S_ASIC
, sizeof( pbLayla24_2S_ASIC
) );
374 case DIGITAL_MODE_ADAT
:
376 // If the currently loaded ASIC is the S/PDIF ASIC, switch
379 AsicOk
= SwitchAsic( pbLayla24_2A_ASIC
, sizeof( pbLayla24_2A_ASIC
) );
383 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED
;
387 return ECHOSTATUS_ASIC_NOT_LOADED
;
390 // Call the base class to tweak the input clock if necessary
392 return CGMLDspCommObject::SetDigitalMode(byNewMode
);
394 } // ECHOSTATUS CLaya24DspCommObject::SetDigitalMode
397 //===========================================================================
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.
403 //===========================================================================
405 BOOL
CLayla24DspCommObject::SwitchAsic
407 BYTE
* pbyAsicNeeded
,
414 // Check to see if this is already loaded
417 if ( pbyAsicNeeded
!= m_pbyAsic
)
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
);
426 // Load the desired ASIC
428 rval
= CDspCommObject::LoadASIC(DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC
,
433 m_pbyAsic
= pbyAsicNeeded
;
435 memmove( m_pDspCommPage
->byMonitors
, byMonitors
, MONITOR_ARRAY_SIZE
);
440 } // BOOL CLayla24DspCommObject::SwitchAsic( DWORD dwMask96 )
443 //===========================================================================
447 //===========================================================================
449 ECHOSTATUS
CLayla24DspCommObject::SetInputClock(WORD wClock
)
452 BOOL bWriteControlReg
;
453 DWORD dwControlReg
, dwSampleRate
;
455 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::SetInputClock:\n" ) );
457 dwControlReg
= GetControlRegister();
460 // Mask off the clock select bits
462 dwControlReg
&= GML_CLOCK_CLEAR_MASK
;
463 dwSampleRate
= GetSampleRate();
466 bWriteControlReg
= TRUE
;
469 // Pick the new clock
473 case ECHO_CLOCK_INTERNAL
:
474 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) );
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 ) )
481 m_pDspCommPage
->dwSampleRate
= SWAP( (DWORD
) 48000 );
482 m_dwSampleRate
= 48000;
486 bWriteControlReg
= FALSE
;
489 case ECHO_CLOCK_SPDIF
:
490 if ( DIGITAL_MODE_ADAT
== GetDigitalMode() )
492 return ECHOSTATUS_CLOCK_NOT_AVAILABLE
;
495 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) );
497 dwControlReg
|= GML_SPDIF_CLOCK
;
500 Since Layla24 doesn't support 96 kHz S/PDIF, this can be ignored
501 if ( GML_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() )
503 dwControlReg |= GML_DOUBLE_SPEED_MODE;
507 dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
510 dwControlReg
&= ~GML_DOUBLE_SPEED_MODE
;
511 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) );
514 case ECHO_CLOCK_WORD
:
515 dwControlReg
|= GML_WORD_CLOCK
;
517 if ( GML_CLOCK_DETECT_BIT_WORD96
& GetInputClockDetect() )
519 dwControlReg
|= GML_DOUBLE_SPEED_MODE
;
523 dwControlReg
&= ~GML_DOUBLE_SPEED_MODE
;
525 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to WORD\n" ) );
529 case ECHO_CLOCK_ADAT
:
530 if ( DIGITAL_MODE_ADAT
!= GetDigitalMode() )
532 return ECHOSTATUS_CLOCK_NOT_AVAILABLE
;
535 dwControlReg
|= GML_ADAT_CLOCK
;
536 dwControlReg
&= ~GML_DOUBLE_SPEED_MODE
;
537 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to ADAT\n" ) );
541 ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock
));
543 return ECHOSTATUS_CLOCK_NOT_SUPPORTED
;
548 // Winner! Save the new input clock.
550 m_wInputClock
= wClock
;
553 // Do things according to the flags
555 if ( bWriteControlReg
)
557 WriteControlReg( dwControlReg
, TRUE
);
561 // If the user just switched to internal clock,
562 // set the sample rate
565 SetSampleRate( m_dwSampleRate
);
567 return ECHOSTATUS_OK
;
569 } // ECHOSTATUS CLayla24DspCommObject::SetInputClock()
572 // **** Layla24DspCommObject.cpp ****