xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/CDspCommObject.cpp (revision 4dd9e43637031d2c5a6755a0184040f0de8f2884)
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