[BeBoB/MAudio] Add PreSonus::FireboxDevice class to support functionality to switch...
[ffado.git] / libffado / src / bebob / bebob_avdevice_subunit.cpp
blob9133ff7c6bb531e00e0b77470d1d18fd4843e048
1 /*
2 * Copyright (C) 2005-2008 by Daniel Wagner
4 * This file is part of FFADO
5 * FFADO = Free Firewire (pro-)audio drivers for linux
7 * FFADO is based upon FreeBoB
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) version 3 of the License.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "bebob/bebob_functionblock.h"
25 #include "bebob/bebob_avdevice_subunit.h"
26 #include "bebob/bebob_avdevice.h"
27 #include "bebob/bebob_avplug.h"
28 #include "libieee1394/configrom.h"
30 #include "libavc/general/avc_plug_info.h"
31 #include "libavc/streamformat/avc_extended_stream_format.h"
32 #include "libutil/cmd_serialize.h"
34 #include <sstream>
36 using namespace AVC;
38 //////////////////////////
40 BeBoB::SubunitAudio::SubunitAudio( AVC::Unit& avDevice,
41 subunit_t id )
42 : AVC::SubunitAudio( avDevice, id )
46 BeBoB::SubunitAudio::SubunitAudio()
47 : AVC::SubunitAudio()
51 BeBoB::SubunitAudio::~SubunitAudio()
53 for ( FunctionBlockVector::iterator it = m_functions.begin();
54 it != m_functions.end();
55 ++it )
57 delete *it;
61 AVC::Plug *
62 BeBoB::SubunitAudio::createPlug( AVC::Unit* unit,
63 AVC::Subunit* subunit,
64 AVC::function_block_type_t functionBlockType,
65 AVC::function_block_type_t functionBlockId,
66 AVC::Plug::EPlugAddressType plugAddressType,
67 AVC::Plug::EPlugDirection plugDirection,
68 AVC::plug_id_t plugId )
71 return new BeBoB::Plug( unit,
72 subunit,
73 functionBlockType,
74 functionBlockId,
75 plugAddressType,
76 plugDirection,
77 plugId );
80 bool
81 BeBoB::SubunitAudio::discover()
83 debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
85 // discover the AV/C generic part
86 if ( !AVC::SubunitAudio::discover() ) {
87 return false;
90 // do the remaining BeBoB audio subunit discovery
91 if ( !discoverFunctionBlocks() ) {
92 debugError( "function block discovering failed\n" );
93 return false;
96 return true;
99 bool
100 BeBoB::SubunitAudio::discoverConnections()
102 debugOutput(DEBUG_LEVEL_NORMAL, "Discovering connections...\n");
103 if ( !Subunit::discoverConnections() ) {
104 return false;
107 for ( FunctionBlockVector::iterator it = m_functions.begin();
108 it != m_functions.end();
109 ++it )
111 FunctionBlock* function = *it;
112 if ( !function->discoverConnections() ) {
113 debugError( "functionblock connection discovering failed ('%s')\n",
114 function->getName() );
115 return false;
119 return true;
122 const char*
123 BeBoB::SubunitAudio::getName()
125 return "BeBoB::AudioSubunit";
128 bool
129 BeBoB::SubunitAudio::discoverFunctionBlocks()
131 debugOutput( DEBUG_LEVEL_NORMAL,
132 "Discovering function blocks...\n");
134 if ( !discoverFunctionBlocksDo(
135 ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector) )
137 debugError( "Could not discover function block selector\n" );
138 return false;
140 if ( !discoverFunctionBlocksDo(
141 ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature) )
143 debugError( "Could not discover function block feature\n" );
144 return false;
146 if ( !discoverFunctionBlocksDo(
147 ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing) )
149 debugError( "Could not discover function block processing\n" );
150 return false;
152 if ( !discoverFunctionBlocksDo(
153 ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec) )
155 debugError( "Could not discover function block codec\n" );
156 return false;
159 // print a function block list
160 #ifdef DEBUG
161 if ((int)getDebugLevel() >= DEBUG_LEVEL_NORMAL) {
163 for ( FunctionBlockVector::iterator it = m_functions.begin();
164 it != m_functions.end();
165 ++it )
167 debugOutput(DEBUG_LEVEL_NORMAL, "%20s FB, type 0x%X, id=%d\n",
168 (*it)->getName(),
169 (*it)->getType(),
170 (*it)->getId());
173 #endif
175 return true;
178 bool
179 BeBoB::SubunitAudio::discoverFunctionBlocksDo(
180 ExtendedSubunitInfoCmd::EFunctionBlockType fbType )
182 int page = 0;
183 bool cmdSuccess = false;
184 bool finished = false;
186 do {
187 ExtendedSubunitInfoCmd
188 extSubunitInfoCmd( m_unit->get1394Service() );
189 extSubunitInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
190 extSubunitInfoCmd.setCommandType( AVCCommand::eCT_Status );
191 extSubunitInfoCmd.setSubunitId( getSubunitId() );
192 extSubunitInfoCmd.setSubunitType( getSubunitType() );
193 extSubunitInfoCmd.setVerbose( (int)getDebugLevel() );
195 extSubunitInfoCmd.m_fbType = fbType;
196 extSubunitInfoCmd.m_page = page;
198 cmdSuccess = extSubunitInfoCmd.fire();
199 if ( cmdSuccess
200 && ( extSubunitInfoCmd.getResponse()
201 == AVCCommand::eR_Implemented ) )
203 for ( ExtendedSubunitInfoPageDataVector::iterator it =
204 extSubunitInfoCmd.m_infoPageDatas.begin();
205 cmdSuccess
206 && ( it != extSubunitInfoCmd.m_infoPageDatas.end() );
207 ++it )
209 cmdSuccess = createFunctionBlock( fbType, **it );
211 if ( ( extSubunitInfoCmd.m_infoPageDatas.size() != 0 )
212 && ( extSubunitInfoCmd.m_infoPageDatas.size() == 5 ) )
214 page++;
215 } else {
216 finished = true;
218 } else {
219 finished = true;
221 } while ( cmdSuccess && !finished );
223 return cmdSuccess;
226 bool
227 BeBoB::SubunitAudio::createFunctionBlock(
228 ExtendedSubunitInfoCmd::EFunctionBlockType fbType,
229 ExtendedSubunitInfoPageData& data )
231 FunctionBlock::ESpecialPurpose purpose
232 = convertSpecialPurpose( data.m_functionBlockSpecialPupose );
234 FunctionBlock* fb = 0;
236 switch ( fbType ) {
237 case ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector:
239 fb = new FunctionBlockSelector( *this,
240 data.m_functionBlockId,
241 purpose,
242 data.m_noOfInputPlugs,
243 data.m_noOfOutputPlugs,
244 (int)getDebugLevel() );
246 break;
247 case ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature:
249 fb = new FunctionBlockFeature( *this,
250 data.m_functionBlockId,
251 purpose,
252 data.m_noOfInputPlugs,
253 data.m_noOfOutputPlugs,
254 (int)getDebugLevel() );
256 break;
257 case ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing:
259 switch ( data.m_functionBlockType ) {
260 case ExtendedSubunitInfoCmd::ePT_EnhancedMixer:
262 fb = new FunctionBlockEnhancedMixer( *this,
263 data.m_functionBlockId,
264 purpose,
265 data.m_noOfInputPlugs,
266 data.m_noOfOutputPlugs,
267 (int)getDebugLevel() );
269 break;
270 case ExtendedSubunitInfoCmd::ePT_Mixer:
271 case ExtendedSubunitInfoCmd::ePT_Generic:
272 case ExtendedSubunitInfoCmd::ePT_UpDown:
273 case ExtendedSubunitInfoCmd::ePT_DolbyProLogic:
274 case ExtendedSubunitInfoCmd::ePT_3DStereoExtender:
275 case ExtendedSubunitInfoCmd::ePT_Reverberation:
276 case ExtendedSubunitInfoCmd::ePT_Chorus:
277 case ExtendedSubunitInfoCmd::ePT_DynamicRangeCompression:
278 default:
279 /* It is no use to add a dummy FunctionBlockProcessing because
280 then the function type is not set in FunctionBlockProcessing.
281 When we try to discover the plugs attached to this function block
282 it will fail. It's better just to skip them. */
283 debugOutput( DEBUG_LEVEL_NORMAL, "Found a processing subfunction (type %d) which is not supported. "
284 "It will be ignored.\n",
285 data.m_functionBlockType);
286 return true;
289 break;
290 case ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec:
292 /* It is no use to add a dummy FunctionBlockProcessing because
293 then the function type is not set in FunctionBlockProcessing.
294 When we try to discover the plugs attached to this function block
295 it will fail. It's better just to skip them. */
296 debugOutput( DEBUG_LEVEL_NORMAL, "Found a codec subfunction (type %d) which is not supported. "
297 "It will be ignored.\n",
298 data.m_functionBlockType);
299 return true;
301 break;
302 default:
303 debugError( "Unhandled function block type found\n" );
304 return false;
307 if ( !fb ) {
308 debugError( "Could create function block\n" );
309 return false;
311 if ( !fb->discover() ) {
312 debugError( "Could not discover function block %s\n",
313 fb->getName() );
314 delete fb;
315 return false;
317 m_functions.push_back( fb );
319 return true;
322 BeBoB::FunctionBlock::ESpecialPurpose
323 BeBoB::SubunitAudio::convertSpecialPurpose(
324 function_block_special_purpose_t specialPurpose )
326 FunctionBlock::ESpecialPurpose p;
327 switch ( specialPurpose ) {
328 case ExtendedSubunitInfoPageData::eSP_InputGain:
329 p = FunctionBlock::eSP_InputGain;
330 break;
331 case ExtendedSubunitInfoPageData::eSP_OutputVolume:
332 p = FunctionBlock::eSP_OutputVolume;
333 break;
334 default:
335 p = FunctionBlock::eSP_NoSpecialPurpose;
337 return p;
340 bool
341 BeBoB::SubunitAudio::serializeChild( std::string basePath,
342 Util::IOSerialize& ser ) const
344 bool result = true;
345 int i = 0;
347 for ( FunctionBlockVector::const_iterator it = m_functions.begin();
348 it != m_functions.end();
349 ++it )
351 FunctionBlock* pFB = *it;
352 std::ostringstream strstrm;
353 strstrm << basePath << "FunctionBlock" << i << "/";
355 result &= pFB->serialize( strstrm.str() , ser );
357 i++;
360 return result;
363 bool
364 BeBoB::SubunitAudio::deserializeChild( std::string basePath,
365 Util::IODeserialize& deser,
366 AVC::Unit& avDevice )
368 int i = 0;
369 bool bFinished = false;
370 do {
371 std::ostringstream strstrm;
372 strstrm << basePath << "FunctionBlock" << i << "/";
373 FunctionBlock* pFB = FunctionBlock::deserialize( strstrm.str(),
374 deser,
375 avDevice,
376 *this );
377 if ( pFB ) {
378 m_functions.push_back( pFB );
379 i++;
380 } else {
381 bFinished = true;
383 } while ( !bFinished );
385 return true;
388 bool
389 BeBoB::SubunitAudio::deserializeUpdateChild( std::string basePath,
390 Util::IODeserialize& deser )
392 bool result = true;
393 int i = 0;
395 for ( FunctionBlockVector::iterator it = m_functions.begin();
396 it != m_functions.end();
397 ++it )
399 std::ostringstream strstrm;
400 strstrm << basePath << "FunctionBlock" << i << "/";
402 result &= (*it)->deserializeUpdate( basePath, deser );
404 i++;
407 return result;
410 ////////////////////////////////////////////
412 BeBoB::SubunitMusic::SubunitMusic( AVC::Unit& avDevice,
413 subunit_t id )
414 : AVC::SubunitMusic( avDevice, id )
418 BeBoB::SubunitMusic::SubunitMusic()
419 : AVC::SubunitMusic()
423 BeBoB::SubunitMusic::~SubunitMusic()
427 AVC::Plug *
428 BeBoB::SubunitMusic::createPlug( AVC::Unit* unit,
429 AVC::Subunit* subunit,
430 AVC::function_block_type_t functionBlockType,
431 AVC::function_block_type_t functionBlockId,
432 AVC::Plug::EPlugAddressType plugAddressType,
433 AVC::Plug::EPlugDirection plugDirection,
434 AVC::plug_id_t plugId )
437 return new BeBoB::Plug( unit,
438 subunit,
439 functionBlockType,
440 functionBlockId,
441 plugAddressType,
442 plugDirection,
443 plugId );
446 bool
447 BeBoB::SubunitMusic::discover()
449 debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
451 // discover the AV/C generic part
452 if ( !AVC::SubunitMusic::discover() ) {
453 return false;
456 // do the remaining BeBoB music subunit discovery
457 // which is nothing
459 return true;
462 const char*
463 BeBoB::SubunitMusic::getName()
465 return "BeBoB::MusicSubunit";
468 bool
469 BeBoB::SubunitMusic::serializeChild( std::string basePath,
470 Util::IOSerialize& ser ) const
472 return true;
475 bool
476 BeBoB::SubunitMusic::deserializeChild( std::string basePath,
477 Util::IODeserialize& deser,
478 AVC::Unit& avDevice )
480 return true;
483 bool
484 BeBoB::SubunitMusic::deserializeUpdateChild( std::string basePath,
485 Util::IODeserialize& deser )
487 return true;