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
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 "CLayla24DspCommObject.h"
33
34 #include LAYLA24_DSP_FILENAME
35 #include "Layla24_1ASIC.c"
36 #include "Layla24_2A_ASIC.c"
37 #include LAYLA24_2ASIC_FILENAME
38
39 //
40 // The ASIC files for Layla24 are always this size
41 //
42 #define LAYLA24_ASIC_SIZE 31146
43
44
45 /****************************************************************************
46
47 Construction and destruction
48
49 ****************************************************************************/
50
51 //===========================================================================
52 //
53 // Constructor
54 //
55 //===========================================================================
56
CLayla24DspCommObject(PDWORD pdwRegBase,PCOsSupport pOsSupport)57 CLayla24DspCommObject::CLayla24DspCommObject
58 (
59 PDWORD pdwRegBase, // Virtual ptr to DSP registers
60 PCOsSupport pOsSupport
61 ) : CGMLDspCommObject( pdwRegBase, pOsSupport )
62 {
63
64 strcpy( m_szCardName, LAYLA24_CARD_NAME);
65
66 m_pdwDspRegBase = pdwRegBase; // Virtual addr DSP's register base
67
68 m_wNumPipesOut = 16;
69 m_wNumPipesIn = 16;
70 m_wNumBussesOut = 16;
71 m_wNumBussesIn = 16;
72 m_wFirstDigitalBusOut = 8;
73 m_wFirstDigitalBusIn = 8;
74
75 m_fHasVmixer = LAYLA24_HAS_VMIXER;
76
77 m_wNumMidiOut = 1; // # MIDI out channels
78 m_wNumMidiIn = 1; // # MIDI in channels
79 m_bHasASIC = TRUE;
80
81 m_pwDspCodeToLoad = LAYLA24_DSP_CODE;
82
83 m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA;
84 m_bProfessionalSpdif = FALSE;
85 m_wMtcState = MIDI_IN_STATE_NORMAL;
86
87 m_dwSampleRate = 48000;
88
89 } // CLayla24DspCommObject::CLayla24DspCommObject( DWORD dwPhysRegBase )
90
91
92 //===========================================================================
93 //
94 // Destructor
95 //
96 //===========================================================================
97
~CLayla24DspCommObject()98 CLayla24DspCommObject::~CLayla24DspCommObject()
99 {
100 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::~CLayla24DspCommObject() "
101 "is toast!\n" ) );
102 } // CLayla24DspCommObject::~CLayla24DspCommObject()
103
104
105
106
107 /****************************************************************************
108
109 Hardware setup and config
110
111 ****************************************************************************/
112
113 //===========================================================================
114 //
115 // Layla24 has an ASIC on the PCI card and another ASIC in the external box;
116 // both need to be loaded.
117 //
118 //===========================================================================
119
LoadASIC()120 BOOL CLayla24DspCommObject::LoadASIC()
121 {
122 DWORD dwControlReg;
123
124 if ( m_bASICLoaded == TRUE )
125 return TRUE;
126
127 ECHO_DEBUGPRINTF(("CLayla24DspCommObject::LoadASIC\n"));
128
129 //
130 // Give the DSP a few milliseconds to settle down
131 //
132 m_pOsSupport->OsSnooze( 10000 );
133
134 //
135 // Load the ASIC for the PCI card
136 //
137 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC,
138 pbLayla24_1ASIC,
139 sizeof( pbLayla24_1ASIC ) ) )
140 return FALSE;
141
142 m_pbyAsic = pbLayla24_2S_ASIC;
143
144 //
145 // Now give the new ASIC a little time to set up
146 //
147 m_pOsSupport->OsSnooze( 10000 );
148
149 //
150 // Do the external one
151 //
152 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
153 pbLayla24_2S_ASIC,
154 sizeof( pbLayla24_2S_ASIC ) ) )
155 return FALSE;
156
157 //
158 // Now give the external ASIC a little time to set up
159 //
160 m_pOsSupport->OsSnooze( 10000 );
161
162 //
163 // See if it worked
164 //
165 CheckAsicStatus();
166
167 //
168 // Set up the control register if the load succeeded -
169 //
170 // 48 kHz, internal clock, S/PDIF RCA mode
171 //
172 if ( m_bASICLoaded )
173 {
174 dwControlReg = GML_CONVERTER_ENABLE | GML_48KHZ;
175 WriteControlReg( dwControlReg, TRUE );
176
177 m_dwSampleRate = 48000;
178 }
179
180 ECHO_DEBUGPRINTF(("\tFinished\n"));
181
182 return m_bASICLoaded;
183 } // BOOL CLayla24DspCommObject::LoadASIC()
184
185
186
187 //===========================================================================
188 //
189 // SetSampleRate
190 //
191 // Set the sample rate for Layla24
192 //
193 // Layla24 is simple; just send it the sampling rate (assuming that the clock
194 // mode is correct).
195 //
196 //===========================================================================
197
SetSampleRate(DWORD dwNewSampleRate)198 DWORD CLayla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate )
199 {
200 DWORD dwControlReg, dwNewClock, dwBaseRate;
201 BOOL bSetFreqReg = FALSE;
202
203 //
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
207 //
208 if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
209 {
210 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::SetSampleRate: Cannot set sample rate - "
211 "clock not set to CLK_CLOCKININTERNAL\n" ) );
212
213 //
214 // Save the rate anyhow
215 //
216 m_dwSampleRate = SWAP( dwNewSampleRate );
217
218 //
219 // Set the input clock to the current value
220 //
221 SetInputClock( m_wInputClock );
222
223 return dwNewSampleRate;
224 }
225
226 //
227 // Get the control register & clear the appropriate bits
228 //
229 dwControlReg = GetControlRegister();
230 dwControlReg &= GML_CLOCK_CLEAR_MASK;
231 dwControlReg &= GML_SPDIF_RATE_CLEAR_MASK;
232
233 //
234 // Set the sample rate
235 //
236 bSetFreqReg = FALSE;
237
238 switch ( dwNewSampleRate )
239 {
240 case 96000 :
241 dwNewClock = GML_96KHZ;
242 break;
243
244 case 88200 :
245 dwNewClock = GML_88KHZ;
246 break;
247
248 case 48000 :
249 dwNewClock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
250 break;
251
252 case 44100 :
253 dwNewClock = GML_44KHZ;
254
255 //
256 // Professional mode
257 //
258 if ( dwControlReg & GML_SPDIF_PRO_MODE )
259 {
260 dwNewClock |= GML_SPDIF_SAMPLE_RATE0;
261 }
262 break;
263
264 case 32000 :
265 dwNewClock = GML_32KHZ |
266 GML_SPDIF_SAMPLE_RATE0 |
267 GML_SPDIF_SAMPLE_RATE1;
268 break;
269
270 case 22050 :
271 dwNewClock = GML_22KHZ;
272 break;
273
274 case 16000 :
275 dwNewClock = GML_16KHZ;
276 break;
277
278 case 11025 :
279 dwNewClock = GML_11KHZ;
280 break;
281
282 case 8000 :
283 dwNewClock = GML_8KHZ;
284 break;
285
286 default :
287 //
288 // Set flag to write the frequency register
289 //
290 bSetFreqReg = TRUE;
291
292 //
293 // Set for continuous mode
294 //
295 dwNewClock = LAYLA24_CONTINUOUS_CLOCK;
296 }
297
298 dwControlReg |= dwNewClock;
299
300 //
301 // If this is a non-standard rate, then the driver
302 // needs to use Layla24's special "continuous frequency" mode
303 //
304 if ( bSetFreqReg )
305 {
306 if ( dwNewSampleRate > 50000 )
307 {
308 dwBaseRate = dwNewSampleRate >> 1;
309 dwControlReg |= GML_DOUBLE_SPEED_MODE;
310 }
311 else
312 {
313 dwBaseRate = dwNewSampleRate;
314 }
315
316 if ( dwBaseRate < 25000 )
317 dwBaseRate = 25000;
318
319 if ( !WaitForHandshake() )
320 return 0xffffffff;
321
322 m_pDspCommPage->dwSampleRate =
323 SWAP( LAYLA24_MAGIC_NUMBER / dwBaseRate - 2 );
324
325 ClearHandshake();
326 SendVector( DSP_VC_SET_LAYLA24_FREQUENCY_REG );
327 }
328
329 //
330 // Tell the DSP about it
331 //
332 if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg ) )
333 {
334 m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
335
336 ECHO_DEBUGPRINTF( ("CLayla24DspCommObject::SetSampleRate: %ld "
337 "clock %lx\n", dwNewSampleRate, dwControlReg) );
338 }
339
340 m_dwSampleRate = dwNewSampleRate;
341
342 return dwNewSampleRate;
343
344 } // DWORD CLayla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate )
345
346
347 //===========================================================================
348 //
349 // SetDigitalMode
350 //
351 //===========================================================================
352
SetDigitalMode(BYTE byNewMode)353 ECHOSTATUS CLayla24DspCommObject::SetDigitalMode
354 (
355 BYTE byNewMode
356 )
357 {
358 BOOL AsicOk;
359
360 //
361 // Change the ASIC
362 //
363 switch ( byNewMode )
364 {
365 case DIGITAL_MODE_SPDIF_RCA :
366 case DIGITAL_MODE_SPDIF_OPTICAL :
367 //
368 // If the currently loaded ASIC is the S/PDIF ASIC, switch
369 // to the ADAT ASIC
370 //
371 AsicOk = SwitchAsic( pbLayla24_2S_ASIC, sizeof( pbLayla24_2S_ASIC ) );
372 break;
373
374 case DIGITAL_MODE_ADAT :
375 //
376 // If the currently loaded ASIC is the S/PDIF ASIC, switch
377 // to the ADAT ASIC
378 //
379 AsicOk = SwitchAsic( pbLayla24_2A_ASIC, sizeof( pbLayla24_2A_ASIC ) );
380 break;
381
382 default :
383 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED;
384 }
385
386 if (FALSE == AsicOk)
387 return ECHOSTATUS_ASIC_NOT_LOADED;
388
389 //
390 // Call the base class to tweak the input clock if necessary
391 //
392 return CGMLDspCommObject::SetDigitalMode(byNewMode);
393
394 } // ECHOSTATUS CLaya24DspCommObject::SetDigitalMode
395
396
397 //===========================================================================
398 //
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.
402 //
403 //===========================================================================
404
SwitchAsic(BYTE * pbyAsicNeeded,DWORD dwAsicSize)405 BOOL CLayla24DspCommObject::SwitchAsic
406 (
407 BYTE * pbyAsicNeeded,
408 DWORD dwAsicSize
409 )
410 {
411 BOOL rval;
412
413 //
414 // Check to see if this is already loaded
415 //
416 rval = TRUE;
417 if ( pbyAsicNeeded != m_pbyAsic )
418 {
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 );
424
425 //
426 // Load the desired ASIC
427 //
428 rval = CDspCommObject::LoadASIC(DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
429 pbyAsicNeeded,
430 dwAsicSize );
431 if (FALSE != rval)
432 {
433 m_pbyAsic = pbyAsicNeeded;
434 }
435 memmove( m_pDspCommPage->byMonitors, byMonitors, MONITOR_ARRAY_SIZE );
436 }
437
438 return rval;
439
440 } // BOOL CLayla24DspCommObject::SwitchAsic( DWORD dwMask96 )
441
442
443 //===========================================================================
444 //
445 // SetInputClock
446 //
447 //===========================================================================
448
SetInputClock(WORD wClock)449 ECHOSTATUS CLayla24DspCommObject::SetInputClock(WORD wClock)
450 {
451 BOOL bSetRate;
452 BOOL bWriteControlReg;
453 DWORD dwControlReg, dwSampleRate;
454
455 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::SetInputClock:\n" ) );
456
457 dwControlReg = GetControlRegister();
458
459 //
460 // Mask off the clock select bits
461 //
462 dwControlReg &= GML_CLOCK_CLEAR_MASK;
463 dwSampleRate = GetSampleRate();
464
465 bSetRate = FALSE;
466 bWriteControlReg = TRUE;
467
468 //
469 // Pick the new clock
470 //
471 switch ( wClock )
472 {
473 case ECHO_CLOCK_INTERNAL :
474 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) );
475
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 ) )
480 {
481 m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
482 m_dwSampleRate = 48000;
483 }
484
485 bSetRate = TRUE;
486 bWriteControlReg = FALSE;
487 break;
488
489 case ECHO_CLOCK_SPDIF:
490 if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
491 {
492 return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
493 }
494
495 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) );
496
497 dwControlReg |= GML_SPDIF_CLOCK;
498
499 /*
500 Since Layla24 doesn't support 96 kHz S/PDIF, this can be ignored
501 if ( GML_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() )
502 {
503 dwControlReg |= GML_DOUBLE_SPEED_MODE;
504 }
505 else
506 {
507 dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
508 }
509 */
510 dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
511 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) );
512 break;
513
514 case ECHO_CLOCK_WORD:
515 dwControlReg |= GML_WORD_CLOCK;
516
517 if ( GML_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() )
518 {
519 dwControlReg |= GML_DOUBLE_SPEED_MODE;
520 }
521 else
522 {
523 dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
524 }
525 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to WORD\n" ) );
526 break;
527
528
529 case ECHO_CLOCK_ADAT :
530 if ( DIGITAL_MODE_ADAT != GetDigitalMode() )
531 {
532 return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
533 }
534
535 dwControlReg |= GML_ADAT_CLOCK;
536 dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
537 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to ADAT\n" ) );
538 break;
539
540 default :
541 ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock));
542 ECHO_DEBUGBREAK();
543 return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
544
545 } // switch (wClock)
546
547 //
548 // Winner! Save the new input clock.
549 //
550 m_wInputClock = wClock;
551
552 //
553 // Do things according to the flags
554 //
555 if ( bWriteControlReg )
556 {
557 WriteControlReg( dwControlReg, TRUE );
558 }
559
560 //
561 // If the user just switched to internal clock,
562 // set the sample rate
563 //
564 if ( bSetRate )
565 SetSampleRate( m_dwSampleRate );
566
567 return ECHOSTATUS_OK;
568
569 } // ECHOSTATUS CLayla24DspCommObject::SetInputClock()
570
571
572 // **** Layla24DspCommObject.cpp ****
573