[BeBoB/AVDevice] add the functions to use processing function block command
[ffado.git] / libffado / src / bebob / bebob_avdevice.cpp
blob048c49a37ee8515a8de3a0becfc9cad52eb9ba13
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 "config.h"
26 #include "devicemanager.h"
27 #include "bebob/bebob_avdevice.h"
28 #include "bebob/bebob_avdevice_subunit.h"
29 #include "bebob/bebob_mixer.h"
31 #include "bebob/focusrite/focusrite_saffire.h"
32 #include "bebob/focusrite/focusrite_saffirepro.h"
33 #include "bebob/terratec/terratec_device.h"
34 #include "bebob/mackie/onyxmixer.h"
35 #include "bebob/edirol/edirol_fa101.h"
36 #include "bebob/edirol/edirol_fa66.h"
37 #include "bebob/esi/quatafire610.h"
38 #include "bebob/yamaha/yamaha_avdevice.h"
40 #include "libieee1394/configrom.h"
41 #include "libieee1394/ieee1394service.h"
43 #include "libavc/general/avc_plug_info.h"
44 #include "libavc/general/avc_extended_plug_info.h"
45 #include "libavc/general/avc_subunit_info.h"
46 #include "libavc/streamformat/avc_extended_stream_format.h"
47 #include "libutil/cmd_serialize.h"
48 #include "libavc/avc_definitions.h"
50 #include "debugmodule/debugmodule.h"
52 #include <iostream>
53 #include <sstream>
54 #include <unistd.h>
55 #include <cstdlib>
56 #include <cstring>
57 #include <sys/stat.h>
59 using namespace AVC;
61 namespace BeBoB {
63 Device::Device( DeviceManager& d, std::auto_ptr< ConfigRom >( configRom ) )
64 : GenericAVC::Device( d, configRom )
65 , m_last_discovery_config_id ( 0xFFFFFFFFFFFFFFFFLLU )
66 , m_Mixer ( 0 )
68 debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Device (NodeID %d)\n",
69 getConfigRom().getNodeId() );
72 Device::~Device()
74 destroyMixer();
77 bool
78 Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
80 if(generic) {
81 // try a bebob-specific command to check for the firmware
82 ExtendedPlugInfoCmd extPlugInfoCmd( configRom.get1394Service() );
83 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
84 configRom.getNodeId() );
85 extPlugInfoCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
86 PlugAddress::ePAM_Unit,
87 unitPlugAddress ) );
88 extPlugInfoCmd.setNodeId( configRom.getNodeId() );
89 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
90 extPlugInfoCmd.setVerbose( configRom.getVerboseLevel() );
91 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
92 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
93 extendedPlugInfoInfoType.initialize();
94 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
96 if ( !extPlugInfoCmd.fire() ) {
97 debugError( "Number of channels command failed\n" );
98 return false;
101 if((extPlugInfoCmd.getResponse() != AVCCommand::eR_Implemented)) {
102 // command not supported
103 return false;
106 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
107 if ( infoType
108 && infoType->m_plugNrOfChns )
110 return true;
112 return false;
113 } else {
114 // check if device is in supported devices list
115 unsigned int vendorId = configRom.getNodeVendorId();
116 unsigned int modelId = configRom.getModelId();
118 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
119 return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
123 FFADODevice *
124 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
126 unsigned int vendorId = configRom->getNodeVendorId();
127 unsigned int modelId = configRom->getModelId();
129 switch (vendorId) {
130 case FW_VENDORID_MACKIE:
131 if (modelId == 0x00010065 ) {
132 return new Mackie::OnyxMixerDevice(d, configRom);
134 case FW_VENDORID_EDIROL:
135 switch (modelId) {
136 case 0x00010048:
137 return new Edirol::EdirolFa101Device(d, configRom);
138 case 0x00010049:
139 return new Edirol::EdirolFa66Device(d, configRom);
140 default:
141 return new Device(d, configRom);
143 case FW_VENDORID_ESI:
144 if (modelId == 0x00010064) {
145 return new ESI::QuataFireDevice(d, configRom);
147 break;
148 case FW_VENDORID_TERRATEC:
149 switch(modelId) {
150 case 0x00000003:
151 return new Terratec::Phase88Device(d, configRom);
152 default: // return a plain BeBoB device
153 return new Device(d, configRom);
155 case FW_VENDORID_FOCUSRITE:
156 switch(modelId) {
157 case 0x00000003:
158 case 0x00000006:
159 return new Focusrite::SaffireProDevice(d, configRom);
160 case 0x00000000:
161 return new Focusrite::SaffireDevice(d, configRom);
162 default: // return a plain BeBoB device
163 return new Device(d, configRom);
165 case FW_VENDORID_YAMAHA:
166 switch (modelId) {
167 case 0x0010000b:
168 case 0x0010000c:
169 return new Yamaha::GoDevice(d, configRom);
170 default: // return a plain BeBoB device
171 return new Device(d, configRom);
173 default:
174 return new Device(d, configRom);
176 return NULL;
179 #define BEBOB_CHECK_AND_ADD_SR(v, x) \
180 { if(supportsSamplingFrequency(x)) \
181 v.push_back(x); }
182 bool
183 Device::discover()
185 unsigned int vendorId = getConfigRom().getNodeVendorId();
186 unsigned int modelId = getConfigRom().getModelId();
188 Util::Configuration &c = getDeviceManager().getConfiguration();
189 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
191 if (c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB) {
192 debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
193 vme.vendor_name.c_str(),
194 vme.model_name.c_str());
195 } else {
196 debugWarning("Using generic BeBoB support for unsupported device '%s %s'\n",
197 getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
200 if ( !Unit::discover() ) {
201 debugError( "Could not discover unit\n" );
202 return false;
205 if((getAudioSubunit( 0 ) == NULL)) {
206 debugError( "Unit doesn't have an Audio subunit.\n");
207 return false;
209 if((getMusicSubunit( 0 ) == NULL)) {
210 debugError( "Unit doesn't have a Music subunit.\n");
211 return false;
214 if(!buildMixer()) {
215 debugWarning("Could not build mixer\n");
218 // keep track of the config id of this discovery
219 m_last_discovery_config_id = getConfigurationId();
221 return true;
224 bool
225 Device::buildMixer()
227 debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
228 // create a Mixer
229 // this removes the mixer if it already exists
230 // note: a mixer self-registers to it's parent
231 delete m_Mixer;
233 // create the mixer & register it
234 if(getAudioSubunit(0) == NULL) {
235 debugWarning("Could not find audio subunit, mixer not available.\n");
236 m_Mixer = NULL;
237 } else {
238 m_Mixer = new Mixer(*this);
240 if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
241 return m_Mixer != NULL;
244 bool
245 Device::destroyMixer()
247 delete m_Mixer;
248 return true;
251 bool
252 Device::setSelectorFBValue(int id, int value) {
253 FunctionBlockCmd fbCmd( get1394Service(),
254 FunctionBlockCmd::eFBT_Selector,
256 FunctionBlockCmd::eCA_Current );
257 fbCmd.setNodeId( getNodeId() );
258 fbCmd.setSubunitId( 0x00 );
259 fbCmd.setCommandType( AVCCommand::eCT_Control );
260 fbCmd.m_pFBSelector->m_inputFbPlugNumber = (value & 0xFF);
261 fbCmd.setVerboseLevel( getDebugLevel() );
263 if ( !fbCmd.fire() ) {
264 debugError( "cmd failed\n" );
265 return false;
268 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
269 // Util::Cmd::CoutSerializer se;
270 // fbCmd.serialize( se );
271 // }
273 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
274 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
277 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
281 Device::getSelectorFBValue(int id) {
283 FunctionBlockCmd fbCmd( get1394Service(),
284 FunctionBlockCmd::eFBT_Selector,
286 FunctionBlockCmd::eCA_Current );
287 fbCmd.setNodeId( getNodeId() );
288 fbCmd.setSubunitId( 0x00 );
289 fbCmd.setCommandType( AVCCommand::eCT_Status );
290 fbCmd.m_pFBSelector->m_inputFbPlugNumber = 0xFF;
291 fbCmd.setVerboseLevel( getDebugLevel() );
293 if ( !fbCmd.fire() ) {
294 debugError( "cmd failed\n" );
295 return -1;
298 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
299 // Util::Cmd::CoutSerializer se;
300 // fbCmd.serialize( se );
301 // }
303 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
304 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
307 return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
310 bool
311 Device::setFeatureFBVolumeCurrent(int id, int channel, int v) {
313 FunctionBlockCmd fbCmd( get1394Service(),
314 FunctionBlockCmd::eFBT_Feature,
316 FunctionBlockCmd::eCA_Current );
317 fbCmd.setNodeId( getNodeId() );
318 fbCmd.setSubunitId( 0x00 );
319 fbCmd.setCommandType( AVCCommand::eCT_Control );
320 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
321 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
322 AVC::FunctionBlockFeatureVolume vl;
323 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
324 fbCmd.m_pFBFeature->m_pVolume->m_volume = v;
325 fbCmd.setVerboseLevel( getDebugLevel() );
327 if ( !fbCmd.fire() ) {
328 debugError( "cmd failed\n" );
329 return false;
332 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
333 // Util::Cmd::CoutSerializer se;
334 // fbCmd.serialize( se );
335 // }
337 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
338 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
341 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
345 Device::getFeatureFBVolumeValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
347 FunctionBlockCmd fbCmd( get1394Service(),
348 FunctionBlockCmd::eFBT_Feature,
350 controlAttribute);
351 fbCmd.setNodeId( getNodeId() );
352 fbCmd.setSubunitId( 0x00 );
353 fbCmd.setCommandType( AVCCommand::eCT_Status );
354 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
355 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
356 AVC::FunctionBlockFeatureVolume vl;
357 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
358 fbCmd.m_pFBFeature->m_pVolume->m_volume = 0;
359 fbCmd.setVerboseLevel( getDebugLevel() );
361 if ( !fbCmd.fire() ) {
362 debugError( "cmd failed\n" );
363 return 0;
366 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
367 // Util::Cmd::CoutSerializer se;
368 // fbCmd.serialize( se );
369 // }
371 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
372 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
375 int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
377 return volume;
380 int
381 Device::getFeatureFBVolumeMinimum(int id, int channel)
383 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
386 int
387 Device::getFeatureFBVolumeMaximum(int id, int channel)
389 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
392 int
393 Device::getFeatureFBVolumeCurrent(int id, int channel)
395 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
398 bool
399 Device::setFeatureFBLRBalanceCurrent(int id, int channel, int v) {
401 FunctionBlockCmd fbCmd( get1394Service(),
402 FunctionBlockCmd::eFBT_Feature,
404 FunctionBlockCmd::eCA_Current );
405 fbCmd.setNodeId( getNodeId() );
406 fbCmd.setSubunitId( 0x00 );
407 fbCmd.setCommandType( AVCCommand::eCT_Control );
408 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
409 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
410 AVC::FunctionBlockFeatureLRBalance bl;
411 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
412 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = v;
413 fbCmd.setVerboseLevel( getDebugLevel() );
415 if ( !fbCmd.fire() ) {
416 debugError( "cmd failed\n" );
417 return false;
420 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
421 // Util::Cmd::CoutSerializer se;
422 // fbCmd.serialize( se );
423 // }
425 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
426 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
429 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
433 Device::getFeatureFBLRBalanceValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
435 FunctionBlockCmd fbCmd( get1394Service(),
436 FunctionBlockCmd::eFBT_Feature,
438 controlAttribute);
439 fbCmd.setNodeId( getNodeId() );
440 fbCmd.setSubunitId( 0x00 );
441 fbCmd.setCommandType( AVCCommand::eCT_Status );
442 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
443 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
444 AVC::FunctionBlockFeatureLRBalance bl;
445 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
446 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = 0;
447 fbCmd.setVerboseLevel( getDebugLevel() );
449 if ( !fbCmd.fire() ) {
450 debugError( "cmd failed\n" );
451 return 0;
454 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
455 // Util::Cmd::CoutSerializer se;
456 // fbCmd.serialize( se );
457 // }
459 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
460 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
463 int16_t balance=(int16_t)(fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance);
465 return balance;
468 int
469 Device::getFeatureFBLRBalanceMinimum(int id, int channel)
471 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
474 int
475 Device::getFeatureFBLRBalanceMaximum(int id, int channel)
477 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
480 int
481 Device::getFeatureFBLRBalanceCurrent(int id, int channel)
483 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
486 bool
487 Device::setProcessingFBMixerSingleCurrent(int id, int iPlugNum,
488 int iAChNum, int oAChNum,
489 int setting)
491 AVC::FunctionBlockCmd fbCmd(get1394Service(),
492 AVC::FunctionBlockCmd::eFBT_Processing,
494 AVC::FunctionBlockCmd::eCA_Current);
495 fbCmd.setNodeId(getNodeId());
496 fbCmd.setSubunitId(0x00);
497 fbCmd.setCommandType(AVCCommand::eCT_Control);
498 fbCmd.setVerboseLevel( getDebugLevel() );
500 AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
501 fbp->m_selectorLength = 0x04;
502 fbp->m_fbInputPlugNumber = iPlugNum;
503 fbp->m_inputAudioChannelNumber = iAChNum;
504 fbp->m_outputAudioChannelNumber = oAChNum;
506 // mixer object is not generated automatically
507 fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
508 fbp->m_pMixer->m_mixerSetting = setting;
510 if ( !fbCmd.fire() ) {
511 debugError( "cmd failed\n" );
512 return false;
515 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
516 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
519 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
523 Device::getProcessingFBMixerSingleCurrent(int id, int iPlugNum,
524 int iAChNum, int oAChNum)
526 AVC::FunctionBlockCmd fbCmd(get1394Service(),
527 AVC::FunctionBlockCmd::eFBT_Processing,
529 AVC::FunctionBlockCmd::eCA_Current);
530 fbCmd.setNodeId(getNodeId());
531 fbCmd.setSubunitId(0x00);
532 fbCmd.setCommandType(AVCCommand::eCT_Status);
533 fbCmd.setVerboseLevel( getDebugLevel() );
535 AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
536 fbp->m_selectorLength = 0x04;
537 fbp->m_fbInputPlugNumber = iPlugNum;
538 fbp->m_inputAudioChannelNumber = iAChNum;
539 fbp->m_outputAudioChannelNumber = oAChNum;
541 // mixer object is not generated automatically
542 fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
544 if ( !fbCmd.fire() ) {
545 debugError( "cmd failed\n" );
546 return 0;
549 if( (fbCmd.getResponse() != AVCCommand::eR_Implemented) ) {
550 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
553 int16_t setting = (int16_t)(fbp->m_pMixer->m_mixerSetting);
555 return setting;
558 void
559 Device::showDevice()
561 debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
562 GenericAVC::Device::showDevice();
563 flushDebugOutput();
566 void
567 Device::setVerboseLevel(int l)
569 if (m_Mixer) m_Mixer->setVerboseLevel( l );
570 GenericAVC::Device::setVerboseLevel( l );
571 debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
574 AVC::Subunit*
575 Device::createSubunit(AVC::Unit& unit,
576 AVC::ESubunitType type,
577 AVC::subunit_t id )
579 AVC::Subunit* s=NULL;
580 switch (type) {
581 case eST_Audio:
582 s=new BeBoB::SubunitAudio(unit, id );
583 break;
584 case eST_Music:
585 s=new BeBoB::SubunitMusic(unit, id );
586 break;
587 default:
588 s=NULL;
589 break;
591 if(s) s->setVerboseLevel(getDebugLevel());
592 return s;
596 AVC::Plug *
597 Device::createPlug( AVC::Unit* unit,
598 AVC::Subunit* subunit,
599 AVC::function_block_type_t functionBlockType,
600 AVC::function_block_type_t functionBlockId,
601 AVC::Plug::EPlugAddressType plugAddressType,
602 AVC::Plug::EPlugDirection plugDirection,
603 AVC::plug_id_t plugId,
604 int globalId )
607 Plug *p= new BeBoB::Plug( unit,
608 subunit,
609 functionBlockType,
610 functionBlockId,
611 plugAddressType,
612 plugDirection,
613 plugId,
614 globalId );
615 if (p) p->setVerboseLevel(getDebugLevel());
616 return p;
619 bool
620 Device::propagatePlugInfo() {
621 // we don't have to propagate since we discover things
622 // another way
623 debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
624 return true;
627 uint8_t
628 Device::getConfigurationIdSampleRate()
630 ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
631 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
632 extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
633 PlugAddress::ePAM_Unit,
634 unitPlugAddress ) );
636 extStreamFormatCmd.setNodeId( getNodeId() );
637 extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
638 extStreamFormatCmd.setVerbose( getDebugLevel() );
640 if ( !extStreamFormatCmd.fire() ) {
641 debugError( "Stream format command failed\n" );
642 return 0;
645 FormatInformation* formatInfo =
646 extStreamFormatCmd.getFormatInformation();
647 FormatInformationStreamsCompound* compoundStream
648 = dynamic_cast< FormatInformationStreamsCompound* > (
649 formatInfo->m_streams );
650 if ( compoundStream ) {
651 debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
652 compoundStream->m_samplingFrequency );
653 return compoundStream->m_samplingFrequency;
656 debugError( "Could not retrieve sample rate\n" );
657 return 0;
660 uint8_t
661 Device::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
663 ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
664 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
665 0 );
666 extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
667 PlugAddress::ePAM_Unit,
668 unitPlugAddress ) );
669 extPlugInfoCmd.setNodeId( getNodeId() );
670 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
671 extPlugInfoCmd.setVerbose( getDebugLevel() );
672 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
673 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
674 extendedPlugInfoInfoType.initialize();
675 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
677 if ( !extPlugInfoCmd.fire() ) {
678 debugError( "Number of channels command failed\n" );
679 return 0;
682 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
683 if ( infoType
684 && infoType->m_plugNrOfChns )
686 debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
687 infoType->m_plugNrOfChns->m_nrOfChannels );
688 return infoType->m_plugNrOfChns->m_nrOfChannels;
691 debugError( "Could not retrieve number of channels\n" );
692 return 0;
695 uint16_t
696 Device::getConfigurationIdSyncMode()
698 SignalSourceCmd signalSourceCmd( get1394Service() );
699 SignalUnitAddress signalUnitAddr;
700 signalUnitAddr.m_plugId = 0x01;
701 signalSourceCmd.setSignalDestination( signalUnitAddr );
702 signalSourceCmd.setNodeId( getNodeId() );
703 signalSourceCmd.setSubunitType( eST_Unit );
704 signalSourceCmd.setSubunitId( 0xff );
705 signalSourceCmd.setVerbose( getDebugLevel() );
707 signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
709 if ( !signalSourceCmd.fire() ) {
710 debugError( "Signal source command failed\n" );
711 return 0;
714 SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
715 SignalSubunitAddress* pSyncPlugSubunitAddress
716 = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
717 if ( pSyncPlugSubunitAddress ) {
718 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
719 ( pSyncPlugSubunitAddress->m_subunitType << 3
720 | pSyncPlugSubunitAddress->m_subunitId ) << 8
721 | pSyncPlugSubunitAddress->m_plugId );
723 return ( pSyncPlugSubunitAddress->m_subunitType << 3
724 | pSyncPlugSubunitAddress->m_subunitId ) << 8
725 | pSyncPlugSubunitAddress->m_plugId;
728 SignalUnitAddress* pSyncPlugUnitAddress
729 = dynamic_cast<SignalUnitAddress*>( pSyncPlugSignalAddress );
730 if ( pSyncPlugUnitAddress ) {
731 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
732 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
734 return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
737 debugError( "Could not retrieve sync mode\n" );
738 return 0;
741 bool
742 Device::needsRediscovery()
744 // require rediscovery if the config id differs from the one saved
745 // in the previous discovery
746 return getConfigurationId() != m_last_discovery_config_id;
749 uint64_t
750 Device::getConfigurationId()
752 // create a unique configuration id.
753 uint64_t id = 0;
754 id = getConfigurationIdSampleRate();
755 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input ) << 8;
756 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) << 16;
757 id |= ((uint64_t)getConfigurationIdSyncMode()) << 24;
758 return id;
761 bool
762 Device::serialize( std::string basePath,
763 Util::IOSerialize& ser ) const
765 bool result;
766 result = GenericAVC::Device::serialize( basePath, ser );
767 return result;
770 bool
771 Device::deserialize( std::string basePath,
772 Util::IODeserialize& deser )
774 bool result;
775 result = GenericAVC::Device::deserialize( basePath, deser );
776 return result;
779 std::string
780 Device::getCachePath()
782 std::string cachePath;
783 char* pCachePath;
785 string path = CACHEDIR;
786 if ( path.size() && path[0] == '~' ) {
787 path.erase( 0, 1 ); // remove ~
788 path.insert( 0, getenv( "HOME" ) ); // prepend the home path
791 if ( asprintf( &pCachePath, "%s/cache/", path.c_str() ) < 0 ) {
792 debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
793 cachePath = "/var/cache/libffado/";
794 } else {
795 cachePath = pCachePath;
796 free( pCachePath );
798 return cachePath;
801 bool
802 Device::loadFromCache()
804 std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
806 char* configId;
807 asprintf(&configId, "%016"PRIx64"", getConfigurationId() );
808 if ( !configId ) {
809 debugError( "could not create id string\n" );
810 return false;
813 std::string sFileName = sDevicePath + "/" + configId + ".xml";
814 free( configId );
815 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
817 struct stat buf;
818 if ( stat( sFileName.c_str(), &buf ) != 0 ) {
819 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" does not exist\n", sFileName.c_str() );
820 return false;
821 } else {
822 if ( !S_ISREG( buf.st_mode ) ) {
823 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" is not a regular file\n", sFileName.c_str() );
824 return false;
828 Util::XMLDeserialize deser( sFileName, getDebugLevel() );
830 if (!deser.isValid()) {
831 debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
832 sFileName.c_str() );
833 return false;
836 bool result = deserialize( "", deser );
837 if ( result ) {
838 debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
839 sFileName.c_str() );
842 if(result) {
843 buildMixer();
846 return result;
849 bool
850 Device::saveCache()
852 // the path looks like this:
853 // PATH_TO_CACHE + GUID + CONFIGURATION_ID
854 string tmp_path = getCachePath() + getConfigRom().getGuidString();
856 // the following piece should do something like
857 // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
858 vector<string> tokens;
859 tokenize( tmp_path, tokens, "/" );
860 string path;
861 for ( vector<string>::const_iterator it = tokens.begin();
862 it != tokens.end();
863 ++it )
865 path += "/" + *it;
867 struct stat buf;
868 if ( stat( path.c_str(), &buf ) == 0 ) {
869 if ( !S_ISDIR( buf.st_mode ) ) {
870 debugError( "\"%s\" is not a directory\n", path.c_str() );
871 return false;
873 } else {
874 if ( mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
875 debugError( "Could not create \"%s\" directory\n", path.c_str() );
876 return false;
881 // come up with an unique file name for the current settings
882 char* configId;
883 asprintf(&configId, "%016"PRIx64"", BeBoB::Device::getConfigurationId() );
884 if ( !configId ) {
885 debugError( "Could not create id string\n" );
886 return false;
888 string filename = path + "/" + configId + ".xml";
889 free( configId );
890 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
892 Util::XMLSerialize ser( filename );
893 return serialize( "", ser );
896 } // end of namespace