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"
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
)
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(),
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
,
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(),
99 Plug::Plug( const Plug
& rhs
)
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
172 return m_unit
->getPlugManager().addPlug( *this );
176 Plug::discoverConnections()
178 return discoverConnectionsInput() && discoverConnectionsOutput();
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" );
196 m_infoPlugType
= eAPT_Unknown
;
198 if ( extPlugInfoCmd
.getResponse() == AVCCommand::eR_Implemented
) {
200 ExtendedPlugInfoInfoType
* infoType
= extPlugInfoCmd
.getInfoType();
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",
210 extendedPlugInfoPlugTypeToString( plugType
) );
211 switch ( plugType
) {
212 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_IsoStream
:
213 m_infoPlugType
= eAPT_IsoStream
;
215 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_AsyncStream
:
216 m_infoPlugType
= eAPT_AsyncStream
;
218 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Midi
:
219 m_infoPlugType
= eAPT_Midi
;
221 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Sync
:
222 m_infoPlugType
= eAPT_Sync
;
224 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Analog
:
225 m_infoPlugType
= eAPT_Analog
;
227 case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Digital
:
228 m_infoPlugType
= eAPT_Digital
;
231 m_infoPlugType
= eAPT_Unknown
;
236 debugError( "Plug does not implement extended plug info plug "
237 "type info command\n" );
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" );
259 ExtendedPlugInfoInfoType
* infoType
= extPlugInfoCmd
.getInfoType();
261 && infoType
->m_plugName
)
264 infoType
->m_plugName
->m_name
;
266 debugOutput( DEBUG_LEVEL_VERBOSE
,
267 "plug %d has name '%s'\n",
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" );
292 ExtendedPlugInfoInfoType
* infoType
= extPlugInfoCmd
.getInfoType();
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",
304 m_nrOfChannels
= nrOfChannels
;
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" );
324 ExtendedPlugInfoInfoType
* infoType
= extPlugInfoCmd
.getInfoType();
326 && infoType
->m_plugChannelPosition
)
328 if ( !copyClusterInfo( *( infoType
->m_plugChannelPosition
) ) ) {
329 debugError( "Could not copy channel position "
334 debugOutput( DEBUG_LEVEL_VERBOSE
,
335 "plug %d: channel position information "
339 debugOutputClusterInfos( DEBUG_LEVEL_VERBOSE
);
346 Plug::copyClusterInfo(ExtendedPlugInfoPlugChannelPositionSpecificData
&
347 channelPositionData
)
350 for ( ExtendedPlugInfoPlugChannelPositionSpecificData::ClusterInfoVector::const_iterator it
351 = channelPositionData
.m_clusterInfos
.begin();
352 it
!= channelPositionData
.m_clusterInfos
.end();
355 const ExtendedPlugInfoPlugChannelPositionSpecificData::ClusterInfo
*
356 extPlugSpClusterInfo
= &( *it
);
358 ClusterInfo clusterInfo
;
359 clusterInfo
.m_nrOfChannels
= extPlugSpClusterInfo
->m_nrOfChannels
;
360 clusterInfo
.m_index
= index
;
363 for ( ExtendedPlugInfoPlugChannelPositionSpecificData::ChannelInfoVector::const_iterator cit
364 = extPlugSpClusterInfo
->m_channelInfos
.begin();
365 cit
!= extPlugSpClusterInfo
->m_channelInfos
.end();
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
);
391 Plug::discoverChannelName()
393 for ( ClusterInfoVector::iterator clit
= m_clusterInfos
.begin();
394 clit
!= m_clusterInfos
.end();
397 ClusterInfo
* clitInfo
= &*clit
;
399 for ( ChannelInfoVector::iterator pit
= clitInfo
->m_channelInfos
.begin();
400 pit
!= clitInfo
->m_channelInfos
.end();
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();
415 infoType
->m_plugChannelName
->m_streamPosition
=
416 channelInfo
->m_streamPosition
+ 1;
418 if ( !extPlugInfoCmd
.fire() ) {
419 debugError( "channel name command failed\n" );
422 infoType
= extPlugInfoCmd
.getInfoType();
424 && infoType
->m_plugChannelName
)
426 debugOutput( DEBUG_LEVEL_VERBOSE
,
428 "position %d: channel name = %s\n",
430 channelInfo
->m_streamPosition
,
431 infoType
->m_plugChannelName
->m_plugChannelName
.c_str() );
432 channelInfo
->m_name
=
433 infoType
->m_plugChannelName
->m_plugChannelName
;
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",
459 for ( ClusterInfoVector::iterator clit
= m_clusterInfos
.begin();
460 clit
!= m_clusterInfos
.end();
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" );
480 ExtendedPlugInfoInfoType
* infoType
= extPlugInfoCmd
.getInfoType();
482 && infoType
->m_plugClusterInfo
)
484 debugOutput( DEBUG_LEVEL_VERBOSE
,
485 "%s plug %d: cluster index = %d, "
486 "portType %s, cluster name = %s\n",
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
;
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" );
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",
525 ExtendedPlugInfoInfoType
* infoType
= extPlugInfoCmd
.getInfoType();
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
539 if ( !discoverConnectionsFromSpecificData( eAPD_Input
,
541 m_inputConnections
) )
543 debugWarning( "Could not discover connections for plug '%s'\n",
547 debugError( "no valid info type for plug '%s'\n", getName() );
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" );
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",
577 ExtendedPlugInfoInfoType
* infoType
= extPlugInfoCmd
.getInfoType();
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
595 for ( unsigned int i
= 0;
596 i
< infoType
->m_plugOutput
->m_outputPlugAddresses
.size();
599 PlugAddressSpecificData
* plugAddress
600 = infoType
->m_plugOutput
->m_outputPlugAddresses
[i
];
602 if ( !discoverConnectionsFromSpecificData( eAPD_Output
,
604 m_outputConnections
) )
606 debugWarning( "Could not discover connections for "
607 "plug '%s'\n", getName() );
611 debugError( "no valid info type for plug '%s'\n", getName() );
619 Plug::setPlugAddrToPlugInfoCmd()
621 ExtendedPlugInfoCmd
extPlugInfoCmd( m_unit
->get1394Service() );
623 switch( getSubunitType() ) {
626 UnitPlugAddress::EPlugType ePlugType
=
627 UnitPlugAddress::ePT_Unknown
;
628 switch ( m_addressType
) {
630 ePlugType
= UnitPlugAddress::ePT_PCR
;
632 case eAPA_ExternalPlug
:
633 ePlugType
= UnitPlugAddress::ePT_ExternalPlug
;
635 case eAPA_AsynchronousPlug
:
636 ePlugType
= UnitPlugAddress::ePT_AsynchronousPlug
;
639 ePlugType
= UnitPlugAddress::ePT_Unknown
;
641 UnitPlugAddress
unitPlugAddress( ePlugType
,
643 extPlugInfoCmd
.setPlugAddress(
644 PlugAddress( convertPlugDirection( getPlugDirection() ),
645 PlugAddress::ePAM_Unit
,
652 switch( m_addressType
) {
653 case eAPA_SubunitPlug
:
655 SubunitPlugAddress
subunitPlugAddress( m_id
);
656 extPlugInfoCmd
.setPlugAddress(
658 convertPlugDirection( getPlugDirection() ),
659 PlugAddress::ePAM_Subunit
,
660 subunitPlugAddress
) );
663 case eAPA_FunctionBlockPlug
:
665 FunctionBlockPlugAddress
functionBlockPlugAddress(
669 extPlugInfoCmd
.setPlugAddress(
671 convertPlugDirection( getPlugDirection() ),
672 PlugAddress::ePAM_FunctionBlock
,
673 functionBlockPlugAddress
) );
677 extPlugInfoCmd
.setPlugAddress(PlugAddress());
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
;