xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/CMonaDspCommObject.cpp (revision d5cd5d63ff0ad395989db6cf4841a64d5b545d1d)
1 // ****************************************************************************
2 //
3 //  	CMonaDspCommObject.cpp
4 //
5 //		Implementation file for EchoGals generic driver Darla 24 DSP
6 //		interface class.
7 //
8 //		Copyright Echo Digital Audio Corporation (c) 1998 - 2002
9 //		All rights reserved
10 //		www.echoaudio.com
11 //
12 //		Permission is hereby granted, free of charge, to any person obtaining a
13 //		copy of this software and associated documentation files (the
14 //		"Software"), to deal with the Software without restriction, including
15 //		without limitation the rights to use, copy, modify, merge, publish,
16 //		distribute, sublicense, and/or sell copies of the Software, and to
17 //		permit persons to whom the Software is furnished to do so, subject to
18 //		the following conditions:
19 //
20 //		- Redistributions of source code must retain the above copyright
21 //		notice, this list of conditions and the following disclaimers.
22 //
23 //		- Redistributions in binary form must reproduce the above copyright
24 //		notice, this list of conditions and the following disclaimers in the
25 //		documentation and/or other materials provided with the distribution.
26 //
27 //		- Neither the name of Echo Digital Audio, nor the names of its
28 //		contributors may be used to endorse or promote products derived from
29 //		this Software without specific prior written permission.
30 //
31 //		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 //		EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 //		MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
34 //		IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
35 //		ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
36 //		TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
37 //		SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
38 //
39 // ****************************************************************************
40 
41 #include "CEchoGals.h"
42 #include "CMonaDspCommObject.h"
43 
44 #include "MonaDSP.c"
45 #include "Mona361DSP.c"
46 
47 #include "Mona1ASIC48.c"
48 #include "Mona1ASIC96.c"
49 #include "Mona1ASIC48_361.c"
50 #include "Mona1ASIC96_361.c"
51 #include "Mona2ASIC.c"
52 
53 
54 /****************************************************************************
55 
56 	Construction and destruction
57 
58  ****************************************************************************/
59 
60 //===========================================================================
61 //
62 // Constructor
63 //
64 //===========================================================================
65 
66 CMonaDspCommObject::CMonaDspCommObject
67 (
68 	PDWORD		pdwRegBase,				// Virtual ptr to DSP registers
69 	PCOsSupport	pOsSupport
70 ) : CGMLDspCommObject( pdwRegBase, pOsSupport )
71 {
72 	strcpy( m_szCardName, "Mona" );
73 	m_pdwDspRegBase = pdwRegBase;		// Virtual addr DSP's register base
74 
75 	m_wNumPipesOut = 14;
76 	m_wNumPipesIn = 12;
77 	m_wNumBussesOut = 14;
78 	m_wNumBussesIn = 12;
79 	m_wFirstDigitalBusOut = 6;
80 	m_wFirstDigitalBusIn = 4;
81 
82 	m_bProfessionalSpdif = FALSE;
83 
84 	m_fHasVmixer = FALSE;
85 
86 	m_wNumMidiOut = 0;					// # MIDI out channels
87 	m_wNumMidiIn = 0;						// # MIDI in  channels
88 	m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 44100 );
89 												// Need this in cse we start with ESYNC
90 	m_bHasASIC = TRUE;
91 	if ( DEVICE_ID_56361 == pOsSupport->GetDeviceId() )
92 		m_pwDspCodeToLoad = pwMona361DSP;
93 	else
94 
95 	m_pwDspCodeToLoad = pwMonaDSP;
96 
97 	m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA;
98 }	// CMonaDspCommObject::CMonaDspCommObject( DWORD dwPhysRegBase )
99 
100 
101 //===========================================================================
102 //
103 // Destructor
104 //
105 //===========================================================================
106 
107 CMonaDspCommObject::~CMonaDspCommObject()
108 {
109 }	// CMonaDspCommObject::~CMonaDspCommObject()
110 
111 
112 
113 
114 /****************************************************************************
115 
116 	Hardware setup and config
117 
118  ****************************************************************************/
119 
120 //===========================================================================
121 //
122 // Mona has an ASIC on the PCI card and another ASIC in the external box;
123 // both need to be loaded.
124 //
125 //===========================================================================
126 
127 BOOL CMonaDspCommObject::LoadASIC()
128 {
129 	DWORD	dwControlReg;
130 	PBYTE	pbAsic1;
131 	DWORD	dwSize;
132 
133 	if ( m_bASICLoaded )
134 		return TRUE;
135 
136 	m_pOsSupport->OsSnooze( 10000 );
137 
138 	if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
139 	{
140 		pbAsic1 = pbMona1ASIC48_361;
141 		dwSize = sizeof( pbMona1ASIC48_361 );
142 	}
143 	else
144 	{
145 		pbAsic1 = pbMona1ASIC48;
146 		dwSize = sizeof( pbMona1ASIC48 );
147 	}
148 	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
149 											  pbAsic1,
150 											  dwSize ) )
151 		return FALSE;
152 
153 	m_pbyAsic = pbAsic1;
154 
155 	m_pOsSupport->OsSnooze( 10000 );
156 
157 	// Do the external one
158 	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_EXTERNAL_ASIC,
159 											  pbMona2ASIC,
160 											  sizeof( pbMona2ASIC ) ) )
161 		return FALSE;
162 
163 	m_pOsSupport->OsSnooze( 10000 );
164 
165 	CheckAsicStatus();
166 
167 	//
168 	// Set up the control register if the load succeeded -
169 	//
170 	// 48 kHz, internal clock, S/PDIF RCA mode
171 	//
172 	if ( m_bASICLoaded )
173 	{
174 		dwControlReg = GML_CONVERTER_ENABLE | GML_48KHZ;
175 		WriteControlReg( dwControlReg );
176 	}
177 
178 	return m_bASICLoaded;
179 
180 }	// BOOL CMonaDspCommObject::LoadASIC()
181 
182 
183 //===========================================================================
184 //
185 // Depending on what digital mode you want, Mona needs different ASICs
186 //	loaded.  This function checks the ASIC needed for the new mode and sees
187 // if it matches the one already loaded.
188 //
189 //===========================================================================
190 
191 BOOL CMonaDspCommObject::SwitchAsic( DWORD dwMask96 )
192 {
193 	BYTE *	pbyAsicNeeded;
194 	DWORD		dwAsicSize;
195 
196 	//
197 	//	Check the clock detect bits to see if this is
198 	// a single-speed clock or a double-speed clock; load
199 	// a new ASIC if necessary.
200 	//
201 	if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
202 	{
203 		pbyAsicNeeded = pbMona1ASIC48_361;
204 		dwAsicSize = sizeof( pbMona1ASIC48_361 );
205 		if ( 0 != ( dwMask96 & GetInputClockDetect() ) )
206 		{
207 			pbyAsicNeeded = pbMona1ASIC96_361;
208 			dwAsicSize = sizeof( pbMona1ASIC96_361 );
209 		}
210 	}
211 	else
212 	{
213 		pbyAsicNeeded = pbMona1ASIC48;
214 		dwAsicSize = sizeof( pbMona1ASIC48 );
215 		if ( 0 != ( dwMask96 & GetInputClockDetect() ) )
216 		{
217 			pbyAsicNeeded = pbMona1ASIC96;
218 			dwAsicSize = sizeof( pbMona1ASIC96 );
219 		}
220 	}
221 
222 	if ( pbyAsicNeeded != m_pbyAsic )
223 	{
224 		//
225 		// Load the desired ASIC
226 		//
227 		if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
228 												  pbyAsicNeeded,
229 												  dwAsicSize ) )
230 			return FALSE;
231 
232 		m_pbyAsic = pbyAsicNeeded;
233 	}
234 
235 	return TRUE;
236 
237 }	// BOOL CMonaDspCommObject::SwitchAsic( DWORD dwMask96 )
238 
239 
240 //===========================================================================
241 //
242 // SetInputClock
243 //
244 //===========================================================================
245 
246 ECHOSTATUS CMonaDspCommObject::SetInputClock(WORD wClock)
247 {
248 	BOOL			bSetRate;
249 	BOOL			bWriteControlReg;
250 	DWORD			dwControlReg, dwSampleRate;
251 
252 	ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetInputClock:\n") );
253 
254 	dwControlReg = GetControlRegister();
255 
256 	//
257 	// Mask off the clock select bits
258 	//
259 	dwControlReg &= GML_CLOCK_CLEAR_MASK;
260 	dwSampleRate = GetSampleRate();
261 
262 	bSetRate = FALSE;
263 	bWriteControlReg = TRUE;
264 	switch ( wClock )
265 	{
266 		case ECHO_CLOCK_INTERNAL :
267 		{
268 			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to INTERNAL\n" ) );
269 
270 			// If the sample rate is out of range for some reason, set it
271 			// to a reasonable value.  mattg
272 			if ( ( dwSampleRate < 8000  ) ||
273 			     ( dwSampleRate > 96000 ) )
274 			{
275 				dwSampleRate = 48000;
276 			}
277 
278 			bSetRate = TRUE;
279 			bWriteControlReg = FALSE;
280 
281 			break;
282 		} // CLK_CLOCKININTERNAL
283 
284 		case ECHO_CLOCK_SPDIF :
285 		{
286 			if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
287 			{
288 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
289 			}
290 
291 			if ( FALSE == SwitchAsic( GML_CLOCK_DETECT_BIT_SPDIF96 ) )
292 			{
293 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
294 			}
295 
296 			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to SPDIF\n" ) );
297 
298 			dwControlReg |= GML_SPDIF_CLOCK;
299 
300 			if ( GML_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() )
301 			{
302 				dwControlReg |= GML_DOUBLE_SPEED_MODE;
303 			}
304 			else
305 			{
306 				dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
307 			}
308 			break;
309 		} // CLK_CLOCKINSPDIF
310 
311 		case ECHO_CLOCK_WORD :
312 		{
313 			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to WORD\n" ) );
314 
315 			if ( FALSE == SwitchAsic( GML_CLOCK_DETECT_BIT_WORD96 ) )
316 			{
317 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
318 			}
319 
320 			dwControlReg |= GML_WORD_CLOCK;
321 
322 			if ( GML_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() )
323 			{
324 				dwControlReg |= GML_DOUBLE_SPEED_MODE;
325 			}
326 			else
327 			{
328 				dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
329 			}
330 			break;
331 		} // CLK_CLOCKINWORD
332 
333 		case ECHO_CLOCK_ADAT :
334 		{
335 			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to ADAT\n" ) );
336 
337 			if ( DIGITAL_MODE_ADAT != GetDigitalMode() )
338 			{
339 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
340 			}
341 
342 			dwControlReg |= GML_ADAT_CLOCK;
343 			dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
344 			break;
345 		} // CLK_CLOCKINADAT
346 
347 		default :
348 			ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Mona\n",wClock));
349 			ECHO_DEBUGBREAK();
350 				return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
351 	}	// switch (wClock)
352 
353 	//
354 	// Winner! Save the new input clock.
355 	//
356 	m_wInputClock = wClock;
357 
358 	//
359 	// Do things according to the flags
360 	//
361 	if ( bWriteControlReg )
362 	{
363 		WriteControlReg( dwControlReg );
364 	}
365 
366 	// Set Mona sample rate to something sane if word or superword is
367 	// being turned off
368 	if ( bSetRate )
369 	{
370 		SetSampleRate( GetSampleRate() );
371 	}
372 
373 	return ECHOSTATUS_OK;
374 
375 }	// ECHOSTATUS CMonaDspCommObject::SetInputClock
376 
377 
378 
379 //===========================================================================
380 //
381 // SetSampleRate
382 //
383 // Set the audio sample rate for CMona
384 //
385 //===========================================================================
386 
387 DWORD CMonaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
388 {
389 	BYTE *pbyAsicNeeded;
390 	DWORD	dwAsicSize, dwControlReg, dwNewClock;
391 
392 	//
393 	// Only set the clock for internal mode.  If the clock is not set to
394 	// internal, try and re-set the input clock; this more transparently
395 	// handles switching between single and double-speed mode
396 	//
397 	if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
398 	{
399 		ECHO_DEBUGPRINTF( ( "CMonaDspCommObject::SetSampleRate: Cannot set sample rate - "
400 								  "clock not set to CLK_CLOCKININTERNAL\n" ) );
401 
402 		//
403 		// Save the rate anyhow
404 		//
405 		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
406 
407 		//
408 		// Set the input clock to the current value
409 		//
410 		SetInputClock( m_wInputClock );
411 
412 		return GetSampleRate();
413 	}
414 
415 	//
416 	// Now, check to see if the required ASIC is loaded
417 	//
418 	if ( dwNewSampleRate >= 88200 )
419 	{
420 		if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
421 			return( GetSampleRate() );
422 
423 		if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
424 		{
425 			pbyAsicNeeded = pbMona1ASIC96_361;
426 			dwAsicSize = sizeof(pbMona1ASIC96_361);
427 		}
428 		else
429 		{
430 			pbyAsicNeeded = pbMona1ASIC96;
431 			dwAsicSize = sizeof(pbMona1ASIC96);
432 		}
433 	}
434 	else
435 	{
436 		if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
437 		{
438 			pbyAsicNeeded = pbMona1ASIC48_361;
439 			dwAsicSize = sizeof(pbMona1ASIC48_361);
440 		}
441 		else
442 		{
443 			pbyAsicNeeded = pbMona1ASIC48;
444 			dwAsicSize = sizeof(pbMona1ASIC48);
445 		}
446 	}
447 
448 	if ( pbyAsicNeeded != m_pbyAsic )
449 	{
450 		//
451 		// Load the desired ASIC
452 		//
453 		if ( FALSE == CDspCommObject::LoadASIC
454 													( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
455 													  pbyAsicNeeded,
456 													  dwAsicSize ) )
457 			return( GetSampleRate() );
458 
459 		m_pbyAsic = pbyAsicNeeded;
460 	}
461 
462 	//
463 	// Get the new control register value
464 	//
465 	dwNewClock = 0;
466 
467 	dwControlReg = GetControlRegister();
468 	dwControlReg &= GML_CLOCK_CLEAR_MASK;
469 	dwControlReg &= GML_SPDIF_RATE_CLEAR_MASK;
470 
471 	switch ( dwNewSampleRate )
472 	{
473 		case 96000 :
474 			dwNewClock = GML_96KHZ;
475 			break;
476 
477 		case 88200 :
478 			dwNewClock = GML_88KHZ;
479 			break;
480 
481 		case 48000 :
482 			dwNewClock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
483 			break;
484 
485 		case 44100 :
486 			dwNewClock = GML_44KHZ;
487 			//
488 			// Professional mode
489 			//
490 			if ( dwControlReg & GML_SPDIF_PRO_MODE )
491 			{
492 				dwNewClock |= GML_SPDIF_SAMPLE_RATE0;
493 			}
494 			break;
495 
496 		case 32000 :
497 			dwNewClock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 | GML_SPDIF_SAMPLE_RATE1;
498 			break;
499 
500 		case 22050 :
501 			dwNewClock = GML_22KHZ;
502 			break;
503 
504 		case 16000 :
505 			dwNewClock = GML_16KHZ;
506 			break;
507 
508 		case 11025 :
509 			dwNewClock = GML_11KHZ;
510 			break;
511 
512 		case 8000 :
513 			dwNewClock = GML_8KHZ;
514 			break;
515 	}
516 
517 	dwControlReg |= dwNewClock;
518 
519 	//
520 	// Send the new value to the card
521 	//
522 	if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg ) )
523 	{
524 		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
525 
526 		ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetSampleRate: %ld "
527 								 "clock %ld\n", dwNewSampleRate, dwNewClock) );
528 	}
529 
530 	return GetSampleRate();
531 
532 } // DWORD CMonaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
533 
534 
535 //===========================================================================
536 //
537 //	Set digital mode
538 //
539 //===========================================================================
540 
541 ECHOSTATUS CMonaDspCommObject::SetDigitalMode
542 (
543 	BYTE	byNewMode
544 )
545 {
546 	DWORD		dwControlReg;
547 
548 	dwControlReg = GetControlRegister();
549 	//
550 	// Clear the current digital mode
551 	//
552 	dwControlReg &= GML_DIGITAL_MODE_CLEAR_MASK;
553 
554 	//
555 	// Tweak the control reg
556 	//
557 	switch ( byNewMode )
558 	{
559 		default :
560 			return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED;
561 
562 		case DIGITAL_MODE_SPDIF_OPTICAL :
563 
564 			dwControlReg |= GML_SPDIF_OPTICAL_MODE;
565 
566 			// fall through
567 
568 		case DIGITAL_MODE_SPDIF_RCA :
569 
570 			//
571 			//	If the input clock is set to ADAT, set the
572 			// input clock to internal and the sample rate to 48 KHz
573 			//
574 			if ( ECHO_CLOCK_ADAT == GetInputClock() )
575 			{
576 				m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
577 				SetInputClock( ECHO_CLOCK_INTERNAL );
578 			}
579 
580 			break;
581 
582 		case DIGITAL_MODE_ADAT :
583 
584 			//
585 			//	If the input clock is set to S/PDIF, set the
586 			// input clock to internal and the sample rate to 48 KHz
587 			//
588 			if ( ECHO_CLOCK_SPDIF == GetInputClock() )
589 			{
590 				m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
591 				SetInputClock( ECHO_CLOCK_INTERNAL );
592 			}
593 
594 			//
595 			// If the current ASIC is the 96KHz ASIC, switch
596 			// the ASIC and set to 48 KHz
597 			//
598 			if ( ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() &&
599 						pbMona1ASIC96_361 == m_pbyAsic ) ||
600 				  ( DEVICE_ID_56301 == m_pOsSupport->GetDeviceId() &&
601 						pbMona1ASIC96 == m_pbyAsic ) )
602 			{
603 				SetSampleRate( 48000 );
604 			}
605 
606 			dwControlReg |= GML_ADAT_MODE;
607 			dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
608 			break;
609 	}
610 
611 	//
612 	// Write the control reg
613 	//
614 	WriteControlReg( dwControlReg );
615 
616 	m_byDigitalMode = byNewMode;
617 
618 	ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetDigitalMode to %ld\n",
619 							(DWORD) m_byDigitalMode) );
620 
621 	return ECHOSTATUS_OK;
622 
623 }	// ECHOSTATUS CMonaDspCommObject::SetDigitalMode
624 
625 
626 // **** CMonaDspCommObject.cpp ****
627