xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/C3g.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 // ****************************************************************************
2 //
3 //		C3g.cpp
4 //
5 //		Implementation file for the C3g driver class.
6 //		Set editor tabs to 3 for your viewing pleasure.
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 "C3g.h"
32 
33 #define ECHO3G_ANALOG_OUTPUT_LATENCY_1X		(1 + 32 + 12)		// ASIC + DSP + DAC
34 #define ECHO3G_ANALOG_OUTPUT_LATENCY_2X		(1 + 32 + 5)
35 #define ECHO3G_ANALOG_INPUT_LATENCY_1X			(1 + 32 + 12)
36 #define ECHO3G_ANALOG_INPUT_LATENCY_2X			(1 + 32 + 9)
37 
38 #define ECHO3G_DIGITAL_OUTPUT_LATENCY			(1 + 32)
39 #define ECHO3G_DIGITAL_INPUT_LATENCY			(1 + 32)
40 
41 
42 
43 /****************************************************************************
44 
45 	Construction and destruction
46 
47  ****************************************************************************/
48 
49 //===========================================================================
50 //
51 // Overload new & delete so memory for this object is allocated
52 //	from non-paged memory.
53 //
54 //===========================================================================
55 
56 PVOID C3g::operator new( size_t Size )
57 {
58 	PVOID 		pMemory;
59 	ECHOSTATUS 	Status;
60 
61 	Status = OsAllocateNonPaged(Size,&pMemory);
62 
63 	if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory ))
64 	{
65 		ECHO_DEBUGPRINTF(("C3g::operator new - memory allocation failed\n"));
66 
67 		pMemory = NULL;
68 	}
69 	else
70 	{
71 		memset( pMemory, 0, Size );
72 	}
73 
74 	return pMemory;
75 
76 }	// PVOID C3g::operator new( size_t Size )
77 
78 
79 VOID  C3g::operator delete( PVOID pVoid )
80 {
81 	if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) )
82 	{
83 		ECHO_DEBUGPRINTF(("C3g::operator delete memory free failed\n"));
84 	}
85 }	// VOID C3g::operator delete( PVOID pVoid )
86 
87 
88 //===========================================================================
89 //
90 // Constructor and destructor
91 //
92 //===========================================================================
93 
94 C3g::C3g( PCOsSupport pOsSupport )
95 	  : CEchoGalsMTC( pOsSupport )
96 {
97 	ECHO_DEBUGPRINTF( ( "C3g::C3g() is born!\n" ) );
98 
99 	m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
100 	m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
101 	m_wDigitalOutputLatency = ECHO3G_DIGITAL_OUTPUT_LATENCY;
102 	m_wDigitalInputLatency = ECHO3G_DIGITAL_INPUT_LATENCY;
103 }
104 
105 
106 C3g::~C3g()
107 {
108 	ECHO_DEBUGPRINTF( ( "C3g::~C3g() is toast!\n" ) );
109 }
110 
111 
112 
113 
114 /****************************************************************************
115 
116 	Setup and hardware initialization
117 
118  ****************************************************************************/
119 
120 //===========================================================================
121 //
122 // Every card has an InitHw method
123 //
124 //===========================================================================
125 
126 ECHOSTATUS C3g::InitHw()
127 {
128 	ECHOSTATUS	Status;
129 	WORD			i;
130 
131 	//
132 	// Call the base method
133 	//
134 	if ( ECHOSTATUS_OK != ( Status = CEchoGals::InitHw() ) )
135 		return Status;
136 
137 	//
138 	// Create the DSP comm object
139 	//
140 	ASSERT( NULL == m_pDspCommObject );
141 	m_pDspCommObject = new C3gDco( (PDWORD) m_pvSharedMemory, m_pOsSupport );
142 	if (NULL == m_pDspCommObject)
143 	{
144 		ECHO_DEBUGPRINTF(("C3g::InitHw - could not create DSP comm object\n"));
145 		return ECHOSTATUS_NO_MEM;
146 	}
147 
148 	//
149 	// Load the DSP
150 	//
151 	DWORD dwBoxType;
152 
153 	GetDspCommObject()->LoadFirmware();
154 
155 	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
156 	if (NO3GBOX == dwBoxType)
157 		return ECHOSTATUS_NO_3G_BOX;
158 
159 	if ( GetDspCommObject()->IsBoardBad() )
160 		return ECHOSTATUS_DSP_DEAD;
161 
162 	//
163 	// Clear the "bad board" flag; set the flags to indicate that
164 	// 3G can handle super-interleave.
165 	//
166 	m_wFlags &= ~ECHOGALS_FLAG_BADBOARD;
167 	m_wFlags |= ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK;
168 
169 	//
170 	//	Must call this here after DSP is init to
171 	//	init gains and mutes
172 	//
173 	Status = InitLineLevels();
174 	if ( ECHOSTATUS_OK != Status )
175 		return Status;
176 
177 	//
178 	// Initialize the MIDI input
179 	//
180 	Status = m_MidiIn.Init( this );
181 	if ( ECHOSTATUS_OK != Status )
182 		return Status;
183 
184 	//
185 	// Set defaults for +4/-10
186 	//
187 	for (i = 0; i < GetFirstDigitalBusOut(); i++ )
188 	{
189 		GetDspCommObject()->
190 			SetNominalLevel( i, FALSE );	// FALSE is +4 here
191 	}
192 	for ( i = 0; i < GetFirstDigitalBusIn(); i++ )
193 	{
194 		GetDspCommObject()->
195 			SetNominalLevel( GetNumBussesOut() + i, FALSE );
196 	}
197 
198 	//
199 	// Set the digital mode to S/PDIF RCA
200 	//
201 	SetDigitalMode( DIGITAL_MODE_SPDIF_RCA );
202 
203 	//
204 	//	Get default sample rate from DSP
205 	//
206 	m_dwSampleRate = GetDspCommObject()->GetSampleRate();
207 
208 	ECHO_DEBUGPRINTF( ( "C3g::InitHw()\n" ) );
209 	return Status;
210 
211 }	// ECHOSTATUS C3g::InitHw()
212 
213 
214 
215 
216 /****************************************************************************
217 
218 	Informational methods
219 
220  ****************************************************************************/
221 
222 //===========================================================================
223 //
224 // Override GetCapabilities to enumerate unique capabilties for this card
225 //
226 //===========================================================================
227 
228 ECHOSTATUS C3g::GetCapabilities
229 (
230 	PECHOGALS_CAPS	pCapabilities
231 )
232 {
233 	ECHOSTATUS	Status;
234 	WORD			i;
235 
236 	Status = GetBaseCapabilities(pCapabilities);
237 	if ( ECHOSTATUS_OK != Status )
238 		return Status;
239 
240 	//
241 	// Add nominal level control to all ins & outs except the universal
242 	//
243 	for (i = 0 ; i < pCapabilities->wNumBussesOut; i++)
244 	{
245 		pCapabilities->dwBusOutCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
246 	}
247 
248 	for (i = 2 ; i < pCapabilities->wNumBussesIn; i++)
249 	{
250 		pCapabilities->dwBusInCaps[i] |= ECHOCAPS_NOMINAL_LEVEL;
251 	}
252 
253 	pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_SPDIF		|
254 												ECHO_CLOCK_BIT_ADAT		|
255 												ECHO_CLOCK_BIT_MTC;
256 
257 	//
258 	// Box-specific capabilities
259 	//
260 	DWORD dwBoxType;
261 
262 	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
263 	switch (dwBoxType)
264 	{
265 		case GINA3G :
266 			pCapabilities->dwBusInCaps[0] |= ECHOCAPS_PHANTOM_POWER;
267 			pCapabilities->dwBusInCaps[1] |= ECHOCAPS_PHANTOM_POWER;
268 			break;
269 
270 		case LAYLA3G :
271 			pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_WORD;
272 			break;
273 
274 	}
275 
276 	pCapabilities->dwOutClockTypes = 0;
277 
278 	return Status;
279 
280 }	// ECHOSTATUS C3g::GetCapabilities
281 
282 
283 //===========================================================================
284 //
285 // QueryAudioSampleRate is used to find out if this card can handle a
286 // given sample rate.
287 //
288 //===========================================================================
289 
290 ECHOSTATUS C3g::QueryAudioSampleRate
291 (
292 	DWORD		dwSampleRate
293 )
294 {
295 	//
296 	// Check rates that are supported by continuous mode; only allow
297 	// double-speed rates if not in ADAT mode
298 	//
299 	if ((dwSampleRate >= 32000) && (dwSampleRate <= 50000))
300 		return ECHOSTATUS_OK;
301 
302 	if (	(DIGITAL_MODE_ADAT != GetDigitalMode()) &&
303 			(dwSampleRate > 50000) &&
304 			(dwSampleRate <= 100000))
305 		return ECHOSTATUS_OK;
306 
307 	ECHO_DEBUGPRINTF(("C3g::QueryAudioSampleRate() - rate %ld invalid\n",dwSampleRate) );
308 
309 	return ECHOSTATUS_BAD_FORMAT;
310 
311 }	// ECHOSTATUS C3g::QueryAudioSampleRate
312 
313 
314 //===========================================================================
315 //
316 // GetInputClockDetect returns a bitmask consisting of all the input
317 // clocks currently connected to the hardware; this changes as the user
318 // connects and disconnects clock inputs.
319 //
320 // You should use this information to determine which clocks the user is
321 // allowed to select.
322 //
323 //===========================================================================
324 
325 ECHOSTATUS C3g::GetInputClockDetect(DWORD &dwClockDetectBits)
326 {
327 	if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
328 	{
329 		ECHO_DEBUGPRINTF( ("C3g::GetInputClockDetect: DSP Dead!\n") );
330 		return ECHOSTATUS_DSP_DEAD;
331 	}
332 
333 	//
334 	// Map the DSP clock detect bits to the generic driver clock detect bits
335 	//
336 	DWORD dwClocksFromDsp = GetDspCommObject()->GetInputClockDetect();
337 
338 	dwClockDetectBits = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_MTC;
339 
340 	if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_WORD))
341 		dwClockDetectBits |= ECHO_CLOCK_BIT_WORD;
342 
343 	switch (GetDigitalMode())
344 	{
345 		case DIGITAL_MODE_SPDIF_RCA :
346 		case DIGITAL_MODE_SPDIF_OPTICAL :
347 			if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_SPDIF))
348 				dwClockDetectBits |= ECHO_CLOCK_BIT_SPDIF;
349 			break;
350 
351 		case DIGITAL_MODE_ADAT :
352 			if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_ADAT))
353 				dwClockDetectBits |= ECHO_CLOCK_BIT_ADAT;
354 			break;
355 	}
356 
357 	return ECHOSTATUS_OK;
358 
359 }	// GetInputClockDetect
360 
361 
362 //===========================================================================
363 //
364 // Get the external box type
365 //
366 //===========================================================================
367 
368 void C3g::Get3gBoxType(DWORD *pOriginalBoxType,DWORD *pCurrentBoxType)
369 {
370 	GetDspCommObject()->Get3gBoxType(pOriginalBoxType,pCurrentBoxType);
371 }
372 
373 
374 //===========================================================================
375 //
376 // Get the external box name
377 //
378 //===========================================================================
379 
380 char *C3g::Get3gBoxName()
381 {
382 	char *pszName;
383 	DWORD dwBoxType;
384 
385 	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
386 	switch (dwBoxType)
387 	{
388 		case GINA3G :
389 			pszName = "Gina3G";
390 			break;
391 
392 		case LAYLA3G :
393 			pszName = "Layla3G";
394 			break;
395 
396 		case NO3GBOX :
397 		default :
398 			pszName = "Echo3G";
399 			break;
400 	}
401 
402 	return pszName;
403 }
404 
405 
406 //===========================================================================
407 //
408 // Get phantom power state for Gina3G
409 //
410 //===========================================================================
411 
412 void C3g::GetPhantomPower(BOOL *pfPhantom)
413 {
414 	*pfPhantom = m_fPhantomPower;
415 }
416 
417 
418 //===========================================================================
419 //
420 // Set phantom power state for Gina3G
421 //
422 //===========================================================================
423 
424 void C3g::SetPhantomPower(BOOL fPhantom)
425 {
426 	DWORD dwBoxType;
427 
428 	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
429 	if (GINA3G == dwBoxType)
430 	{
431 		GetDspCommObject()->SetPhantomPower( fPhantom );
432 		m_fPhantomPower = fPhantom;
433 	}
434 }
435 
436 
437 //===========================================================================
438 //
439 // GetAudioLatency - returns the latency for a single pipe
440 //
441 //===========================================================================
442 
443 void C3g::GetAudioLatency(ECHO_AUDIO_LATENCY *pLatency)
444 {
445 	DWORD dwSampleRate;
446 
447 	//
448 	// Adjust the stored latency values based on the sample rate
449 	//
450 	dwSampleRate = GetDspCommObject()->GetSampleRate();
451 	if (dwSampleRate <= 50000)
452 	{
453 		m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
454 		m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
455 	}
456 	else
457 	{
458 		m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_2X;
459 		m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_2X;
460 	}
461 
462 	//
463 	// Let the base class worry about analog vs. digital
464 	//
465 	CEchoGals::GetAudioLatency(pLatency);
466 
467 }	// GetAudioLatency
468 
469 
470 
471 //===========================================================================
472 //
473 //	Start transport for a group of pipes
474 //
475 // Use this to make sure no one tries to start digital channels 3-8
476 // with the hardware in double speed mode.
477 //
478 //===========================================================================
479 
480 ECHOSTATUS C3g::Start
481 (
482 	PCChannelMask	pChannelMask
483 )
484 {
485 	PC3gDco pDCO;
486 
487 	//
488 	// Double speed mode?
489 	//
490 	pDCO = GetDspCommObject();
491 	if (pDCO->DoubleSpeedMode())
492 	{
493 		BOOL intersect;
494 
495 		//
496 		// See if ADAT in 3-8 or out 3-8 have been opened
497 		//
498 		intersect = m_cmAudioOpen.IsIntersectionOf( pDCO->m_Adat38Mask );
499 		if (intersect)
500 		{
501 			ECHO_DEBUGPRINTF(("Cannot start ADAT channels 3-8 in double speed mode\n"));
502 			return ECHOSTATUS_INVALID_CHANNEL;
503 		}
504 	}
505 
506 	return CEchoGals::Start(pChannelMask);
507 }
508 
509 // *** C3g.cpp ***
510