1 // **************************************************************************** 2 // 3 // CDspCommObject.cpp 4 // 5 // Implementation file for EchoGals generic driver DSP interface class. 6 // 7 // Copyright Echo Digital Audio Corporation (c) 1998 - 2002 8 // All rights reserved 9 // www.echoaudio.com 10 // 11 // Permission is hereby granted, free of charge, to any person obtaining a 12 // copy of this software and associated documentation files (the 13 // "Software"), to deal with the Software without restriction, including 14 // without limitation the rights to use, copy, modify, merge, publish, 15 // distribute, sublicense, and/or sell copies of the Software, and to 16 // permit persons to whom the Software is furnished to do so, subject to 17 // the following conditions: 18 // 19 // - Redistributions of source code must retain the above copyright 20 // notice, this list of conditions and the following disclaimers. 21 // 22 // - Redistributions in binary form must reproduce the above copyright 23 // notice, this list of conditions and the following disclaimers in the 24 // documentation and/or other materials provided with the distribution. 25 // 26 // - Neither the name of Echo Digital Audio, nor the names of its 27 // contributors may be used to endorse or promote products derived from 28 // this Software without specific prior written permission. 29 // 30 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 31 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 32 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 33 // IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR 34 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 35 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 36 // SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. 37 // 38 // **************************************************************************** 39 40 #include "CEchoGals.h" 41 42 #ifdef DSP_56361 43 #include "LoaderDSP.c" 44 #endif 45 46 47 /**************************************************************************** 48 49 Construction and destruction 50 51 ****************************************************************************/ 52 53 //=========================================================================== 54 // 55 // Overload new & delete so memory for this object is allocated 56 // from non-paged memory. 57 // 58 //=========================================================================== 59 60 PVOID CDspCommObject::operator new( size_t Size ) 61 { 62 PVOID pMemory; 63 ECHOSTATUS Status; 64 65 Status = OsAllocateNonPaged(Size,&pMemory); 66 67 if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory )) 68 { 69 ECHO_DEBUGPRINTF(("CDspCommObject::operator new - memory allocation failed\n")); 70 71 pMemory = NULL; 72 } 73 else 74 { 75 memset( pMemory, 0, Size ); 76 } 77 78 return pMemory; 79 80 } // PVOID CDspCommObject::operator new( size_t Size ) 81 82 83 VOID CDspCommObject::operator delete( PVOID pVoid ) 84 { 85 if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) ) 86 { 87 ECHO_DEBUGPRINTF( ("CDspCommObject::operator delete memory free " 88 "failed\n") ); 89 } 90 } // VOID CDspCommObject::operator delete( PVOID pVoid ) 91 92 93 //=========================================================================== 94 // 95 // Constructor 96 // 97 //=========================================================================== 98 99 CDspCommObject::CDspCommObject 100 ( 101 PDWORD pdwDspRegBase, // Virtual ptr to DSP registers 102 PCOsSupport pOsSupport 103 ) 104 { 105 int i; 106 107 ASSERT( pOsSupport ); 108 109 // 110 // Init all the basic stuff 111 // 112 strcpy( m_szCardName, "??????" ); 113 m_pOsSupport = pOsSupport; // Ptr to OS Support methods & data 114 m_pdwDspRegBase = pdwDspRegBase; // Virtual addr DSP's register base 115 m_bBadBoard = TRUE; // Set TRUE until DSP loaded 116 m_pwDspCode = NULL; // Current DSP code not loaded 117 m_byDigitalMode = DIGITAL_MODE_NONE; 118 m_wInputClock = ECHO_CLOCK_INTERNAL; 119 m_wOutputClock = ECHO_CLOCK_WORD; 120 m_ullLastLoadAttemptTime = 0L - DSP_LOAD_ATTEMPT_PERIOD; // force first load to go 121 122 #ifdef MIDI_SUPPORT 123 m_ullNextMidiWriteTime = 0; 124 #endif 125 126 // 127 // Create the DSP comm page - this is the area of memory read and written by 128 // the DSP via bus mastering 129 // 130 if ( ECHOSTATUS_OK != 131 pOsSupport->OsPageAllocate( sizeof( DspCommPage ) / PAGE_SIZE + 1, 132 (VOID ** )&m_pDspCommPage, 133 &m_dwCommPagePhys ) || 134 m_pDspCommPage == NULL ) 135 { 136 ECHO_DEBUGPRINTF( ("CDspCommObject::CDspCommObject DSP comm page " 137 "memory allocation failed\n") ); 138 pOsSupport->EchoErrorMsg( 139 "CDspCommObject::CDspCommObject DSP comm page " 140 "memory allocation failed", 141 "Critical Failure" ); 142 return; 143 } 144 145 // 146 // Init the comm page 147 // 148 m_pDspCommPage->dwCommSize = SWAP( sizeof( DspCommPage ) ); 149 // Size of DSP comm page 150 151 m_pDspCommPage->dwHandshake = 0xffffffff; 152 m_pDspCommPage->dwMidiXmitStatus = 0xffffffff; 153 154 for ( i = 0; i < DSP_MAXAUDIOINPUTS; i++ ) 155 m_pDspCommPage->InLineLevel[ i ] = 0x00; 156 // Set line levels so we don't blast 157 // any inputs on startup 158 memset( m_pDspCommPage->byMonitors, 159 GENERIC_TO_DSP(ECHOGAIN_MUTED), 160 MONITOR_ARRAY_SIZE ); // Mute all monitors 161 162 memset( m_pDspCommPage->byVmixerLevel, 163 GENERIC_TO_DSP(ECHOGAIN_MUTED), 164 VMIXER_ARRAY_SIZE ); // Mute all virtual mixer levels 165 166 #ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT 167 168 m_fDigitalInAutoMute = TRUE; 169 170 #endif 171 172 } // CDspCommObject::CDspCommObject 173 174 175 //=========================================================================== 176 // 177 // Destructor 178 // 179 //=========================================================================== 180 181 CDspCommObject::~CDspCommObject() 182 { 183 // 184 // Reset transport 185 // 186 CChannelMask cmActive = m_cmActive; 187 ResetTransport( &cmActive ); 188 189 // 190 // Meters off 191 // 192 m_wMeterOnCount = 1; 193 SetMetersOn( FALSE ); 194 195 #ifdef MIDI_SUPPORT 196 197 // 198 // MIDI input off 199 // 200 m_wMidiOnCount = 1; 201 SetMidiOn( FALSE ); 202 203 #endif // MIDI_SUPPORT 204 205 // 206 // Go to sleep 207 // 208 GoComatose(); 209 210 // 211 // Free the comm page 212 // 213 if ( NULL != m_pDspCommPage ) 214 { 215 if ( ECHOSTATUS_OK != m_pOsSupport->OsPageFree( 216 sizeof( DspCommPage ) / PAGE_SIZE + 1, 217 m_pDspCommPage, 218 m_dwCommPagePhys ) ) 219 { 220 ECHO_DEBUGPRINTF(("CDspCommObject::~CDspCommObject " 221 "DSP comm page memory free failed\n")); 222 } 223 } 224 225 ECHO_DEBUGPRINTF( ( "CDspCommObject::~CDspCommObject() is toast!\n" ) ); 226 227 } // CDspCommObject::~CDspCommObject() 228 229 230 231 232 /**************************************************************************** 233 234 Firmware loading functions 235 236 ****************************************************************************/ 237 238 //=========================================================================== 239 // 240 // ASIC status check - some cards have one or two ASICs that need to be 241 // loaded. Once that load is complete, this function is called to see if 242 // the load was successful. 243 // 244 // If this load fails, it does not necessarily mean that the hardware is 245 // defective - the external box may be disconnected or turned off. 246 // 247 // This routine sometimes fails for Layla20; for Layla20, the loop runs 5 times 248 // and succeeds if it wins on three of the loops. 249 // 250 //=========================================================================== 251 252 BOOL CDspCommObject::CheckAsicStatus() 253 { 254 #if NUM_ASIC_TESTS!=1 255 DWORD dwGoodCt = 0; 256 #endif 257 258 DWORD dwAsicStatus; 259 DWORD dwReturn; 260 int iNumTests; 261 262 if ( !m_bHasASIC ) 263 { 264 m_bASICLoaded = TRUE; 265 return TRUE; 266 } 267 268 iNumTests = NUM_ASIC_TESTS; 269 270 for ( int i = 0; i < iNumTests; i++ ) 271 { 272 // Send the vector command 273 SendVector( DSP_VC_TEST_ASIC ); 274 275 // Since this is a Layla, the DSP will return a value to 276 // indicate whether or not the ASIC is currently loaded 277 dwReturn = Read_DSP( &dwAsicStatus); 278 if ( ECHOSTATUS_OK != dwReturn ) 279 { 280 ECHO_DEBUGPRINTF(("CDspCommObject::CheckAsicStatus - failed on Read_DSP\n")); 281 ECHO_DEBUGBREAK(); 282 m_bASICLoaded = FALSE; 283 return FALSE; 284 } 285 286 #ifdef ECHO_DEBUG 287 if ( dwAsicStatus != ASIC_ALREADY_LOADED && 288 dwAsicStatus != ASIC_NOT_LOADED ) 289 { 290 ECHO_DEBUGBREAK(); 291 } 292 #endif 293 294 if ( dwAsicStatus == ASIC_ALREADY_LOADED ) 295 { 296 297 #if NUM_ASIC_TESTS==1 298 m_bASICLoaded = TRUE; 299 break; 300 #else 301 // 302 // For Layla20 303 // 304 if ( ++dwGoodCt == 3 ) 305 { 306 m_bASICLoaded = TRUE; 307 break; 308 } 309 #endif 310 } 311 else 312 { 313 m_bASICLoaded = FALSE; 314 } 315 } 316 317 return m_bASICLoaded; 318 319 } // BOOL CDspCommObject::CheckAsicStatus() 320 321 322 //=========================================================================== 323 // 324 // Load ASIC code - done after the DSP is loaded 325 // 326 //=========================================================================== 327 328 BOOL CDspCommObject::LoadASIC 329 ( 330 DWORD dwCmd, 331 PBYTE pCode, 332 DWORD dwSize 333 ) 334 { 335 DWORD i; 336 337 ECHO_DEBUGPRINTF(("CDspCommObject::LoadASIC\n")); 338 339 if ( !m_bHasASIC ) 340 return TRUE; 341 342 #ifdef _DEBUG 343 DWORD dwChecksum = 0; 344 ULONGLONG ullStartTime, ullCurTime; 345 m_pOsSupport->OsGetSystemTime( &ullStartTime ); 346 #endif 347 348 // Send the "Here comes the ASIC" command 349 if ( ECHOSTATUS_OK != Write_DSP( dwCmd ) ) 350 return FALSE; 351 352 // Write length of ASIC file in bytes 353 if ( ECHOSTATUS_OK != Write_DSP( dwSize ) ) 354 return FALSE; 355 356 for ( i = 0; i < dwSize; i++ ) 357 { 358 #ifdef _DEBUG 359 dwChecksum += pCode[i]; 360 #endif 361 362 if ( ECHOSTATUS_OK != Write_DSP( pCode[ i ] ) ) 363 { 364 ECHO_DEBUGPRINTF(("\tfailed on Write_DSP\n")); 365 return FALSE; 366 } 367 } 368 369 #ifdef _DEBUG 370 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 371 ECHO_DEBUGPRINTF( ("CDspCommObject::LoadASIC took %ld usec.\n", 372 (ULONG) ( ullCurTime - ullStartTime ) ) ); 373 ECHO_DEBUGPRINTF(("\tChecksum is 0x%lx\n",dwChecksum)); 374 ECHO_DEBUGPRINTF(("ASIC load OK\n")); 375 #endif 376 377 return TRUE; 378 } // BOOL CDspCommObject::LoadASIC( DWORD dwCmd, PBYTE pCode, DWORD dwSize ) 379 380 381 //=========================================================================== 382 // 383 // InstallResidentLoader 384 // 385 // Install the resident loader for 56361 DSPs; The resident loader 386 // is on the EPROM on the board for 56301 DSP. 387 // 388 // The resident loader is a tiny little program that is used to load 389 // the real DSP code. 390 // 391 //=========================================================================== 392 393 #ifdef DSP_56361 394 395 ECHOSTATUS CDspCommObject::InstallResidentLoader() 396 { 397 DWORD dwAddress; 398 DWORD dwIndex; 399 int iNum; 400 int i; 401 DWORD dwReturn; 402 PWORD pCode; 403 404 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader\n") ); 405 406 // 407 // 56361 cards only! 408 // 409 if (DEVICE_ID_56361 != m_pOsSupport->GetDeviceId() ) 410 return ECHOSTATUS_OK; 411 412 // 413 // Look to see if the resident loader is present. If the resident loader 414 // is already installed, host flag 5 will be on. 415 // 416 DWORD dwStatus; 417 dwStatus = GetDspRegister( CHI32_STATUS_REG ); 418 if ( 0 != (dwStatus & CHI32_STATUS_REG_HF5 ) ) 419 { 420 ECHO_DEBUGPRINTF(("\tResident loader already installed; status is 0x%lx\n", 421 dwStatus)); 422 return ECHOSTATUS_OK; 423 } 424 // 425 // Set DSP format bits for 24 bit mode 426 // 427 SetDspRegister( CHI32_CONTROL_REG, 428 GetDspRegister( CHI32_CONTROL_REG ) | 0x900 ); 429 430 //--------------------------------------------------------------------------- 431 // 432 // Loader 433 // 434 // The DSP code is an array of 16 bit words. The array is divided up into 435 // sections. The first word of each section is the size in words, followed 436 // by the section type. 437 // 438 // Since DSP addresses and data are 24 bits wide, they each take up two 439 // 16 bit words in the array. 440 // 441 // This is a lot like the other loader loop, but it's not a loop, 442 // you don't write the memory type, and you don't write a zero at the end. 443 // 444 //--------------------------------------------------------------------------- 445 446 pCode = pwLoaderDSP; 447 // 448 // Skip the header section; the first word in the array is the size of 449 // the first section, so the first real section of code is pointed to 450 // by pCode[0]. 451 // 452 dwIndex = pCode[ 0 ]; 453 // 454 // Skip the section size, LRS block type, and DSP memory type 455 // 456 dwIndex += 3; 457 // 458 // Get the number of DSP words to write 459 // 460 iNum = pCode[ dwIndex++ ]; 461 // 462 // Get the DSP address for this block; 24 bits, so build from two words 463 // 464 dwAddress = ( pCode[ dwIndex ] << 16 ) + pCode[ dwIndex + 1 ]; 465 dwIndex += 2; 466 // 467 // Write the count to the DSP 468 // 469 dwReturn = Write_DSP( (DWORD) iNum ); 470 if ( dwReturn != 0 ) 471 { 472 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader: Failed to " 473 "write word count!\n") ); 474 return ECHOSTATUS_DSP_DEAD; 475 } 476 477 // Write the DSP address 478 dwReturn = Write_DSP( dwAddress ); 479 if ( dwReturn != 0 ) 480 { 481 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader: Failed to " 482 "write DSP address!\n") ); 483 return ECHOSTATUS_DSP_DEAD; 484 } 485 486 487 // Write out this block of code to the DSP 488 for ( i = 0; i < iNum; i++) // 489 { 490 DWORD dwData; 491 492 dwData = ( pCode[ dwIndex ] << 16 ) + pCode[ dwIndex + 1 ]; 493 dwReturn = Write_DSP( dwData ); 494 if ( dwReturn != 0 ) 495 { 496 ECHO_DEBUGPRINTF( ("CDspCommObject::InstallResidentLoader: Failed to " 497 "write DSP code\n") ); 498 return ECHOSTATUS_DSP_DEAD; 499 } 500 501 dwIndex+=2; 502 } 503 504 // 505 // Wait for flag 5 to come up 506 // 507 BOOL fSuccess; 508 ULONGLONG ullCurTime,ullTimeout; 509 510 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 511 ullTimeout = ullCurTime + 10000L; // 10m.s. 512 fSuccess = FALSE; 513 do 514 { 515 m_pOsSupport->OsSnooze(50); // Give the DSP some time; 516 // no need to hog the CPU 517 518 dwStatus = GetDspRegister( CHI32_STATUS_REG ); 519 if (0 != (dwStatus & CHI32_STATUS_REG_HF5)) 520 { 521 fSuccess = TRUE; 522 break; 523 } 524 525 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 526 527 } while (ullCurTime < ullTimeout); 528 529 if (FALSE == fSuccess) 530 { 531 ECHO_DEBUGPRINTF(("\tResident loader failed to set HF5\n")); 532 return ECHOSTATUS_DSP_DEAD; 533 } 534 535 ECHO_DEBUGPRINTF(("\tResident loader successfully installed\n")); 536 537 return ECHOSTATUS_OK; 538 539 } // ECHOSTATUS CDspCommObject::InstallResidentLoader() 540 541 #endif // DSP_56361 542 543 544 //=========================================================================== 545 // 546 // LoadDSP 547 // 548 // This loads the DSP code. 549 // 550 //=========================================================================== 551 552 ECHOSTATUS CDspCommObject::LoadDSP 553 ( 554 PWORD pCode // Ptr to DSP object code 555 ) 556 { 557 DWORD dwAddress; 558 DWORD dwIndex; 559 int iNum; 560 int i; 561 DWORD dwReturn; 562 ULONGLONG ullTimeout, ullCurTime; 563 ECHOSTATUS Status; 564 565 ECHO_DEBUGPRINTF(("CDspCommObject::LoadDSP\n")); 566 if ( m_pwDspCode == pCode ) 567 { 568 ECHO_DEBUGPRINTF( ("\tDSP is already loaded!\n") ); 569 return ECHOSTATUS_FIRMWARE_LOADED; 570 } 571 m_bBadBoard = TRUE; // Set TRUE until DSP loaded 572 m_pwDspCode = NULL; // Current DSP code not loaded 573 m_bASICLoaded = FALSE; // Loading the DSP code will reset the ASIC 574 575 ECHO_DEBUGPRINTF(("CDspCommObject::LoadDSP Set m_bBadBoard to TRUE\n")); 576 577 // 578 // If this board requires a resident loader, install it. 579 // 580 #ifdef DSP_56361 581 InstallResidentLoader(); 582 #endif 583 584 // Send software reset command 585 if ( ECHOSTATUS_OK != SendVector( DSP_VC_RESET ) ) 586 { 587 m_pOsSupport->EchoErrorMsg( 588 "CDspCommObject::LoadDsp SendVector DSP_VC_RESET failed", 589 "Critical Failure" ); 590 return ECHOSTATUS_DSP_DEAD; 591 } 592 593 // Delay 10us 594 m_pOsSupport->OsSnooze( 10L ); 595 596 // Wait 10ms for HF3 to indicate that software reset is complete 597 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 598 ullTimeout = ullCurTime + 10000L; // 10m.s. 599 600 while ( 1 ) 601 { 602 if ( GetDspRegister( CHI32_STATUS_REG ) & CHI32_STATUS_REG_HF3 ) 603 break; 604 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 605 if ( ullCurTime > ullTimeout) 606 { 607 ECHO_DEBUGPRINTF( ("CDspCommObject::LoadDSP Timeout waiting for " 608 "CHI32_STATUS_REG_HF3\n") ); 609 m_pOsSupport->EchoErrorMsg( 610 "CDspCommObject::LoadDSP SendVector DSP_VC_RESET failed", 611 "Critical Failure" ); 612 return ECHOSTATUS_DSP_TIMEOUT; 613 } 614 } 615 616 // Set DSP format bits for 24 bit mode now that soft reset is done 617 SetDspRegister( CHI32_CONTROL_REG, 618 GetDspRegister( CHI32_CONTROL_REG ) | (DWORD) 0x900 ); 619 620 //--------------------------------------------------------------------------- 621 // Main loader loop 622 //--------------------------------------------------------------------------- 623 624 dwIndex = pCode[ 0 ]; 625 626 for (;;) 627 { 628 int iBlockType; 629 int iMemType; 630 631 // Total Block Size 632 dwIndex++; 633 634 // Block Type 635 iBlockType = pCode[ dwIndex ]; 636 if ( iBlockType == 4 ) // We're finished 637 break; 638 639 dwIndex++; 640 641 // Memory Type P=0,X=1,Y=2 642 iMemType = pCode[ dwIndex ]; 643 dwIndex++; 644 645 // Block Code Size 646 iNum = pCode[ dwIndex ]; 647 dwIndex++; 648 if ( iNum == 0 ) // We're finished 649 break; 650 651 // Start Address 652 dwAddress = ( (DWORD) pCode[ dwIndex ] << 16 ) + pCode[ dwIndex + 1 ]; 653 // ECHO_DEBUGPRINTF( ("\tdwAddress %lX\n", dwAddress) ); 654 dwIndex += 2; 655 656 dwReturn = Write_DSP( (DWORD)iNum ); 657 if ( dwReturn != 0 ) 658 { 659 ECHO_DEBUGPRINTF(("LoadDSP - failed to write number of DSP words\n")); 660 return ECHOSTATUS_DSP_DEAD; 661 } 662 663 dwReturn = Write_DSP( dwAddress ); 664 if ( dwReturn != 0 ) 665 { 666 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP address\n")); 667 return ECHOSTATUS_DSP_DEAD; 668 } 669 670 dwReturn = Write_DSP( (DWORD)iMemType ); 671 if ( dwReturn != 0 ) 672 { 673 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP memory type\n")); 674 return ECHOSTATUS_DSP_DEAD; 675 } 676 677 // Code 678 for ( i = 0; i < iNum; i++ ) 679 { 680 DWORD dwData; 681 682 dwData = ( (DWORD) pCode[ dwIndex ] << 16 ) + pCode[ dwIndex + 1 ]; 683 dwReturn = Write_DSP( dwData ); 684 if ( dwReturn != 0 ) 685 { 686 ECHO_DEBUGPRINTF(("LoadDSP - failed to write DSP data\n")); 687 return ECHOSTATUS_DSP_DEAD; 688 } 689 690 dwIndex += 2; 691 } 692 // ECHO_DEBUGPRINTF( ("\tEnd Code Block\n") ); 693 } 694 dwReturn = Write_DSP( 0 ); // We're done!!! 695 if ( dwReturn != 0 ) 696 { 697 ECHO_DEBUGPRINTF(("LoadDSP: Failed to write final zero\n")); 698 return ECHOSTATUS_DSP_DEAD; 699 } 700 701 702 // Delay 10us 703 m_pOsSupport->OsSnooze( 10L ); 704 705 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 706 ullTimeout = ullCurTime + 500000L; // 1/2 sec. timeout 707 708 while ( ullCurTime <= ullTimeout) 709 { 710 // 711 // Wait for flag 4 - indicates that the DSP loaded OK 712 // 713 if ( GetDspRegister( CHI32_STATUS_REG ) & CHI32_STATUS_REG_HF4 ) 714 { 715 SetDspRegister( CHI32_CONTROL_REG, 716 GetDspRegister( CHI32_CONTROL_REG ) & ~0x1b00 ); 717 718 dwReturn = Write_DSP( DSP_FNC_SET_COMMPAGE_ADDR ); 719 if ( dwReturn != 0 ) 720 { 721 ECHO_DEBUGPRINTF(("LoadDSP - Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n")); 722 return ECHOSTATUS_DSP_DEAD; 723 } 724 725 dwReturn = Write_DSP( m_dwCommPagePhys ); 726 if ( dwReturn != 0 ) 727 { 728 ECHO_DEBUGPRINTF(("LoadDSP - Failed to write comm page address\n")); 729 return ECHOSTATUS_DSP_DEAD; 730 } 731 732 // 733 // Get the serial number via slave mode. 734 // This is triggered by the SET_COMMPAGE_ADDR command. 735 // We don't actually use the serial number but we have to get 736 // it as part of the DSP init vodoo. 737 // 738 Status = ReadSn(); 739 if ( ECHOSTATUS_OK != Status ) 740 { 741 ECHO_DEBUGPRINTF(("LoadDSP - Failed to read serial number\n")); 742 return Status; 743 } 744 745 m_pwDspCode = pCode; // Show which DSP code loaded 746 m_bBadBoard = FALSE; // DSP OK 747 748 ECHO_DEBUGPRINTF(("CDspCommObject::LoadDSP Set m_bBadBoard to FALSE\n")); 749 750 return ECHOSTATUS_OK; 751 } 752 753 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 754 } 755 756 ECHO_DEBUGPRINTF( ("LoadDSP: DSP load timed out waiting for HF4\n") ); 757 758 return ECHOSTATUS_DSP_TIMEOUT; 759 760 } // DWORD CDspCommObject::LoadDSP 761 762 763 //=========================================================================== 764 // 765 // LoadFirmware takes care of loading the DSP and any ASIC code. 766 // 767 //=========================================================================== 768 769 ECHOSTATUS CDspCommObject::LoadFirmware() 770 { 771 ECHOSTATUS dwReturn; 772 ULONGLONG ullRightNow; 773 774 // Try to load the DSP 775 if ( NULL == m_pwDspCodeToLoad || NULL == m_pDspCommPage ) 776 { 777 ECHO_DEBUGBREAK(); 778 return ECHOSTATUS_NO_MEM; 779 } 780 781 // 782 // Even if the external box is off, an application may still try 783 // to repeatedly open the driver, causing multiple load attempts and 784 // making the machine spend lots of time in the kernel. If the ASIC is not 785 // loaded, this code will gate the loading attempts so it doesn't happen 786 // more than once per second. 787 // 788 m_pOsSupport->OsGetSystemTime(&ullRightNow); 789 if ( (FALSE == m_bASICLoaded) && 790 (DSP_LOAD_ATTEMPT_PERIOD > (ullRightNow - m_ullLastLoadAttemptTime)) ) 791 return ECHOSTATUS_ASIC_NOT_LOADED; 792 793 // 794 // Update the timestamp 795 // 796 m_ullLastLoadAttemptTime = ullRightNow; 797 798 // 799 // See if the ASIC is present and working - only if the DSP is already loaded 800 // 801 if (NULL != m_pwDspCode) 802 { 803 dwReturn = CheckAsicStatus(); 804 if (TRUE == dwReturn) 805 return ECHOSTATUS_OK; 806 807 // 808 // ASIC check failed; force the DSP to reload 809 // 810 m_pwDspCode = NULL; 811 } 812 813 // 814 // Try and load the DSP 815 // 816 dwReturn = LoadDSP( m_pwDspCodeToLoad ); 817 if ( (ECHOSTATUS_OK != dwReturn) && 818 (ECHOSTATUS_FIRMWARE_LOADED != dwReturn) ) 819 { 820 return dwReturn; 821 } 822 823 ECHO_DEBUGPRINTF(("DSP load OK\n")); 824 825 // 826 // Load the ASIC if the DSP load succeeded; LoadASIC will 827 // always return TRUE for cards that don't have an ASIC. 828 // 829 dwReturn = LoadASIC(); 830 if ( FALSE == dwReturn ) 831 { 832 dwReturn = ECHOSTATUS_ASIC_NOT_LOADED; 833 } 834 else 835 { 836 // 837 // ASIC load was successful 838 // 839 RestoreDspSettings(); 840 841 dwReturn = ECHOSTATUS_OK; 842 } 843 844 return dwReturn; 845 846 } // BOOL CDspCommObject::LoadFirmware() 847 848 849 //=========================================================================== 850 // 851 // This function is used to read back the serial number from the DSP; 852 // this is triggered by the SET_COMMPAGE_ADDR command. 853 // 854 // Only some early Echogals products have serial numbers in the ROM; 855 // the serial number is not used, but you still need to do this as 856 // part of the DSP load process. 857 // 858 //=========================================================================== 859 860 ECHOSTATUS CDspCommObject::ReadSn() 861 { 862 int j; 863 DWORD dwSn[ 6 ]; 864 ECHOSTATUS Status; 865 866 ECHO_DEBUGPRINTF( ("CDspCommObject::ReadSn\n") ); 867 for ( j = 0; j < 5; j++ ) 868 { 869 Status = Read_DSP( &dwSn[ j ] ); 870 if ( Status != 0 ) 871 { 872 ECHO_DEBUGPRINTF( ("\tFailed to read serial number word %d\n", 873 j) ); 874 return ECHOSTATUS_DSP_DEAD; 875 } 876 } 877 ECHO_DEBUGPRINTF( ("\tRead serial number %08lx %08lx %08lx %08lx %08lx\n", 878 dwSn[0], dwSn[1], dwSn[2], dwSn[3], dwSn[4]) ); 879 return ECHOSTATUS_OK; 880 881 } // DWORD CDspCommObject::ReadSn 882 883 884 885 886 //=========================================================================== 887 // 888 // This is called after LoadFirmware to restore old gains, meters on, 889 // monitors, etc. 890 // 891 //=========================================================================== 892 893 void CDspCommObject::RestoreDspSettings() 894 { 895 ECHO_DEBUGPRINTF(("RestoreDspSettings\n")); 896 897 if ( !CheckAsicStatus() ) 898 return; 899 900 m_pDspCommPage->dwHandshake = 0xffffffff; 901 902 #ifdef MIDI_SUPPORT 903 m_ullNextMidiWriteTime = 0; 904 #endif 905 906 SetSampleRate(); 907 if ( 0 != m_wMeterOnCount ) 908 { 909 SendVector( DSP_VC_METERS_ON ); 910 } 911 if ( !WaitForHandshake() ) 912 return; 913 914 SetInputClock( m_wInputClock ); 915 SetOutputClock( m_wOutputClock ); 916 917 if ( !WaitForHandshake() ) 918 return; 919 UpdateAudioOutLineLevel(); 920 921 if ( !WaitForHandshake() ) 922 return; 923 UpdateAudioInLineLevel(); 924 925 if ( HasVmixer() ) 926 { 927 if ( !WaitForHandshake() ) 928 return; 929 UpdateVmixerLevel(); 930 } 931 932 if ( !WaitForHandshake() ) 933 return; 934 935 ClearHandshake(); 936 SendVector( DSP_VC_UPDATE_FLAGS ); 937 938 ECHO_DEBUGPRINTF(("RestoreDspSettings done\n")); 939 940 } // void CDspCommObject::RestoreDspSettings() 941 942 943 944 945 /**************************************************************************** 946 947 DSP utilities 948 949 ****************************************************************************/ 950 951 //=========================================================================== 952 // 953 // Write_DSP writes a 32-bit value to the DSP; this is used almost 954 // exclusively for loading the DSP. 955 // 956 //=========================================================================== 957 958 ECHOSTATUS CDspCommObject::Write_DSP 959 ( 960 DWORD dwData // 32 bit value to write to DSP data register 961 ) 962 { 963 DWORD dwStatus; 964 ULONGLONG ullCurTime, ullTimeout; 965 966 // ECHO_DEBUGPRINTF(("Write_DSP\n")); 967 968 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 969 ullTimeout = ullCurTime + 10000000L; // 10 sec. 970 while ( ullTimeout >= ullCurTime ) 971 { 972 dwStatus = GetDspRegister( CHI32_STATUS_REG ); 973 if ( ( dwStatus & CHI32_STATUS_HOST_WRITE_EMPTY ) != 0 ) 974 { 975 SetDspRegister( CHI32_DATA_REG, dwData ); 976 // ECHO_DEBUGPRINTF(("Write DSP: 0x%x", dwData)); 977 return ECHOSTATUS_OK; 978 } 979 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 980 } 981 982 m_bBadBoard = TRUE; // Set TRUE until DSP re-loaded 983 984 ECHO_DEBUGPRINTF(("CDspCommObject::Write_DSP Set m_bBadBoard to TRUE\n")); 985 986 return ECHOSTATUS_DSP_TIMEOUT; 987 988 } // ECHOSTATUS CDspCommObject::Write_DSP 989 990 991 //=========================================================================== 992 // 993 // Read_DSP reads a 32-bit value from the DSP; this is used almost 994 // exclusively for loading the DSP and checking the status of the ASIC. 995 // 996 //=========================================================================== 997 998 ECHOSTATUS CDspCommObject::Read_DSP 999 ( 1000 DWORD *pdwData // Ptr to 32 bit value read from DSP data register 1001 ) 1002 { 1003 DWORD dwStatus; 1004 ULONGLONG ullCurTime, ullTimeout; 1005 1006 // ECHO_DEBUGPRINTF(("Read_DSP\n")); 1007 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 1008 1009 ullTimeout = ullCurTime + READ_DSP_TIMEOUT; 1010 while ( ullTimeout >= ullCurTime ) 1011 { 1012 dwStatus = GetDspRegister( CHI32_STATUS_REG ); 1013 if ( ( dwStatus & CHI32_STATUS_HOST_READ_FULL ) != 0 ) 1014 { 1015 *pdwData = GetDspRegister( CHI32_DATA_REG ); 1016 // ECHO_DEBUGPRINTF(("Read DSP: 0x%x\n", *pdwData)); 1017 return ECHOSTATUS_OK; 1018 } 1019 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 1020 } 1021 1022 m_bBadBoard = TRUE; // Set TRUE until DSP re-loaded 1023 1024 ECHO_DEBUGPRINTF(("CDspCommObject::Read_DSP Set m_bBadBoard to TRUE\n")); 1025 1026 return ECHOSTATUS_DSP_TIMEOUT; 1027 } // ECHOSTATUS CDspCommObject::Read_DSP 1028 1029 1030 //=========================================================================== 1031 // 1032 // Much of the interaction between the DSP and the driver is done via vector 1033 // commands; SendVector writes a vector command to the DSP. Typically, 1034 // this causes the DSP to read or write fields in the comm page. 1035 // 1036 // Returns ECHOSTATUS_OK if sent OK. 1037 // 1038 //=========================================================================== 1039 1040 ECHOSTATUS CDspCommObject::SendVector 1041 ( 1042 DWORD dwCommand // 32 bit command to send to DSP vector register 1043 ) 1044 { 1045 ULONGLONG ullTimeout; 1046 ULONGLONG ullCurTime; 1047 1048 // 1049 // Turn this on if you want to see debug prints for every vector command 1050 // 1051 #if 0 1052 //#ifdef ECHO_DEBUG 1053 char * pszCmd; 1054 switch ( dwCommand ) 1055 { 1056 case DSP_VC_ACK_INT : 1057 pszCmd = "DSP_VC_ACK_INT"; 1058 break; 1059 case DSP_VC_SET_VMIXER_GAIN : 1060 pszCmd = "DSP_VC_SET_VMIXER_GAIN"; 1061 break; 1062 case DSP_VC_START_TRANSFER : 1063 pszCmd = "DSP_VC_START_TRANSFER"; 1064 break; 1065 case DSP_VC_METERS_ON : 1066 pszCmd = "DSP_VC_METERS_ON"; 1067 break; 1068 case DSP_VC_METERS_OFF : 1069 pszCmd = "DSP_VC_METERS_OFF"; 1070 break; 1071 case DSP_VC_UPDATE_OUTVOL : 1072 pszCmd = "DSP_VC_UPDATE_OUTVOL"; 1073 break; 1074 case DSP_VC_UPDATE_INGAIN : 1075 pszCmd = "DSP_VC_UPDATE_INGAIN"; 1076 break; 1077 case DSP_VC_ADD_AUDIO_BUFFER : 1078 pszCmd = "DSP_VC_ADD_AUDIO_BUFFER"; 1079 break; 1080 case DSP_VC_TEST_ASIC : 1081 pszCmd = "DSP_VC_TEST_ASIC"; 1082 break; 1083 case DSP_VC_UPDATE_CLOCKS : 1084 pszCmd = "DSP_VC_UPDATE_CLOCKS"; 1085 break; 1086 case DSP_VC_SET_LAYLA_SAMPLE_RATE : 1087 if ( GetCardType() == LAYLA ) 1088 pszCmd = "DSP_VC_SET_LAYLA_RATE"; 1089 else if ( GetCardType() == GINA || GetCardType() == DARLA ) 1090 pszCmd = "DSP_VC_SET_GD_AUDIO_STATE"; 1091 else 1092 pszCmd = "DSP_VC_WRITE_CONTROL_REG"; 1093 break; 1094 case DSP_VC_MIDI_WRITE : 1095 pszCmd = "DSP_VC_MIDI_WRITE"; 1096 break; 1097 case DSP_VC_STOP_TRANSFER : 1098 pszCmd = "DSP_VC_STOP_TRANSFER"; 1099 break; 1100 case DSP_VC_UPDATE_FLAGS : 1101 pszCmd = "DSP_VC_UPDATE_FLAGS"; 1102 break; 1103 case DSP_VC_RESET : 1104 pszCmd = "DSP_VC_RESET"; 1105 break; 1106 default : 1107 pszCmd = "?????"; 1108 break; 1109 } 1110 1111 ECHO_DEBUGPRINTF( ("SendVector: %s dwCommand %s (0x%x)\n", 1112 GetCardName(), 1113 pszCmd, 1114 dwCommand) ); 1115 #endif 1116 1117 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 1118 ullTimeout = ullCurTime + 100000L; // 100m.s. 1119 1120 // 1121 // Wait for the "vector busy" bit to be off 1122 // 1123 while ( ullCurTime <= ullTimeout) 1124 { 1125 if ( 0 == ( GetDspRegister( CHI32_VECTOR_REG ) & CHI32_VECTOR_BUSY ) ) 1126 { 1127 SetDspRegister( CHI32_VECTOR_REG, dwCommand ); 1128 return ECHOSTATUS_OK; 1129 } 1130 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 1131 } 1132 1133 ECHO_DEBUGPRINTF( ("\tPunked out on SendVector\n") ); 1134 ECHO_DEBUGBREAK(); 1135 return ECHOSTATUS_DSP_TIMEOUT; 1136 1137 } // ECHOSTATUS CDspCommObject::SendVector 1138 1139 1140 //=========================================================================== 1141 // 1142 // Some vector commands involve the DSP reading or writing data to and 1143 // from the comm page; if you send one of these commands to the DSP, 1144 // it will complete the command and then write a non-zero value to 1145 // the dwHandshake field in the comm page. This function waits for the 1146 // handshake to show up. 1147 // 1148 //=========================================================================== 1149 1150 BOOL CDspCommObject::WaitForHandshake() 1151 { 1152 int i; 1153 1154 // 1155 // Wait up to three milliseconds for the handshake from the DSP 1156 // 1157 for ( i = 0; i < HANDSHAKE_TIMEOUT; i++ ) 1158 { 1159 // Look for the handshake value 1160 if ( 0 != GetHandshakeFlag() ) 1161 break; 1162 1163 // Give the DSP time to access the comm page 1164 m_pOsSupport->OsSnooze( 2 ); 1165 } 1166 1167 if ( HANDSHAKE_TIMEOUT == i ) 1168 { 1169 ECHO_DEBUGPRINTF( ("CDspCommObject::WaitForHandshake: Timeout waiting " 1170 "for DSP\n") ); 1171 ECHO_DEBUGBREAK(); 1172 return FALSE; 1173 } 1174 1175 return TRUE; 1176 1177 } // DWORD CDspCommObject::WaitForHandshake() 1178 1179 1180 1181 1182 /**************************************************************************** 1183 1184 Transport methods 1185 1186 ****************************************************************************/ 1187 1188 //=========================================================================== 1189 // 1190 // StartTransport starts transport for a set of pipes 1191 // 1192 //=========================================================================== 1193 1194 ECHOSTATUS CDspCommObject::StartTransport 1195 ( 1196 PCChannelMask pChannelMask, // Pipes to start 1197 PCChannelMask pCyclicMask // Which pipes are cyclic buffers 1198 ) 1199 { 1200 ECHO_DEBUGPRINTF( ("StartTransport\n") ); 1201 1202 // 1203 // Wait for the previous command to complete 1204 // 1205 if ( !WaitForHandshake() ) 1206 return ECHOSTATUS_DSP_DEAD; 1207 1208 // 1209 // Write the appropriate fields in the comm page 1210 // 1211 m_pDspCommPage->cmdStart += *pChannelMask; 1212 m_pDspCommPage->cmdCyclicBuffer += *pCyclicMask; 1213 if ( !m_pDspCommPage->cmdStart.IsEmpty() ) 1214 { 1215 // 1216 // Clear the handshake and send the vector command 1217 // 1218 ClearHandshake(); 1219 SendVector( DSP_VC_START_TRANSFER ); 1220 1221 // 1222 // Wait for transport to start 1223 // 1224 if ( !WaitForHandshake() ) 1225 return ECHOSTATUS_DSP_DEAD; 1226 1227 // 1228 // Keep track of which pipes are transporting 1229 // 1230 m_cmActive += *pChannelMask; 1231 m_pDspCommPage->cmdStart.Clear(); 1232 1233 return ECHOSTATUS_OK; 1234 } // if this monkey is being started 1235 1236 ECHO_DEBUGPRINTF( ("CDspCommObject::StartTransport: No pipes to start!\n") ); 1237 return ECHOSTATUS_INVALID_CHANNEL; 1238 1239 } // ECHOSTATUS CDspCommObject::StartTransport 1240 1241 1242 //=========================================================================== 1243 // 1244 // StopTransport pauses transport for a set of pipes 1245 // 1246 //=========================================================================== 1247 1248 ECHOSTATUS CDspCommObject::StopTransport 1249 ( 1250 PCChannelMask pChannelMask 1251 ) 1252 { 1253 ECHO_DEBUGPRINTF(("StopTransport\n")); 1254 1255 // 1256 // Wait for the last command to finish 1257 // 1258 if ( !WaitForHandshake() ) 1259 return ECHOSTATUS_DSP_DEAD; 1260 1261 // 1262 // Write to the comm page 1263 // 1264 m_pDspCommPage->cmdStop += *pChannelMask; 1265 m_pDspCommPage->cmdReset.Clear(); 1266 if ( !m_pDspCommPage->cmdStop.IsEmpty() ) 1267 { 1268 // 1269 // Clear the handshake and send the vector command 1270 // 1271 ClearHandshake(); 1272 SendVector( DSP_VC_STOP_TRANSFER ); 1273 1274 // 1275 // Wait for transport to stop 1276 // 1277 if ( !WaitForHandshake() ) 1278 return ECHOSTATUS_DSP_DEAD; 1279 1280 // 1281 // Keep track of which pipes are transporting 1282 // 1283 m_cmActive -= *pChannelMask; 1284 m_pDspCommPage->cmdStop.Clear(); 1285 m_pDspCommPage->cmdReset.Clear(); 1286 1287 return ECHOSTATUS_OK; 1288 } // if this monkey is being started 1289 1290 ECHO_DEBUGPRINTF( ("CDspCommObject::StopTransport: No pipes to stop!\n") ); 1291 return ECHOSTATUS_OK; 1292 1293 } // ECHOSTATUS CDspCommObject::StopTransport 1294 1295 1296 //=========================================================================== 1297 // 1298 // ResetTransport resets transport for a set of pipes 1299 // 1300 //=========================================================================== 1301 1302 ECHOSTATUS CDspCommObject::ResetTransport 1303 ( 1304 PCChannelMask pChannelMask 1305 ) 1306 { 1307 ECHO_DEBUGPRINTF(("ResetTransport\n")); 1308 1309 // 1310 // Wait for the last command to finish 1311 // 1312 if ( !WaitForHandshake() ) 1313 return ECHOSTATUS_DSP_DEAD; 1314 1315 // 1316 // Write to the comm page 1317 // 1318 m_pDspCommPage->cmdStop += *pChannelMask; 1319 m_pDspCommPage->cmdReset += *pChannelMask; 1320 if ( !m_pDspCommPage->cmdReset.IsEmpty() ) 1321 { 1322 // 1323 // Clear the handshake and send the vector command 1324 // 1325 ClearHandshake(); 1326 SendVector( DSP_VC_STOP_TRANSFER ); 1327 1328 // 1329 // Wait for transport to stop 1330 // 1331 if ( !WaitForHandshake() ) 1332 return ECHOSTATUS_DSP_DEAD; 1333 1334 // 1335 // Keep track of which pipes are transporting 1336 // 1337 m_cmActive -= *pChannelMask; 1338 m_pDspCommPage->cmdStop.Clear(); 1339 m_pDspCommPage->cmdReset.Clear(); 1340 1341 return ECHOSTATUS_OK; 1342 } // if this monkey is being started 1343 1344 ECHO_DEBUGPRINTF( ("CDspCommObject::ResetTransport: No pipes to reset!\n") ); 1345 return ECHOSTATUS_OK; 1346 1347 } // ECHOSTATUS CDspCommObject::ResetTransport 1348 1349 1350 //=========================================================================== 1351 // 1352 // Calling AddBuffer tells the DSP to increment its internal buffer 1353 // count for a given pipe. 1354 // 1355 //=========================================================================== 1356 1357 ECHOSTATUS CDspCommObject::AddBuffer( WORD wPipeIndex ) 1358 { 1359 // 1360 // Parameter check 1361 // 1362 if ( wPipeIndex >= GetNumPipes()) 1363 { 1364 ECHO_DEBUGPRINTF( ("CDspCommObject::AddBuffer: Invalid pipe %d\n", 1365 wPipeIndex) ); 1366 return ECHOSTATUS_INVALID_CHANNEL; 1367 } 1368 1369 // 1370 // Wait for the last command 1371 // 1372 if ( !WaitForHandshake() ) 1373 return ECHOSTATUS_DSP_DEAD; 1374 1375 // 1376 // Write to the comm page 1377 // 1378 m_pDspCommPage->cmdAddBuffer.Clear(); 1379 m_pDspCommPage->cmdAddBuffer.SetIndexInMask( wPipeIndex ); 1380 1381 // 1382 // Clear the handshake and send the vector command 1383 // 1384 ClearHandshake(); 1385 return SendVector( DSP_VC_ADD_AUDIO_BUFFER ); 1386 1387 } // ECHOSTATUS CDspCommObject::AddOutBuffer( WORD wPipeIndex ) 1388 1389 1390 //=========================================================================== 1391 // 1392 // This tells the DSP where to start reading the scatter-gather list 1393 // for a given pipe. 1394 // 1395 //=========================================================================== 1396 1397 void CDspCommObject::SetAudioDuckListPhys 1398 ( 1399 WORD wPipeIndex, // Pipe index 1400 DWORD dwNewPhysAdr // Physical address asserted on the PCI bus 1401 ) 1402 { 1403 if (wPipeIndex < GetNumPipes() ) 1404 { 1405 m_pDspCommPage->dwDuckListPhys[ wPipeIndex ].PhysAddr = 1406 SWAP( dwNewPhysAdr ); 1407 } 1408 } // void CDspCommObject::SetAudioDuckListPhys 1409 1410 1411 1412 //=========================================================================== 1413 // 1414 // Get a mask with active pipes 1415 // 1416 //=========================================================================== 1417 1418 void CDspCommObject::GetActivePipes 1419 ( 1420 PCChannelMask pChannelMask 1421 ) 1422 { 1423 pChannelMask->Clear(); 1424 *pChannelMask += m_cmActive; 1425 } // void CDspCommObject::GetActivePipes() 1426 1427 1428 //=========================================================================== 1429 // 1430 // Set the audio format for a pipe 1431 // 1432 //=========================================================================== 1433 1434 ECHOSTATUS CDspCommObject::SetAudioFormat 1435 ( 1436 WORD wPipeIndex, 1437 PECHOGALS_AUDIOFORMAT pFormat, 1438 BOOL fDitherDigitalInputs 1439 ) 1440 { 1441 WORD wDspFormat = DSP_AUDIOFORM_SS_16LE; 1442 1443 // 1444 // Check the pipe number 1445 // 1446 if (wPipeIndex >= GetNumPipes() ) 1447 { 1448 ECHO_DEBUGPRINTF( ("CDspCommObject::SetAudioFormat: Invalid pipe" 1449 "%d\n", 1450 wPipeIndex) ); 1451 return ECHOSTATUS_INVALID_CHANNEL; 1452 } 1453 1454 // 1455 // Look for super-interleave 1456 // 1457 if (pFormat->wDataInterleave > 2) 1458 { 1459 wDspFormat = DSP_AUDIOFORM_SUPER_INTERLEAVE_32LE 1460 | pFormat->wDataInterleave; 1461 } 1462 else 1463 { 1464 // 1465 // For big-endian data, only 32 bit mono->mono samples and 32 bit stereo->stereo 1466 // are supported 1467 // 1468 if (pFormat->byDataAreBigEndian) 1469 { 1470 1471 switch ( pFormat->wDataInterleave ) 1472 { 1473 case 1 : 1474 wDspFormat = DSP_AUDIOFORM_MM_32BE; 1475 break; 1476 1477 #ifdef STEREO_BIG_ENDIAN32_SUPPORT 1478 case 2 : 1479 wDspFormat = DSP_AUDIOFORM_SS_32BE; 1480 break; 1481 #endif 1482 1483 } 1484 } 1485 else 1486 { 1487 // 1488 // Check for 32 bit little-endian mono->mono case 1489 // 1490 if ( (1 == pFormat->wDataInterleave) && 1491 (32 == pFormat->wBitsPerSample) && 1492 (0 == pFormat->byMonoToStereo) ) 1493 { 1494 wDspFormat = DSP_AUDIOFORM_MM_32LE; 1495 } 1496 else 1497 { 1498 // 1499 // Handle the other little-endian formats 1500 // 1501 switch (pFormat->wBitsPerSample) 1502 { 1503 case 8 : 1504 if (2 == pFormat->wDataInterleave) 1505 wDspFormat = DSP_AUDIOFORM_SS_8; 1506 else 1507 wDspFormat = DSP_AUDIOFORM_MS_8; 1508 1509 break; 1510 1511 default : 1512 case 16 : 1513 1514 // 1515 // If this is a digital input and 1516 // the no dither flag is set, use the no-dither format 1517 // 1518 if ( fDitherDigitalInputs && 1519 (wPipeIndex >= (m_wNumPipesOut + m_wFirstDigitalBusIn)) ) 1520 1521 { 1522 // 1523 // 16 bit, no dither 1524 // 1525 if (2 == pFormat->wDataInterleave) 1526 wDspFormat = DSP_AUDIOFORM_SS_16LE_ND; 1527 else 1528 wDspFormat = DSP_AUDIOFORM_MS_16LE_ND; 1529 } 1530 else 1531 { 1532 // 1533 // 16 bit with dither 1534 // 1535 if (2 == pFormat->wDataInterleave) 1536 wDspFormat = DSP_AUDIOFORM_SS_16LE; 1537 else 1538 wDspFormat = DSP_AUDIOFORM_MS_16LE; 1539 } 1540 1541 break; 1542 1543 case 32 : 1544 if (2 == pFormat->wDataInterleave) 1545 wDspFormat = DSP_AUDIOFORM_SS_32LE; 1546 else 1547 wDspFormat = DSP_AUDIOFORM_MS_32LE; 1548 break; 1549 } 1550 1551 } // check other little-endian formats 1552 1553 } // not big endian data 1554 1555 } // not super-interleave 1556 1557 m_pDspCommPage->wAudioFormat[wPipeIndex] = SWAP( wDspFormat ); 1558 1559 return ECHOSTATUS_OK; 1560 1561 } // ECHOSTATUS CDspCommObject::SetAudioFormat 1562 1563 1564 //=========================================================================== 1565 // 1566 // Get the audio format for a pipe 1567 // 1568 //=========================================================================== 1569 1570 ECHOSTATUS CDspCommObject::GetAudioFormat 1571 ( 1572 WORD wPipeIndex, 1573 PECHOGALS_AUDIOFORMAT pFormat 1574 ) 1575 { 1576 if (wPipeIndex >= GetNumPipes() ) 1577 { 1578 ECHO_DEBUGPRINTF( ("CDspCommObject::GetAudioFormat: Invalid pipe %d\n", 1579 wPipeIndex) ); 1580 1581 return ECHOSTATUS_INVALID_CHANNEL; 1582 } 1583 1584 pFormat->byDataAreBigEndian = 0; // true for most of the formats 1585 pFormat->byMonoToStereo = 0; 1586 1587 switch (SWAP(m_pDspCommPage->wAudioFormat[wPipeIndex])) 1588 { 1589 case DSP_AUDIOFORM_MS_8 : 1590 pFormat->wDataInterleave = 1; 1591 pFormat->wBitsPerSample = 8; 1592 pFormat->byMonoToStereo = 1; 1593 break; 1594 1595 case DSP_AUDIOFORM_MS_16LE_ND : 1596 case DSP_AUDIOFORM_MS_16LE : 1597 pFormat->wDataInterleave = 1; 1598 pFormat->wBitsPerSample = 16; 1599 pFormat->byMonoToStereo = 1; 1600 break; 1601 1602 case DSP_AUDIOFORM_SS_8 : 1603 pFormat->wDataInterleave = 2; 1604 pFormat->wBitsPerSample = 8; 1605 break; 1606 1607 case DSP_AUDIOFORM_SS_16LE_ND : 1608 case DSP_AUDIOFORM_SS_16LE : 1609 pFormat->wDataInterleave = 2; 1610 pFormat->wBitsPerSample = 16; 1611 break; 1612 1613 case DSP_AUDIOFORM_SS_32LE : 1614 pFormat->wDataInterleave = 2; 1615 pFormat->wBitsPerSample = 32; 1616 break; 1617 1618 case DSP_AUDIOFORM_MS_32LE : 1619 pFormat->byMonoToStereo = 1; 1620 // fall through 1621 1622 case DSP_AUDIOFORM_MM_32LE : 1623 pFormat->wDataInterleave = 1; 1624 pFormat->wBitsPerSample = 32; 1625 break; 1626 1627 case DSP_AUDIOFORM_MM_32BE : 1628 pFormat->wDataInterleave = 1; 1629 pFormat->wBitsPerSample = 32; 1630 pFormat->byDataAreBigEndian = 1; 1631 break; 1632 1633 case DSP_AUDIOFORM_SS_32BE : 1634 pFormat->wDataInterleave = 2; 1635 pFormat->wBitsPerSample = 32; 1636 pFormat->byDataAreBigEndian = 1; 1637 break; 1638 1639 } 1640 1641 return ECHOSTATUS_OK; 1642 1643 } // void CDspCommObject::GetAudioFormat 1644 1645 1646 /**************************************************************************** 1647 1648 Mixer methods 1649 1650 ****************************************************************************/ 1651 1652 //=========================================================================== 1653 // 1654 // SetPipeOutGain - set the gain for a single output pipe 1655 // 1656 //=========================================================================== 1657 1658 ECHOSTATUS CDspCommObject::SetPipeOutGain 1659 ( 1660 WORD wPipeOut, 1661 WORD wBusOut, 1662 int iGain, 1663 BOOL fImmediate 1664 ) 1665 { 1666 if ( wPipeOut < m_wNumPipesOut ) 1667 { 1668 // 1669 // Wait for the handshake 1670 // 1671 if ( !WaitForHandshake() ) 1672 return ECHOSTATUS_DSP_DEAD; 1673 1674 // 1675 // Save the new value 1676 // 1677 iGain = GENERIC_TO_DSP(iGain); 1678 m_pDspCommPage->OutLineLevel[ wPipeOut ] = (BYTE) iGain; 1679 1680 ECHO_DEBUGPRINTF( ("CDspCommObject::SetPipeOutGain: Out pipe %d " 1681 "= 0x%x\n", 1682 wPipeOut, 1683 iGain) ); 1684 1685 // 1686 // If fImmediate is true, then do the gain setting right now. 1687 // If you want to do a batch of gain settings all at once, it's 1688 // more efficient to call this several times and then only set 1689 // fImmediate for the last one; then the DSP picks up all of 1690 // them at once. 1691 // 1692 if (fImmediate) 1693 { 1694 return UpdateAudioOutLineLevel(); 1695 } 1696 1697 return ECHOSTATUS_OK; 1698 1699 } 1700 1701 ECHO_DEBUGPRINTF( ("CDspCommObject::SetPipeOutGain: Invalid out pipe " 1702 "%d\n", 1703 wPipeOut) ); 1704 ECHO_DEBUGBREAK(); 1705 1706 return ECHOSTATUS_INVALID_CHANNEL; 1707 1708 } // SetPipeOutGain 1709 1710 1711 //=========================================================================== 1712 // 1713 // GetPipeOutGain returns the current gain for an output pipe. This isn't 1714 // really used as the mixer code in CEchoGals stores logical values for 1715 // these, but it's here for completeness. 1716 // 1717 //=========================================================================== 1718 1719 ECHOSTATUS CDspCommObject::GetPipeOutGain 1720 ( 1721 WORD wPipeOut, 1722 WORD wBusOut, 1723 int &iGain 1724 ) 1725 { 1726 if (wPipeOut < m_wNumPipesOut) 1727 { 1728 iGain = (int) (char) m_pDspCommPage->OutLineLevel[ wPipeOut ]; 1729 iGain = DSP_TO_GENERIC(8); 1730 return ECHOSTATUS_OK; 1731 } 1732 1733 ECHO_DEBUGPRINTF( ("CDspCommObject::GetPipeOutGain: Invalid out pipe " 1734 "%d\n", 1735 wPipeOut) ); 1736 1737 return ECHOSTATUS_INVALID_CHANNEL; 1738 1739 } // GetPipeOutGain 1740 1741 1742 1743 //=========================================================================== 1744 // 1745 // Set input bus gain - iGain is in units of 0.5 dB 1746 // 1747 //=========================================================================== 1748 1749 ECHOSTATUS CDspCommObject::SetBusInGain( WORD wBusIn, int iGain) 1750 { 1751 if (wBusIn > m_wNumBussesIn) 1752 return ECHOSTATUS_INVALID_CHANNEL; 1753 1754 // 1755 // Wait for the handshake (OK even if ASIC is not loaded) 1756 // 1757 if ( !WaitForHandshake() ) 1758 return ECHOSTATUS_DSP_DEAD; 1759 1760 // 1761 // Adjust the gain value 1762 // 1763 iGain += GL20_INPUT_GAIN_MAGIC_NUMBER; 1764 1765 // 1766 // Put it in the comm page 1767 // 1768 m_pDspCommPage->InLineLevel[wBusIn] = (BYTE) iGain; 1769 1770 return UpdateAudioInLineLevel(); 1771 } 1772 1773 1774 //=========================================================================== 1775 // 1776 // Get the input bus gain in units of 0.5 dB 1777 // 1778 //=========================================================================== 1779 1780 ECHOSTATUS CDspCommObject::GetBusInGain( WORD wBusIn, int &iGain) 1781 { 1782 if (wBusIn > m_wNumBussesIn) 1783 return ECHOSTATUS_INVALID_CHANNEL; 1784 1785 iGain = m_pDspCommPage->InLineLevel[wBusIn]; 1786 iGain -= GL20_INPUT_GAIN_MAGIC_NUMBER; 1787 1788 return ECHOSTATUS_OK; 1789 } 1790 1791 1792 //=========================================================================== 1793 // 1794 // Set the nominal level for an input or output bus 1795 // 1796 // bState TRUE -10 nominal level 1797 // bState FALSE +4 nominal level 1798 // 1799 //=========================================================================== 1800 1801 ECHOSTATUS CDspCommObject::SetNominalLevel 1802 ( 1803 WORD wBus, 1804 BOOL bState 1805 ) 1806 { 1807 // 1808 // Check the pipe index 1809 // 1810 if (wBus < (m_wNumBussesOut + m_wNumBussesIn)) 1811 { 1812 // 1813 // Wait for the handshake (OK even if ASIC is not loaded) 1814 // 1815 if ( !WaitForHandshake() ) 1816 return ECHOSTATUS_DSP_DEAD; 1817 1818 // 1819 // Set the nominal bit 1820 // 1821 if ( bState ) 1822 m_pDspCommPage->cmdNominalLevel.SetIndexInMask( wBus ); 1823 else 1824 m_pDspCommPage->cmdNominalLevel.ClearIndexInMask( wBus ); 1825 1826 return UpdateAudioOutLineLevel(); 1827 } 1828 1829 ECHO_DEBUGPRINTF( ("CDspCommObject::SetNominalOutLineLevel Invalid " 1830 "index %d\n", 1831 wBus ) ); 1832 return ECHOSTATUS_INVALID_CHANNEL; 1833 1834 } // ECHOSTATUS CDspCommObject::SetNominalLevel 1835 1836 1837 //=========================================================================== 1838 // 1839 // Get the nominal level for an input or output bus 1840 // 1841 // bState TRUE -10 nominal level 1842 // bState FALSE +4 nominal level 1843 // 1844 //=========================================================================== 1845 1846 ECHOSTATUS CDspCommObject::GetNominalLevel 1847 ( 1848 WORD wBus, 1849 PBYTE pbyState 1850 ) 1851 { 1852 1853 if (wBus < (m_wNumBussesOut + m_wNumBussesIn)) 1854 { 1855 *pbyState = (BYTE) 1856 m_pDspCommPage->cmdNominalLevel.TestIndexInMask( wBus ); 1857 return ECHOSTATUS_OK; 1858 } 1859 1860 ECHO_DEBUGPRINTF( ("CDspCommObject::GetNominalLevel Invalid " 1861 "index %d\n", 1862 wBus ) ); 1863 return ECHOSTATUS_INVALID_CHANNEL; 1864 } // ECHOSTATUS CDspCommObject::GetNominalLevel 1865 1866 1867 //=========================================================================== 1868 // 1869 // Set the monitor level from an input bus to an output bus. 1870 // 1871 //=========================================================================== 1872 1873 ECHOSTATUS CDspCommObject::SetAudioMonitor 1874 ( 1875 WORD wBusOut, // output bus 1876 WORD wBusIn, // input bus 1877 int iGain, 1878 BOOL fImmediate 1879 ) 1880 { 1881 /* 1882 ECHO_DEBUGPRINTF( ("CDspCommObject::SetAudioMonitor: " 1883 "Out %d in %d Gain %d (0x%x)\n", 1884 wBusOut, wBusIn, iGain, iGain) ); 1885 */ 1886 1887 // 1888 // The monitor array is a one-dimensional array; 1889 // compute the offset into the array 1890 // 1891 WORD wOffset = ComputeAudioMonitorIndex( wBusOut, wBusIn ); 1892 1893 // 1894 // Wait for the offset 1895 // 1896 if ( !WaitForHandshake() ) 1897 return ECHOSTATUS_DSP_DEAD; 1898 1899 // 1900 // Write the gain value to the comm page 1901 // 1902 iGain = GENERIC_TO_DSP(iGain); 1903 m_pDspCommPage->byMonitors[ wOffset ] = (BYTE) (iGain); 1904 1905 // 1906 // If fImmediate is set, do the command right now 1907 // 1908 if (fImmediate) 1909 { 1910 return UpdateAudioOutLineLevel(); 1911 } 1912 1913 return ECHOSTATUS_OK; 1914 1915 } // ECHOSTATUS CDspCommObject::SetAudioMonitor 1916 1917 1918 //=========================================================================== 1919 // 1920 // SetMetersOn turns the meters on or off. If meters are turned on, the 1921 // DSP will write the meter and clock detect values to the comm page 1922 // at about 30 Hz. 1923 // 1924 //=========================================================================== 1925 1926 ECHOSTATUS CDspCommObject::SetMetersOn 1927 ( 1928 BOOL bOn 1929 ) 1930 { 1931 if ( bOn ) 1932 { 1933 if ( 0 == m_wMeterOnCount ) 1934 { 1935 SendVector( DSP_VC_METERS_ON ); 1936 } 1937 m_wMeterOnCount++; 1938 } 1939 else 1940 { 1941 int iDevice; 1942 1943 if ( m_wMeterOnCount == 0 ) 1944 return ECHOSTATUS_OK; 1945 1946 if ( 0 == --m_wMeterOnCount ) 1947 { 1948 SendVector( DSP_VC_METERS_OFF ); 1949 1950 for ( iDevice = 0; iDevice < DSP_MAXPIPES; iDevice++ ) 1951 { 1952 m_pDspCommPage->VULevel[ iDevice ] = GENERIC_TO_DSP(ECHOGAIN_MUTED); 1953 m_pDspCommPage->PeakMeter[ iDevice ] = GENERIC_TO_DSP(ECHOGAIN_MUTED); 1954 } 1955 } 1956 } 1957 return ECHOSTATUS_OK; 1958 1959 } // ECHOSTATUS CDspCommObject::SetMetersOn 1960 1961 1962 //=========================================================================== 1963 // 1964 // Tell the DSP to read and update output, nominal & monitor levels 1965 // in comm page. 1966 // 1967 //=========================================================================== 1968 1969 ECHOSTATUS CDspCommObject::UpdateAudioOutLineLevel() 1970 { 1971 ECHO_DEBUGPRINTF( ( "CDspCommObject::UpdateAudioOutLineLevel:\n" ) ); 1972 1973 if (FALSE == m_bASICLoaded) 1974 return ECHOSTATUS_ASIC_NOT_LOADED; 1975 1976 ClearHandshake(); 1977 return( SendVector( DSP_VC_UPDATE_OUTVOL ) ); 1978 } // ECHOSTATUS CDspCommObject::UpdateAudioOutLineLevel() 1979 1980 1981 //=========================================================================== 1982 // 1983 // Tell the DSP to read and update input levels in comm page 1984 // 1985 //=========================================================================== 1986 1987 ECHOSTATUS CDspCommObject::UpdateAudioInLineLevel() 1988 { 1989 //ECHO_DEBUGPRINTF( ( "CDspCommObject::UpdateAudioInLineLevel:\n" ) ); 1990 1991 if (FALSE == m_bASICLoaded) 1992 return ECHOSTATUS_ASIC_NOT_LOADED; 1993 1994 ClearHandshake(); 1995 return( SendVector( DSP_VC_UPDATE_INGAIN ) ); 1996 } // ECHOSTATUS CDspCommObject::UpdateAudioInLineLevel() 1997 1998 1999 //=========================================================================== 2000 // 2001 // Tell the DSP to read and update virtual mixer levels 2002 // in comm page. This method is overridden by cards that actually 2003 // support a vmixer. 2004 // 2005 //=========================================================================== 2006 2007 ECHOSTATUS CDspCommObject::UpdateVmixerLevel() 2008 { 2009 ECHO_DEBUGPRINTF(("CDspCommObject::UpdateVmixerLevel\n")); 2010 return ECHOSTATUS_NOT_SUPPORTED; 2011 } // ECHOSTATUS CDspCommObject::UpdateVmixerLevel() 2012 2013 2014 //=========================================================================== 2015 // 2016 // Tell the DSP to change the input clock 2017 // 2018 //=========================================================================== 2019 2020 ECHOSTATUS CDspCommObject::SetInputClock(WORD wClock) 2021 { 2022 // 2023 // Wait for the last command 2024 // 2025 if (!WaitForHandshake()) 2026 return ECHOSTATUS_DSP_DEAD; 2027 2028 ECHO_DEBUGPRINTF( ("CDspCommObject::SetInputClock:\n") ); 2029 2030 // 2031 // Write to the comm page 2032 // 2033 m_pDspCommPage->wInputClock = SWAP(wClock); 2034 2035 // 2036 // Clear the handshake and send the command 2037 // 2038 ClearHandshake(); 2039 ECHOSTATUS Status = SendVector(DSP_VC_UPDATE_CLOCKS); 2040 2041 return Status; 2042 2043 } // ECHOSTATUS CDspCommObject::SetInputClock 2044 2045 2046 //=========================================================================== 2047 // 2048 // Tell the DSP to change the output clock - Layla20 only 2049 // 2050 //=========================================================================== 2051 2052 ECHOSTATUS CDspCommObject::SetOutputClock(WORD wClock) 2053 { 2054 2055 return ECHOSTATUS_CLOCK_NOT_SUPPORTED; 2056 2057 } // ECHOSTATUS CDspCommObject::SetOutputClock 2058 2059 2060 //=========================================================================== 2061 // 2062 // Fill out an ECHOGALS_METERS struct using the current values in the 2063 // comm page. This method is overridden for vmixer cards. 2064 // 2065 //=========================================================================== 2066 2067 ECHOSTATUS CDspCommObject::GetAudioMeters 2068 ( 2069 PECHOGALS_METERS pMeters 2070 ) 2071 { 2072 pMeters->iNumPipesOut = 0; 2073 pMeters->iNumPipesIn = 0; 2074 2075 // 2076 // Output 2077 // 2078 DWORD dwCh = 0; 2079 WORD i; 2080 2081 pMeters->iNumBussesOut = (int) m_wNumBussesOut; 2082 for (i = 0; i < m_wNumBussesOut; i++) 2083 { 2084 pMeters->iBusOutVU[i] = 2085 DSP_TO_GENERIC( ((int) (char) m_pDspCommPage->VULevel[ dwCh ]) ); 2086 2087 pMeters->iBusOutPeak[i] = 2088 DSP_TO_GENERIC( ((int) (char) m_pDspCommPage->PeakMeter[ dwCh ]) ); 2089 2090 dwCh++; 2091 } 2092 2093 pMeters->iNumBussesIn = (int) m_wNumBussesIn; 2094 for (i = 0; i < m_wNumBussesIn; i++) 2095 { 2096 pMeters->iBusInVU[i] = 2097 DSP_TO_GENERIC( ((int) (char) m_pDspCommPage->VULevel[ dwCh ]) ); 2098 pMeters->iBusInPeak[i] = 2099 DSP_TO_GENERIC( ((int) (char) m_pDspCommPage->PeakMeter[ dwCh ]) ); 2100 2101 dwCh++; 2102 } 2103 2104 return ECHOSTATUS_OK; 2105 2106 } // GetAudioMeters 2107 2108 2109 #ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT 2110 2111 //=========================================================================== 2112 // 2113 // Digital input auto-mute - Gina24, Layla24, and Mona only 2114 // 2115 //=========================================================================== 2116 2117 ECHOSTATUS CDspCommObject::GetDigitalInputAutoMute(BOOL &fAutoMute) 2118 { 2119 fAutoMute = m_fDigitalInAutoMute; 2120 2121 ECHO_DEBUGPRINTF(("CDspCommObject::GetDigitalInputAutoMute %d\n",fAutoMute)); 2122 2123 return ECHOSTATUS_OK; 2124 } 2125 2126 ECHOSTATUS CDspCommObject::SetDigitalInputAutoMute(BOOL fAutoMute) 2127 { 2128 ECHO_DEBUGPRINTF(("CDspCommObject::SetDigitalInputAutoMute %d\n",fAutoMute)); 2129 2130 // 2131 // Store the flag 2132 // 2133 m_fDigitalInAutoMute = fAutoMute; 2134 2135 // 2136 // Re-set the input clock to the current value - indirectly causes the 2137 // auto-mute flag to be sent to the DSP 2138 // 2139 SetInputClock(m_wInputClock); 2140 2141 return ECHOSTATUS_OK; 2142 } 2143 2144 #endif // DIGITAL_INPUT_AUTO_MUTE_SUPPORT 2145 2146 2147 2148 2149 /**************************************************************************** 2150 2151 Power management 2152 2153 ****************************************************************************/ 2154 2155 //=========================================================================== 2156 // 2157 // Tell the DSP to go into low-power mode 2158 // 2159 //=========================================================================== 2160 2161 ECHOSTATUS CDspCommObject::GoComatose() 2162 { 2163 ECHO_DEBUGPRINTF(("CDspCommObject::GoComatose\n")); 2164 2165 if (NULL != m_pwDspCode) 2166 { 2167 // 2168 // Make LoadFirmware do a complete reload 2169 // 2170 m_pwDspCode = NULL; 2171 2172 // 2173 // Put the DSP to sleep 2174 // 2175 return SendVector(DSP_VC_GO_COMATOSE); 2176 } 2177 2178 return ECHOSTATUS_OK; 2179 2180 } // end of GoComatose 2181 2182 2183 2184 #ifdef MIDI_SUPPORT 2185 2186 /**************************************************************************** 2187 2188 MIDI 2189 2190 ****************************************************************************/ 2191 2192 //=========================================================================== 2193 // 2194 // Send a buffer full of MIDI data to the DSP 2195 // 2196 //=========================================================================== 2197 2198 ECHOSTATUS CDspCommObject::WriteMidi 2199 ( 2200 PBYTE pData, // Ptr to data buffer 2201 DWORD dwLength, // How many bytes to write 2202 PDWORD pdwActualCt // Return how many actually written 2203 ) 2204 { 2205 ECHOSTATUS Status; 2206 DWORD dwLengthTemp, dwShift, dwPacked, i; 2207 #ifdef ECHO_DEBUG 2208 DWORD dwOrgLgth = dwLength; 2209 #endif 2210 2211 // 2212 // Send all the MIDI data 2213 // 2214 *pdwActualCt = 0; 2215 Status = ECHOSTATUS_OK; 2216 2217 while ( dwLength > 0 ) 2218 { 2219 // 2220 // Wait for the last command to complete 2221 // 2222 if (FALSE == WaitForHandshake()) 2223 { 2224 ECHO_DEBUGPRINTF(("CDspCommObject::WriteMidi - Timed out waiting for handshake\n")); 2225 2226 Status = ECHOSTATUS_DSP_DEAD; 2227 break; 2228 } 2229 2230 // 2231 // See if the DSP is ready to go 2232 // 2233 if (0 == (GetDspRegister( CHI32_STATUS_REG) & CHI32_STATUS_REG_HF4)) 2234 { 2235 // 2236 // MIDI output is full 2237 // 2238 break; 2239 } 2240 2241 // 2242 // Pack the MIDI data three bytes at a time 2243 // 2244 if ( dwLength > 3 ) 2245 dwLengthTemp = 3; 2246 else 2247 dwLengthTemp = dwLength; 2248 2249 dwShift = 16; 2250 dwPacked = 0; 2251 for ( i = 0; i < dwLengthTemp; i++ ) 2252 { 2253 dwPacked |= (DWORD) *pData++ << dwShift; 2254 dwShift -= 8; 2255 } 2256 2257 dwPacked |= dwLengthTemp << 24; 2258 dwLength -= dwLengthTemp; 2259 2260 // 2261 // Write the data to the DSP 2262 // 2263 m_pDspCommPage->dwMIDIOutData = SWAP( dwPacked ); 2264 ClearHandshake(); 2265 SendVector( DSP_VC_MIDI_WRITE ); 2266 2267 ECHO_DEBUGPRINTF(("CDspCommObject::WriteMidi - wrote 0x%08lx\n",dwPacked)); 2268 2269 // 2270 // Update the count 2271 // 2272 *pdwActualCt += dwLengthTemp; 2273 2274 } // while( dwLength ) 2275 2276 if ( 0 != *pdwActualCt ) 2277 { 2278 // 2279 // Save the current time - used to detect if MIDI out is currently busy 2280 // 2281 m_pOsSupport->OsGetSystemTime( &m_ullMidiOutTime ); 2282 // Last time MIDI out occured 2283 } 2284 2285 ECHO_DEBUGPRINTF( ("CDspCommObject::WriteMidi: Actual %ld " 2286 "Expected %ld OK\n", 2287 *pdwActualCt, 2288 dwOrgLgth) ); 2289 2290 return Status; 2291 2292 } // ECHOSTATUS CDspCommObject::WriteMidi 2293 2294 2295 //=========================================================================== 2296 // 2297 // Called from the interrupt handler - get a MIDI input byte 2298 // 2299 //=========================================================================== 2300 2301 ECHOSTATUS CDspCommObject::ReadMidi 2302 ( 2303 WORD wIndex, // Buffer index 2304 DWORD & dwData // Return data 2305 ) 2306 { 2307 if ( wIndex >= DSP_MIDI_BUFFER_SIZE - 1 ) 2308 return ECHOSTATUS_INVALID_INDEX; 2309 2310 // 2311 // Get the data 2312 // 2313 dwData = SWAP( m_pDspCommPage->wMidiInData[ wIndex ] ); 2314 2315 // 2316 // Timestamp for the MIDI input activity indicator 2317 // 2318 m_pOsSupport->OsGetSystemTime( &m_ullMidiInTime ); 2319 2320 return ECHOSTATUS_OK; 2321 2322 } // ECHOSTATUS CDspCommObject::ReadMidi 2323 2324 2325 ECHOSTATUS CDspCommObject::SetMidiOn( BOOL bOn ) 2326 { 2327 if ( bOn ) 2328 { 2329 if ( 0 == m_wMidiOnCount ) 2330 { 2331 if ( !WaitForHandshake() ) 2332 return ECHOSTATUS_DSP_DEAD; 2333 2334 m_pDspCommPage->dwFlags |= SWAP( (DWORD) DSP_FLAG_MIDI_INPUT ); 2335 2336 ClearHandshake(); 2337 SendVector( DSP_VC_UPDATE_FLAGS ); 2338 } 2339 m_wMidiOnCount++; 2340 } 2341 else 2342 { 2343 if ( m_wMidiOnCount == 0 ) 2344 return ECHOSTATUS_OK; 2345 2346 if ( 0 == --m_wMidiOnCount ) 2347 { 2348 if ( !WaitForHandshake() ) 2349 return ECHOSTATUS_DSP_DEAD; 2350 2351 m_pDspCommPage->dwFlags &= SWAP( (DWORD) ~DSP_FLAG_MIDI_INPUT ); 2352 2353 ClearHandshake(); 2354 SendVector( DSP_VC_UPDATE_FLAGS ); 2355 } 2356 } 2357 2358 return ECHOSTATUS_OK; 2359 2360 } // ECHOSTATUS CDspCommObject::SetMidiOn 2361 2362 2363 #endif // MIDI_SUPPORT 2364 2365 2366 2367 // **** CDspCommObject.cpp **** 2368