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

Revision 1154, 15.3 kB (checked in by ppalmers, 14 years ago)

add expat based parsing of the device cache. add compile-time selection between libxml++ and expat. will allow to get rid of the libxml++ dependency on the long run. scons SERIALIZE_USE_EXPAT=0Only compile testedscons SERIALIZE_USE_EXPAT=0

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 "bebob/bebob_avdevice.h"
27 #include "bebob/bebob_avdevice_subunit.h"
28 #include "bebob/bebob_mixer.h"
29
30 #include "bebob/focusrite/focusrite_saffire.h"
31 #include "bebob/focusrite/focusrite_saffirepro.h"
32 #include "bebob/terratec/terratec_device.h"
33 #include "bebob/esi/quatafire610.h"
34
35 #include "libieee1394/configrom.h"
36 #include "libieee1394/ieee1394service.h"
37
38 #include "genericavc/avc_vendormodel.h"
39
40 #include "libavc/general/avc_plug_info.h"
41 #include "libavc/general/avc_extended_plug_info.h"
42 #include "libavc/general/avc_subunit_info.h"
43 #include "libavc/streamformat/avc_extended_stream_format.h"
44 #include "libutil/cmd_serialize.h"
45 #include "libavc/avc_definitions.h"
46
47 #include "debugmodule/debugmodule.h"
48
49 #include <iostream>
50 #include <sstream>
51 #include <unistd.h>
52 #include <sys/stat.h>
53
54 using namespace AVC;
55
56 namespace BeBoB {
57
58 AvDevice::AvDevice( DeviceManager& d, std::auto_ptr< ConfigRom >( configRom ) )
59     : GenericAVC::AvDevice( d, configRom )
60     , m_Mixer ( 0 )
61 {
62     debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::AvDevice (NodeID %d)\n",
63                  getConfigRom().getNodeId() );
64
65     // DM1500 based devices seem to upset the linux1394 stack when commands are
66     // sent too fast.
67     if (AVC::AVCCommand::getSleepAfterAVCCommand() < 200) {
68         AVC::AVCCommand::setSleepAfterAVCCommand( 200 );
69     }
70
71 }
72
73 AvDevice::~AvDevice()
74 {
75     destroyMixer();
76 }
77
78 bool
79 AvDevice::probe( ConfigRom& configRom )
80 {
81     unsigned int vendorId = configRom.getNodeVendorId();
82     unsigned int modelId = configRom.getModelId();
83
84     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_bebob.txt" );
85     if ( vendorModel.parse() ) {
86         return vendorModel.isPresent( vendorId, modelId );
87     }
88
89     return false;
90 }
91
92 FFADODevice *
93 AvDevice::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
94 {
95     unsigned int vendorId = configRom->getNodeVendorId();
96     unsigned int modelId = configRom->getModelId();
97
98     switch (vendorId) {
99         case FW_VENDORID_ESI:
100             if (modelId == 0x00010064) {
101                 return new ESI::QuataFireDevice(d, configRom);
102             }
103             break;
104         case FW_VENDORID_TERRATEC:
105             return new Terratec::PhaseSeriesDevice(d, configRom);
106         case FW_VENDORID_FOCUSRITE:
107             switch(modelId) {
108                 case 0x00000003:
109                 case 0x00000006:
110                     return new Focusrite::SaffireProDevice(d, configRom);
111                 case 0x00000000:
112                     return new Focusrite::SaffireDevice(d, configRom);
113                 default: // return a plain BeBoB device
114                     return new AvDevice(d, configRom);
115            }
116         default:
117             return new AvDevice(d, configRom);
118     }
119     return NULL;
120 }
121
122 bool
123 AvDevice::discover()
124 {
125     unsigned int vendorId = getConfigRom().getNodeVendorId();
126     unsigned int modelId = getConfigRom().getModelId();
127
128     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_bebob.txt" );
129     if ( vendorModel.parse() ) {
130         m_model = vendorModel.find( vendorId, modelId );
131     }
132
133     if (GenericAVC::VendorModel::isValid(m_model)) {
134         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
135                      m_model.vendor_name.c_str(),
136                      m_model.model_name.c_str());
137     } else return false;
138
139     if ( !Unit::discover() ) {
140         debugError( "Could not discover unit\n" );
141         return false;
142     }
143
144     if((getAudioSubunit( 0 ) == NULL)) {
145         debugError( "Unit doesn't have an Audio subunit.\n");
146         return false;
147     }
148     if((getMusicSubunit( 0 ) == NULL)) {
149         debugError( "Unit doesn't have a Music subunit.\n");
150         return false;
151     }
152
153     if(!buildMixer()) {
154         debugWarning("Could not build mixer\n");
155     }
156     return true;
157 }
158
159 bool
160 AvDevice::buildMixer()
161 {
162     debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
163     // create a Mixer
164     // this removes the mixer if it already exists
165     // note: a mixer self-registers to it's parent
166     delete m_Mixer;
167
168     // create the mixer & register it
169     if(getAudioSubunit(0) == NULL) {
170         debugWarning("Could not find audio subunit, mixer not available.\n");
171         m_Mixer = NULL;
172     } else {
173         m_Mixer = new Mixer(*this);
174     }
175     if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
176     return m_Mixer != NULL;
177 }
178
179 bool
180 AvDevice::destroyMixer()
181 {
182     delete m_Mixer;
183     return true;
184 }
185
186 void
187 AvDevice::showDevice()
188 {
189     debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
190     GenericAVC::AvDevice::showDevice();
191     flushDebugOutput();
192 }
193
194 void
195 AvDevice::setVerboseLevel(int l)
196 {
197     if (m_Mixer) m_Mixer->setVerboseLevel( l );
198     GenericAVC::AvDevice::setVerboseLevel( l );
199     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
200 }
201
202 AVC::Subunit*
203 AvDevice::createSubunit(AVC::Unit& unit,
204                         AVC::ESubunitType type,
205                         AVC::subunit_t id )
206 {
207     AVC::Subunit* s=NULL;
208     switch (type) {
209         case eST_Audio:
210             s=new BeBoB::SubunitAudio(unit, id );
211             break;
212         case eST_Music:
213             s=new BeBoB::SubunitMusic(unit, id );
214             break;
215         default:
216             s=NULL;
217             break;
218     }
219     if(s) s->setVerboseLevel(getDebugLevel());
220     return s;
221 }
222
223
224 AVC::Plug *
225 AvDevice::createPlug( AVC::Unit* unit,
226                       AVC::Subunit* subunit,
227                       AVC::function_block_type_t functionBlockType,
228                       AVC::function_block_type_t functionBlockId,
229                       AVC::Plug::EPlugAddressType plugAddressType,
230                       AVC::Plug::EPlugDirection plugDirection,
231                       AVC::plug_id_t plugId )
232 {
233
234     Plug *p= new BeBoB::Plug( unit,
235                               subunit,
236                               functionBlockType,
237                               functionBlockId,
238                               plugAddressType,
239                               plugDirection,
240                               plugId );
241     if (p) p->setVerboseLevel(getDebugLevel());
242     return p;
243 }
244
245 bool
246 AvDevice::propagatePlugInfo() {
247     // we don't have to propagate since we discover things
248     // another way
249     debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
250     return true;
251 }
252
253
254 int
255 AvDevice::getConfigurationIdSampleRate()
256 {
257     ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
258     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
259     extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
260                                                     PlugAddress::ePAM_Unit,
261                                                     unitPlugAddress ) );
262
263     extStreamFormatCmd.setNodeId( getNodeId() );
264     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
265     extStreamFormatCmd.setVerbose( getDebugLevel() );
266
267     if ( !extStreamFormatCmd.fire() ) {
268         debugError( "Stream format command failed\n" );
269         return false;
270     }
271
272     FormatInformation* formatInfo =
273         extStreamFormatCmd.getFormatInformation();
274     FormatInformationStreamsCompound* compoundStream
275         = dynamic_cast< FormatInformationStreamsCompound* > (
276             formatInfo->m_streams );
277     if ( compoundStream ) {
278         debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
279                     compoundStream->m_samplingFrequency );
280         return compoundStream->m_samplingFrequency;
281     }
282
283     debugError( "Could not retrieve sample rate\n" );
284     return 0;
285 }
286
287 int
288 AvDevice::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
289 {
290     ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
291     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
292                                      getNodeId() );
293     extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
294                                                 PlugAddress::ePAM_Unit,
295                                                 unitPlugAddress ) );
296     extPlugInfoCmd.setNodeId( getNodeId() );
297     extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
298     extPlugInfoCmd.setVerbose( getDebugLevel() );
299     ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
300         ExtendedPlugInfoInfoType::eIT_NoOfChannels );
301     extendedPlugInfoInfoType.initialize();
302     extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
303
304     if ( !extPlugInfoCmd.fire() ) {
305         debugError( "Number of channels command failed\n" );
306         return false;
307     }
308
309     ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
310     if ( infoType
311          && infoType->m_plugNrOfChns )
312     {
313         debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
314                     infoType->m_plugNrOfChns->m_nrOfChannels );
315         return infoType->m_plugNrOfChns->m_nrOfChannels;
316     }
317
318     debugError( "Could not retrieve number of channels\n" );
319     return 0;
320 }
321
322 int
323 AvDevice::getConfigurationIdSyncMode()
324 {
325     SignalSourceCmd signalSourceCmd( get1394Service() );
326     SignalUnitAddress signalUnitAddr;
327     signalUnitAddr.m_plugId = 0x01;
328     signalSourceCmd.setSignalDestination( signalUnitAddr );
329     signalSourceCmd.setNodeId( getNodeId() );
330     signalSourceCmd.setSubunitType( eST_Unit  );
331     signalSourceCmd.setSubunitId( 0xff );
332     signalSourceCmd.setVerbose( getDebugLevel() );
333
334     signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
335
336     if ( !signalSourceCmd.fire() ) {
337         debugError( "Signal source command failed\n" );
338         return false;
339     }
340
341     SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
342     SignalSubunitAddress* pSyncPlugSubunitAddress
343         = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
344     if ( pSyncPlugSubunitAddress ) {
345         debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
346                     ( pSyncPlugSubunitAddress->m_subunitType << 3
347                       | pSyncPlugSubunitAddress->m_subunitId ) << 8
348                     | pSyncPlugSubunitAddress->m_plugId );
349
350         return ( pSyncPlugSubunitAddress->m_subunitType << 3
351                  | pSyncPlugSubunitAddress->m_subunitId ) << 8
352             | pSyncPlugSubunitAddress->m_plugId;
353     }
354
355     SignalUnitAddress* pSyncPlugUnitAddress
356       = dynamic_cast<SignalUnitAddress*>( pSyncPlugSignalAddress );
357     if ( pSyncPlugUnitAddress ) {
358         debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
359                       0xff << 8 | pSyncPlugUnitAddress->m_plugId );
360
361         return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
362     }
363
364     debugError( "Could not retrieve sync mode\n" );
365     return 0;
366 }
367
368 int
369 AvDevice::getConfigurationId()
370 {
371     // create a unique configuration id.
372     int id = 0;
373     id = getConfigurationIdSampleRate();
374     id |= ( getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input )
375             + getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) ) << 8;
376     id |= getConfigurationIdSyncMode() << 16;
377
378     return id;
379 }
380
381 bool
382 AvDevice::serialize( std::string basePath,
383                      Util::IOSerialize& ser ) const
384 {
385     bool result;
386     result  = GenericAVC::AvDevice::serialize( basePath, ser );
387     return result;
388 }
389
390 bool
391 AvDevice::deserialize( std::string basePath,
392                        Util::IODeserialize& deser )
393 {
394     bool result;
395     result  = GenericAVC::AvDevice::deserialize( basePath, deser );
396     return result;
397 }
398
399 std::string
400 AvDevice::getCachePath()
401 {
402     std::string cachePath;
403     char* pCachePath;
404
405     string path = CACHEDIR;
406     if ( path.size() && path[0] == '~' ) {
407         path.erase( 0, 1 ); // remove ~
408         path.insert( 0, getenv( "HOME" ) ); // prepend the home path
409     }
410
411     if ( asprintf( &pCachePath, "%s/cache/",  path.c_str() ) < 0 ) {
412         debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
413         cachePath == "/var/cache/libffado/";
414     } else {
415         cachePath = pCachePath;
416         free( pCachePath );
417     }
418     return cachePath;
419 }
420
421 bool
422 AvDevice::loadFromCache()
423 {
424     std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
425
426     char* configId;
427     asprintf(&configId, "%08x", getConfigurationId() );
428     if ( !configId ) {
429         debugError( "could not create id string\n" );
430         return false;
431     }
432
433     std::string sFileName = sDevicePath + "/" + configId + ".xml";
434     free( configId );
435     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
436
437     struct stat buf;
438     if ( stat( sFileName.c_str(), &buf ) != 0 ) {
439         debugOutput( DEBUG_LEVEL_NORMAL,  "\"%s\" does not exist\n",  sFileName.c_str() );
440         return false;
441     } else {
442         if ( !S_ISREG( buf.st_mode ) ) {
443             debugOutput( DEBUG_LEVEL_NORMAL,  "\"%s\" is not a regular file\n",  sFileName.c_str() );
444             return false;
445         }
446     }
447
448     Util::XMLDeserialize deser( sFileName, getDebugLevel() );
449
450     if (!deser.isValid()) {
451         debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
452                      sFileName.c_str() );
453         return false;
454     }
455
456     bool result = deserialize( "", deser );
457     if ( result ) {
458         debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
459                      sFileName.c_str() );
460     }
461
462     if(result) {
463         buildMixer();
464     }
465
466     return result;
467 }
468
469 bool
470 AvDevice::saveCache()
471 {
472     // the path looks like this:
473     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
474     string tmp_path = getCachePath() + getConfigRom().getGuidString();
475
476     // the following piece should do something like
477     // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
478     vector<string> tokens;
479     tokenize( tmp_path, tokens, "/" );
480     string path;
481     for ( vector<string>::const_iterator it = tokens.begin();
482           it != tokens.end();
483           ++it )
484     {
485         path +=  "/" + *it;
486
487         struct stat buf;
488         if ( stat( path.c_str(), &buf ) == 0 ) {
489             if ( !S_ISDIR( buf.st_mode ) ) {
490                 debugError( "\"%s\" is not a directory\n",  path.c_str() );
491                 return false;
492             }
493         } else {
494             if (  mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
495                 debugError( "Could not create \"%s\" directory\n", path.c_str() );
496                 return false;
497             }
498         }
499     }
500
501     // come up with an unique file name for the current settings
502     char* configId;
503     asprintf(&configId, "%08x", BeBoB::AvDevice::getConfigurationId() );
504     if ( !configId ) {
505         debugError( "Could not create id string\n" );
506         return false;
507     }
508     string filename = path + "/" + configId + ".xml";
509     free( configId );
510     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
511
512     Util::XMLSerialize ser( filename );
513     return serialize( "", ser );
514 }
515
516 } // end of namespace
Note: See TracBrowser for help on using the browser.