1 // ****************************************************************************
2 //
3 // C3g.cpp
4 //
5 // Implementation file for the C3g driver class.
6 // Set editor tabs to 3 for your viewing pleasure.
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 "C3g.h"
32
33 #define ECHO3G_ANALOG_OUTPUT_LATENCY_1X (1 + 32 + 12) // ASIC + DSP + DAC
34 #define ECHO3G_ANALOG_OUTPUT_LATENCY_2X (1 + 32 + 5)
35 #define ECHO3G_ANALOG_INPUT_LATENCY_1X (1 + 32 + 12)
36 #define ECHO3G_ANALOG_INPUT_LATENCY_2X (1 + 32 + 9)
37
38 #define ECHO3G_DIGITAL_OUTPUT_LATENCY (1 + 32)
39 #define ECHO3G_DIGITAL_INPUT_LATENCY (1 + 32)
40
41
42
43 /****************************************************************************
44
45 Construction and destruction
46
47 ****************************************************************************/
48
49 //===========================================================================
50 //
51 // Overload new & delete so memory for this object is allocated
52 // from non-paged memory.
53 //
54 //===========================================================================
55
operator new(size_t Size)56 PVOID C3g::operator new( size_t Size )
57 {
58 PVOID pMemory;
59 ECHOSTATUS Status;
60
61 Status = OsAllocateNonPaged(Size,&pMemory);
62
63 if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory ))
64 {
65 ECHO_DEBUGPRINTF(("C3g::operator new - memory allocation failed\n"));
66
67 pMemory = NULL;
68 }
69 else
70 {
71 memset( pMemory, 0, Size );
72 }
73
74 return pMemory;
75
76 } // PVOID C3g::operator new( size_t Size )
77
78
operator delete(PVOID pVoid)79 VOID C3g::operator delete( PVOID pVoid )
80 {
81 if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) )
82 {
83 ECHO_DEBUGPRINTF(("C3g::operator delete memory free failed\n"));
84 }
85 } // VOID C3g::operator delete( PVOID pVoid )
86
87
88 //===========================================================================
89 //
90 // Constructor and destructor
91 //
92 //===========================================================================
93
C3g(PCOsSupport pOsSupport)94 C3g::C3g( PCOsSupport pOsSupport )
95 : CEchoGalsMTC( pOsSupport )
96 {
97 ECHO_DEBUGPRINTF( ( "C3g::C3g() is born!\n" ) );
98
99 m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
100 m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
101 m_wDigitalOutputLatency = ECHO3G_DIGITAL_OUTPUT_LATENCY;
102 m_wDigitalInputLatency = ECHO3G_DIGITAL_INPUT_LATENCY;
103 }
104
105
~C3g()106 C3g::~C3g()
107 {
108 ECHO_DEBUGPRINTF( ( "C3g::~C3g() is toast!\n" ) );
109 }
110
111
112
113
114 /****************************************************************************
115
116 Setup and hardware initialization
117
118 ****************************************************************************/
119
120 //===========================================================================
121 //
122 // Every card has an InitHw method
123 //
124 //===========================================================================
125
InitHw()126 ECHOSTATUS C3g::InitHw()
127 {
128 ECHOSTATUS Status;
129 WORD i;
130
131 //
132 // Call the base method
133 //
134 if ( ECHOSTATUS_OK != ( Status = CEchoGals::InitHw() ) )
135 return Status;
136
137 //
138 // Create the DSP comm object
139 //
140 ECHO_ASSERT(NULL == m_pDspCommObject );
141 m_pDspCommObject = new C3gDco( (PDWORD) m_pvSharedMemory, m_pOsSupport );
142 if (NULL == m_pDspCommObject)
143 {
144 ECHO_DEBUGPRINTF(("C3g::InitHw - could not create DSP comm object\n"));
145 return ECHOSTATUS_NO_MEM;
146 }
147
148 //
149 // Load the DSP
150 //
151 DWORD dwBoxType;
152
153 GetDspCommObject()->LoadFirmware();
154
155 GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
156 if (NO3GBOX == dwBoxType)
157 return ECHOSTATUS_NO_3G_BOX;
158
159 if ( GetDspCommObject()->IsBoardBad() )
160 return ECHOSTATUS_DSP_DEAD;
161
162 //
163 // Clear the "bad board" flag; set the flags to indicate that
164 // 3G can handle super-interleave.
165 //
166 m_wFlags &= ~ECHOGALS_FLAG_BADBOARD;
167 m_wFlags |= ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK;
168
169 //
170 // Must call this here after DSP is init to
171 // init gains and mutes
172 //
173 Status = InitLineLevels();
174 if ( ECHOSTATUS_OK != Status )
175 return Status;
176
177 //
178 // Initialize the MIDI input
179 //
180 Status = m_MidiIn.Init( this );
181 if ( ECHOSTATUS_OK != Status )
182 return Status;
183
184 //
185 // Set defaults for +4/-10
186 //
187 for (i = 0; i < GetFirstDigitalBusOut(); i++ )
188 {
189 GetDspCommObject()->
190 SetNominalLevel( i, FALSE ); // FALSE is +4 here
191 }
192 for ( i = 0; i < GetFirstDigitalBusIn(); i++ )
193 {
194 GetDspCommObject()->
195 SetNominalLevel( GetNumBussesOut() + i, FALSE );
196 }
197
198 //
199 // Set the digital mode to S/PDIF RCA
200 //
201 SetDigitalMode( DIGITAL_MODE_SPDIF_RCA );
202
203 //
204 // Get default sample rate from DSP
205 //
206 m_dwSampleRate = GetDspCommObject()->GetSampleRate();
207
208 ECHO_DEBUGPRINTF( ( "C3g::InitHw()\n" ) );
209 return Status;
210
211 } // ECHOSTATUS C3g::InitHw()
212
213
214
215
216 /****************************************************************************
217
218 Informational methods
219
220 ****************************************************************************/
221
222 //===========================================================================
223 //
224 // Override GetCapabilities to enumerate unique capabilties for this card
225 //
226 //===========================================================================
227
GetCapabilities(PECHOGALS_CAPS pCapabilities)228 ECHOSTATUS C3g::GetCapabilities
229 (
230 PECHOGALS_CAPS pCapabilities
231 )
232 {
233 ECHOSTATUS Status;
234 WORD i;
235
236 Status = GetBaseCapabilities(pCapabilities);
237 if ( ECHOSTATUS_OK != Status )
238 return Status;
239
240 //
241 // Add nominal level control to all ins & outs except the universal
242 //
243 for (i = 0 ; i < pCapabilities->wNumBussesOut; i++)
244 {
245 pCapabilities->dwBusOutCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
246 }
247
248 for (i = 2 ; i < pCapabilities->wNumBussesIn; i++)
249 {
250 pCapabilities->dwBusInCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
251 }
252
253 pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_SPDIF |
254 ECHO_CLOCK_BIT_ADAT |
255 ECHO_CLOCK_BIT_MTC;
256
257 //
258 // Box-specific capabilities
259 //
260 DWORD dwBoxType;
261
262 GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
263 switch (dwBoxType)
264 {
265 case GINA3G :
266 pCapabilities->dwBusInCaps[0] |= ECHOCAPS_PHANTOM_POWER;
267 pCapabilities->dwBusInCaps[1] |= ECHOCAPS_PHANTOM_POWER;
268 break;
269
270 case LAYLA3G :
271 pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_WORD;
272 break;
273
274 }
275
276 pCapabilities->dwOutClockTypes = 0;
277
278 return Status;
279
280 } // ECHOSTATUS C3g::GetCapabilities
281
282
283 //===========================================================================
284 //
285 // QueryAudioSampleRate is used to find out if this card can handle a
286 // given sample rate.
287 //
288 //===========================================================================
289
QueryAudioSampleRate(DWORD dwSampleRate)290 ECHOSTATUS C3g::QueryAudioSampleRate
291 (
292 DWORD dwSampleRate
293 )
294 {
295 //
296 // Check rates that are supported by continuous mode; only allow
297 // double-speed rates if not in ADAT mode
298 //
299 if ((dwSampleRate >= 32000) && (dwSampleRate <= 50000))
300 return ECHOSTATUS_OK;
301
302 if ( (DIGITAL_MODE_ADAT != GetDigitalMode()) &&
303 (dwSampleRate > 50000) &&
304 (dwSampleRate <= 100000))
305 return ECHOSTATUS_OK;
306
307 ECHO_DEBUGPRINTF(("C3g::QueryAudioSampleRate() - rate %ld invalid\n",dwSampleRate) );
308
309 return ECHOSTATUS_BAD_FORMAT;
310
311 } // ECHOSTATUS C3g::QueryAudioSampleRate
312
313
QuerySampleRateRange(DWORD & dwMinRate,DWORD & dwMaxRate)314 void C3g::QuerySampleRateRange(DWORD &dwMinRate,DWORD &dwMaxRate)
315 {
316 dwMinRate = 32000;
317 dwMaxRate = 96000;
318 }
319
320
321
322 //===========================================================================
323 //
324 // GetInputClockDetect returns a bitmask consisting of all the input
325 // clocks currently connected to the hardware; this changes as the user
326 // connects and disconnects clock inputs.
327 //
328 // You should use this information to determine which clocks the user is
329 // allowed to select.
330 //
331 //===========================================================================
332
GetInputClockDetect(DWORD & dwClockDetectBits)333 ECHOSTATUS C3g::GetInputClockDetect(DWORD &dwClockDetectBits)
334 {
335 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
336 {
337 ECHO_DEBUGPRINTF( ("C3g::GetInputClockDetect: DSP Dead!\n") );
338 return ECHOSTATUS_DSP_DEAD;
339 }
340
341 //
342 // Map the DSP clock detect bits to the generic driver clock detect bits
343 //
344 DWORD dwClocksFromDsp = GetDspCommObject()->GetInputClockDetect();
345
346 dwClockDetectBits = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_MTC;
347
348 if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_WORD))
349 dwClockDetectBits |= ECHO_CLOCK_BIT_WORD;
350
351 switch (GetDigitalMode())
352 {
353 case DIGITAL_MODE_SPDIF_RCA :
354 case DIGITAL_MODE_SPDIF_OPTICAL :
355 if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_SPDIF))
356 dwClockDetectBits |= ECHO_CLOCK_BIT_SPDIF;
357 break;
358
359 case DIGITAL_MODE_ADAT :
360 if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_ADAT))
361 dwClockDetectBits |= ECHO_CLOCK_BIT_ADAT;
362 break;
363 }
364
365 return ECHOSTATUS_OK;
366
367 } // GetInputClockDetect
368
369
370 //===========================================================================
371 //
372 // Get the external box type
373 //
374 //===========================================================================
375
Get3gBoxType(DWORD * pOriginalBoxType,DWORD * pCurrentBoxType)376 void C3g::Get3gBoxType(DWORD *pOriginalBoxType,DWORD *pCurrentBoxType)
377 {
378 GetDspCommObject()->Get3gBoxType(pOriginalBoxType,pCurrentBoxType);
379 }
380
381
382 //===========================================================================
383 //
384 // Get the external box name
385 //
386 //===========================================================================
387
Get3gBoxName()388 char *C3g::Get3gBoxName()
389 {
390 char *pszName;
391 DWORD dwBoxType;
392
393 GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
394 switch (dwBoxType)
395 {
396 case GINA3G :
397 pszName = "Gina3G";
398 break;
399
400 case LAYLA3G :
401 pszName = "Layla3G";
402 break;
403
404 case NO3GBOX :
405 default :
406 pszName = "Echo3G";
407 break;
408 }
409
410 return pszName;
411 }
412
413
414 //===========================================================================
415 //
416 // Get phantom power state for Gina3G
417 //
418 //===========================================================================
419
GetPhantomPower(BOOL * pfPhantom)420 void C3g::GetPhantomPower(BOOL *pfPhantom)
421 {
422 *pfPhantom = m_fPhantomPower;
423 }
424
425
426 //===========================================================================
427 //
428 // Set phantom power state for Gina3G
429 //
430 //===========================================================================
431
SetPhantomPower(BOOL fPhantom)432 void C3g::SetPhantomPower(BOOL fPhantom)
433 {
434 DWORD dwBoxType;
435
436 GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
437 if (GINA3G == dwBoxType)
438 {
439 GetDspCommObject()->SetPhantomPower( fPhantom );
440 m_fPhantomPower = fPhantom;
441 }
442 }
443
444
445 //===========================================================================
446 //
447 // GetAudioLatency - returns the latency for a single pipe
448 //
449 //===========================================================================
450
GetAudioLatency(ECHO_AUDIO_LATENCY * pLatency)451 void C3g::GetAudioLatency(ECHO_AUDIO_LATENCY *pLatency)
452 {
453 DWORD dwSampleRate;
454
455 //
456 // Adjust the stored latency values based on the sample rate
457 //
458 dwSampleRate = GetDspCommObject()->GetSampleRate();
459 if (dwSampleRate <= 50000)
460 {
461 m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
462 m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
463 }
464 else
465 {
466 m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_2X;
467 m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_2X;
468 }
469
470 //
471 // Let the base class worry about analog vs. digital
472 //
473 CEchoGals::GetAudioLatency(pLatency);
474
475 } // GetAudioLatency
476
477
478
479 //===========================================================================
480 //
481 // Start transport for a group of pipes
482 //
483 // Use this to make sure no one tries to start digital channels 3-8
484 // with the hardware in double speed mode.
485 //
486 //===========================================================================
487
Start(PCChannelMask pChannelMask)488 ECHOSTATUS C3g::Start
489 (
490 PCChannelMask pChannelMask
491 )
492 {
493 PC3gDco pDCO;
494
495 //
496 // Double speed mode?
497 //
498 pDCO = GetDspCommObject();
499 if (pDCO->DoubleSpeedMode())
500 {
501 BOOL intersect;
502
503 //
504 // See if ADAT in 3-8 or out 3-8 are being started
505 //
506 intersect = pChannelMask->IsIntersectionOf( pDCO->m_Adat38Mask );
507 if (intersect)
508 {
509 ECHO_DEBUGPRINTF(("Cannot start ADAT channels 3-8 in double speed mode\n"));
510 return ECHOSTATUS_INVALID_CHANNEL;
511 }
512 }
513
514 return CEchoGals::Start(pChannelMask);
515 }
516
517 // *** C3g.cpp ***
518