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 56PVOID 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 79VOID 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 94C3g::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 106C3g::~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 126ECHOSTATUS 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 228ECHOSTATUS 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 290ECHOSTATUS 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 314void 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 333ECHOSTATUS 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 376void 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 388char *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 420void C3g::GetPhantomPower(BOOL *pfPhantom) 421{ 422 *pfPhantom = m_fPhantomPower; 423} 424 425 426//=========================================================================== 427// 428// Set phantom power state for Gina3G 429// 430//=========================================================================== 431 432void 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 451void 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 488ECHOSTATUS 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