[BeBoB/MAudio] Add PreSonus::FireboxDevice class to support functionality to switch...
[ffado.git] / libffado / src / bebob / bebob_avplug.cpp
blob09ef32d871d773e40ccae0ceefd04a51c1db19c1
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_avplug.h"
25 #include "bebob/bebob_avdevice.h"
26 #include "libieee1394/configrom.h"
28 #include "libieee1394/ieee1394service.h"
29 #include "libutil/cmd_serialize.h"
31 #include <sstream>
33 using namespace AVC;
35 namespace BeBoB {
37 Plug::Plug( AVC::Unit* unit,
38 AVC::Subunit* subunit,
39 AVC::function_block_type_t functionBlockType,
40 AVC::function_block_type_t functionBlockId,
41 AVC::Plug::EPlugAddressType plugAddressType,
42 AVC::Plug::EPlugDirection plugDirection,
43 AVC::plug_id_t plugId )
44 : AVC::Plug( unit,
45 subunit,
46 functionBlockType,
47 functionBlockId,
48 plugAddressType,
49 plugDirection,
50 plugId )
52 debugOutput( DEBUG_LEVEL_VERBOSE,
53 "nodeId = %d, subunitType = %d, "
54 "subunitId = %d, functionBlockType = %d, "
55 "functionBlockId = %d, addressType = %d, "
56 "direction = %d, id = %d\n",
57 unit->getConfigRom().getNodeId(),
58 getSubunitType(),
59 getSubunitId(),
60 functionBlockType,
61 functionBlockId,
62 plugAddressType,
63 plugDirection,
64 plugId );
67 Plug::Plug( AVC::Unit* unit,
68 AVC::Subunit* subunit,
69 AVC::function_block_type_t functionBlockType,
70 AVC::function_block_type_t functionBlockId,
71 AVC::Plug::EPlugAddressType plugAddressType,
72 AVC::Plug::EPlugDirection plugDirection,
73 AVC::plug_id_t plugId,
74 int globalId )
75 : AVC::Plug( unit,
76 subunit,
77 functionBlockType,
78 functionBlockId,
79 plugAddressType,
80 plugDirection,
81 plugId,
82 globalId )
84 debugOutput( DEBUG_LEVEL_VERBOSE,
85 "nodeId = %d, subunitType = %d, "
86 "subunitId = %d, functionBlockType = %d, "
87 "functionBlockId = %d, addressType = %d, "
88 "direction = %d, id = %d\n",
89 unit->getConfigRom().getNodeId(),
90 getSubunitType(),
91 getSubunitId(),
92 functionBlockType,
93 functionBlockId,
94 plugAddressType,
95 plugDirection,
96 plugId );
99 Plug::Plug( const Plug& rhs )
100 : AVC::Plug( rhs )
105 Plug::Plug()
106 : AVC::Plug()
110 Plug::~Plug()
115 bool
116 Plug::discover()
118 if ( !discoverPlugType() ) {
119 debugError( "discover: Could not discover plug type (%d,%d,%d,%d,%d)\n",
120 m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
121 return false;
124 if ( !discoverName() ) {
125 debugError( "Could not discover name (%d,%d,%d,%d,%d)\n",
126 m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
127 return false;
130 if ( !discoverNoOfChannels() ) {
131 debugError( "Could not discover number of channels "
132 "(%d,%d,%d,%d,%d)\n",
133 m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
134 return false;
137 if ( !discoverChannelPosition() ) {
138 debugError( "Could not discover channel positions "
139 "(%d,%d,%d,%d,%d)\n",
140 m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
141 return false;
144 if ( !discoverChannelName() ) {
145 debugError( "Could not discover channel name "
146 "(%d,%d,%d,%d,%d)\n",
147 m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
148 return false;
151 if ( !discoverClusterInfo() ) {
152 debugError( "Could not discover channel name "
153 "(%d,%d,%d,%d,%d)\n",
154 m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
155 return false;
158 if ( !discoverStreamFormat() ) {
159 debugError( "Could not discover stream format "
160 "(%d,%d,%d,%d,%d)\n",
161 m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
162 return false;
165 if ( !discoverSupportedStreamFormats() ) {
166 debugError( "Could not discover supported stream formats "
167 "(%d,%d,%d,%d,%d)\n",
168 m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
169 return false;
172 return m_unit->getPlugManager().addPlug( *this );
175 bool
176 Plug::discoverConnections()
178 return discoverConnectionsInput() && discoverConnectionsOutput();
181 bool
182 Plug::discoverPlugType()
184 ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
185 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
186 ExtendedPlugInfoInfoType::eIT_PlugType );
187 extendedPlugInfoInfoType.initialize();
188 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
189 extPlugInfoCmd.setVerbose( getDebugLevel() );
191 if ( !extPlugInfoCmd.fire() ) {
192 debugError( "plug type command failed\n" );
193 return false;
196 m_infoPlugType = eAPT_Unknown;
198 if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Implemented ) {
200 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
201 if ( infoType
202 && infoType->m_plugType )
204 plug_type_t plugType = infoType->m_plugType->m_plugType;
206 debugOutput( DEBUG_LEVEL_VERBOSE,
207 "plug %d is of type %d (%s)\n",
208 m_id,
209 plugType,
210 extendedPlugInfoPlugTypeToString( plugType ) );
211 switch ( plugType ) {
212 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_IsoStream:
213 m_infoPlugType = eAPT_IsoStream;
214 break;
215 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_AsyncStream:
216 m_infoPlugType = eAPT_AsyncStream;
217 break;
218 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Midi:
219 m_infoPlugType = eAPT_Midi;
220 break;
221 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Sync:
222 m_infoPlugType = eAPT_Sync;
223 break;
224 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Analog:
225 m_infoPlugType = eAPT_Analog;
226 break;
227 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Digital:
228 m_infoPlugType = eAPT_Digital;
229 break;
230 default:
231 m_infoPlugType = eAPT_Unknown;
235 } else {
236 debugError( "Plug does not implement extended plug info plug "
237 "type info command\n" );
238 return false;
241 return true;
244 bool
245 Plug::discoverName()
247 ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
248 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
249 ExtendedPlugInfoInfoType::eIT_PlugName );
250 extendedPlugInfoInfoType.initialize();
251 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
252 extPlugInfoCmd.setVerbose( getDebugLevel() );
254 if ( !extPlugInfoCmd.fire() ) {
255 debugError( "name command failed\n" );
256 return false;
259 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
260 if ( infoType
261 && infoType->m_plugName )
263 std::string name =
264 infoType->m_plugName->m_name;
266 debugOutput( DEBUG_LEVEL_VERBOSE,
267 "plug %d has name '%s'\n",
268 m_id,
269 name.c_str() );
271 m_name = name;
273 return true;
276 bool
277 Plug::discoverNoOfChannels()
279 ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
280 //extPlugInfoCmd.setVerbose( true );
281 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
282 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
283 extendedPlugInfoInfoType.initialize();
284 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
285 extPlugInfoCmd.setVerbose( getDebugLevel() );
287 if ( !extPlugInfoCmd.fire() ) {
288 debugError( "number of channels command failed\n" );
289 return false;
292 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
293 if ( infoType
294 && infoType->m_plugNrOfChns )
296 nr_of_channels_t nrOfChannels
297 = infoType->m_plugNrOfChns->m_nrOfChannels;
299 debugOutput( DEBUG_LEVEL_VERBOSE,
300 "plug %d has %d channels\n",
301 m_id,
302 nrOfChannels );
304 m_nrOfChannels = nrOfChannels;
306 return true;
309 bool
310 Plug::discoverChannelPosition()
312 ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
313 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
314 ExtendedPlugInfoInfoType::eIT_ChannelPosition );
315 extendedPlugInfoInfoType.initialize();
316 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
317 extPlugInfoCmd.setVerbose( getDebugLevel() );
319 if ( !extPlugInfoCmd.fire() ) {
320 debugError( "channel position command failed\n" );
321 return false;
324 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
325 if ( infoType
326 && infoType->m_plugChannelPosition )
328 if ( !copyClusterInfo( *( infoType->m_plugChannelPosition ) ) ) {
329 debugError( "Could not copy channel position "
330 "information\n" );
331 return false;
334 debugOutput( DEBUG_LEVEL_VERBOSE,
335 "plug %d: channel position information "
336 "retrieved\n",
337 m_id );
339 debugOutputClusterInfos( DEBUG_LEVEL_VERBOSE );
342 return true;
345 bool
346 Plug::copyClusterInfo(ExtendedPlugInfoPlugChannelPositionSpecificData&
347 channelPositionData )
349 int index = 1;
350 for ( ExtendedPlugInfoPlugChannelPositionSpecificData::ClusterInfoVector::const_iterator it
351 = channelPositionData.m_clusterInfos.begin();
352 it != channelPositionData.m_clusterInfos.end();
353 ++it )
355 const ExtendedPlugInfoPlugChannelPositionSpecificData::ClusterInfo*
356 extPlugSpClusterInfo = &( *it );
358 ClusterInfo clusterInfo;
359 clusterInfo.m_nrOfChannels = extPlugSpClusterInfo->m_nrOfChannels;
360 clusterInfo.m_index = index;
361 index++;
363 for ( ExtendedPlugInfoPlugChannelPositionSpecificData::ChannelInfoVector::const_iterator cit
364 = extPlugSpClusterInfo->m_channelInfos.begin();
365 cit != extPlugSpClusterInfo->m_channelInfos.end();
366 ++cit )
368 const ExtendedPlugInfoPlugChannelPositionSpecificData::ChannelInfo*
369 extPlugSpChannelInfo = &( *cit );
371 ChannelInfo channelInfo;
372 channelInfo.m_streamPosition =
373 extPlugSpChannelInfo->m_streamPosition-1;
374 // FIXME: this can only become a mess with the two meanings
375 // of the location parameter. the audio style meaning
376 // starts from 1, the midi style meaning from 0
377 // lucky for us we recalculate this for the midi channels
378 // and don't use this value.
379 channelInfo.m_location =
380 extPlugSpChannelInfo->m_location;
382 clusterInfo.m_channelInfos.push_back( channelInfo );
384 m_clusterInfos.push_back( clusterInfo );
387 return true;
390 bool
391 Plug::discoverChannelName()
393 for ( ClusterInfoVector::iterator clit = m_clusterInfos.begin();
394 clit != m_clusterInfos.end();
395 ++clit )
397 ClusterInfo* clitInfo = &*clit;
399 for ( ChannelInfoVector::iterator pit = clitInfo->m_channelInfos.begin();
400 pit != clitInfo->m_channelInfos.end();
401 ++pit )
403 ChannelInfo* channelInfo = &*pit;
405 ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
406 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
407 ExtendedPlugInfoInfoType::eIT_ChannelName );
408 extendedPlugInfoInfoType.initialize();
409 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
410 extPlugInfoCmd.setVerbose( getDebugLevel() );
412 ExtendedPlugInfoInfoType* infoType =
413 extPlugInfoCmd.getInfoType();
414 if ( infoType ) {
415 infoType->m_plugChannelName->m_streamPosition =
416 channelInfo->m_streamPosition + 1;
418 if ( !extPlugInfoCmd.fire() ) {
419 debugError( "channel name command failed\n" );
420 return false;
422 infoType = extPlugInfoCmd.getInfoType();
423 if ( infoType
424 && infoType->m_plugChannelName )
426 debugOutput( DEBUG_LEVEL_VERBOSE,
427 "plug %d stream "
428 "position %d: channel name = %s\n",
429 m_id,
430 channelInfo->m_streamPosition,
431 infoType->m_plugChannelName->m_plugChannelName.c_str() );
432 channelInfo->m_name =
433 infoType->m_plugChannelName->m_plugChannelName;
439 return true;
442 bool
443 Plug::discoverClusterInfo()
445 if ( m_infoPlugType == eAPT_Sync )
447 // If the plug is of type sync it is either a normal 2 channel
448 // stream (not compound stream) or it is a compound stream
449 // with exactly one cluster. This depends on the
450 // extended stream format command version which is used.
451 // We are not interested in this plug so we skip it.
452 debugOutput( DEBUG_LEVEL_VERBOSE,
453 "%s plug %d is of type sync -> skip\n",
454 getName(),
455 m_id );
456 return true;
459 for ( ClusterInfoVector::iterator clit = m_clusterInfos.begin();
460 clit != m_clusterInfos.end();
461 ++clit )
463 ClusterInfo* clusterInfo = &*clit;
465 ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
466 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
467 ExtendedPlugInfoInfoType::eIT_ClusterInfo );
468 extendedPlugInfoInfoType.initialize();
469 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
470 extPlugInfoCmd.setVerbose( getDebugLevel() );
472 extPlugInfoCmd.getInfoType()->m_plugClusterInfo->m_clusterIndex =
473 clusterInfo->m_index;
475 if ( !extPlugInfoCmd.fire() ) {
476 debugError( "cluster info command failed\n" );
477 return false;
480 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
481 if ( infoType
482 && infoType->m_plugClusterInfo )
484 debugOutput( DEBUG_LEVEL_VERBOSE,
485 "%s plug %d: cluster index = %d, "
486 "portType %s, cluster name = %s\n",
487 getName(),
488 m_id,
489 infoType->m_plugClusterInfo->m_clusterIndex,
490 extendedPlugInfoClusterInfoPortTypeToString(
491 infoType->m_plugClusterInfo->m_portType ),
492 infoType->m_plugClusterInfo->m_clusterName.c_str() );
494 clusterInfo->m_portType = infoType->m_plugClusterInfo->m_portType;
495 clusterInfo->m_name = infoType->m_plugClusterInfo->m_clusterName;
499 return true;
502 bool
503 Plug::discoverConnectionsInput()
505 ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
506 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
507 ExtendedPlugInfoInfoType::eIT_PlugInput );
508 extendedPlugInfoInfoType.initialize();
509 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
510 extPlugInfoCmd.setVerbose( getDebugLevel() );
512 if ( !extPlugInfoCmd.fire() ) {
513 debugError( "plug type command failed\n" );
514 return false;
517 if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Rejected ) {
518 // Plugs does not like to be asked about connections
519 debugOutput( DEBUG_LEVEL_VERBOSE, "Plug '%s' rejects "
520 "connections command\n",
521 getName() );
522 return true;
525 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
526 if ( infoType
527 && infoType->m_plugInput )
529 PlugAddressSpecificData* plugAddress
530 = infoType->m_plugInput->m_plugAddress;
532 if ( plugAddress->m_addressMode ==
533 PlugAddressSpecificData::ePAM_Undefined )
535 // This plug has no input connection
536 return true;
539 if ( !discoverConnectionsFromSpecificData( eAPD_Input,
540 plugAddress,
541 m_inputConnections ) )
543 debugWarning( "Could not discover connections for plug '%s'\n",
544 getName() );
546 } else {
547 debugError( "no valid info type for plug '%s'\n", getName() );
548 return false;
551 return true;
554 bool
555 Plug::discoverConnectionsOutput()
557 ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
558 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
559 ExtendedPlugInfoInfoType::eIT_PlugOutput );
560 extendedPlugInfoInfoType.initialize();
561 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
562 extPlugInfoCmd.setVerbose( getDebugLevel() );
564 if ( !extPlugInfoCmd.fire() ) {
565 debugError( "plug type command failed\n" );
566 return false;
569 if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Rejected ) {
570 // Plugs does not like to be asked about connections
571 debugOutput( DEBUG_LEVEL_VERBOSE, "Plug '%s' rejects "
572 "connections command\n",
573 getName() );
574 return true;
577 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
578 if ( infoType
579 && infoType->m_plugOutput )
581 if ( infoType->m_plugOutput->m_nrOfOutputPlugs
582 != infoType->m_plugOutput->m_outputPlugAddresses.size() )
584 debugError( "number of output plugs (%d) disagree with "
585 "number of elements in plug address vector (%zd)\n",
586 infoType->m_plugOutput->m_nrOfOutputPlugs,
587 infoType->m_plugOutput->m_outputPlugAddresses.size());
590 if ( infoType->m_plugOutput->m_nrOfOutputPlugs == 0 ) {
591 // This plug has no output connections
592 return true;
595 for ( unsigned int i = 0;
596 i < infoType->m_plugOutput->m_outputPlugAddresses.size();
597 ++i )
599 PlugAddressSpecificData* plugAddress
600 = infoType->m_plugOutput->m_outputPlugAddresses[i];
602 if ( !discoverConnectionsFromSpecificData( eAPD_Output,
603 plugAddress,
604 m_outputConnections ) )
606 debugWarning( "Could not discover connections for "
607 "plug '%s'\n", getName() );
610 } else {
611 debugError( "no valid info type for plug '%s'\n", getName() );
612 return false;
615 return true;
618 ExtendedPlugInfoCmd
619 Plug::setPlugAddrToPlugInfoCmd()
621 ExtendedPlugInfoCmd extPlugInfoCmd( m_unit->get1394Service() );
623 switch( getSubunitType() ) {
624 case eST_Unit:
626 UnitPlugAddress::EPlugType ePlugType =
627 UnitPlugAddress::ePT_Unknown;
628 switch ( m_addressType ) {
629 case eAPA_PCR:
630 ePlugType = UnitPlugAddress::ePT_PCR;
631 break;
632 case eAPA_ExternalPlug:
633 ePlugType = UnitPlugAddress::ePT_ExternalPlug;
634 break;
635 case eAPA_AsynchronousPlug:
636 ePlugType = UnitPlugAddress::ePT_AsynchronousPlug;
637 break;
638 default:
639 ePlugType = UnitPlugAddress::ePT_Unknown;
641 UnitPlugAddress unitPlugAddress( ePlugType,
642 m_id );
643 extPlugInfoCmd.setPlugAddress(
644 PlugAddress( convertPlugDirection( getPlugDirection() ),
645 PlugAddress::ePAM_Unit,
646 unitPlugAddress ) );
648 break;
649 case eST_Music:
650 case eST_Audio:
652 switch( m_addressType ) {
653 case eAPA_SubunitPlug:
655 SubunitPlugAddress subunitPlugAddress( m_id );
656 extPlugInfoCmd.setPlugAddress(
657 PlugAddress(
658 convertPlugDirection( getPlugDirection() ),
659 PlugAddress::ePAM_Subunit,
660 subunitPlugAddress ) );
662 break;
663 case eAPA_FunctionBlockPlug:
665 FunctionBlockPlugAddress functionBlockPlugAddress(
666 m_functionBlockType,
667 m_functionBlockId,
668 m_id );
669 extPlugInfoCmd.setPlugAddress(
670 PlugAddress(
671 convertPlugDirection( getPlugDirection() ),
672 PlugAddress::ePAM_FunctionBlock,
673 functionBlockPlugAddress ) );
675 break;
676 default:
677 extPlugInfoCmd.setPlugAddress(PlugAddress());
680 break;
681 default:
682 debugError( "Unknown subunit type\n" );
685 extPlugInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
686 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
687 extPlugInfoCmd.setSubunitId( getSubunitId() );
688 extPlugInfoCmd.setSubunitType( getSubunitType() );
690 return extPlugInfoCmd;