A series of fixes provided by Andreas Hehn. These were mostly discovered when attemp...
[ffado.git] / libffado / src / bebob / bebob_avdevice.cpp
blobcd0f95d2983ab8d9b4d990e5b52a7b1ad7b4c50a
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"
39 #include "libieee1394/configrom.h"
40 #include "libieee1394/ieee1394service.h"
42 #include "libavc/general/avc_plug_info.h"
43 #include "libavc/general/avc_extended_plug_info.h"
44 #include "libavc/general/avc_subunit_info.h"
45 #include "libavc/streamformat/avc_extended_stream_format.h"
46 #include "libutil/cmd_serialize.h"
47 #include "libavc/avc_definitions.h"
49 #include "debugmodule/debugmodule.h"
51 #include <iostream>
52 #include <sstream>
53 #include <unistd.h>
54 #include <cstdlib>
55 #include <cstring>
56 #include <sys/stat.h>
58 using namespace AVC;
60 namespace BeBoB {
62 Device::Device( DeviceManager& d, std::auto_ptr< ConfigRom >( configRom ) )
63 : GenericAVC::Device( d, configRom )
64 , m_last_discovery_config_id ( 0xFFFFFFFFFFFFFFFFLLU )
65 , m_Mixer ( 0 )
67 debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Device (NodeID %d)\n",
68 getConfigRom().getNodeId() );
71 Device::~Device()
73 destroyMixer();
76 bool
77 Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
79 if(generic) {
80 // try a bebob-specific command to check for the firmware
81 ExtendedPlugInfoCmd extPlugInfoCmd( configRom.get1394Service() );
82 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
83 configRom.getNodeId() );
84 extPlugInfoCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
85 PlugAddress::ePAM_Unit,
86 unitPlugAddress ) );
87 extPlugInfoCmd.setNodeId( configRom.getNodeId() );
88 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
89 extPlugInfoCmd.setVerbose( configRom.getVerboseLevel() );
90 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
91 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
92 extendedPlugInfoInfoType.initialize();
93 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
95 if ( !extPlugInfoCmd.fire() ) {
96 debugError( "Number of channels command failed\n" );
97 return false;
100 if((extPlugInfoCmd.getResponse() != AVCCommand::eR_Implemented)) {
101 // command not supported
102 return false;
105 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
106 if ( infoType
107 && infoType->m_plugNrOfChns )
109 return true;
111 return false;
112 } else {
113 // check if device is in supported devices list
114 unsigned int vendorId = configRom.getNodeVendorId();
115 unsigned int modelId = configRom.getModelId();
117 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
118 return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
122 FFADODevice *
123 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
125 unsigned int vendorId = configRom->getNodeVendorId();
126 unsigned int modelId = configRom->getModelId();
128 switch (vendorId) {
129 case FW_VENDORID_MACKIE:
130 if (modelId == 0x00010065 ) {
131 return new Mackie::OnyxMixerDevice(d, configRom);
133 case FW_VENDORID_EDIROL:
134 switch (modelId) {
135 case 0x00010048:
136 return new Edirol::EdirolFa101Device(d, configRom);
137 case 0x00010049:
138 return new Edirol::EdirolFa66Device(d, configRom);
139 default:
140 return new Device(d, configRom);
142 case FW_VENDORID_ESI:
143 if (modelId == 0x00010064) {
144 return new ESI::QuataFireDevice(d, configRom);
146 break;
147 case FW_VENDORID_TERRATEC:
148 switch(modelId) {
149 case 0x00000003:
150 return new Terratec::Phase88Device(d, configRom);
151 default: // return a plain BeBoB device
152 return new Device(d, configRom);
154 case FW_VENDORID_FOCUSRITE:
155 switch(modelId) {
156 case 0x00000003:
157 case 0x00000006:
158 return new Focusrite::SaffireProDevice(d, configRom);
159 case 0x00000000:
160 return new Focusrite::SaffireDevice(d, configRom);
161 default: // return a plain BeBoB device
162 return new Device(d, configRom);
164 default:
165 return new Device(d, configRom);
167 return NULL;
170 #define BEBOB_CHECK_AND_ADD_SR(v, x) \
171 { if(supportsSamplingFrequency(x)) \
172 v.push_back(x); }
173 bool
174 Device::discover()
176 unsigned int vendorId = getConfigRom().getNodeVendorId();
177 unsigned int modelId = getConfigRom().getModelId();
179 Util::Configuration &c = getDeviceManager().getConfiguration();
180 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
182 if (c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB) {
183 debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
184 vme.vendor_name.c_str(),
185 vme.model_name.c_str());
186 } else {
187 debugWarning("Using generic BeBoB support for unsupported device '%s %s'\n",
188 getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
191 if ( !Unit::discover() ) {
192 debugError( "Could not discover unit\n" );
193 return false;
196 if((getAudioSubunit( 0 ) == NULL)) {
197 debugError( "Unit doesn't have an Audio subunit.\n");
198 return false;
200 if((getMusicSubunit( 0 ) == NULL)) {
201 debugError( "Unit doesn't have a Music subunit.\n");
202 return false;
205 if(!buildMixer()) {
206 debugWarning("Could not build mixer\n");
209 // keep track of the config id of this discovery
210 m_last_discovery_config_id = getConfigurationId();
212 return true;
215 bool
216 Device::buildMixer()
218 debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
219 // create a Mixer
220 // this removes the mixer if it already exists
221 // note: a mixer self-registers to it's parent
222 delete m_Mixer;
224 // create the mixer & register it
225 if(getAudioSubunit(0) == NULL) {
226 debugWarning("Could not find audio subunit, mixer not available.\n");
227 m_Mixer = NULL;
228 } else {
229 m_Mixer = new Mixer(*this);
231 if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
232 return m_Mixer != NULL;
235 bool
236 Device::destroyMixer()
238 delete m_Mixer;
239 return true;
242 bool
243 Device::setSelectorFBValue(int id, int value) {
244 FunctionBlockCmd fbCmd( get1394Service(),
245 FunctionBlockCmd::eFBT_Selector,
247 FunctionBlockCmd::eCA_Current );
248 fbCmd.setNodeId( getNodeId() );
249 fbCmd.setSubunitId( 0x00 );
250 fbCmd.setCommandType( AVCCommand::eCT_Control );
251 fbCmd.m_pFBSelector->m_inputFbPlugNumber = (value & 0xFF);
252 fbCmd.setVerboseLevel( getDebugLevel() );
254 if ( !fbCmd.fire() ) {
255 debugError( "cmd failed\n" );
256 return false;
259 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
260 // Util::Cmd::CoutSerializer se;
261 // fbCmd.serialize( se );
262 // }
264 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
265 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
268 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
272 Device::getSelectorFBValue(int id) {
274 FunctionBlockCmd fbCmd( get1394Service(),
275 FunctionBlockCmd::eFBT_Selector,
277 FunctionBlockCmd::eCA_Current );
278 fbCmd.setNodeId( getNodeId() );
279 fbCmd.setSubunitId( 0x00 );
280 fbCmd.setCommandType( AVCCommand::eCT_Status );
281 fbCmd.m_pFBSelector->m_inputFbPlugNumber = 0xFF;
282 fbCmd.setVerboseLevel( getDebugLevel() );
284 if ( !fbCmd.fire() ) {
285 debugError( "cmd failed\n" );
286 return -1;
289 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
290 // Util::Cmd::CoutSerializer se;
291 // fbCmd.serialize( se );
292 // }
294 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
295 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
298 return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
301 bool
302 Device::setFeatureFBVolumeCurrent(int id, int channel, int v) {
304 FunctionBlockCmd fbCmd( get1394Service(),
305 FunctionBlockCmd::eFBT_Feature,
307 FunctionBlockCmd::eCA_Current );
308 fbCmd.setNodeId( getNodeId() );
309 fbCmd.setSubunitId( 0x00 );
310 fbCmd.setCommandType( AVCCommand::eCT_Control );
311 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
312 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
313 AVC::FunctionBlockFeatureVolume vl;
314 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
315 fbCmd.m_pFBFeature->m_pVolume->m_volume = v;
316 fbCmd.setVerboseLevel( getDebugLevel() );
318 if ( !fbCmd.fire() ) {
319 debugError( "cmd failed\n" );
320 return false;
323 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
324 // Util::Cmd::CoutSerializer se;
325 // fbCmd.serialize( se );
326 // }
328 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
329 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
332 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
336 Device::getFeatureFBVolumeValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
338 FunctionBlockCmd fbCmd( get1394Service(),
339 FunctionBlockCmd::eFBT_Feature,
341 controlAttribute);
342 fbCmd.setNodeId( getNodeId() );
343 fbCmd.setSubunitId( 0x00 );
344 fbCmd.setCommandType( AVCCommand::eCT_Status );
345 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
346 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
347 AVC::FunctionBlockFeatureVolume vl;
348 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
349 fbCmd.m_pFBFeature->m_pVolume->m_volume = 0;
350 fbCmd.setVerboseLevel( getDebugLevel() );
352 if ( !fbCmd.fire() ) {
353 debugError( "cmd failed\n" );
354 return 0;
357 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
358 // Util::Cmd::CoutSerializer se;
359 // fbCmd.serialize( se );
360 // }
362 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
363 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
366 int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
368 return volume;
371 int
372 Device::getFeatureFBVolumeMinimum(int id, int channel)
374 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
377 int
378 Device::getFeatureFBVolumeMaximum(int id, int channel)
380 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
383 int
384 Device::getFeatureFBVolumeCurrent(int id, int channel)
386 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
389 bool
390 Device::setFeatureFBLRBalanceCurrent(int id, int channel, int v) {
392 FunctionBlockCmd fbCmd( get1394Service(),
393 FunctionBlockCmd::eFBT_Feature,
395 FunctionBlockCmd::eCA_Current );
396 fbCmd.setNodeId( getNodeId() );
397 fbCmd.setSubunitId( 0x00 );
398 fbCmd.setCommandType( AVCCommand::eCT_Control );
399 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
400 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
401 AVC::FunctionBlockFeatureLRBalance bl;
402 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
403 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = v;
404 fbCmd.setVerboseLevel( getDebugLevel() );
406 if ( !fbCmd.fire() ) {
407 debugError( "cmd failed\n" );
408 return false;
411 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
412 // Util::Cmd::CoutSerializer se;
413 // fbCmd.serialize( se );
414 // }
416 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
417 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
420 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
424 Device::getFeatureFBLRBalanceValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
426 FunctionBlockCmd fbCmd( get1394Service(),
427 FunctionBlockCmd::eFBT_Feature,
429 controlAttribute);
430 fbCmd.setNodeId( getNodeId() );
431 fbCmd.setSubunitId( 0x00 );
432 fbCmd.setCommandType( AVCCommand::eCT_Status );
433 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
434 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
435 AVC::FunctionBlockFeatureLRBalance bl;
436 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
437 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = 0;
438 fbCmd.setVerboseLevel( getDebugLevel() );
440 if ( !fbCmd.fire() ) {
441 debugError( "cmd failed\n" );
442 return 0;
445 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
446 // Util::Cmd::CoutSerializer se;
447 // fbCmd.serialize( se );
448 // }
450 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
451 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
454 int16_t balance=(int16_t)(fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance);
456 return balance;
459 int
460 Device::getFeatureFBLRBalanceMinimum(int id, int channel)
462 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
465 int
466 Device::getFeatureFBLRBalanceMaximum(int id, int channel)
468 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
471 int
472 Device::getFeatureFBLRBalanceCurrent(int id, int channel)
474 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
477 void
478 Device::showDevice()
480 debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
481 GenericAVC::Device::showDevice();
482 flushDebugOutput();
485 void
486 Device::setVerboseLevel(int l)
488 if (m_Mixer) m_Mixer->setVerboseLevel( l );
489 GenericAVC::Device::setVerboseLevel( l );
490 debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
493 AVC::Subunit*
494 Device::createSubunit(AVC::Unit& unit,
495 AVC::ESubunitType type,
496 AVC::subunit_t id )
498 AVC::Subunit* s=NULL;
499 switch (type) {
500 case eST_Audio:
501 s=new BeBoB::SubunitAudio(unit, id );
502 break;
503 case eST_Music:
504 s=new BeBoB::SubunitMusic(unit, id );
505 break;
506 default:
507 s=NULL;
508 break;
510 if(s) s->setVerboseLevel(getDebugLevel());
511 return s;
515 AVC::Plug *
516 Device::createPlug( AVC::Unit* unit,
517 AVC::Subunit* subunit,
518 AVC::function_block_type_t functionBlockType,
519 AVC::function_block_type_t functionBlockId,
520 AVC::Plug::EPlugAddressType plugAddressType,
521 AVC::Plug::EPlugDirection plugDirection,
522 AVC::plug_id_t plugId,
523 int globalId )
526 Plug *p= new BeBoB::Plug( unit,
527 subunit,
528 functionBlockType,
529 functionBlockId,
530 plugAddressType,
531 plugDirection,
532 plugId,
533 globalId );
534 if (p) p->setVerboseLevel(getDebugLevel());
535 return p;
538 bool
539 Device::propagatePlugInfo() {
540 // we don't have to propagate since we discover things
541 // another way
542 debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
543 return true;
546 uint8_t
547 Device::getConfigurationIdSampleRate()
549 ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
550 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
551 extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
552 PlugAddress::ePAM_Unit,
553 unitPlugAddress ) );
555 extStreamFormatCmd.setNodeId( getNodeId() );
556 extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
557 extStreamFormatCmd.setVerbose( getDebugLevel() );
559 if ( !extStreamFormatCmd.fire() ) {
560 debugError( "Stream format command failed\n" );
561 return 0;
564 FormatInformation* formatInfo =
565 extStreamFormatCmd.getFormatInformation();
566 FormatInformationStreamsCompound* compoundStream
567 = dynamic_cast< FormatInformationStreamsCompound* > (
568 formatInfo->m_streams );
569 if ( compoundStream ) {
570 debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
571 compoundStream->m_samplingFrequency );
572 return compoundStream->m_samplingFrequency;
575 debugError( "Could not retrieve sample rate\n" );
576 return 0;
579 uint8_t
580 Device::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
582 ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
583 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
584 0 );
585 extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
586 PlugAddress::ePAM_Unit,
587 unitPlugAddress ) );
588 extPlugInfoCmd.setNodeId( getNodeId() );
589 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
590 extPlugInfoCmd.setVerbose( getDebugLevel() );
591 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
592 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
593 extendedPlugInfoInfoType.initialize();
594 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
596 if ( !extPlugInfoCmd.fire() ) {
597 debugError( "Number of channels command failed\n" );
598 return 0;
601 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
602 if ( infoType
603 && infoType->m_plugNrOfChns )
605 debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
606 infoType->m_plugNrOfChns->m_nrOfChannels );
607 return infoType->m_plugNrOfChns->m_nrOfChannels;
610 debugError( "Could not retrieve number of channels\n" );
611 return 0;
614 uint16_t
615 Device::getConfigurationIdSyncMode()
617 SignalSourceCmd signalSourceCmd( get1394Service() );
618 SignalUnitAddress signalUnitAddr;
619 signalUnitAddr.m_plugId = 0x01;
620 signalSourceCmd.setSignalDestination( signalUnitAddr );
621 signalSourceCmd.setNodeId( getNodeId() );
622 signalSourceCmd.setSubunitType( eST_Unit );
623 signalSourceCmd.setSubunitId( 0xff );
624 signalSourceCmd.setVerbose( getDebugLevel() );
626 signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
628 if ( !signalSourceCmd.fire() ) {
629 debugError( "Signal source command failed\n" );
630 return 0;
633 SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
634 SignalSubunitAddress* pSyncPlugSubunitAddress
635 = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
636 if ( pSyncPlugSubunitAddress ) {
637 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
638 ( pSyncPlugSubunitAddress->m_subunitType << 3
639 | pSyncPlugSubunitAddress->m_subunitId ) << 8
640 | pSyncPlugSubunitAddress->m_plugId );
642 return ( pSyncPlugSubunitAddress->m_subunitType << 3
643 | pSyncPlugSubunitAddress->m_subunitId ) << 8
644 | pSyncPlugSubunitAddress->m_plugId;
647 SignalUnitAddress* pSyncPlugUnitAddress
648 = dynamic_cast<SignalUnitAddress*>( pSyncPlugSignalAddress );
649 if ( pSyncPlugUnitAddress ) {
650 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
651 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
653 return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
656 debugError( "Could not retrieve sync mode\n" );
657 return 0;
660 bool
661 Device::needsRediscovery()
663 // require rediscovery if the config id differs from the one saved
664 // in the previous discovery
665 return getConfigurationId() != m_last_discovery_config_id;
668 uint64_t
669 Device::getConfigurationId()
671 // create a unique configuration id.
672 uint64_t id = 0;
673 id = getConfigurationIdSampleRate();
674 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input ) << 8;
675 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) << 16;
676 id |= ((uint64_t)getConfigurationIdSyncMode()) << 24;
677 return id;
680 bool
681 Device::serialize( std::string basePath,
682 Util::IOSerialize& ser ) const
684 bool result;
685 result = GenericAVC::Device::serialize( basePath, ser );
686 return result;
689 bool
690 Device::deserialize( std::string basePath,
691 Util::IODeserialize& deser )
693 bool result;
694 result = GenericAVC::Device::deserialize( basePath, deser );
695 return result;
698 std::string
699 Device::getCachePath()
701 std::string cachePath;
702 char* pCachePath;
704 string path = CACHEDIR;
705 if ( path.size() && path[0] == '~' ) {
706 path.erase( 0, 1 ); // remove ~
707 path.insert( 0, getenv( "HOME" ) ); // prepend the home path
710 if ( asprintf( &pCachePath, "%s/cache/", path.c_str() ) < 0 ) {
711 debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
712 cachePath = "/var/cache/libffado/";
713 } else {
714 cachePath = pCachePath;
715 free( pCachePath );
717 return cachePath;
720 bool
721 Device::loadFromCache()
723 std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
725 char* configId;
726 asprintf(&configId, "%016"PRIx64"", getConfigurationId() );
727 if ( !configId ) {
728 debugError( "could not create id string\n" );
729 return false;
732 std::string sFileName = sDevicePath + "/" + configId + ".xml";
733 free( configId );
734 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
736 struct stat buf;
737 if ( stat( sFileName.c_str(), &buf ) != 0 ) {
738 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" does not exist\n", sFileName.c_str() );
739 return false;
740 } else {
741 if ( !S_ISREG( buf.st_mode ) ) {
742 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" is not a regular file\n", sFileName.c_str() );
743 return false;
747 Util::XMLDeserialize deser( sFileName, getDebugLevel() );
749 if (!deser.isValid()) {
750 debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
751 sFileName.c_str() );
752 return false;
755 bool result = deserialize( "", deser );
756 if ( result ) {
757 debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
758 sFileName.c_str() );
761 if(result) {
762 buildMixer();
765 return result;
768 bool
769 Device::saveCache()
771 // the path looks like this:
772 // PATH_TO_CACHE + GUID + CONFIGURATION_ID
773 string tmp_path = getCachePath() + getConfigRom().getGuidString();
775 // the following piece should do something like
776 // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
777 vector<string> tokens;
778 tokenize( tmp_path, tokens, "/" );
779 string path;
780 for ( vector<string>::const_iterator it = tokens.begin();
781 it != tokens.end();
782 ++it )
784 path += "/" + *it;
786 struct stat buf;
787 if ( stat( path.c_str(), &buf ) == 0 ) {
788 if ( !S_ISDIR( buf.st_mode ) ) {
789 debugError( "\"%s\" is not a directory\n", path.c_str() );
790 return false;
792 } else {
793 if ( mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
794 debugError( "Could not create \"%s\" directory\n", path.c_str() );
795 return false;
800 // come up with an unique file name for the current settings
801 char* configId;
802 asprintf(&configId, "%016"PRIx64"", BeBoB::Device::getConfigurationId() );
803 if ( !configId ) {
804 debugError( "Could not create id string\n" );
805 return false;
807 string filename = path + "/" + configId + ".xml";
808 free( configId );
809 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
811 Util::XMLSerialize ser( filename );
812 return serialize( "", ser );
815 } // end of namespace