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