[BeBoB/PreSonus] Apply FireboxDevice class to PreSonus FIREBOX
[ffado.git] / libffado / src / bebob / bebob_avdevice.cpp
blob71f2c9b8afefe8a1d14ccf5b450e3a3a51c4ad3d
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"
39 #include "bebob/maudio/maudio_normal_avdevice.h"
40 #include "bebob/presonus/presonus_avdevice.h"
42 #include "libieee1394/configrom.h"
43 #include "libieee1394/ieee1394service.h"
45 #include "libavc/general/avc_plug_info.h"
46 #include "libavc/general/avc_extended_plug_info.h"
47 #include "libavc/general/avc_subunit_info.h"
48 #include "libavc/streamformat/avc_extended_stream_format.h"
49 #include "libutil/cmd_serialize.h"
50 #include "libavc/avc_definitions.h"
52 #include "debugmodule/debugmodule.h"
54 #include <iostream>
55 #include <sstream>
56 #include <unistd.h>
57 #include <cstdlib>
58 #include <cstring>
59 #include <sys/stat.h>
61 using namespace AVC;
63 namespace BeBoB {
65 Device::Device( DeviceManager& d, std::auto_ptr< ConfigRom >( configRom ) )
66 : GenericAVC::Device( d, configRom )
67 , m_last_discovery_config_id ( 0xFFFFFFFFFFFFFFFFLLU )
68 , m_Mixer ( 0 )
70 debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Device (NodeID %d)\n",
71 getConfigRom().getNodeId() );
74 Device::~Device()
76 destroyMixer();
79 bool
80 Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
82 if(generic) {
83 // try a bebob-specific command to check for the firmware
84 ExtendedPlugInfoCmd extPlugInfoCmd( configRom.get1394Service() );
85 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
86 configRom.getNodeId() );
87 extPlugInfoCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
88 PlugAddress::ePAM_Unit,
89 unitPlugAddress ) );
90 extPlugInfoCmd.setNodeId( configRom.getNodeId() );
91 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
92 extPlugInfoCmd.setVerbose( configRom.getVerboseLevel() );
93 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
94 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
95 extendedPlugInfoInfoType.initialize();
96 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
98 if ( !extPlugInfoCmd.fire() ) {
99 debugError( "Number of channels command failed\n" );
100 return false;
103 if((extPlugInfoCmd.getResponse() != AVCCommand::eR_Implemented)) {
104 // command not supported
105 return false;
108 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
109 if ( infoType
110 && infoType->m_plugNrOfChns )
112 return true;
114 return false;
115 } else {
116 // check if device is in supported devices list
117 unsigned int vendorId = configRom.getNodeVendorId();
118 unsigned int modelId = configRom.getModelId();
120 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
121 return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
125 FFADODevice *
126 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
128 unsigned int vendorId = configRom->getNodeVendorId();
129 unsigned int modelId = configRom->getModelId();
131 switch (vendorId) {
132 case FW_VENDORID_MACKIE:
133 if (modelId == 0x00010065 ) {
134 return new Mackie::OnyxMixerDevice(d, configRom);
136 case FW_VENDORID_EDIROL:
137 switch (modelId) {
138 case 0x00010048:
139 return new Edirol::EdirolFa101Device(d, configRom);
140 case 0x00010049:
141 return new Edirol::EdirolFa66Device(d, configRom);
142 default:
143 return new Device(d, configRom);
145 case FW_VENDORID_ESI:
146 if (modelId == 0x00010064) {
147 return new ESI::QuataFireDevice(d, configRom);
149 break;
150 case FW_VENDORID_TERRATEC:
151 switch(modelId) {
152 case 0x00000003:
153 return new Terratec::Phase88Device(d, configRom);
154 default: // return a plain BeBoB device
155 return new Device(d, configRom);
157 case FW_VENDORID_FOCUSRITE:
158 switch(modelId) {
159 case 0x00000003:
160 case 0x00000006:
161 return new Focusrite::SaffireProDevice(d, configRom);
162 case 0x00000000:
163 return new Focusrite::SaffireDevice(d, configRom);
164 default: // return a plain BeBoB device
165 return new Device(d, configRom);
167 case FW_VENDORID_YAMAHA:
168 switch (modelId) {
169 case 0x0010000b:
170 case 0x0010000c:
171 return new Yamaha::GoDevice(d, configRom);
172 default: // return a plain BeBoB device
173 return new Device(d, configRom);
175 case FW_VENDORID_MAUDIO:
176 switch (modelId) {
177 case 0x0000000a: // Ozonic
178 case 0x00010046: // fw410
179 case 0x00010060: // Audiophile
180 case 0x00010062: // Solo
181 return new MAudio::NormalDevice(d, configRom, modelId);
182 default:
183 return new Device(d, configRom);
185 case FW_VENDORID_PRESONUS:
186 switch (modelId) {
187 case 0x00010000:
188 return new Presonus::FireboxDevice(d, configRom);
189 default:
190 return new Device(d, configRom);
192 default:
193 return new Device(d, configRom);
195 return NULL;
198 #define BEBOB_CHECK_AND_ADD_SR(v, x) \
199 { if(supportsSamplingFrequency(x)) \
200 v.push_back(x); }
201 bool
202 Device::discover()
204 unsigned int vendorId = getConfigRom().getNodeVendorId();
205 unsigned int modelId = getConfigRom().getModelId();
207 Util::Configuration &c = getDeviceManager().getConfiguration();
208 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
210 if (c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB) {
211 debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
212 vme.vendor_name.c_str(),
213 vme.model_name.c_str());
214 } else {
215 debugWarning("Using generic BeBoB support for unsupported device '%s %s'\n",
216 getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
219 if ( !Unit::discover() ) {
220 debugError( "Could not discover unit\n" );
221 return false;
224 if((getAudioSubunit( 0 ) == NULL)) {
225 debugError( "Unit doesn't have an Audio subunit.\n");
226 return false;
228 if((getMusicSubunit( 0 ) == NULL)) {
229 debugError( "Unit doesn't have a Music subunit.\n");
230 return false;
233 if(!buildMixer()) {
234 debugWarning("Could not build mixer\n");
237 // keep track of the config id of this discovery
238 m_last_discovery_config_id = getConfigurationId();
240 return true;
243 bool
244 Device::buildMixer()
246 debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
247 // create a Mixer
248 // this removes the mixer if it already exists
249 // note: a mixer self-registers to it's parent
250 delete m_Mixer;
252 // create the mixer & register it
253 if(getAudioSubunit(0) == NULL) {
254 debugWarning("Could not find audio subunit, mixer not available.\n");
255 m_Mixer = NULL;
256 } else {
257 m_Mixer = new Mixer(*this);
259 if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
260 return m_Mixer != NULL;
263 bool
264 Device::destroyMixer()
266 delete m_Mixer;
267 return true;
270 bool
271 Device::setSelectorFBValue(int id, int value) {
272 FunctionBlockCmd fbCmd( get1394Service(),
273 FunctionBlockCmd::eFBT_Selector,
275 FunctionBlockCmd::eCA_Current );
276 fbCmd.setNodeId( getNodeId() );
277 fbCmd.setSubunitId( 0x00 );
278 fbCmd.setCommandType( AVCCommand::eCT_Control );
279 fbCmd.m_pFBSelector->m_inputFbPlugNumber = (value & 0xFF);
280 fbCmd.setVerboseLevel( getDebugLevel() );
282 if ( !fbCmd.fire() ) {
283 debugError( "cmd failed\n" );
284 return false;
287 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
288 // Util::Cmd::CoutSerializer se;
289 // fbCmd.serialize( se );
290 // }
292 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
293 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
296 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
300 Device::getSelectorFBValue(int id) {
302 FunctionBlockCmd fbCmd( get1394Service(),
303 FunctionBlockCmd::eFBT_Selector,
305 FunctionBlockCmd::eCA_Current );
306 fbCmd.setNodeId( getNodeId() );
307 fbCmd.setSubunitId( 0x00 );
308 fbCmd.setCommandType( AVCCommand::eCT_Status );
309 fbCmd.m_pFBSelector->m_inputFbPlugNumber = 0xFF;
310 fbCmd.setVerboseLevel( getDebugLevel() );
312 if ( !fbCmd.fire() ) {
313 debugError( "cmd failed\n" );
314 return -1;
317 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
318 // Util::Cmd::CoutSerializer se;
319 // fbCmd.serialize( se );
320 // }
322 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
323 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
326 return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
329 bool
330 Device::setFeatureFBVolumeCurrent(int id, int channel, int v) {
332 FunctionBlockCmd fbCmd( get1394Service(),
333 FunctionBlockCmd::eFBT_Feature,
335 FunctionBlockCmd::eCA_Current );
336 fbCmd.setNodeId( getNodeId() );
337 fbCmd.setSubunitId( 0x00 );
338 fbCmd.setCommandType( AVCCommand::eCT_Control );
339 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
340 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
341 AVC::FunctionBlockFeatureVolume vl;
342 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
343 fbCmd.m_pFBFeature->m_pVolume->m_volume = v;
344 fbCmd.setVerboseLevel( getDebugLevel() );
346 if ( !fbCmd.fire() ) {
347 debugError( "cmd failed\n" );
348 return false;
351 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
352 // Util::Cmd::CoutSerializer se;
353 // fbCmd.serialize( se );
354 // }
356 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
357 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
360 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
364 Device::getFeatureFBVolumeValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
366 FunctionBlockCmd fbCmd( get1394Service(),
367 FunctionBlockCmd::eFBT_Feature,
369 controlAttribute);
370 fbCmd.setNodeId( getNodeId() );
371 fbCmd.setSubunitId( 0x00 );
372 fbCmd.setCommandType( AVCCommand::eCT_Status );
373 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
374 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
375 AVC::FunctionBlockFeatureVolume vl;
376 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
377 fbCmd.m_pFBFeature->m_pVolume->m_volume = 0;
378 fbCmd.setVerboseLevel( getDebugLevel() );
380 if ( !fbCmd.fire() ) {
381 debugError( "cmd failed\n" );
382 return 0;
385 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
386 // Util::Cmd::CoutSerializer se;
387 // fbCmd.serialize( se );
388 // }
390 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
391 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
394 int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
396 return volume;
399 int
400 Device::getFeatureFBVolumeMinimum(int id, int channel)
402 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
405 int
406 Device::getFeatureFBVolumeMaximum(int id, int channel)
408 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
411 int
412 Device::getFeatureFBVolumeCurrent(int id, int channel)
414 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
417 bool
418 Device::setFeatureFBLRBalanceCurrent(int id, int channel, int v) {
420 FunctionBlockCmd fbCmd( get1394Service(),
421 FunctionBlockCmd::eFBT_Feature,
423 FunctionBlockCmd::eCA_Current );
424 fbCmd.setNodeId( getNodeId() );
425 fbCmd.setSubunitId( 0x00 );
426 fbCmd.setCommandType( AVCCommand::eCT_Control );
427 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
428 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
429 AVC::FunctionBlockFeatureLRBalance bl;
430 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
431 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = v;
432 fbCmd.setVerboseLevel( getDebugLevel() );
434 if ( !fbCmd.fire() ) {
435 debugError( "cmd failed\n" );
436 return false;
439 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
440 // Util::Cmd::CoutSerializer se;
441 // fbCmd.serialize( se );
442 // }
444 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
445 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
448 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
452 Device::getFeatureFBLRBalanceValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
454 FunctionBlockCmd fbCmd( get1394Service(),
455 FunctionBlockCmd::eFBT_Feature,
457 controlAttribute);
458 fbCmd.setNodeId( getNodeId() );
459 fbCmd.setSubunitId( 0x00 );
460 fbCmd.setCommandType( AVCCommand::eCT_Status );
461 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
462 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
463 AVC::FunctionBlockFeatureLRBalance bl;
464 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
465 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = 0;
466 fbCmd.setVerboseLevel( getDebugLevel() );
468 if ( !fbCmd.fire() ) {
469 debugError( "cmd failed\n" );
470 return 0;
473 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
474 // Util::Cmd::CoutSerializer se;
475 // fbCmd.serialize( se );
476 // }
478 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
479 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
482 int16_t balance=(int16_t)(fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance);
484 return balance;
487 int
488 Device::getFeatureFBLRBalanceMinimum(int id, int channel)
490 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
493 int
494 Device::getFeatureFBLRBalanceMaximum(int id, int channel)
496 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
499 int
500 Device::getFeatureFBLRBalanceCurrent(int id, int channel)
502 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
505 bool
506 Device::setProcessingFBMixerSingleCurrent(int id, int iPlugNum,
507 int iAChNum, int oAChNum,
508 int setting)
510 AVC::FunctionBlockCmd fbCmd(get1394Service(),
511 AVC::FunctionBlockCmd::eFBT_Processing,
513 AVC::FunctionBlockCmd::eCA_Current);
514 fbCmd.setNodeId(getNodeId());
515 fbCmd.setSubunitId(0x00);
516 fbCmd.setCommandType(AVCCommand::eCT_Control);
517 fbCmd.setVerboseLevel( getDebugLevel() );
519 AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
520 fbp->m_selectorLength = 0x04;
521 fbp->m_fbInputPlugNumber = iPlugNum;
522 fbp->m_inputAudioChannelNumber = iAChNum;
523 fbp->m_outputAudioChannelNumber = oAChNum;
525 // mixer object is not generated automatically
526 fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
527 fbp->m_pMixer->m_mixerSetting = setting;
529 if ( !fbCmd.fire() ) {
530 debugError( "cmd failed\n" );
531 return false;
534 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
535 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
538 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
542 Device::getProcessingFBMixerSingleCurrent(int id, int iPlugNum,
543 int iAChNum, int oAChNum)
545 AVC::FunctionBlockCmd fbCmd(get1394Service(),
546 AVC::FunctionBlockCmd::eFBT_Processing,
548 AVC::FunctionBlockCmd::eCA_Current);
549 fbCmd.setNodeId(getNodeId());
550 fbCmd.setSubunitId(0x00);
551 fbCmd.setCommandType(AVCCommand::eCT_Status);
552 fbCmd.setVerboseLevel( getDebugLevel() );
554 AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
555 fbp->m_selectorLength = 0x04;
556 fbp->m_fbInputPlugNumber = iPlugNum;
557 fbp->m_inputAudioChannelNumber = iAChNum;
558 fbp->m_outputAudioChannelNumber = oAChNum;
560 // mixer object is not generated automatically
561 fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
563 if ( !fbCmd.fire() ) {
564 debugError( "cmd failed\n" );
565 return 0;
568 if( (fbCmd.getResponse() != AVCCommand::eR_Implemented) ) {
569 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
572 int16_t setting = (int16_t)(fbp->m_pMixer->m_mixerSetting);
574 return setting;
577 void
578 Device::showDevice()
580 debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
581 GenericAVC::Device::showDevice();
582 flushDebugOutput();
585 void
586 Device::setVerboseLevel(int l)
588 if (m_Mixer) m_Mixer->setVerboseLevel( l );
589 GenericAVC::Device::setVerboseLevel( l );
590 debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
593 AVC::Subunit*
594 Device::createSubunit(AVC::Unit& unit,
595 AVC::ESubunitType type,
596 AVC::subunit_t id )
598 AVC::Subunit* s=NULL;
599 switch (type) {
600 case eST_Audio:
601 s=new BeBoB::SubunitAudio(unit, id );
602 break;
603 case eST_Music:
604 s=new BeBoB::SubunitMusic(unit, id );
605 break;
606 default:
607 s=NULL;
608 break;
610 if(s) s->setVerboseLevel(getDebugLevel());
611 return s;
615 AVC::Plug *
616 Device::createPlug( AVC::Unit* unit,
617 AVC::Subunit* subunit,
618 AVC::function_block_type_t functionBlockType,
619 AVC::function_block_type_t functionBlockId,
620 AVC::Plug::EPlugAddressType plugAddressType,
621 AVC::Plug::EPlugDirection plugDirection,
622 AVC::plug_id_t plugId,
623 int globalId )
626 Plug *p= new BeBoB::Plug( unit,
627 subunit,
628 functionBlockType,
629 functionBlockId,
630 plugAddressType,
631 plugDirection,
632 plugId,
633 globalId );
634 if (p) p->setVerboseLevel(getDebugLevel());
635 return p;
638 bool
639 Device::propagatePlugInfo() {
640 // we don't have to propagate since we discover things
641 // another way
642 debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
643 return true;
646 uint8_t
647 Device::getConfigurationIdSampleRate()
649 ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
650 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
651 extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
652 PlugAddress::ePAM_Unit,
653 unitPlugAddress ) );
655 extStreamFormatCmd.setNodeId( getNodeId() );
656 extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
657 extStreamFormatCmd.setVerbose( getDebugLevel() );
659 if ( !extStreamFormatCmd.fire() ) {
660 debugError( "Stream format command failed\n" );
661 return 0;
664 FormatInformation* formatInfo =
665 extStreamFormatCmd.getFormatInformation();
666 FormatInformationStreamsCompound* compoundStream
667 = dynamic_cast< FormatInformationStreamsCompound* > (
668 formatInfo->m_streams );
669 if ( compoundStream ) {
670 debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
671 compoundStream->m_samplingFrequency );
672 return compoundStream->m_samplingFrequency;
675 debugError( "Could not retrieve sample rate\n" );
676 return 0;
679 uint8_t
680 Device::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
682 ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
683 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
684 0 );
685 extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
686 PlugAddress::ePAM_Unit,
687 unitPlugAddress ) );
688 extPlugInfoCmd.setNodeId( getNodeId() );
689 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
690 extPlugInfoCmd.setVerbose( getDebugLevel() );
691 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
692 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
693 extendedPlugInfoInfoType.initialize();
694 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
696 if ( !extPlugInfoCmd.fire() ) {
697 debugError( "Number of channels command failed\n" );
698 return 0;
701 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
702 if ( infoType
703 && infoType->m_plugNrOfChns )
705 debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
706 infoType->m_plugNrOfChns->m_nrOfChannels );
707 return infoType->m_plugNrOfChns->m_nrOfChannels;
710 debugError( "Could not retrieve number of channels\n" );
711 return 0;
714 uint16_t
715 Device::getConfigurationIdSyncMode()
717 SignalSourceCmd signalSourceCmd( get1394Service() );
718 SignalUnitAddress signalUnitAddr;
719 signalUnitAddr.m_plugId = 0x01;
720 signalSourceCmd.setSignalDestination( signalUnitAddr );
721 signalSourceCmd.setNodeId( getNodeId() );
722 signalSourceCmd.setSubunitType( eST_Unit );
723 signalSourceCmd.setSubunitId( 0xff );
724 signalSourceCmd.setVerbose( getDebugLevel() );
726 signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
728 if ( !signalSourceCmd.fire() ) {
729 debugError( "Signal source command failed\n" );
730 return 0;
733 SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
734 SignalSubunitAddress* pSyncPlugSubunitAddress
735 = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
736 if ( pSyncPlugSubunitAddress ) {
737 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
738 ( pSyncPlugSubunitAddress->m_subunitType << 3
739 | pSyncPlugSubunitAddress->m_subunitId ) << 8
740 | pSyncPlugSubunitAddress->m_plugId );
742 return ( pSyncPlugSubunitAddress->m_subunitType << 3
743 | pSyncPlugSubunitAddress->m_subunitId ) << 8
744 | pSyncPlugSubunitAddress->m_plugId;
747 SignalUnitAddress* pSyncPlugUnitAddress
748 = dynamic_cast<SignalUnitAddress*>( pSyncPlugSignalAddress );
749 if ( pSyncPlugUnitAddress ) {
750 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
751 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
753 return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
756 debugError( "Could not retrieve sync mode\n" );
757 return 0;
760 bool
761 Device::needsRediscovery()
763 // require rediscovery if the config id differs from the one saved
764 // in the previous discovery
765 return getConfigurationId() != m_last_discovery_config_id;
768 uint64_t
769 Device::getConfigurationId()
771 // create a unique configuration id.
772 uint64_t id = 0;
773 id = getConfigurationIdSampleRate();
774 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input ) << 8;
775 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) << 16;
776 id |= ((uint64_t)getConfigurationIdSyncMode()) << 24;
777 return id;
780 bool
781 Device::serialize( std::string basePath,
782 Util::IOSerialize& ser ) const
784 bool result;
785 result = GenericAVC::Device::serialize( basePath, ser );
786 return result;
789 bool
790 Device::deserialize( std::string basePath,
791 Util::IODeserialize& deser )
793 bool result;
794 result = GenericAVC::Device::deserialize( basePath, deser );
795 return result;
798 std::string
799 Device::getCachePath()
801 std::string cachePath;
802 char* pCachePath;
804 string path = CACHEDIR;
805 if ( path.size() && path[0] == '~' ) {
806 path.erase( 0, 1 ); // remove ~
807 path.insert( 0, getenv( "HOME" ) ); // prepend the home path
810 if ( asprintf( &pCachePath, "%s/cache/", path.c_str() ) < 0 ) {
811 debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
812 cachePath = "/var/cache/libffado/";
813 } else {
814 cachePath = pCachePath;
815 free( pCachePath );
817 return cachePath;
820 bool
821 Device::loadFromCache()
823 std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
825 char* configId;
826 asprintf(&configId, "%016"PRIx64"", getConfigurationId() );
827 if ( !configId ) {
828 debugError( "could not create id string\n" );
829 return false;
832 std::string sFileName = sDevicePath + "/" + configId + ".xml";
833 free( configId );
834 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
836 struct stat buf;
837 if ( stat( sFileName.c_str(), &buf ) != 0 ) {
838 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" does not exist\n", sFileName.c_str() );
839 return false;
840 } else {
841 if ( !S_ISREG( buf.st_mode ) ) {
842 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" is not a regular file\n", sFileName.c_str() );
843 return false;
847 Util::XMLDeserialize deser( sFileName, getDebugLevel() );
849 if (!deser.isValid()) {
850 debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
851 sFileName.c_str() );
852 return false;
855 bool result = deserialize( "", deser );
856 if ( result ) {
857 debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
858 sFileName.c_str() );
861 if(result) {
862 buildMixer();
865 return result;
868 bool
869 Device::saveCache()
871 // the path looks like this:
872 // PATH_TO_CACHE + GUID + CONFIGURATION_ID
873 string tmp_path = getCachePath() + getConfigRom().getGuidString();
875 // the following piece should do something like
876 // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
877 vector<string> tokens;
878 tokenize( tmp_path, tokens, "/" );
879 string path;
880 for ( vector<string>::const_iterator it = tokens.begin();
881 it != tokens.end();
882 ++it )
884 path += "/" + *it;
886 struct stat buf;
887 if ( stat( path.c_str(), &buf ) == 0 ) {
888 if ( !S_ISDIR( buf.st_mode ) ) {
889 debugError( "\"%s\" is not a directory\n", path.c_str() );
890 return false;
892 } else {
893 if ( mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
894 debugError( "Could not create \"%s\" directory\n", path.c_str() );
895 return false;
900 // come up with an unique file name for the current settings
901 char* configId;
902 asprintf(&configId, "%016"PRIx64"", BeBoB::Device::getConfigurationId() );
903 if ( !configId ) {
904 debugError( "Could not create id string\n" );
905 return false;
907 string filename = path + "/" + configId + ".xml";
908 free( configId );
909 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
911 Util::XMLSerialize ser( filename );
912 return serialize( "", ser );
915 } // end of namespace