Clean up compiler warnings when compiling on 64-bit systems. These are mostly fixing...
[ffado.git] / libffado / src / bebob / bebob_avdevice.cpp
blob5fa76afe32659e302b145879678ba3973e37240f
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/normal_avdevice.h"
40 #include "bebob/maudio/special_avdevice.h"
41 #include "bebob/presonus/firebox_avdevice.h"
42 #include "bebob/presonus/inspire1394_avdevice.h"
44 #include "libieee1394/configrom.h"
45 #include "libieee1394/ieee1394service.h"
47 #include "libavc/general/avc_plug_info.h"
48 #include "libavc/general/avc_extended_plug_info.h"
49 #include "libavc/general/avc_subunit_info.h"
50 #include "libavc/streamformat/avc_extended_stream_format.h"
51 #include "libutil/cmd_serialize.h"
52 #include "libavc/avc_definitions.h"
54 #include "debugmodule/debugmodule.h"
56 #include <iostream>
57 #include <sstream>
58 #include <unistd.h>
59 #include <cstdlib>
60 #include <cstring>
61 #include <sys/stat.h>
63 using namespace AVC;
65 namespace BeBoB {
67 Device::Device( DeviceManager& d, std::auto_ptr< ConfigRom >( configRom ) )
68 : GenericAVC::Device( d, configRom )
69 , m_last_discovery_config_id ( 0xFFFFFFFFFFFFFFFFLLU )
70 , m_Mixer ( 0 )
72 debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Device (NodeID %d)\n",
73 getConfigRom().getNodeId() );
76 Device::~Device()
78 destroyMixer();
81 bool
82 Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
84 unsigned int vendorId = configRom.getNodeVendorId();
85 unsigned int modelId = configRom.getModelId();
87 if(generic) {
88 /* M-Audio Special Devices don't support followed commands */
89 if ((vendorId == FW_VENDORID_MAUDIO) &&
90 ((modelId == 0x00010071) || (modelId == 0x00010091)))
91 return true;
93 // try a bebob-specific command to check for the firmware
94 ExtendedPlugInfoCmd extPlugInfoCmd( configRom.get1394Service() );
95 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
96 configRom.getNodeId() );
97 extPlugInfoCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
98 PlugAddress::ePAM_Unit,
99 unitPlugAddress ) );
100 extPlugInfoCmd.setNodeId( configRom.getNodeId() );
101 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
102 extPlugInfoCmd.setVerbose( configRom.getVerboseLevel() );
103 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
104 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
105 extendedPlugInfoInfoType.initialize();
106 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
108 if ( !extPlugInfoCmd.fire() ) {
109 debugError( "Number of channels command failed\n" );
110 return false;
113 if((extPlugInfoCmd.getResponse() != AVCCommand::eR_Implemented)) {
114 // command not supported
115 return false;
118 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
119 if ( infoType
120 && infoType->m_plugNrOfChns )
122 return true;
124 return false;
125 } else {
126 // check if device is in supported devices list
127 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
128 return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
132 FFADODevice *
133 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
135 unsigned int vendorId = configRom->getNodeVendorId();
136 unsigned int modelId = configRom->getModelId();
138 switch (vendorId) {
139 case FW_VENDORID_MACKIE:
140 if (modelId == 0x00010065 ) {
141 return new Mackie::OnyxMixerDevice(d, configRom);
143 case FW_VENDORID_EDIROL:
144 switch (modelId) {
145 case 0x00010048:
146 return new Edirol::EdirolFa101Device(d, configRom);
147 case 0x00010049:
148 return new Edirol::EdirolFa66Device(d, configRom);
149 default:
150 return new Device(d, configRom);
152 case FW_VENDORID_ESI:
153 if (modelId == 0x00010064) {
154 return new ESI::QuataFireDevice(d, configRom);
156 break;
157 case FW_VENDORID_TERRATEC:
158 switch(modelId) {
159 case 0x00000003:
160 return new Terratec::Phase88Device(d, configRom);
161 default: // return a plain BeBoB device
162 return new Device(d, configRom);
164 case FW_VENDORID_FOCUSRITE:
165 switch(modelId) {
166 case 0x00000003:
167 case 0x00000006:
168 return new Focusrite::SaffireProDevice(d, configRom);
169 case 0x00000000:
170 return new Focusrite::SaffireDevice(d, configRom);
171 default: // return a plain BeBoB device
172 return new Device(d, configRom);
174 case FW_VENDORID_YAMAHA:
175 switch (modelId) {
176 case 0x0010000b:
177 case 0x0010000c:
178 return new Yamaha::GoDevice(d, configRom);
179 default: // return a plain BeBoB device
180 return new Device(d, configRom);
182 case FW_VENDORID_MAUDIO:
183 switch (modelId) {
184 case 0x0000000a: // Ozonic
185 case 0x00010046: // fw410
186 case 0x00010060: // Audiophile
187 case 0x00010062: // Solo
188 return new MAudio::Normal::Device(d, configRom, modelId);
189 case 0x00010071: // Firewire 1814
190 case 0x00010091: // ProjectMix I/O
191 return new MAudio::Special::Device(d, configRom);
192 default:
193 return new Device(d, configRom);
195 case FW_VENDORID_PRESONUS:
196 switch (modelId) {
197 case 0x00010000:
198 return new Presonus::Firebox::Device(d, configRom);
199 case 0x00010001:
200 return new Presonus::Inspire1394::Device(d, configRom);
201 default:
202 return new Device(d, configRom);
204 default:
205 return new Device(d, configRom);
207 return NULL;
210 #define BEBOB_CHECK_AND_ADD_SR(v, x) \
211 { if(supportsSamplingFrequency(x)) \
212 v.push_back(x); }
213 bool
214 Device::discover()
216 unsigned int vendorId = getConfigRom().getNodeVendorId();
217 unsigned int modelId = getConfigRom().getModelId();
219 Util::Configuration &c = getDeviceManager().getConfiguration();
220 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
222 if (c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB) {
223 debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
224 vme.vendor_name.c_str(),
225 vme.model_name.c_str());
226 } else {
227 debugWarning("Using generic BeBoB support for unsupported device '%s %s'\n",
228 getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
231 if ( !Unit::discover() ) {
232 debugError( "Could not discover unit\n" );
233 return false;
236 if((getAudioSubunit( 0 ) == NULL)) {
237 debugError( "Unit doesn't have an Audio subunit.\n");
238 return false;
240 if((getMusicSubunit( 0 ) == NULL)) {
241 debugError( "Unit doesn't have a Music subunit.\n");
242 return false;
245 if(!buildMixer()) {
246 debugWarning("Could not build mixer\n");
249 // keep track of the config id of this discovery
250 m_last_discovery_config_id = getConfigurationId();
252 return true;
255 bool
256 Device::buildMixer()
258 debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
259 // create a Mixer
260 // this removes the mixer if it already exists
261 // note: a mixer self-registers to it's parent
262 delete m_Mixer;
264 // create the mixer & register it
265 if(getAudioSubunit(0) == NULL) {
266 debugWarning("Could not find audio subunit, mixer not available.\n");
267 m_Mixer = NULL;
268 } else {
269 m_Mixer = new Mixer(*this);
271 if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
272 return m_Mixer != NULL;
275 bool
276 Device::destroyMixer()
278 delete m_Mixer;
279 return true;
282 bool
283 Device::setSelectorFBValue(int id, int value) {
284 FunctionBlockCmd fbCmd( get1394Service(),
285 FunctionBlockCmd::eFBT_Selector,
287 FunctionBlockCmd::eCA_Current );
288 fbCmd.setNodeId( getNodeId() );
289 fbCmd.setSubunitId( 0x00 );
290 fbCmd.setCommandType( AVCCommand::eCT_Control );
291 fbCmd.m_pFBSelector->m_inputFbPlugNumber = (value & 0xFF);
292 fbCmd.setVerboseLevel( getDebugLevel() );
294 if ( !fbCmd.fire() ) {
295 debugError( "cmd failed\n" );
296 return false;
299 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
300 // Util::Cmd::CoutSerializer se;
301 // fbCmd.serialize( se );
302 // }
304 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
305 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
308 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
312 Device::getSelectorFBValue(int id) {
314 FunctionBlockCmd fbCmd( get1394Service(),
315 FunctionBlockCmd::eFBT_Selector,
317 FunctionBlockCmd::eCA_Current );
318 fbCmd.setNodeId( getNodeId() );
319 fbCmd.setSubunitId( 0x00 );
320 fbCmd.setCommandType( AVCCommand::eCT_Status );
321 fbCmd.m_pFBSelector->m_inputFbPlugNumber = 0xFF;
322 fbCmd.setVerboseLevel( getDebugLevel() );
324 if ( !fbCmd.fire() ) {
325 debugError( "cmd failed\n" );
326 return -1;
329 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
330 // Util::Cmd::CoutSerializer se;
331 // fbCmd.serialize( se );
332 // }
334 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
335 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
338 return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
341 bool
342 Device::setFeatureFBVolumeCurrent(int id, int channel, int v) {
344 FunctionBlockCmd fbCmd( get1394Service(),
345 FunctionBlockCmd::eFBT_Feature,
347 FunctionBlockCmd::eCA_Current );
348 fbCmd.setNodeId( getNodeId() );
349 fbCmd.setSubunitId( 0x00 );
350 fbCmd.setCommandType( AVCCommand::eCT_Control );
351 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
352 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
353 AVC::FunctionBlockFeatureVolume vl;
354 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
355 fbCmd.m_pFBFeature->m_pVolume->m_volume = v;
356 fbCmd.setVerboseLevel( getDebugLevel() );
358 if ( !fbCmd.fire() ) {
359 debugError( "cmd failed\n" );
360 return false;
363 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
364 // Util::Cmd::CoutSerializer se;
365 // fbCmd.serialize( se );
366 // }
368 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
369 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
372 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
376 Device::getFeatureFBVolumeValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
378 FunctionBlockCmd fbCmd( get1394Service(),
379 FunctionBlockCmd::eFBT_Feature,
381 controlAttribute);
382 fbCmd.setNodeId( getNodeId() );
383 fbCmd.setSubunitId( 0x00 );
384 fbCmd.setCommandType( AVCCommand::eCT_Status );
385 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
386 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
387 AVC::FunctionBlockFeatureVolume vl;
388 fbCmd.m_pFBFeature->m_pVolume = vl.clone();
389 fbCmd.m_pFBFeature->m_pVolume->m_volume = 0;
390 fbCmd.setVerboseLevel( getDebugLevel() );
392 if ( !fbCmd.fire() ) {
393 debugError( "cmd failed\n" );
394 return 0;
397 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
398 // Util::Cmd::CoutSerializer se;
399 // fbCmd.serialize( se );
400 // }
402 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
403 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
406 int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
408 return volume;
411 int
412 Device::getFeatureFBVolumeMinimum(int id, int channel)
414 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
417 int
418 Device::getFeatureFBVolumeMaximum(int id, int channel)
420 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
423 int
424 Device::getFeatureFBVolumeCurrent(int id, int channel)
426 return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
429 bool
430 Device::setFeatureFBLRBalanceCurrent(int id, int channel, int v) {
432 FunctionBlockCmd fbCmd( get1394Service(),
433 FunctionBlockCmd::eFBT_Feature,
435 FunctionBlockCmd::eCA_Current );
436 fbCmd.setNodeId( getNodeId() );
437 fbCmd.setSubunitId( 0x00 );
438 fbCmd.setCommandType( AVCCommand::eCT_Control );
439 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
440 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
441 AVC::FunctionBlockFeatureLRBalance bl;
442 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
443 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = v;
444 fbCmd.setVerboseLevel( getDebugLevel() );
446 if ( !fbCmd.fire() ) {
447 debugError( "cmd failed\n" );
448 return false;
451 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
452 // Util::Cmd::CoutSerializer se;
453 // fbCmd.serialize( se );
454 // }
456 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
457 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
460 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
464 Device::getFeatureFBLRBalanceValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
466 FunctionBlockCmd fbCmd( get1394Service(),
467 FunctionBlockCmd::eFBT_Feature,
469 controlAttribute);
470 fbCmd.setNodeId( getNodeId() );
471 fbCmd.setSubunitId( 0x00 );
472 fbCmd.setCommandType( AVCCommand::eCT_Status );
473 fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
474 fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
475 AVC::FunctionBlockFeatureLRBalance bl;
476 fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
477 fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = 0;
478 fbCmd.setVerboseLevel( getDebugLevel() );
480 if ( !fbCmd.fire() ) {
481 debugError( "cmd failed\n" );
482 return 0;
485 // if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
486 // Util::Cmd::CoutSerializer se;
487 // fbCmd.serialize( se );
488 // }
490 if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
491 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
494 int16_t balance=(int16_t)(fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance);
496 return balance;
499 int
500 Device::getFeatureFBLRBalanceMinimum(int id, int channel)
502 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
505 int
506 Device::getFeatureFBLRBalanceMaximum(int id, int channel)
508 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
511 int
512 Device::getFeatureFBLRBalanceCurrent(int id, int channel)
514 return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
517 bool
518 Device::setProcessingFBMixerSingleCurrent(int id, int iPlugNum,
519 int iAChNum, int oAChNum,
520 int setting)
522 AVC::FunctionBlockCmd fbCmd(get1394Service(),
523 AVC::FunctionBlockCmd::eFBT_Processing,
525 AVC::FunctionBlockCmd::eCA_Current);
526 fbCmd.setNodeId(getNodeId());
527 fbCmd.setSubunitId(0x00);
528 fbCmd.setCommandType(AVCCommand::eCT_Control);
529 fbCmd.setVerboseLevel( getDebugLevel() );
531 AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
532 fbp->m_selectorLength = 0x04;
533 fbp->m_fbInputPlugNumber = iPlugNum;
534 fbp->m_inputAudioChannelNumber = iAChNum;
535 fbp->m_outputAudioChannelNumber = oAChNum;
537 // mixer object is not generated automatically
538 fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
539 fbp->m_pMixer->m_mixerSetting = setting;
541 if ( !fbCmd.fire() ) {
542 debugError( "cmd failed\n" );
543 return false;
546 if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
547 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
550 return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
554 Device::getProcessingFBMixerSingleCurrent(int id, int iPlugNum,
555 int iAChNum, int oAChNum)
557 AVC::FunctionBlockCmd fbCmd(get1394Service(),
558 AVC::FunctionBlockCmd::eFBT_Processing,
560 AVC::FunctionBlockCmd::eCA_Current);
561 fbCmd.setNodeId(getNodeId());
562 fbCmd.setSubunitId(0x00);
563 fbCmd.setCommandType(AVCCommand::eCT_Status);
564 fbCmd.setVerboseLevel( getDebugLevel() );
566 AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
567 fbp->m_selectorLength = 0x04;
568 fbp->m_fbInputPlugNumber = iPlugNum;
569 fbp->m_inputAudioChannelNumber = iAChNum;
570 fbp->m_outputAudioChannelNumber = oAChNum;
572 // mixer object is not generated automatically
573 fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
575 if ( !fbCmd.fire() ) {
576 debugError( "cmd failed\n" );
577 return 0;
580 if( (fbCmd.getResponse() != AVCCommand::eR_Implemented) ) {
581 debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
584 int16_t setting = (int16_t)(fbp->m_pMixer->m_mixerSetting);
586 return setting;
589 void
590 Device::showDevice()
592 debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
593 GenericAVC::Device::showDevice();
594 flushDebugOutput();
597 void
598 Device::setVerboseLevel(int l)
600 if (m_Mixer) m_Mixer->setVerboseLevel( l );
601 GenericAVC::Device::setVerboseLevel( l );
602 debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
605 AVC::Subunit*
606 Device::createSubunit(AVC::Unit& unit,
607 AVC::ESubunitType type,
608 AVC::subunit_t id )
610 AVC::Subunit* s=NULL;
611 switch (type) {
612 case eST_Audio:
613 s=new BeBoB::SubunitAudio(unit, id );
614 break;
615 case eST_Music:
616 s=new BeBoB::SubunitMusic(unit, id );
617 break;
618 default:
619 s=NULL;
620 break;
622 if(s) s->setVerboseLevel(getDebugLevel());
623 return s;
627 AVC::Plug *
628 Device::createPlug( AVC::Unit* unit,
629 AVC::Subunit* subunit,
630 AVC::function_block_type_t functionBlockType,
631 AVC::function_block_type_t functionBlockId,
632 AVC::Plug::EPlugAddressType plugAddressType,
633 AVC::Plug::EPlugDirection plugDirection,
634 AVC::plug_id_t plugId,
635 int globalId )
638 Plug *p= new BeBoB::Plug( unit,
639 subunit,
640 functionBlockType,
641 functionBlockId,
642 plugAddressType,
643 plugDirection,
644 plugId,
645 globalId );
646 if (p) p->setVerboseLevel(getDebugLevel());
647 return p;
650 bool
651 Device::propagatePlugInfo() {
652 // we don't have to propagate since we discover things
653 // another way
654 debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
655 return true;
658 uint8_t
659 Device::getConfigurationIdSampleRate()
661 ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
662 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
663 extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
664 PlugAddress::ePAM_Unit,
665 unitPlugAddress ) );
667 extStreamFormatCmd.setNodeId( getNodeId() );
668 extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
669 extStreamFormatCmd.setVerbose( getDebugLevel() );
671 if ( !extStreamFormatCmd.fire() ) {
672 debugError( "Stream format command failed\n" );
673 return 0;
676 FormatInformation* formatInfo =
677 extStreamFormatCmd.getFormatInformation();
678 FormatInformationStreamsCompound* compoundStream
679 = dynamic_cast< FormatInformationStreamsCompound* > (
680 formatInfo->m_streams );
681 if ( compoundStream ) {
682 debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
683 compoundStream->m_samplingFrequency );
684 return compoundStream->m_samplingFrequency;
687 debugError( "Could not retrieve sample rate\n" );
688 return 0;
691 uint8_t
692 Device::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
694 ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
695 UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
696 0 );
697 extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
698 PlugAddress::ePAM_Unit,
699 unitPlugAddress ) );
700 extPlugInfoCmd.setNodeId( getNodeId() );
701 extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
702 extPlugInfoCmd.setVerbose( getDebugLevel() );
703 ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
704 ExtendedPlugInfoInfoType::eIT_NoOfChannels );
705 extendedPlugInfoInfoType.initialize();
706 extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
708 if ( !extPlugInfoCmd.fire() ) {
709 debugError( "Number of channels command failed\n" );
710 return 0;
713 ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
714 if ( infoType
715 && infoType->m_plugNrOfChns )
717 debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
718 infoType->m_plugNrOfChns->m_nrOfChannels );
719 return infoType->m_plugNrOfChns->m_nrOfChannels;
722 debugError( "Could not retrieve number of channels\n" );
723 return 0;
726 uint16_t
727 Device::getConfigurationIdSyncMode()
729 SignalSourceCmd signalSourceCmd( get1394Service() );
730 SignalUnitAddress signalUnitAddr;
731 signalUnitAddr.m_plugId = 0x01;
732 signalSourceCmd.setSignalDestination( signalUnitAddr );
733 signalSourceCmd.setNodeId( getNodeId() );
734 signalSourceCmd.setSubunitType( eST_Unit );
735 signalSourceCmd.setSubunitId( 0xff );
736 signalSourceCmd.setVerbose( getDebugLevel() );
738 signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
740 if ( !signalSourceCmd.fire() ) {
741 debugError( "Signal source command failed\n" );
742 return 0;
745 SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
746 SignalSubunitAddress* pSyncPlugSubunitAddress
747 = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
748 if ( pSyncPlugSubunitAddress ) {
749 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
750 ( pSyncPlugSubunitAddress->m_subunitType << 3
751 | pSyncPlugSubunitAddress->m_subunitId ) << 8
752 | pSyncPlugSubunitAddress->m_plugId );
754 return ( pSyncPlugSubunitAddress->m_subunitType << 3
755 | pSyncPlugSubunitAddress->m_subunitId ) << 8
756 | pSyncPlugSubunitAddress->m_plugId;
759 SignalUnitAddress* pSyncPlugUnitAddress
760 = dynamic_cast<SignalUnitAddress*>( pSyncPlugSignalAddress );
761 if ( pSyncPlugUnitAddress ) {
762 debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
763 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
765 return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
768 debugError( "Could not retrieve sync mode\n" );
769 return 0;
772 bool
773 Device::needsRediscovery()
775 // require rediscovery if the config id differs from the one saved
776 // in the previous discovery
777 return getConfigurationId() != m_last_discovery_config_id;
780 uint64_t
781 Device::getConfigurationId()
783 // create a unique configuration id.
784 uint64_t id = 0;
785 id = getConfigurationIdSampleRate();
786 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input ) << 8;
787 id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) << 16;
788 id |= ((uint64_t)getConfigurationIdSyncMode()) << 24;
789 return id;
792 bool
793 Device::serialize( std::string basePath,
794 Util::IOSerialize& ser ) const
796 bool result;
797 result = GenericAVC::Device::serialize( basePath, ser );
798 return result;
801 bool
802 Device::deserialize( std::string basePath,
803 Util::IODeserialize& deser )
805 bool result;
806 result = GenericAVC::Device::deserialize( basePath, deser );
807 return result;
810 std::string
811 Device::getCachePath()
813 std::string cachePath;
814 char* pCachePath;
816 string path = CACHEDIR;
817 if ( path.size() && path[0] == '~' ) {
818 path.erase( 0, 1 ); // remove ~
819 path.insert( 0, getenv( "HOME" ) ); // prepend the home path
822 if ( asprintf( &pCachePath, "%s/cache/", path.c_str() ) < 0 ) {
823 debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
824 cachePath = "/var/cache/libffado/";
825 } else {
826 cachePath = pCachePath;
827 free( pCachePath );
829 return cachePath;
832 bool
833 Device::loadFromCache()
835 std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
837 char* configId;
838 asprintf(&configId, "%016"PRIx64"", getConfigurationId() );
839 if ( !configId ) {
840 debugError( "could not create id string\n" );
841 return false;
844 std::string sFileName = sDevicePath + "/" + configId + ".xml";
845 free( configId );
846 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
848 struct stat buf;
849 if ( stat( sFileName.c_str(), &buf ) != 0 ) {
850 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" does not exist\n", sFileName.c_str() );
851 return false;
852 } else {
853 if ( !S_ISREG( buf.st_mode ) ) {
854 debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" is not a regular file\n", sFileName.c_str() );
855 return false;
859 Util::XMLDeserialize deser( sFileName, getDebugLevel() );
861 if (!deser.isValid()) {
862 debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
863 sFileName.c_str() );
864 return false;
867 bool result = deserialize( "", deser );
868 if ( result ) {
869 debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
870 sFileName.c_str() );
873 if(result) {
874 buildMixer();
877 return result;
880 bool
881 Device::saveCache()
883 // the path looks like this:
884 // PATH_TO_CACHE + GUID + CONFIGURATION_ID
885 string tmp_path = getCachePath() + getConfigRom().getGuidString();
887 // the following piece should do something like
888 // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
889 vector<string> tokens;
890 tokenize( tmp_path, tokens, "/" );
891 string path;
892 for ( vector<string>::const_iterator it = tokens.begin();
893 it != tokens.end();
894 ++it )
896 path += "/" + *it;
898 struct stat buf;
899 if ( stat( path.c_str(), &buf ) == 0 ) {
900 if ( !S_ISDIR( buf.st_mode ) ) {
901 debugError( "\"%s\" is not a directory\n", path.c_str() );
902 return false;
904 } else {
905 if ( mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
906 debugError( "Could not create \"%s\" directory\n", path.c_str() );
907 return false;
912 // come up with an unique file name for the current settings
913 char* configId;
914 asprintf(&configId, "%016"PRIx64"", BeBoB::Device::getConfigurationId() );
915 if ( !configId ) {
916 debugError( "Could not create id string\n" );
917 return false;
919 string filename = path + "/" + configId + ".xml";
920 free( configId );
921 debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
923 Util::XMLSerialize ser( filename );
924 return serialize( "", ser );
927 } // end of namespace