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
operator new(size_t Size)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
operator delete(PVOID pVoid)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
CDspCommObject(PDWORD pdwDspRegBase,PCOsSupport pOsSupport)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
~CDspCommObject()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
CheckAsicStatus()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
LoadASIC(DWORD dwCmd,PBYTE pCode,DWORD dwSize)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
InstallResidentLoader()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
LoadDSP(PWORD pCode)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
LoadFirmware()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
ReadSn()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
RestoreDspSettings()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
Write_DSP(DWORD dwData)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
Read_DSP(DWORD * pdwData)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
SendVector(DWORD dwCommand)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
WaitForHandshake()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
StartTransport(PCChannelMask pChannelMask)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
StopTransport(PCChannelMask pChannelMask)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
ResetTransport(PCChannelMask pChannelMask)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
SetAudioDuckListPhys(WORD wPipeIndex,DWORD dwNewPhysAdr)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
GetActivePipes(PCChannelMask pChannelMask)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
SetAudioFormat(WORD wPipeIndex,PECHOGALS_AUDIOFORMAT pFormat)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
GetAudioFormat(WORD wPipeIndex,PECHOGALS_AUDIOFORMAT pFormat)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
SetPipeOutGain(WORD wPipeOut,WORD wBusOut,INT32 iGain,BOOL fImmediate)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
GetPipeOutGain(WORD wPipeOut,WORD wBusOut,INT32 & iGain)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
SetBusInGain(WORD wBusIn,INT32 iGain)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
GetBusInGain(WORD wBusIn,INT32 & iGain)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
SetNominalLevel(WORD wBus,BOOL bState)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
GetNominalLevel(WORD wBus,PBYTE pbyState)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
SetAudioMonitor(WORD wBusOut,WORD wBusIn,INT32 iGain,BOOL fImmediate)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
SetMetersOn(BOOL bOn)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
UpdateAudioOutLineLevel()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
UpdateAudioInLineLevel()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
UpdateVmixerLevel()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
SetInputClock(WORD wClock)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
SetOutputClock(WORD wClock)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
GetAudioMeters(PECHOGALS_METERS pMeters)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
GetDigitalInputAutoMute(BOOL & fAutoMute)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
SetDigitalInputAutoMute(BOOL fAutoMute)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
GoComatose()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
WriteMidi(PBYTE pData,DWORD dwLength,PDWORD pdwActualCt)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
ReadMidi(WORD wIndex,DWORD & dwData)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
SetMidiOn(BOOL bOn)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
IsMidiOutActive()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