BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / audio / echo / generic / CLayla24DspCommObject.cpp
blob94a042585541435a0348b5fb0a60527b4c6635fd
1 // ****************************************************************************
2 //
3 // CLayla24DspCommObject.cpp
4 //
5 // Implementation file for EchoGals generic driver Layla24 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
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 //===========================================================================
53 // Constructor
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
68 m_wNumPipesOut = 16;
69 m_wNumPipesIn = 16;
70 m_wNumBussesOut = 16;
71 m_wNumBussesIn = 16;
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
79 m_bHasASIC = TRUE;
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 //===========================================================================
94 // Destructor
96 //===========================================================================
98 CLayla24DspCommObject::~CLayla24DspCommObject()
100 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::~CLayla24DspCommObject() "
101 "is toast!\n" ) );
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()
122 DWORD dwControlReg;
124 if ( m_bASICLoaded == TRUE )
125 return 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,
138 pbLayla24_1ASIC,
139 sizeof( pbLayla24_1ASIC ) ) )
140 return FALSE;
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,
153 pbLayla24_2S_ASIC,
154 sizeof( pbLayla24_2S_ASIC ) ) )
155 return FALSE;
158 // Now give the external ASIC a little time to set up
160 m_pOsSupport->OsSnooze( 10000 );
163 // See if it worked
165 CheckAsicStatus();
168 // Set up the control register if the load succeeded -
170 // 48 kHz, internal clock, S/PDIF RCA mode
172 if ( m_bASICLoaded )
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 //===========================================================================
189 // SetSampleRate
191 // Set the sample rate for Layla24
193 // Layla24 is simple; just send it the sampling rate (assuming that the clock
194 // mode is correct).
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
236 bSetFreqReg = FALSE;
238 switch ( dwNewSampleRate )
240 case 96000 :
241 dwNewClock = GML_96KHZ;
242 break;
244 case 88200 :
245 dwNewClock = GML_88KHZ;
246 break;
248 case 48000 :
249 dwNewClock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
250 break;
252 case 44100 :
253 dwNewClock = GML_44KHZ;
256 // Professional mode
258 if ( dwControlReg & GML_SPDIF_PRO_MODE )
260 dwNewClock |= GML_SPDIF_SAMPLE_RATE0;
262 break;
264 case 32000 :
265 dwNewClock = GML_32KHZ |
266 GML_SPDIF_SAMPLE_RATE0 |
267 GML_SPDIF_SAMPLE_RATE1;
268 break;
270 case 22050 :
271 dwNewClock = GML_22KHZ;
272 break;
274 case 16000 :
275 dwNewClock = GML_16KHZ;
276 break;
278 case 11025 :
279 dwNewClock = GML_11KHZ;
280 break;
282 case 8000 :
283 dwNewClock = GML_8KHZ;
284 break;
286 default :
288 // Set flag to write the frequency register
290 bSetFreqReg = TRUE;
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
304 if ( bSetFreqReg )
306 if ( dwNewSampleRate > 50000 )
308 dwBaseRate = dwNewSampleRate >> 1;
309 dwControlReg |= GML_DOUBLE_SPEED_MODE;
311 else
313 dwBaseRate = dwNewSampleRate;
316 if ( dwBaseRate < 25000 )
317 dwBaseRate = 25000;
319 if ( !WaitForHandshake() )
320 return 0xffffffff;
322 m_pDspCommPage->dwSampleRate =
323 SWAP( LAYLA24_MAGIC_NUMBER / dwBaseRate - 2 );
325 ClearHandshake();
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 //===========================================================================
349 // SetDigitalMode
351 //===========================================================================
353 ECHOSTATUS CLayla24DspCommObject::SetDigitalMode
355 BYTE byNewMode
358 BOOL AsicOk;
361 // Change the ASIC
363 switch ( byNewMode )
365 case DIGITAL_MODE_SPDIF_RCA :
366 case DIGITAL_MODE_SPDIF_OPTICAL :
368 // If the currently loaded ASIC is the S/PDIF ASIC, switch
369 // to the ADAT ASIC
371 AsicOk = SwitchAsic( pbLayla24_2S_ASIC, sizeof( pbLayla24_2S_ASIC ) );
372 break;
374 case DIGITAL_MODE_ADAT :
376 // If the currently loaded ASIC is the S/PDIF ASIC, switch
377 // to the ADAT ASIC
379 AsicOk = SwitchAsic( pbLayla24_2A_ASIC, sizeof( pbLayla24_2A_ASIC ) );
380 break;
382 default :
383 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED;
386 if (FALSE == AsicOk)
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,
408 DWORD dwAsicSize
411 BOOL rval;
414 // Check to see if this is already loaded
416 rval = TRUE;
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,
429 pbyAsicNeeded,
430 dwAsicSize );
431 if (FALSE != rval)
433 m_pbyAsic = pbyAsicNeeded;
435 memmove( m_pDspCommPage->byMonitors, byMonitors, MONITOR_ARRAY_SIZE );
438 return rval;
440 } // BOOL CLayla24DspCommObject::SwitchAsic( DWORD dwMask96 )
443 //===========================================================================
445 // SetInputClock
447 //===========================================================================
449 ECHOSTATUS CLayla24DspCommObject::SetInputClock(WORD wClock)
451 BOOL bSetRate;
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();
465 bSetRate = FALSE;
466 bWriteControlReg = TRUE;
469 // Pick the new clock
471 switch ( wClock )
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;
485 bSetRate = TRUE;
486 bWriteControlReg = FALSE;
487 break;
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;
505 else
507 dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
510 dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
511 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) );
512 break;
514 case ECHO_CLOCK_WORD:
515 dwControlReg |= GML_WORD_CLOCK;
517 if ( GML_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() )
519 dwControlReg |= GML_DOUBLE_SPEED_MODE;
521 else
523 dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
525 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to WORD\n" ) );
526 break;
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" ) );
538 break;
540 default :
541 ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock));
542 ECHO_DEBUGBREAK();
543 return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
545 } // switch (wClock)
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
564 if ( bSetRate )
565 SetSampleRate( m_dwSampleRate );
567 return ECHOSTATUS_OK;
569 } // ECHOSTATUS CLayla24DspCommObject::SetInputClock()
572 // **** Layla24DspCommObject.cpp ****