bebob: improve support for PreSonus Inspire1394
[ffado.git] / libffado / src / bebob / bebob_avdevice.cpp
blob42a6e9ce9650d934e1015d7bfa38640359e88a16
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/firebox_avdevice.h"
41 #include "bebob/presonus/inspire1394_avdevice.h"
43 #include "libieee1394/configrom.h"
44 #include "libieee1394/ieee1394service.h"
46 #include "libavc/general/avc_plug_info.h"
47 #include "libavc/general/avc_extended_plug_info.h"
48 #include "libavc/general/avc_subunit_info.h"
49 #include "libavc/streamformat/avc_extended_stream_format.h"
50 #include "libutil/cmd_serialize.h"
51 #include "libavc/avc_definitions.h"
53 #include "debugmodule/debugmodule.h"
55 #include <iostream>
56 #include <sstream>
57 #include <unistd.h>
58 #include <cstdlib>
59 #include <cstring>
60 #include <sys/stat.h>
62 using namespace AVC;
64 namespace BeBoB {
66 Device::Device( DeviceManager& d, std::auto_ptr< ConfigRom >( configRom ) )
67 : GenericAVC::Device( d, configRom )
68 , m_last_discovery_config_id ( 0xFFFFFFFFFFFFFFFFLLU )
69 , m_Mixer ( 0 )
71 debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Device (NodeID %d)\n",
72 getConfigRom().getNodeId() );
75 Device::~Device()
77 destroyMixer();
80 bool
81 Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
83 if(generic) {
84 // try a bebob-specific command to check for the firmware
85 ExtendedPlugInfoCmd extPlugInfoCmd( configRom.get1394Service() );
86 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
87 configRom.getNodeId() );
88 extPlugInfoCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
89 PlugAddress::ePAM_Unit,
90 unitPlugAddress ) );
91 extPlugInfoCmd.setNodeId( configRom.getNodeId() );
92 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
93 extPlugInfoCmd.setVerbose( configRom.getVerboseLevel() );
94 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
95 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
96 extendedPlugInfoInfoType.initialize();
97 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
99 if ( !extPlugInfoCmd.fire() ) {
100 debugError( "Number of channels command failed\n" );
101 return false;
104 if((extPlugInfoCmd.getResponse() != AVCCommand::eR_Implemented)) {
105 // command not supported
106 return false;
109 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
110 if ( infoType
111 && infoType->m_plugNrOfChns )
113 return true;
115 return false;
116 } else {
117 // check if device is in supported devices list
118 unsigned int vendorId = configRom.getNodeVendorId();
119 unsigned int modelId = configRom.getModelId();
121 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
122 return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
126 FFADODevice *
127 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
129 unsigned int vendorId = configRom->getNodeVendorId();
130 unsigned int modelId = configRom->getModelId();
132 switch (vendorId) {
133 case FW_VENDORID_MACKIE:
134 if (modelId == 0x00010065 ) {
135 return new Mackie::OnyxMixerDevice(d, configRom);
137 case FW_VENDORID_EDIROL:
138 switch (modelId) {
139 case 0x00010048:
140 return new Edirol::EdirolFa101Device(d, configRom);
141 case 0x00010049:
142 return new Edirol::EdirolFa66Device(d, configRom);
143 default:
144 return new Device(d, configRom);
146 case FW_VENDORID_ESI:
147 if (modelId == 0x00010064) {
148 return new ESI::QuataFireDevice(d, configRom);
150 break;
151 case FW_VENDORID_TERRATEC:
152 switch(modelId) {
153 case 0x00000003:
154 return new Terratec::Phase88Device(d, configRom);
155 default: // return a plain BeBoB device
156 return new Device(d, configRom);
158 case FW_VENDORID_FOCUSRITE:
159 switch(modelId) {
160 case 0x00000003:
161 case 0x00000006:
162 return new Focusrite::SaffireProDevice(d, configRom);
163 case 0x00000000:
164 return new Focusrite::SaffireDevice(d, configRom);
165 default: // return a plain BeBoB device
166 return new Device(d, configRom);
168 case FW_VENDORID_YAMAHA:
169 switch (modelId) {
170 case 0x0010000b:
171 case 0x0010000c:
172 return new Yamaha::GoDevice(d, configRom);
173 default: // return a plain BeBoB device
174 return new Device(d, configRom);
176 case FW_VENDORID_MAUDIO:
177 switch (modelId) {
178 case 0x0000000a: // Ozonic
179 case 0x00010046: // fw410
180 case 0x00010060: // Audiophile
181 case 0x00010062: // Solo
182 return new MAudio::NormalDevice(d, configRom, modelId);
183 default:
184 return new Device(d, configRom);
186 case FW_VENDORID_PRESONUS:
187 switch (modelId) {
188 case 0x00010000:
189 return new Presonus::FireboxDevice(d, configRom);
190 case 0x00010001:
191 return new Presonus::Inspire1394Device(d, configRom);
192 default:
193 return new Device(d, configRom);
195 default:
196 return new Device(d, configRom);
198 return NULL;
201 #define BEBOB_CHECK_AND_ADD_SR(v, x) \
202 { if(supportsSamplingFrequency(x)) \
203 v.push_back(x); }
204 bool
205 Device::discover()
207 unsigned int vendorId = getConfigRom().getNodeVendorId();
208 unsigned int modelId = getConfigRom().getModelId();
210 Util::Configuration &c = getDeviceManager().getConfiguration();
211 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
213 if (c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB) {
214 debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
215 vme.vendor_name.c_str(),
216 vme.model_name.c_str());
217 } else {
218 debugWarning("Using generic BeBoB support for unsupported device '%s %s'\n",
219 getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
222 if ( !Unit::discover() ) {
223 debugError( "Could not discover unit\n" );
224 return false;
227 if((getAudioSubunit( 0 ) == NULL)) {
228 debugError( "Unit doesn't have an Audio subunit.\n");
229 return false;
231 if((getMusicSubunit( 0 ) == NULL)) {
232 debugError( "Unit doesn't have a Music subunit.\n");
233 return false;
236 if(!buildMixer()) {
237 debugWarning("Could not build mixer\n");
240 // keep track of the config id of this discovery
241 m_last_discovery_config_id = getConfigurationId();
243 return true;
246 bool
247 Device::buildMixer()
249 debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
250 // create a Mixer
251 // this removes the mixer if it already exists
252 // note: a mixer self-registers to it's parent
253 delete m_Mixer;
255 // create the mixer & register it
256 if(getAudioSubunit(0) == NULL) {
257 debugWarning("Could not find audio subunit, mixer not available.\n");
258 m_Mixer = NULL;
259 } else {
260 m_Mixer = new Mixer(*this);
262 if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
263 return m_Mixer != NULL;
266 bool
267 Device::destroyMixer()
269 delete m_Mixer;
270 return true;
273 bool
274 Device::setSelectorFBValue(int id, int value) {
275 FunctionBlockCmd fbCmd( get1394Service(),
276 FunctionBlockCmd::eFBT_Selector,
278 FunctionBlockCmd::eCA_Current );
279 fbCmd.setNodeId( getNodeId() );
280 fbCmd.setSubunitId( 0x00 );
281 fbCmd.setCommandType( AVCCommand::eCT_Control );
282 fbCmd.m_pFBSelector->m_inputFbPlugNumber = (value & 0xFF);
283 fbCmd.setVerboseLevel( getDebugLevel() );
285 if ( !fbCmd.fire() ) {
286 debugError( "cmd failed\n" );
287 return false;
290 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
291 // Util::Cmd::CoutSerializer se;
292 // fbCmd.serialize( se );
293 // }
295 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
296 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
299 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
303 Device::getSelectorFBValue(int id) {
305 FunctionBlockCmd fbCmd( get1394Service(),
306 FunctionBlockCmd::eFBT_Selector,
308 FunctionBlockCmd::eCA_Current );
309 fbCmd.setNodeId( getNodeId() );
310 fbCmd.setSubunitId( 0x00 );
311 fbCmd.setCommandType( AVCCommand::eCT_Status );
312 fbCmd.m_pFBSelector->m_inputFbPlugNumber = 0xFF;
313 fbCmd.setVerboseLevel( getDebugLevel() );
315 if ( !fbCmd.fire() ) {
316 debugError( "cmd failed\n" );
317 return -1;
320 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
321 // Util::Cmd::CoutSerializer se;
322 // fbCmd.serialize( se );
323 // }
325 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
326 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
329 return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
332 bool
333 Device::setFeatureFBVolumeCurrent(int id, int channel, int v) {
335 FunctionBlockCmd fbCmd( get1394Service(),
336 FunctionBlockCmd::eFBT_Feature,
338 FunctionBlockCmd::eCA_Current );
339 fbCmd.setNodeId( getNodeId() );
340 fbCmd.setSubunitId( 0x00 );
341 fbCmd.setCommandType( AVCCommand::eCT_Control );
342 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
343 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
344 AVC::FunctionBlockFeatureVolume vl;
345 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
346 fbCmd.m_pFBFeature->m_pVolume->m_volume = v;
347 fbCmd.setVerboseLevel( getDebugLevel() );
349 if ( !fbCmd.fire() ) {
350 debugError( "cmd failed\n" );
351 return false;
354 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
355 // Util::Cmd::CoutSerializer se;
356 // fbCmd.serialize( se );
357 // }
359 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
360 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
363 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
367 Device::getFeatureFBVolumeValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
369 FunctionBlockCmd fbCmd( get1394Service(),
370 FunctionBlockCmd::eFBT_Feature,
372 controlAttribute);
373 fbCmd.setNodeId( getNodeId() );
374 fbCmd.setSubunitId( 0x00 );
375 fbCmd.setCommandType( AVCCommand::eCT_Status );
376 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
377 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
378 AVC::FunctionBlockFeatureVolume vl;
379 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
380 fbCmd.m_pFBFeature->m_pVolume->m_volume = 0;
381 fbCmd.setVerboseLevel( getDebugLevel() );
383 if ( !fbCmd.fire() ) {
384 debugError( "cmd failed\n" );
385 return 0;
388 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
389 // Util::Cmd::CoutSerializer se;
390 // fbCmd.serialize( se );
391 // }
393 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
394 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
397 int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
399 return volume;
402 int
403 Device::getFeatureFBVolumeMinimum(int id, int channel)
405 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
408 int
409 Device::getFeatureFBVolumeMaximum(int id, int channel)
411 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
414 int
415 Device::getFeatureFBVolumeCurrent(int id, int channel)
417 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
420 bool
421 Device::setFeatureFBLRBalanceCurrent(int id, int channel, int v) {
423 FunctionBlockCmd fbCmd( get1394Service(),
424 FunctionBlockCmd::eFBT_Feature,
426 FunctionBlockCmd::eCA_Current );
427 fbCmd.setNodeId( getNodeId() );
428 fbCmd.setSubunitId( 0x00 );
429 fbCmd.setCommandType( AVCCommand::eCT_Control );
430 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
431 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
432 AVC::FunctionBlockFeatureLRBalance bl;
433 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
434 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = v;
435 fbCmd.setVerboseLevel( getDebugLevel() );
437 if ( !fbCmd.fire() ) {
438 debugError( "cmd failed\n" );
439 return false;
442 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
443 // Util::Cmd::CoutSerializer se;
444 // fbCmd.serialize( se );
445 // }
447 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
448 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
451 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
455 Device::getFeatureFBLRBalanceValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
457 FunctionBlockCmd fbCmd( get1394Service(),
458 FunctionBlockCmd::eFBT_Feature,
460 controlAttribute);
461 fbCmd.setNodeId( getNodeId() );
462 fbCmd.setSubunitId( 0x00 );
463 fbCmd.setCommandType( AVCCommand::eCT_Status );
464 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
465 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
466 AVC::FunctionBlockFeatureLRBalance bl;
467 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
468 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = 0;
469 fbCmd.setVerboseLevel( getDebugLevel() );
471 if ( !fbCmd.fire() ) {
472 debugError( "cmd failed\n" );
473 return 0;
476 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
477 // Util::Cmd::CoutSerializer se;
478 // fbCmd.serialize( se );
479 // }
481 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
482 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
485 int16_t balance=(int16_t)(fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance);
487 return balance;
490 int
491 Device::getFeatureFBLRBalanceMinimum(int id, int channel)
493 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
496 int
497 Device::getFeatureFBLRBalanceMaximum(int id, int channel)
499 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
502 int
503 Device::getFeatureFBLRBalanceCurrent(int id, int channel)
505 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
508 bool
509 Device::setProcessingFBMixerSingleCurrent(int id, int iPlugNum,
510 int iAChNum, int oAChNum,
511 int setting)
513 AVC::FunctionBlockCmd fbCmd(get1394Service(),
514 AVC::FunctionBlockCmd::eFBT_Processing,
516 AVC::FunctionBlockCmd::eCA_Current);
517 fbCmd.setNodeId(getNodeId());
518 fbCmd.setSubunitId(0x00);
519 fbCmd.setCommandType(AVCCommand::eCT_Control);
520 fbCmd.setVerboseLevel( getDebugLevel() );
522 AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
523 fbp->m_selectorLength = 0x04;
524 fbp->m_fbInputPlugNumber = iPlugNum;
525 fbp->m_inputAudioChannelNumber = iAChNum;
526 fbp->m_outputAudioChannelNumber = oAChNum;
528 // mixer object is not generated automatically
529 fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
530 fbp->m_pMixer->m_mixerSetting = setting;
532 if ( !fbCmd.fire() ) {
533 debugError( "cmd failed\n" );
534 return false;
537 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
538 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
541 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
545 Device::getProcessingFBMixerSingleCurrent(int id, int iPlugNum,
546 int iAChNum, int oAChNum)
548 AVC::FunctionBlockCmd fbCmd(get1394Service(),
549 AVC::FunctionBlockCmd::eFBT_Processing,
551 AVC::FunctionBlockCmd::eCA_Current);
552 fbCmd.setNodeId(getNodeId());
553 fbCmd.setSubunitId(0x00);
554 fbCmd.setCommandType(AVCCommand::eCT_Status);
555 fbCmd.setVerboseLevel( getDebugLevel() );
557 AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
558 fbp->m_selectorLength = 0x04;
559 fbp->m_fbInputPlugNumber = iPlugNum;
560 fbp->m_inputAudioChannelNumber = iAChNum;
561 fbp->m_outputAudioChannelNumber = oAChNum;
563 // mixer object is not generated automatically
564 fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
566 if ( !fbCmd.fire() ) {
567 debugError( "cmd failed\n" );
568 return 0;
571 if( (fbCmd.getResponse() != AVCCommand::eR_Implemented) ) {
572 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
575 int16_t setting = (int16_t)(fbp->m_pMixer->m_mixerSetting);
577 return setting;
580 void
581 Device::showDevice()
583 debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
584 GenericAVC::Device::showDevice();
585 flushDebugOutput();
588 void
589 Device::setVerboseLevel(int l)
591 if (m_Mixer) m_Mixer->setVerboseLevel( l );
592 GenericAVC::Device::setVerboseLevel( l );
593 debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
596 AVC::Subunit*
597 Device::createSubunit(AVC::Unit& unit,
598 AVC::ESubunitType type,
599 AVC::subunit_t id )
601 AVC::Subunit* s=NULL;
602 switch (type) {
603 case eST_Audio:
604 s=new BeBoB::SubunitAudio(unit, id );
605 break;
606 case eST_Music:
607 s=new BeBoB::SubunitMusic(unit, id );
608 break;
609 default:
610 s=NULL;
611 break;
613 if(s) s->setVerboseLevel(getDebugLevel());
614 return s;
618 AVC::Plug *
619 Device::createPlug( AVC::Unit* unit,
620 AVC::Subunit* subunit,
621 AVC::function_block_type_t functionBlockType,
622 AVC::function_block_type_t functionBlockId,
623 AVC::Plug::EPlugAddressType plugAddressType,
624 AVC::Plug::EPlugDirection plugDirection,
625 AVC::plug_id_t plugId,
626 int globalId )
629 Plug *p= new BeBoB::Plug( unit,
630 subunit,
631 functionBlockType,
632 functionBlockId,
633 plugAddressType,
634 plugDirection,
635 plugId,
636 globalId );
637 if (p) p->setVerboseLevel(getDebugLevel());
638 return p;
641 bool
642 Device::propagatePlugInfo() {
643 // we don't have to propagate since we discover things
644 // another way
645 debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
646 return true;
649 uint8_t
650 Device::getConfigurationIdSampleRate()
652 ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
653 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
654 extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
655 PlugAddress::ePAM_Unit,
656 unitPlugAddress ) );
658 extStreamFormatCmd.setNodeId( getNodeId() );
659 extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
660 extStreamFormatCmd.setVerbose( getDebugLevel() );
662 if ( !extStreamFormatCmd.fire() ) {
663 debugError( "Stream format command failed\n" );
664 return 0;
667 FormatInformation* formatInfo =
668 extStreamFormatCmd.getFormatInformation();
669 FormatInformationStreamsCompound* compoundStream
670 = dynamic_cast< FormatInformationStreamsCompound* > (
671 formatInfo->m_streams );
672 if ( compoundStream ) {
673 debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
674 compoundStream->m_samplingFrequency );
675 return compoundStream->m_samplingFrequency;
678 debugError( "Could not retrieve sample rate\n" );
679 return 0;
682 uint8_t
683 Device::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
685 ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
686 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
687 0 );
688 extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
689 PlugAddress::ePAM_Unit,
690 unitPlugAddress ) );
691 extPlugInfoCmd.setNodeId( getNodeId() );
692 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
693 extPlugInfoCmd.setVerbose( getDebugLevel() );
694 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
695 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
696 extendedPlugInfoInfoType.initialize();
697 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
699 if ( !extPlugInfoCmd.fire() ) {
700 debugError( "Number of channels command failed\n" );
701 return 0;
704 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
705 if ( infoType
706 && infoType->m_plugNrOfChns )
708 debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
709 infoType->m_plugNrOfChns->m_nrOfChannels );
710 return infoType->m_plugNrOfChns->m_nrOfChannels;
713 debugError( "Could not retrieve number of channels\n" );
714 return 0;
717 uint16_t
718 Device::getConfigurationIdSyncMode()
720 SignalSourceCmd signalSourceCmd( get1394Service() );
721 SignalUnitAddress signalUnitAddr;
722 signalUnitAddr.m_plugId = 0x01;
723 signalSourceCmd.setSignalDestination( signalUnitAddr );
724 signalSourceCmd.setNodeId( getNodeId() );
725 signalSourceCmd.setSubunitType( eST_Unit );
726 signalSourceCmd.setSubunitId( 0xff );
727 signalSourceCmd.setVerbose( getDebugLevel() );
729 signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
731 if ( !signalSourceCmd.fire() ) {
732 debugError( "Signal source command failed\n" );
733 return 0;
736 SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
737 SignalSubunitAddress* pSyncPlugSubunitAddress
738 = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
739 if ( pSyncPlugSubunitAddress ) {
740 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
741 ( pSyncPlugSubunitAddress->m_subunitType << 3
742 | pSyncPlugSubunitAddress->m_subunitId ) << 8
743 | pSyncPlugSubunitAddress->m_plugId );
745 return ( pSyncPlugSubunitAddress->m_subunitType << 3
746 | pSyncPlugSubunitAddress->m_subunitId ) << 8
747 | pSyncPlugSubunitAddress->m_plugId;
750 SignalUnitAddress* pSyncPlugUnitAddress
751 = dynamic_cast<SignalUnitAddress*>( pSyncPlugSignalAddress );
752 if ( pSyncPlugUnitAddress ) {
753 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
754 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
756 return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
759 debugError( "Could not retrieve sync mode\n" );
760 return 0;
763 bool
764 Device::needsRediscovery()
766 // require rediscovery if the config id differs from the one saved
767 // in the previous discovery
768 return getConfigurationId() != m_last_discovery_config_id;
771 uint64_t
772 Device::getConfigurationId()
774 // create a unique configuration id.
775 uint64_t id = 0;
776 id = getConfigurationIdSampleRate();
777 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input ) << 8;
778 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) << 16;
779 id |= ((uint64_t)getConfigurationIdSyncMode()) << 24;
780 return id;
783 bool
784 Device::serialize( std::string basePath,
785 Util::IOSerialize& ser ) const
787 bool result;
788 result = GenericAVC::Device::serialize( basePath, ser );
789 return result;
792 bool
793 Device::deserialize( std::string basePath,
794 Util::IODeserialize& deser )
796 bool result;
797 result = GenericAVC::Device::deserialize( basePath, deser );
798 return result;
801 std::string
802 Device::getCachePath()
804 std::string cachePath;
805 char* pCachePath;
807 string path = CACHEDIR;
808 if ( path.size() && path[0] == '~' ) {
809 path.erase( 0, 1 ); // remove ~
810 path.insert( 0, getenv( "HOME" ) ); // prepend the home path
813 if ( asprintf( &pCachePath, "%s/cache/", path.c_str() ) < 0 ) {
814 debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
815 cachePath = "/var/cache/libffado/";
816 } else {
817 cachePath = pCachePath;
818 free( pCachePath );
820 return cachePath;
823 bool
824 Device::loadFromCache()
826 std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
828 char* configId;
829 asprintf(&configId, "%016"PRIx64"", getConfigurationId() );
830 if ( !configId ) {
831 debugError( "could not create id string\n" );
832 return false;
835 std::string sFileName = sDevicePath + "/" + configId + ".xml";
836 free( configId );
837 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
839 struct stat buf;
840 if ( stat( sFileName.c_str(), &buf ) != 0 ) {
841 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" does not exist\n", sFileName.c_str() );
842 return false;
843 } else {
844 if ( !S_ISREG( buf.st_mode ) ) {
845 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" is not a regular file\n", sFileName.c_str() );
846 return false;
850 Util::XMLDeserialize deser( sFileName, getDebugLevel() );
852 if (!deser.isValid()) {
853 debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
854 sFileName.c_str() );
855 return false;
858 bool result = deserialize( "", deser );
859 if ( result ) {
860 debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
861 sFileName.c_str() );
864 if(result) {
865 buildMixer();
868 return result;
871 bool
872 Device::saveCache()
874 // the path looks like this:
875 // PATH_TO_CACHE + GUID + CONFIGURATION_ID
876 string tmp_path = getCachePath() + getConfigRom().getGuidString();
878 // the following piece should do something like
879 // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
880 vector<string> tokens;
881 tokenize( tmp_path, tokens, "/" );
882 string path;
883 for ( vector<string>::const_iterator it = tokens.begin();
884 it != tokens.end();
885 ++it )
887 path += "/" + *it;
889 struct stat buf;
890 if ( stat( path.c_str(), &buf ) == 0 ) {
891 if ( !S_ISDIR( buf.st_mode ) ) {
892 debugError( "\"%s\" is not a directory\n", path.c_str() );
893 return false;
895 } else {
896 if ( mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
897 debugError( "Could not create \"%s\" directory\n", path.c_str() );
898 return false;
903 // come up with an unique file name for the current settings
904 char* configId;
905 asprintf(&configId, "%016"PRIx64"", BeBoB::Device::getConfigurationId() );
906 if ( !configId ) {
907 debugError( "Could not create id string\n" );
908 return false;
910 string filename = path + "/" + configId + ".xml";
911 free( configId );
912 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
914 Util::XMLSerialize ser( filename );
915 return serialize( "", ser );
918 } // end of namespace