xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/CMonaDspCommObject.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
1 // ****************************************************************************
2 //
3 //  	CMonaDspCommObject.cpp
4 //
5 //		Implementation file for EchoGals generic driver Mona DSP
6 //		interface class.
7 //
8 // ----------------------------------------------------------------------------
9 //
10 // This file is part of Echo Digital Audio's generic driver library.
11 // Copyright Echo Digital Audio Corporation (c) 1998 - 2005
12 // All rights reserved
13 // www.echoaudio.com
14 //
15 // This library is free software; you can redistribute it and/or
16 // modify it under the terms of the GNU Lesser General Public
17 // License as published by the Free Software Foundation; either
18 // version 2.1 of the License, or (at your option) any later version.
19 //
20 // This library is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23 // Lesser General Public License for more details.
24 //
25 // You should have received a copy of the GNU Lesser General Public
26 // License along with this library; if not, write to the Free Software
27 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28 //
29 // ****************************************************************************
30 
31 #include "CEchoGals.h"
32 #include "CMonaDspCommObject.h"
33 
34 #include "MonaDSP.c"
35 #include "Mona361DSP.c"
36 
37 #include "Mona1ASIC48.c"
38 #include "Mona1ASIC96.c"
39 #include "Mona1ASIC48_361.c"
40 #include "Mona1ASIC96_361.c"
41 #include "Mona2ASIC.c"
42 
43 
44 /****************************************************************************
45 
46 	Construction and destruction
47 
48  ****************************************************************************/
49 
50 //===========================================================================
51 //
52 // Constructor
53 //
54 //===========================================================================
55 
56 CMonaDspCommObject::CMonaDspCommObject
57 (
58 	PDWORD		pdwRegBase,				// Virtual ptr to DSP registers
59 	PCOsSupport	pOsSupport
60 ) : CGMLDspCommObject( pdwRegBase, pOsSupport )
61 {
62 	strcpy( m_szCardName, "Mona" );
63 	m_pdwDspRegBase = pdwRegBase;		// Virtual addr DSP's register base
64 
65 	m_wNumPipesOut = 14;
66 	m_wNumPipesIn = 12;
67 	m_wNumBussesOut = 14;
68 	m_wNumBussesIn = 12;
69 	m_wFirstDigitalBusOut = 6;
70 	m_wFirstDigitalBusIn = 4;
71 
72 	m_bProfessionalSpdif = FALSE;
73 
74 	m_fHasVmixer = FALSE;
75 
76 	m_wNumMidiOut = 0;					// # MIDI out channels
77 	m_wNumMidiIn = 0;						// # MIDI in  channels
78 	m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 44100 );
79 												// Need this in cse we start with ESYNC
80 	m_bHasASIC = TRUE;
81 	if ( DEVICE_ID_56361 == pOsSupport->GetDeviceId() )
82 		m_pwDspCodeToLoad = pwMona361DSP;
83 	else
84 		m_pwDspCodeToLoad = pwMonaDSP;
85 
86 	m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA;
87 }	// CMonaDspCommObject::CMonaDspCommObject( DWORD dwPhysRegBase )
88 
89 
90 //===========================================================================
91 //
92 // Destructor
93 //
94 //===========================================================================
95 
96 CMonaDspCommObject::~CMonaDspCommObject()
97 {
98 }	// CMonaDspCommObject::~CMonaDspCommObject()
99 
100 
101 
102 
103 /****************************************************************************
104 
105 	Hardware setup and config
106 
107  ****************************************************************************/
108 
109 //===========================================================================
110 //
111 // Mona has an ASIC on the PCI card and another ASIC in the external box;
112 // both need to be loaded.
113 //
114 //===========================================================================
115 
116 BOOL CMonaDspCommObject::LoadASIC()
117 {
118 	DWORD	dwControlReg;
119 	PBYTE	pbAsic1;
120 	DWORD	dwSize;
121 
122 	if ( m_bASICLoaded )
123 		return TRUE;
124 
125 	m_pOsSupport->OsSnooze( 10000 );
126 
127 	if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
128 	{
129 		pbAsic1 = pbMona1ASIC48_361;
130 		dwSize = sizeof( pbMona1ASIC48_361 );
131 	}
132 	else
133 	{
134 		pbAsic1 = pbMona1ASIC48;
135 		dwSize = sizeof( pbMona1ASIC48 );
136 	}
137 	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
138 											  pbAsic1,
139 											  dwSize ) )
140 		return FALSE;
141 
142 	m_pbyAsic = pbAsic1;
143 
144 	m_pOsSupport->OsSnooze( 10000 );
145 
146 	// Do the external one
147 	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_EXTERNAL_ASIC,
148 											  pbMona2ASIC,
149 											  sizeof( pbMona2ASIC ) ) )
150 		return FALSE;
151 
152 	m_pOsSupport->OsSnooze( 10000 );
153 
154 	CheckAsicStatus();
155 
156 	//
157 	// Set up the control register if the load succeeded -
158 	//
159 	// 48 kHz, internal clock, S/PDIF RCA mode
160 	//
161 	if ( m_bASICLoaded )
162 	{
163 		dwControlReg = GML_CONVERTER_ENABLE | GML_48KHZ;
164 		ECHO_DEBUGPRINTF(("CMonaDspCommObject::LoadASIC - setting control reg for 0x%lx\n",
165 								dwControlReg));
166 		WriteControlReg( dwControlReg, TRUE );
167 	}
168 
169 	return m_bASICLoaded;
170 
171 }	// BOOL CMonaDspCommObject::LoadASIC()
172 
173 
174 //===========================================================================
175 //
176 // Depending on what digital mode you want, Mona needs different ASICs
177 //	loaded.  This function checks the ASIC needed for the new mode and sees
178 // if it matches the one already loaded.
179 //
180 //===========================================================================
181 
182 BOOL CMonaDspCommObject::SwitchAsic( DWORD dwMask96 )
183 {
184 	BYTE *	pbyAsicNeeded;
185 	DWORD		dwAsicSize;
186 
187 	//
188 	//	Check the clock detect bits to see if this is
189 	// a single-speed clock or a double-speed clock; load
190 	// a new ASIC if necessary.
191 	//
192 	if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
193 	{
194 		pbyAsicNeeded = pbMona1ASIC48_361;
195 		dwAsicSize = sizeof( pbMona1ASIC48_361 );
196 		if ( 0 != ( dwMask96 & GetInputClockDetect() ) )
197 		{
198 			pbyAsicNeeded = pbMona1ASIC96_361;
199 			dwAsicSize = sizeof( pbMona1ASIC96_361 );
200 		}
201 	}
202 	else
203 	{
204 		pbyAsicNeeded = pbMona1ASIC48;
205 		dwAsicSize = sizeof( pbMona1ASIC48 );
206 		if ( 0 != ( dwMask96 & GetInputClockDetect() ) )
207 		{
208 			pbyAsicNeeded = pbMona1ASIC96;
209 			dwAsicSize = sizeof( pbMona1ASIC96 );
210 		}
211 	}
212 
213 	if ( pbyAsicNeeded != m_pbyAsic )
214 	{
215 		//
216 		// Load the desired ASIC
217 		//
218 		if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
219 												  pbyAsicNeeded,
220 												  dwAsicSize ) )
221 			return FALSE;
222 
223 		m_pbyAsic = pbyAsicNeeded;
224 
225 		m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
226 	}
227 
228 	return TRUE;
229 
230 }	// BOOL CMonaDspCommObject::SwitchAsic( DWORD dwMask96 )
231 
232 
233 //===========================================================================
234 //
235 // SetInputClock
236 //
237 //===========================================================================
238 
239 ECHOSTATUS CMonaDspCommObject::SetInputClock(WORD wClock)
240 {
241 	BOOL			bSetRate;
242 	BOOL			bWriteControlReg;
243 	DWORD			dwControlReg;
244 
245 	ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetInputClock: clock %d\n",wClock) );
246 
247 	dwControlReg = GetControlRegister();
248 
249 	//
250 	// Mask off the clock select bits
251 	//
252 	dwControlReg &= GML_CLOCK_CLEAR_MASK;
253 
254 	bSetRate = FALSE;
255 	bWriteControlReg = TRUE;
256 	switch ( wClock )
257 	{
258 		case ECHO_CLOCK_INTERNAL :
259 		{
260 			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to INTERNAL\n" ) );
261 
262 			bSetRate = TRUE;
263 			bWriteControlReg = FALSE;
264 
265 			break;
266 		} // CLK_CLOCKININTERNAL
267 
268 		case ECHO_CLOCK_SPDIF :
269 		{
270 			if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
271 			{
272 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
273 			}
274 
275 			if ( FALSE == SwitchAsic( GML_CLOCK_DETECT_BIT_SPDIF96 ) )
276 			{
277 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
278 			}
279 
280 			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to SPDIF\n" ) );
281 
282 			dwControlReg |= GML_SPDIF_CLOCK;
283 
284 			if ( GML_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() )
285 			{
286 				dwControlReg |= GML_DOUBLE_SPEED_MODE;
287 			}
288 			else
289 			{
290 				dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
291 			}
292 			break;
293 		} // CLK_CLOCKINSPDIF
294 
295 		case ECHO_CLOCK_WORD :
296 		{
297 			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to WORD\n" ) );
298 
299 			if ( FALSE == SwitchAsic( GML_CLOCK_DETECT_BIT_WORD96 ) )
300 			{
301 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
302 			}
303 
304 			dwControlReg |= GML_WORD_CLOCK;
305 
306 			if ( GML_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() )
307 			{
308 				dwControlReg |= GML_DOUBLE_SPEED_MODE;
309 			}
310 			else
311 			{
312 				dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
313 			}
314 			break;
315 		} // CLK_CLOCKINWORD
316 
317 		case ECHO_CLOCK_ADAT :
318 		{
319 			ECHO_DEBUGPRINTF( ( "\tSet Mona clock to ADAT\n" ) );
320 
321 			if ( DIGITAL_MODE_ADAT != GetDigitalMode() )
322 			{
323 				return ECHOSTATUS_CLOCK_NOT_AVAILABLE;
324 			}
325 
326 			dwControlReg |= GML_ADAT_CLOCK;
327 			dwControlReg &= ~GML_DOUBLE_SPEED_MODE;
328 			break;
329 		} // CLK_CLOCKINADAT
330 
331 		default :
332 			ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Mona\n",wClock));
333 			ECHO_DEBUGBREAK();
334 				return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
335 	}	// switch (wClock)
336 
337 	//
338 	// Winner! Save the new input clock.
339 	//
340 	m_wInputClock = wClock;
341 
342 	//
343 	// Do things according to the flags
344 	//
345 	if ( bWriteControlReg )
346 	{
347 		WriteControlReg( dwControlReg, TRUE );
348 	}
349 
350 	// Set Mona sample rate to something sane if word or superword is
351 	// being turned off
352 	if ( bSetRate )
353 	{
354 		SetSampleRate( GetSampleRate() );
355 	}
356 
357 	return ECHOSTATUS_OK;
358 
359 }	// ECHOSTATUS CMonaDspCommObject::SetInputClock
360 
361 
362 
363 //===========================================================================
364 //
365 // SetSampleRate
366 //
367 // Set the audio sample rate for CMona
368 //
369 //===========================================================================
370 
371 DWORD CMonaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
372 {
373 	BYTE *pbyAsicNeeded;
374 	DWORD	dwAsicSize, dwControlReg, dwNewClock;
375 	BOOL	fForceControlReg;
376 
377 	ECHO_DEBUGPRINTF(("CMonaDspCommObject::SetSampleRate to %ld\n",dwNewSampleRate));
378 
379 	fForceControlReg = FALSE;
380 
381 	//
382 	// Only set the clock for internal mode.  If the clock is not set to
383 	// internal, try and re-set the input clock; this more transparently
384 	// handles switching between single and double-speed mode
385 	//
386 	if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
387 	{
388 		ECHO_DEBUGPRINTF( ( "CMonaDspCommObject::SetSampleRate: Cannot set sample rate - "
389 								  "clock not set to CLK_CLOCKININTERNAL\n" ) );
390 
391 		//
392 		// Save the rate anyhow
393 		//
394 		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
395 
396 		//
397 		// Set the input clock to the current value
398 		//
399 		SetInputClock( m_wInputClock );
400 
401 		return GetSampleRate();
402 	}
403 
404 	//
405 	// Now, check to see if the required ASIC is loaded
406 	//
407 	if ( dwNewSampleRate >= 88200 )
408 	{
409 		if ( DIGITAL_MODE_ADAT == GetDigitalMode() )
410 			return( GetSampleRate() );
411 
412 		if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
413 		{
414 			pbyAsicNeeded = pbMona1ASIC96_361;
415 			dwAsicSize = sizeof(pbMona1ASIC96_361);
416 		}
417 		else
418 		{
419 			pbyAsicNeeded = pbMona1ASIC96;
420 			dwAsicSize = sizeof(pbMona1ASIC96);
421 		}
422 	}
423 	else
424 	{
425 		if ( DEVICE_ID_56361 == m_pOsSupport->GetDeviceId() )
426 		{
427 			pbyAsicNeeded = pbMona1ASIC48_361;
428 			dwAsicSize = sizeof(pbMona1ASIC48_361);
429 		}
430 		else
431 		{
432 			pbyAsicNeeded = pbMona1ASIC48;
433 			dwAsicSize = sizeof(pbMona1ASIC48);
434 		}
435 	}
436 
437 	if ( pbyAsicNeeded != m_pbyAsic )
438 	{
439 		ECHO_DEBUGPRINTF(("\tLoading a new ASIC\n"));
440 		//
441 		// Load the desired ASIC
442 		//
443 		if ( FALSE == CDspCommObject::LoadASIC
444 													( DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
445 													  pbyAsicNeeded,
446 													  dwAsicSize ) )
447 			return( GetSampleRate() );
448 
449 		m_pbyAsic = pbyAsicNeeded;
450 
451 		fForceControlReg = TRUE;
452 	}
453 
454 	//
455 	// Get the new control register value
456 	//
457 	dwNewClock = 0;
458 
459 	dwControlReg = GetControlRegister();
460 	dwControlReg &= GML_CLOCK_CLEAR_MASK;
461 	dwControlReg &= GML_SPDIF_RATE_CLEAR_MASK;
462 
463 	switch ( dwNewSampleRate )
464 	{
465 		case 96000 :
466 			dwNewClock = GML_96KHZ;
467 			break;
468 
469 		case 88200 :
470 			dwNewClock = GML_88KHZ;
471 			break;
472 
473 		case 48000 :
474 			dwNewClock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
475 			break;
476 
477 		case 44100 :
478 			dwNewClock = GML_44KHZ;
479 			//
480 			// Professional mode
481 			//
482 			if ( dwControlReg & GML_SPDIF_PRO_MODE )
483 			{
484 				dwNewClock |= GML_SPDIF_SAMPLE_RATE0;
485 			}
486 			break;
487 
488 		case 32000 :
489 			dwNewClock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 | GML_SPDIF_SAMPLE_RATE1;
490 			break;
491 
492 		case 22050 :
493 			dwNewClock = GML_22KHZ;
494 			break;
495 
496 		case 16000 :
497 			dwNewClock = GML_16KHZ;
498 			break;
499 
500 		case 11025 :
501 			dwNewClock = GML_11KHZ;
502 			break;
503 
504 		case 8000 :
505 			dwNewClock = GML_8KHZ;
506 			break;
507 	}
508 
509 	dwControlReg |= dwNewClock;
510 
511 	//
512 	// Send the new value to the card
513 	//
514 	if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg, fForceControlReg ) )
515 	{
516 		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
517 
518 		ECHO_DEBUGPRINTF( ("CMonaDspCommObject::SetSampleRate: %ld "
519 								 "clock %ld\n", dwNewSampleRate, dwNewClock) );
520 	}
521 
522 	return GetSampleRate();
523 
524 } // DWORD CMonaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
525 
526 
527 //===========================================================================
528 //
529 //	Set digital mode
530 //
531 //===========================================================================
532 
533 ECHOSTATUS CMonaDspCommObject::SetDigitalMode
534 (
535 	BYTE	byNewMode
536 )
537 {
538 	ECHO_DEBUGPRINTF(("CMonaDspCommObject::SetDigitalMode %d\n",byNewMode));
539 
540 	//
541 	// If the new mode is ADAT mode, make sure that the single speed ASIC is loaded
542 	//
543 	BYTE *pbAsic96;
544 
545 	if (DIGITAL_MODE_ADAT == byNewMode)
546 	{
547 		switch (m_pOsSupport->GetDeviceId())
548 		{
549 			case DEVICE_ID_56301 :
550 				pbAsic96 = pbMona1ASIC96;
551 				break;
552 
553 			case DEVICE_ID_56361 :
554 				pbAsic96 = pbMona1ASIC96_361;
555 				break;
556 
557 			default :				// should never happen, but it's good to cover all the bases
558 				return ECHOSTATUS_BAD_CARDID;
559 		}
560 		if (pbAsic96 == m_pbyAsic)
561 			SetSampleRate( 48000 );
562 	}
563 
564 	//
565 	// Call the base class to tweak the input clock if necessary
566 	//
567 	return CGMLDspCommObject::SetDigitalMode(byNewMode);
568 
569 }	// ECHOSTATUS CMonaDspCommObject::SetDigitalMode
570 
571 
572 // **** CMonaDspCommObject.cpp ****
573