xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/CLaylaDspCommObject.cpp (revision be188ae133da3258026dc1f9c1330f0d27e53494)
1 // ****************************************************************************
2 //
3 //  	CLaylaDspCommObject.cpp
4 //
5 //		Implementation file for EchoGals generic driver Layla 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 "CLaylaDspCommObject.h"
33 
34 #include "Layla20DSP.c"
35 #include "LaylaASIC.c"
36 
37 //
38 // The ASIC files for Layla20 are always this size
39 //
40 #define LAYLA_ASIC_SIZE		32385
41 
42 
43 /****************************************************************************
44 
45 	Construction and destruction
46 
47  ****************************************************************************/
48 
49 //===========================================================================
50 //
51 // Constructor
52 //
53 //===========================================================================
54 
CLaylaDspCommObject(PDWORD pdwRegBase,PCOsSupport pOsSupport)55 CLaylaDspCommObject::CLaylaDspCommObject
56 (
57 	PDWORD		pdwRegBase,				// Virtual ptr to DSP registers
58 	PCOsSupport	pOsSupport
59 ) : CDspCommObject( pdwRegBase, pOsSupport )
60 {
61 	strcpy( m_szCardName, "Layla" );
62 	m_pdwDspRegBase = pdwRegBase;		// Virtual addr DSP's register base
63 
64 	m_wNumPipesOut = 12;
65 	m_wNumPipesIn = 10;
66 	m_wNumBussesOut = 12;
67 	m_wNumBussesIn = 10;
68 	m_wFirstDigitalBusOut = 10;
69 	m_wFirstDigitalBusIn = 8;
70 
71 	m_fHasVmixer = FALSE;
72 
73 	m_wNumMidiOut = 1;					// # MIDI out channels
74 	m_wNumMidiIn = 1;						// # MIDI in  channels
75 
76 	m_bHasASIC = TRUE;
77 
78 	m_pwDspCodeToLoad = pwLayla20DSP;
79 
80 }	// CLaylaDspCommObject::CLaylaDspCommObject( DWORD dwPhysRegBase )
81 
82 
83 //===========================================================================
84 //
85 // Destructor
86 //
87 //===========================================================================
88 
~CLaylaDspCommObject()89 CLaylaDspCommObject::~CLaylaDspCommObject()
90 {
91 	ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::~CLaylaDspCommObject() is toast!\n" ) );
92 }	// CLaylaDspCommObject::~CLaylaDspCommObject()
93 
94 
95 
96 
97 /****************************************************************************
98 
99 	Hardware setup and config
100 
101  ****************************************************************************/
102 
103 //===========================================================================
104 //
105 // Layla20 has an ASIC in the external box
106 //
107 //===========================================================================
108 
LoadASIC()109 BOOL CLaylaDspCommObject::LoadASIC()
110 {
111 	if ( m_bASICLoaded == TRUE )
112 		return TRUE;
113 
114 	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA_ASIC,
115 											  pbLaylaASIC,
116 											  LAYLA_ASIC_SIZE ) )
117 		return FALSE;
118 	//
119 	// Check if ASIC is alive and well.
120 	//
121 	return( CheckAsicStatus() );
122 }	// BOOL CLaylaDspCommObject::LoadASIC()
123 
124 
125 //===========================================================================
126 //
127 // SetSampleRate
128 //
129 // Set the sample rate for Layla
130 //
131 // Layla is simple; just send it the sampling rate (assuming that the clock
132 // mode is correct).
133 //
134 //===========================================================================
135 
SetSampleRate(DWORD dwNewSampleRate)136 DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
137 {
138 	//
139 	// Only set the clock for internal mode
140 	//	Do not return failure, simply treat it as a non-event.
141 	//
142 	if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
143 	{
144 		ECHO_DEBUGPRINTF( ( "SetSampleRate: Cannot set sample rate because "
145 								  "Layla clock NOT set to CLK_CLOCKININTERNAL\n" ) );
146 		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
147 		return GetSampleRate();
148 	}
149 
150 	//
151 	// Sanity check - check the sample rate
152 	//
153 	if ( ( dwNewSampleRate < 8000 ) ||
154 		  ( dwNewSampleRate > 50000 ) )
155 	{
156 		ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate %ld out of range, "
157 								  "no change made\n",
158 								  dwNewSampleRate) );
159 		return 0xffffffff;
160 	}
161 
162 	if ( !WaitForHandshake() )
163 		return 0xffffffff;
164 
165 	m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
166 
167 	ClearHandshake();
168 	SendVector( DSP_VC_SET_LAYLA_SAMPLE_RATE );
169 	ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate changed to %ld\n",
170 							  dwNewSampleRate ) );
171 	return( dwNewSampleRate );
172 }	// DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
173 
174 
175 //===========================================================================
176 //
177 // Send new input clock setting to DSP
178 //
179 //===========================================================================
180 
SetInputClock(WORD wClock)181 ECHOSTATUS CLaylaDspCommObject::SetInputClock(WORD wClock)
182 {
183 	BOOL			bSetRate;
184 	WORD			wNewClock;
185 
186 	ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::SetInputClock:\n" ) );
187 
188 	bSetRate = FALSE;
189 
190 	switch ( wClock )
191 	{
192 		case ECHO_CLOCK_INTERNAL :
193 			ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) );
194 
195 			// If the sample rate is out of range for some reason, set it
196 			// to a reasonable value.  mattg
197 			if ( ( GetSampleRate() < 8000 ) ||
198 			     ( GetSampleRate() > 50000 ) )
199 			{
200 				m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
201 			}
202 
203 			bSetRate = TRUE;
204 			wNewClock = LAYLA20_CLOCK_INTERNAL;
205 			break;
206 
207 		case ECHO_CLOCK_SPDIF:
208 			ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SPDIF\n" ) );
209 
210 			wNewClock = LAYLA20_CLOCK_SPDIF;
211 			break;
212 
213 		case ECHO_CLOCK_WORD:
214 			ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to WORD\n" ) );
215 
216 			wNewClock = LAYLA20_CLOCK_WORD;
217 
218 			break;
219 
220 		case ECHO_CLOCK_SUPER:
221 			ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SUPER\n" ) );
222 
223 			wNewClock = LAYLA20_CLOCK_SUPER;
224 
225 			break;
226 
227 		default :
228 			ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock));
229 			ECHO_DEBUGBREAK();
230 				return ECHOSTATUS_CLOCK_NOT_SUPPORTED;
231 
232 	}		// switch (wClock)
233 
234 	//
235 	// Winner! Save the new input clock.
236 	//
237 	m_wInputClock = wClock;
238 
239 	//
240 	// Send the new clock to the DSP
241 	//
242 	m_pDspCommPage->wInputClock = SWAP(wNewClock);
243 	ClearHandshake();
244 	SendVector( DSP_VC_UPDATE_CLOCKS );
245 
246 	if ( bSetRate )
247 		SetSampleRate();
248 
249 	return ECHOSTATUS_OK;
250 }		// ECHOSTATUS CLaylaDspCommObject::SetInputClock()
251 
252 
253 //===========================================================================
254 //
255 // Set new output clock
256 //
257 //===========================================================================
258 
SetOutputClock(WORD wClock)259 ECHOSTATUS CLaylaDspCommObject::SetOutputClock(WORD wClock)
260 {
261 	WORD wLaylaOutClock;
262 
263 	if (FALSE == m_bASICLoaded)
264 		return ECHOSTATUS_ASIC_NOT_LOADED;
265 
266 	if (!WaitForHandshake())
267 		return ECHOSTATUS_DSP_DEAD;
268 
269 	ECHO_DEBUGPRINTF( ("CDspCommObject::SetOutputClock:\n") );
270 
271 	//
272 	// Translate generic driver clock constants to values for Layla20 firmware
273 	//
274 	switch (wClock)
275 	{
276 		case ECHO_CLOCK_SUPER :
277 			wLaylaOutClock = LAYLA20_OUTPUT_CLOCK_SUPER;
278 			break;
279 
280 		case ECHO_CLOCK_WORD :
281 			wLaylaOutClock = LAYLA20_OUTPUT_CLOCK_WORD;
282 			break;
283 
284 		default :
285 			return ECHOSTATUS_INVALID_PARAM;
286 	}
287 
288 	m_pDspCommPage->wOutputClock = SWAP(wLaylaOutClock);
289 	m_wOutputClock = wClock;
290 
291 	ClearHandshake();
292 	ECHOSTATUS Status = SendVector(DSP_VC_UPDATE_CLOCKS);
293 
294 	return Status;
295 }	// ECHOSTATUS CLaylaDspCommObject::SetOutputClock
296 
297 
298 //===========================================================================
299 //
300 // Input bus gain - iGain is in units of .5 dB
301 //
302 //===========================================================================
303 
SetBusInGain(WORD wBusIn,INT32 iGain)304 ECHOSTATUS CLaylaDspCommObject::SetBusInGain( WORD wBusIn, INT32 iGain)
305 {
306 	ECHO_DEBUGPRINTF(("CLaylaDspCommObject::SetBusInGain\n"));
307 
308 	if (wBusIn >= LAYLA20_INPUT_TRIMS)
309 		return ECHOSTATUS_INVALID_CHANNEL;
310 
311 	//
312 	// Store the gain for later use
313 	//
314 	m_byInputTrims[wBusIn] = (BYTE) iGain;
315 
316 	//
317 	// Adjust the input gain depending on the nominal level switch
318 	//
319 	BYTE byMinus10;
320 	GetNominalLevel( wBusIn + m_wNumBussesOut, &byMinus10);
321 
322 	if (0 == byMinus10)
323 	{
324 		//
325 		// This channel is in +4 mode; subtract 12 dB from the input gain
326 		// (note that iGain is in units of .5 dB)
327 		//
328 		iGain -= 12 << 1;
329 	}
330 
331 	return CDspCommObject::SetBusInGain(wBusIn,iGain);
332 
333 }
334 
335 
GetBusInGain(WORD wBusIn,INT32 & iGain)336 ECHOSTATUS CLaylaDspCommObject::GetBusInGain( WORD wBusIn, INT32 &iGain)
337 {
338 	if (wBusIn >= LAYLA20_INPUT_TRIMS)
339 		return ECHOSTATUS_INVALID_CHANNEL;
340 
341 	iGain = (INT32) m_byInputTrims[wBusIn];
342 
343 	return ECHOSTATUS_OK;
344 }
345 
346 
347 //===========================================================================
348 //
349 // Set the nominal level for an input or output bus
350 //
351 //	Set bState to TRUE for -10, FALSE for +4
352 //
353 // Layla20 sets the input nominal level by adjusting the
354 // input trim
355 //
356 //===========================================================================
357 
SetNominalLevel(WORD wBus,BOOL bState)358 ECHOSTATUS CLaylaDspCommObject::SetNominalLevel
359 (
360 	WORD	wBus,
361 	BOOL	bState
362 )
363 {
364 	ECHO_DEBUGPRINTF(("CLaylaDspCommObject::SetNominalLevel\n"));
365 
366 	if (wBus < m_wNumBussesOut)
367 	{
368 		//
369 		//	This is an output bus; call the base class routine to service it
370 		//
371 		return CDspCommObject::SetNominalLevel(wBus,bState);
372 	}
373 
374 	//
375 	// Check the bus number
376 	//
377 	ECHO_DEBUGPRINTF(("\tChecking the bus number\n"));
378 	if (wBus < (m_wNumBussesOut + LAYLA20_INPUT_TRIMS))
379 	{
380 		ECHO_DEBUGPRINTF(("\twBus %d  m_pDspCommPage %p\n",wBus,m_pDspCommPage));
381 		//
382 		// Set the nominal bit in the comm page
383 		//
384 		if ( bState )
385 			m_pDspCommPage->cmdNominalLevel.SetIndexInMask( wBus );
386 		else
387 			m_pDspCommPage->cmdNominalLevel.ClearIndexInMask( wBus );
388 
389 		//
390 		// Set the input trim, using the current gain
391 		//
392 		ECHO_DEBUGPRINTF(("\tCalling SetBusInGain\n"));
393 
394 		wBus = wBus - m_wNumBussesOut;
395 		return SetBusInGain(	wBus, (INT32) m_byInputTrims[wBus]);
396 	}
397 
398 	ECHO_DEBUGPRINTF( ("CLaylaDspCommObject::SetNominalOutLineLevel Invalid "
399 							 "index %d\n",
400 							 wBus ) );
401 	return ECHOSTATUS_INVALID_CHANNEL;
402 
403 }	// ECHOSTATUS CLaylaDspCommObject::SetNominalLevel
404 
405 
406 //===========================================================================
407 //
408 // ASIC status check
409 //
410 // This test sometimes fails for Layla20; for Layla20, the loop runs 5 times
411 // and succeeds if it wins on three of the loops.
412 //
413 //===========================================================================
414 
CheckAsicStatus()415 BOOL CLaylaDspCommObject::CheckAsicStatus()
416 {
417 	DWORD dwNumTests;
418 	DWORD dwNumWins;
419 	BOOL bLoaded;
420 
421 	dwNumTests = NUM_ASIC_ATTEMPTS;
422 	dwNumWins = 0;
423 	do
424 	{
425 		bLoaded = CDspCommObject::CheckAsicStatus();
426 		if (FALSE != bLoaded)
427 		{
428 			dwNumWins++;
429 			if (NUM_ASIC_WINS == dwNumWins)
430 			{
431 				m_bASICLoaded = TRUE;
432 				break;
433 			}
434 		}
435 
436 		m_bASICLoaded = FALSE;
437 		dwNumTests--;
438 	} while (dwNumTests != 0);
439 
440 	return m_bASICLoaded;
441 
442 }	// BOOL CLaylaDspCommObject::CheckAsicStatus()
443 
444 
445 // **** LaylaDspCommObject.cpp ****
446