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