root/trunk/libffado/src/bebob/bebob_avdevice.cpp

Revision 2413, 25.5 kB (checked in by jwoithe, 6 years ago)

A series of fixes provided by Andreas Hehn. These were mostly discovered when attempting to compile FFADO with clang:
* libavc: implement a better way to quieten an "unused parameter" warning
* bebob: fix a typo when assigning to cachePath
* dice: correctly create routes for the ARM audio ports
* fireworks-downloader: really zero the "args" variable
* saffire-pro: fix a typo when applying sync lock mask

I'm not sure what the correct approach should be for the DICE fix. Andreas's patch originally commented this out. The DICE chip does provide 8 ARM audio ports on the router's input and output sides though, so perhaps they ought to be included (although the present entries only seem to cover the router outputs to the ARM, not the returns from it). Those with DICE-based interfaces are encouraged to test this patch to verify there are no regressions caused by this change.

Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
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.
13  *
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.
18  *
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/>.
21  *
22  */
23
24 #include "config.h"
25
26 #include "devicemanager.h"
27 #include "bebob/bebob_avdevice.h"
28 #include "bebob/bebob_avdevice_subunit.h"
29 #include "bebob/bebob_mixer.h"
30
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
39 #include "libieee1394/configrom.h"
40 #include "libieee1394/ieee1394service.h"
41
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"
48
49 #include "debugmodule/debugmodule.h"
50
51 #include <iostream>
52 #include <sstream>
53 #include <unistd.h>
54 #include <cstdlib>
55 #include <cstring>
56 #include <sys/stat.h>
57
58 using namespace AVC;
59
60 namespace BeBoB {
61
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 )
66 {
67     debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Device (NodeID %d)\n",
68                  getConfigRom().getNodeId() );
69 }
70
71 Device::~Device()
72 {
73     destroyMixer();
74 }
75
76 bool
77 Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
78 {
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 );
94
95         if ( !extPlugInfoCmd.fire() ) {
96             debugError( "Number of channels command failed\n" );
97             return false;
98         }
99
100         if((extPlugInfoCmd.getResponse() != AVCCommand::eR_Implemented)) {
101             // command not supported
102             return false;
103         }
104
105         ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
106         if ( infoType
107             && infoType->m_plugNrOfChns )
108         {
109             return true;
110         }
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();
116
117         Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
118         return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
119     }
120 }
121
122 FFADODevice *
123 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
124 {
125     unsigned int vendorId = configRom->getNodeVendorId();
126     unsigned int modelId = configRom->getModelId();
127
128     switch (vendorId) {
129         case FW_VENDORID_MACKIE:
130             if (modelId == 0x00010065 ) {
131                 return new Mackie::OnyxMixerDevice(d, configRom);
132             }
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);
141             }
142         case FW_VENDORID_ESI:
143             if (modelId == 0x00010064) {
144                 return new ESI::QuataFireDevice(d, configRom);
145             }
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);
153             }
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);
163            }
164         default:
165             return new Device(d, configRom);
166     }
167     return NULL;
168 }
169
170 #define BEBOB_CHECK_AND_ADD_SR(v, x) \
171     { if(supportsSamplingFrequency(x)) \
172       v.push_back(x); }
173 bool
174 Device::discover()
175 {
176     unsigned int vendorId = getConfigRom().getNodeVendorId();
177     unsigned int modelId = getConfigRom().getModelId();
178
179     Util::Configuration &c = getDeviceManager().getConfiguration();
180     Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
181
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());
189     }
190
191     if ( !Unit::discover() ) {
192         debugError( "Could not discover unit\n" );
193         return false;
194     }
195
196     if((getAudioSubunit( 0 ) == NULL)) {
197         debugError( "Unit doesn't have an Audio subunit.\n");
198         return false;
199     }
200     if((getMusicSubunit( 0 ) == NULL)) {
201         debugError( "Unit doesn't have a Music subunit.\n");
202         return false;
203     }
204
205     if(!buildMixer()) {
206         debugWarning("Could not build mixer\n");
207     }
208
209     // keep track of the config id of this discovery
210     m_last_discovery_config_id = getConfigurationId();
211
212     return true;
213 }
214
215 bool
216 Device::buildMixer()
217 {
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;
223
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);
230     }
231     if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
232     return m_Mixer != NULL;
233 }
234
235 bool
236 Device::destroyMixer()
237 {
238     delete m_Mixer;
239     return true;
240 }
241
242 bool
243 Device::setSelectorFBValue(int id, int value) {
244     FunctionBlockCmd fbCmd( get1394Service(),
245                             FunctionBlockCmd::eFBT_Selector,
246                             id,
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() );
253
254     if ( !fbCmd.fire() ) {
255         debugError( "cmd failed\n" );
256         return false;
257     }
258
259 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
260 //         Util::Cmd::CoutSerializer se;
261 //         fbCmd.serialize( se );
262 //     }
263 //     
264     if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
265         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
266     }
267
268     return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
269 }
270
271 int
272 Device::getSelectorFBValue(int id) {
273
274     FunctionBlockCmd fbCmd( get1394Service(),
275                             FunctionBlockCmd::eFBT_Selector,
276                             id,
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() );
283
284     if ( !fbCmd.fire() ) {
285         debugError( "cmd failed\n" );
286         return -1;
287     }
288    
289 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
290 //         Util::Cmd::CoutSerializer se;
291 //         fbCmd.serialize( se );
292 //     }
293
294     if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
295         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
296     }
297    
298     return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
299 }
300
301 bool
302 Device::setFeatureFBVolumeCurrent(int id, int channel, int v) {
303
304     FunctionBlockCmd fbCmd( get1394Service(),
305                             FunctionBlockCmd::eFBT_Feature,
306                             id,
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() );
317
318     if ( !fbCmd.fire() ) {
319         debugError( "cmd failed\n" );
320         return false;
321     }
322
323 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
324 //         Util::Cmd::CoutSerializer se;
325 //         fbCmd.serialize( se );
326 //     }
327    
328     if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
329         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
330     }
331
332     return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
333 }
334
335 int
336 Device::getFeatureFBVolumeValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
337 {
338     FunctionBlockCmd fbCmd( get1394Service(),
339                             FunctionBlockCmd::eFBT_Feature,
340                             id,
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() );
351
352     if ( !fbCmd.fire() ) {
353         debugError( "cmd failed\n" );
354         return 0;
355     }
356    
357 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
358 //         Util::Cmd::CoutSerializer se;
359 //         fbCmd.serialize( se );
360 //     }
361
362     if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
363         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
364     }
365    
366     int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
367    
368     return volume;
369 }
370
371 int
372 Device::getFeatureFBVolumeMinimum(int id, int channel)
373 {
374     return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
375 }
376
377 int
378 Device::getFeatureFBVolumeMaximum(int id, int channel)
379 {
380     return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
381 }
382
383 int
384 Device::getFeatureFBVolumeCurrent(int id, int channel)
385 {
386     return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);   
387 }
388
389 bool
390 Device::setFeatureFBLRBalanceCurrent(int id, int channel, int v) {
391
392     FunctionBlockCmd fbCmd( get1394Service(),
393                             FunctionBlockCmd::eFBT_Feature,
394                             id,
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() );
405
406     if ( !fbCmd.fire() ) {
407         debugError( "cmd failed\n" );
408         return false;
409     }
410
411 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
412 //         Util::Cmd::CoutSerializer se;
413 //         fbCmd.serialize( se );
414 //     }
415    
416     if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
417         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
418     }
419
420     return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
421 }
422
423 int
424 Device::getFeatureFBLRBalanceValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
425 {
426     FunctionBlockCmd fbCmd( get1394Service(),
427                             FunctionBlockCmd::eFBT_Feature,
428                             id,
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() );
439
440     if ( !fbCmd.fire() ) {
441         debugError( "cmd failed\n" );
442         return 0;
443     }
444    
445 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
446 //         Util::Cmd::CoutSerializer se;
447 //         fbCmd.serialize( se );
448 //     }
449
450     if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
451         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
452     }
453    
454     int16_t balance=(int16_t)(fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance);
455
456     return balance;
457 }
458
459 int
460 Device::getFeatureFBLRBalanceMinimum(int id, int channel)
461 {
462     return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
463 }
464
465 int
466 Device::getFeatureFBLRBalanceMaximum(int id, int channel)
467 {
468     return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
469 }
470
471 int
472 Device::getFeatureFBLRBalanceCurrent(int id, int channel)
473 {
474     return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);   
475 }
476
477 void
478 Device::showDevice()
479 {
480     debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
481     GenericAVC::Device::showDevice();
482     flushDebugOutput();
483 }
484
485 void
486 Device::setVerboseLevel(int l)
487 {
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 );
491 }
492
493 AVC::Subunit*
494 Device::createSubunit(AVC::Unit& unit,
495                         AVC::ESubunitType type,
496                         AVC::subunit_t id )
497 {
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;
509     }
510     if(s) s->setVerboseLevel(getDebugLevel());
511     return s;
512 }
513
514
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 )
524 {
525
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;
536 }
537
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;
544 }
545
546 uint8_t
547 Device::getConfigurationIdSampleRate()
548 {
549     ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
550     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
551     extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
552                                                     PlugAddress::ePAM_Unit,
553                                                     unitPlugAddress ) );
554
555     extStreamFormatCmd.setNodeId( getNodeId() );
556     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
557     extStreamFormatCmd.setVerbose( getDebugLevel() );
558
559     if ( !extStreamFormatCmd.fire() ) {
560         debugError( "Stream format command failed\n" );
561         return 0;
562     }
563
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;
573     }
574
575     debugError( "Could not retrieve sample rate\n" );
576     return 0;
577 }
578
579 uint8_t
580 Device::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
581 {
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 );
595
596     if ( !extPlugInfoCmd.fire() ) {
597         debugError( "Number of channels command failed\n" );
598         return 0;
599     }
600
601     ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
602     if ( infoType
603          && infoType->m_plugNrOfChns )
604     {
605         debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
606                     infoType->m_plugNrOfChns->m_nrOfChannels );
607         return infoType->m_plugNrOfChns->m_nrOfChannels;
608     }
609
610     debugError( "Could not retrieve number of channels\n" );
611     return 0;
612 }
613
614 uint16_t
615 Device::getConfigurationIdSyncMode()
616 {
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() );
625
626     signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
627
628     if ( !signalSourceCmd.fire() ) {
629         debugError( "Signal source command failed\n" );
630         return 0;
631     }
632
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 );
641
642         return ( pSyncPlugSubunitAddress->m_subunitType << 3
643                  | pSyncPlugSubunitAddress->m_subunitId ) << 8
644             | pSyncPlugSubunitAddress->m_plugId;
645     }
646
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 );
652
653         return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
654     }
655
656     debugError( "Could not retrieve sync mode\n" );
657     return 0;
658 }
659
660 bool
661 Device::needsRediscovery()
662 {
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;
666 }
667
668 uint64_t
669 Device::getConfigurationId()
670 {
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;
678 }
679
680 bool
681 Device::serialize( std::string basePath,
682                      Util::IOSerialize& ser ) const
683 {
684     bool result;
685     result  = GenericAVC::Device::serialize( basePath, ser );
686     return result;
687 }
688
689 bool
690 Device::deserialize( std::string basePath,
691                        Util::IODeserialize& deser )
692 {
693     bool result;
694     result  = GenericAVC::Device::deserialize( basePath, deser );
695     return result;
696 }
697
698 std::string
699 Device::getCachePath()
700 {
701     std::string cachePath;
702     char* pCachePath;
703
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
708     }
709
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 );
716     }
717     return cachePath;
718 }
719
720 bool
721 Device::loadFromCache()
722 {
723     std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
724
725     char* configId;
726     asprintf(&configId, "%016"PRIx64"", getConfigurationId() );
727     if ( !configId ) {
728         debugError( "could not create id string\n" );
729         return false;
730     }
731
732     std::string sFileName = sDevicePath + "/" + configId + ".xml";
733     free( configId );
734     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
735
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;
744         }
745     }
746
747     Util::XMLDeserialize deser( sFileName, getDebugLevel() );
748
749     if (!deser.isValid()) {
750         debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
751                      sFileName.c_str() );
752         return false;
753     }
754
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() );
759     }
760
761     if(result) {
762         buildMixer();
763     }
764
765     return result;
766 }
767
768 bool
769 Device::saveCache()
770 {
771     // the path looks like this:
772     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
773     string tmp_path = getCachePath() + getConfigRom().getGuidString();
774
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 )
783     {
784         path +=  "/" + *it;
785
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;
791             }
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;
796             }
797         }
798     }
799
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;
806     }
807     string filename = path + "/" + configId + ".xml";
808     free( configId );
809     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
810
811     Util::XMLSerialize ser( filename );
812     return serialize( "", ser );
813 }
814
815 } // end of namespace
Note: See TracBrowser for help on using the browser.