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