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