xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/C3g.cpp (revision 4dd9e43637031d2c5a6755a0184040f0de8f2884)
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 
operator new(size_t Size)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 
operator delete(PVOID pVoid)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 
C3g(PCOsSupport pOsSupport)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 
~C3g()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 
InitHw()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 	ECHO_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 
GetCapabilities(PECHOGALS_CAPS pCapabilities)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 
QueryAudioSampleRate(DWORD dwSampleRate)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 
QuerySampleRateRange(DWORD & dwMinRate,DWORD & dwMaxRate)314 void C3g::QuerySampleRateRange(DWORD &dwMinRate,DWORD &dwMaxRate)
315 {
316 	dwMinRate = 32000;
317 	dwMaxRate = 96000;
318 }
319 
320 
321 
322 //===========================================================================
323 //
324 // GetInputClockDetect returns a bitmask consisting of all the input
325 // clocks currently connected to the hardware; this changes as the user
326 // connects and disconnects clock inputs.
327 //
328 // You should use this information to determine which clocks the user is
329 // allowed to select.
330 //
331 //===========================================================================
332 
GetInputClockDetect(DWORD & dwClockDetectBits)333 ECHOSTATUS C3g::GetInputClockDetect(DWORD &dwClockDetectBits)
334 {
335 	if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
336 	{
337 		ECHO_DEBUGPRINTF( ("C3g::GetInputClockDetect: DSP Dead!\n") );
338 		return ECHOSTATUS_DSP_DEAD;
339 	}
340 
341 	//
342 	// Map the DSP clock detect bits to the generic driver clock detect bits
343 	//
344 	DWORD dwClocksFromDsp = GetDspCommObject()->GetInputClockDetect();
345 
346 	dwClockDetectBits = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_MTC;
347 
348 	if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_WORD))
349 		dwClockDetectBits |= ECHO_CLOCK_BIT_WORD;
350 
351 	switch (GetDigitalMode())
352 	{
353 		case DIGITAL_MODE_SPDIF_RCA :
354 		case DIGITAL_MODE_SPDIF_OPTICAL :
355 			if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_SPDIF))
356 				dwClockDetectBits |= ECHO_CLOCK_BIT_SPDIF;
357 			break;
358 
359 		case DIGITAL_MODE_ADAT :
360 			if (0 != (dwClocksFromDsp & E3G_CLOCK_DETECT_BIT_ADAT))
361 				dwClockDetectBits |= ECHO_CLOCK_BIT_ADAT;
362 			break;
363 	}
364 
365 	return ECHOSTATUS_OK;
366 
367 }	// GetInputClockDetect
368 
369 
370 //===========================================================================
371 //
372 // Get the external box type
373 //
374 //===========================================================================
375 
Get3gBoxType(DWORD * pOriginalBoxType,DWORD * pCurrentBoxType)376 void C3g::Get3gBoxType(DWORD *pOriginalBoxType,DWORD *pCurrentBoxType)
377 {
378 	GetDspCommObject()->Get3gBoxType(pOriginalBoxType,pCurrentBoxType);
379 }
380 
381 
382 //===========================================================================
383 //
384 // Get the external box name
385 //
386 //===========================================================================
387 
Get3gBoxName()388 char *C3g::Get3gBoxName()
389 {
390 	char *pszName;
391 	DWORD dwBoxType;
392 
393 	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
394 	switch (dwBoxType)
395 	{
396 		case GINA3G :
397 			pszName = "Gina3G";
398 			break;
399 
400 		case LAYLA3G :
401 			pszName = "Layla3G";
402 			break;
403 
404 		case NO3GBOX :
405 		default :
406 			pszName = "Echo3G";
407 			break;
408 	}
409 
410 	return pszName;
411 }
412 
413 
414 //===========================================================================
415 //
416 // Get phantom power state for Gina3G
417 //
418 //===========================================================================
419 
GetPhantomPower(BOOL * pfPhantom)420 void C3g::GetPhantomPower(BOOL *pfPhantom)
421 {
422 	*pfPhantom = m_fPhantomPower;
423 }
424 
425 
426 //===========================================================================
427 //
428 // Set phantom power state for Gina3G
429 //
430 //===========================================================================
431 
SetPhantomPower(BOOL fPhantom)432 void C3g::SetPhantomPower(BOOL fPhantom)
433 {
434 	DWORD dwBoxType;
435 
436 	GetDspCommObject()->Get3gBoxType(&dwBoxType,NULL);
437 	if (GINA3G == dwBoxType)
438 	{
439 		GetDspCommObject()->SetPhantomPower( fPhantom );
440 		m_fPhantomPower = fPhantom;
441 	}
442 }
443 
444 
445 //===========================================================================
446 //
447 // GetAudioLatency - returns the latency for a single pipe
448 //
449 //===========================================================================
450 
GetAudioLatency(ECHO_AUDIO_LATENCY * pLatency)451 void C3g::GetAudioLatency(ECHO_AUDIO_LATENCY *pLatency)
452 {
453 	DWORD dwSampleRate;
454 
455 	//
456 	// Adjust the stored latency values based on the sample rate
457 	//
458 	dwSampleRate = GetDspCommObject()->GetSampleRate();
459 	if (dwSampleRate <= 50000)
460 	{
461 		m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_1X;
462 		m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_1X;
463 	}
464 	else
465 	{
466 		m_wAnalogOutputLatency = ECHO3G_ANALOG_OUTPUT_LATENCY_2X;
467 		m_wAnalogInputLatency = ECHO3G_ANALOG_INPUT_LATENCY_2X;
468 	}
469 
470 	//
471 	// Let the base class worry about analog vs. digital
472 	//
473 	CEchoGals::GetAudioLatency(pLatency);
474 
475 }	// GetAudioLatency
476 
477 
478 
479 //===========================================================================
480 //
481 //	Start transport for a group of pipes
482 //
483 // Use this to make sure no one tries to start digital channels 3-8
484 // with the hardware in double speed mode.
485 //
486 //===========================================================================
487 
Start(PCChannelMask pChannelMask)488 ECHOSTATUS C3g::Start
489 (
490 	PCChannelMask	pChannelMask
491 )
492 {
493 	PC3gDco pDCO;
494 
495 	//
496 	// Double speed mode?
497 	//
498 	pDCO = GetDspCommObject();
499 	if (pDCO->DoubleSpeedMode())
500 	{
501 		BOOL intersect;
502 
503 		//
504 		// See if ADAT in 3-8 or out 3-8 are being started
505 		//
506 		intersect = pChannelMask->IsIntersectionOf( pDCO->m_Adat38Mask );
507 		if (intersect)
508 		{
509 			ECHO_DEBUGPRINTF(("Cannot start ADAT channels 3-8 in double speed mode\n"));
510 			return ECHOSTATUS_INVALID_CHANNEL;
511 		}
512 	}
513 
514 	return CEchoGals::Start(pChannelMask);
515 }
516 
517 // *** C3g.cpp ***
518