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

Revision 726, 14.4 kB (checked in by wagi, 16 years ago)

getConfigurationIdSyncMode: debug message corrected

Line 
1 /*
2  * Copyright (C) 2005-2007 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 library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License version 2.1, as published by the Free Software Foundation;
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301 USA
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
34 #include "libieee1394/configrom.h"
35 #include "libieee1394/ieee1394service.h"
36
37 #include "genericavc/avc_vendormodel.h"
38
39 #include "libavc/general/avc_plug_info.h"
40 #include "libavc/general/avc_extended_plug_info.h"
41 #include "libavc/general/avc_subunit_info.h"
42 #include "libavc/streamformat/avc_extended_stream_format.h"
43 #include "libutil/cmd_serialize.h"
44 #include "libavc/avc_definitions.h"
45
46 #include "debugmodule/debugmodule.h"
47
48 #include <iostream>
49 #include <sstream>
50 #include <unistd.h>
51 #include <sys/stat.h>
52
53 using namespace AVC;
54
55 namespace BeBoB {
56
57 AvDevice::AvDevice( Ieee1394Service& ieee1394service,
58                     std::auto_ptr< ConfigRom >( configRom ) )
59     : GenericAVC::AvDevice( ieee1394service, 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( Ieee1394Service& ieee1394Service,
94                         std::auto_ptr<ConfigRom>( configRom ))
95 {
96     unsigned int vendorId = configRom->getNodeVendorId();
97     unsigned int modelId = configRom->getModelId();
98
99     switch (vendorId) {
100         case FW_VENDORID_TERRATEC:
101             return new Terratec::PhaseSeriesDevice(ieee1394Service, configRom);
102         case FW_VENDORID_FOCUSRITE:
103             switch(modelId) {
104                 case 0x00000003:
105                 case 0x00000006:
106                     return new Focusrite::SaffireProDevice(ieee1394Service, configRom);
107                 case 0x00000000:
108                     return new Focusrite::SaffireDevice(ieee1394Service, configRom);
109                 default: // return a plain BeBoB device
110                     return new AvDevice(ieee1394Service, configRom);
111            }
112         default:
113             return new AvDevice(ieee1394Service, configRom);
114     }
115     return NULL;
116 }
117
118 bool
119 AvDevice::discover()
120 {
121     unsigned int vendorId = m_pConfigRom->getNodeVendorId();
122     unsigned int modelId = m_pConfigRom->getModelId();
123
124     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_bebob.txt" );
125     if ( vendorModel.parse() ) {
126         m_model = vendorModel.find( vendorId, modelId );
127     }
128
129     if (GenericAVC::VendorModel::isValid(m_model)) {
130         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
131                      m_model.vendor_name.c_str(),
132                      m_model.model_name.c_str());
133     } else return false;
134
135     if ( !Unit::discover() ) {
136         debugError( "Could not discover unit\n" );
137         return false;
138     }
139
140     if((getAudioSubunit( 0 ) == NULL)) {
141         debugError( "Unit doesn't have an Audio subunit.\n");
142         return false;
143     }
144     if((getMusicSubunit( 0 ) == NULL)) {
145         debugError( "Unit doesn't have a Music subunit.\n");
146         return false;
147     }
148
149     if(!buildMixer()) {
150         debugWarning("Could not build mixer\n");
151     }
152     return true;
153 }
154
155 bool
156 AvDevice::buildMixer()
157 {
158     debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
159     // create a Mixer
160     // this removes the mixer if it already exists
161     // note: a mixer self-registers to it's parent
162     delete m_Mixer;
163
164     // create the mixer & register it
165     if(getAudioSubunit(0) == NULL) {
166         debugWarning("Could not find audio subunit, mixer not available.\n");
167         m_Mixer = NULL;
168     } else {
169         m_Mixer = new Mixer(*this);
170     }
171     return m_Mixer != NULL;
172 }
173
174 bool
175 AvDevice::destroyMixer()
176 {
177     delete m_Mixer;
178     return true;
179 }
180
181 void
182 AvDevice::showDevice()
183 {
184     debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
185     GenericAVC::AvDevice::showDevice();
186     flushDebugOutput();
187 }
188
189 AVC::Subunit*
190 AvDevice::createSubunit(AVC::Unit& unit,
191                         AVC::ESubunitType type,
192                         AVC::subunit_t id )
193 {
194     AVC::Subunit* s=NULL;
195     switch (type) {
196         case eST_Audio:
197             s=new BeBoB::SubunitAudio(unit, id );
198             break;
199         case eST_Music:
200             s=new BeBoB::SubunitMusic(unit, id );
201             break;
202         default:
203             s=NULL;
204             break;
205     }
206     if(s) s->setVerboseLevel(getDebugLevel());
207     return s;
208 }
209
210
211 AVC::Plug *
212 AvDevice::createPlug( AVC::Unit* unit,
213                       AVC::Subunit* subunit,
214                       AVC::function_block_type_t functionBlockType,
215                       AVC::function_block_type_t functionBlockId,
216                       AVC::Plug::EPlugAddressType plugAddressType,
217                       AVC::Plug::EPlugDirection plugDirection,
218                       AVC::plug_id_t plugId )
219 {
220
221     Plug *p= new BeBoB::Plug( unit,
222                               subunit,
223                               functionBlockType,
224                               functionBlockId,
225                               plugAddressType,
226                               plugDirection,
227                               plugId );
228     if (p) p->setVerboseLevel(getDebugLevel());
229     return p;
230 }
231
232 bool
233 AvDevice::propagatePlugInfo() {
234     // we don't have to propagate since we discover things
235     // another way
236     debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
237     return true;
238 }
239
240
241 int
242 AvDevice::getConfigurationIdSampleRate()
243 {
244     ExtendedStreamFormatCmd extStreamFormatCmd( *m_p1394Service );
245     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
246     extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
247                                                     PlugAddress::ePAM_Unit,
248                                                     unitPlugAddress ) );
249
250     extStreamFormatCmd.setNodeId( getNodeId() );
251     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
252     extStreamFormatCmd.setVerbose( true );
253
254     if ( !extStreamFormatCmd.fire() ) {
255         debugError( "Stream format command failed\n" );
256         return false;
257     }
258
259     FormatInformation* formatInfo =
260         extStreamFormatCmd.getFormatInformation();
261     FormatInformationStreamsCompound* compoundStream
262         = dynamic_cast< FormatInformationStreamsCompound* > (
263             formatInfo->m_streams );
264     if ( compoundStream ) {
265         debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
266                     compoundStream->m_samplingFrequency );
267         return compoundStream->m_samplingFrequency;
268     }
269
270     debugError( "Could not retrieve sample rate\n" );
271     return 0;
272 }
273
274 int
275 AvDevice::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
276 {
277     ExtendedPlugInfoCmd extPlugInfoCmd( *m_p1394Service );
278     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
279                                      getNodeId() );
280     extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
281                                                 PlugAddress::ePAM_Unit,
282                                                 unitPlugAddress ) );
283     extPlugInfoCmd.setNodeId( getNodeId() );
284     extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
285     extPlugInfoCmd.setVerbose( true );
286     ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
287         ExtendedPlugInfoInfoType::eIT_NoOfChannels );
288     extendedPlugInfoInfoType.initialize();
289     extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
290
291     if ( !extPlugInfoCmd.fire() ) {
292         debugError( "Number of channels command failed\n" );
293         return false;
294     }
295
296     ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
297     if ( infoType
298          && infoType->m_plugNrOfChns )
299     {
300         debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
301                     infoType->m_plugNrOfChns->m_nrOfChannels );
302         return infoType->m_plugNrOfChns->m_nrOfChannels;
303     }
304
305     debugError( "Could not retrieve number of channels\n" );
306     return 0;
307 }
308
309 int
310 AvDevice::getConfigurationIdSyncMode()
311 {
312     SignalSourceCmd signalSourceCmd( *m_p1394Service );
313     SignalUnitAddress signalUnitAddr;
314     signalUnitAddr.m_plugId = 0x01;
315     signalSourceCmd.setSignalDestination( signalUnitAddr );
316     signalSourceCmd.setNodeId( getNodeId() );
317     signalSourceCmd.setSubunitType( eST_Unit  );
318     signalSourceCmd.setSubunitId( 0xff );
319
320     signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
321
322     if ( !signalSourceCmd.fire() ) {
323         debugError( "Signal source command failed\n" );
324         return false;
325     }
326
327     SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
328     SignalSubunitAddress* pSyncPlugSubunitAddress
329         = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
330     if ( pSyncPlugSubunitAddress ) {
331         debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
332                     ( pSyncPlugSubunitAddress->m_subunitType << 3
333                       | pSyncPlugSubunitAddress->m_subunitId ) << 8
334                     | pSyncPlugSubunitAddress->m_plugId );
335
336         return ( pSyncPlugSubunitAddress->m_subunitType << 3
337                  | pSyncPlugSubunitAddress->m_subunitId ) << 8
338             | pSyncPlugSubunitAddress->m_plugId;
339     }
340
341     debugError( "Could not retrieve sync mode\n" );
342     return 0;
343 }
344
345 int
346 AvDevice::getConfigurationId()
347 {
348     // create a unique configuration id.
349     int id = 0;
350     id = getConfigurationIdSampleRate();
351     id |= ( getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input )
352             + getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) ) << 8;
353     id |= getConfigurationIdSyncMode() << 16;
354
355     return id;
356 }
357
358 bool
359 AvDevice::serialize( Glib::ustring basePath,
360                      Util::IOSerialize& ser ) const
361 {
362     bool result;
363     result  = GenericAVC::AvDevice::serialize( basePath, ser );
364     return result;
365 }
366
367 bool
368 AvDevice::deserialize( Glib::ustring basePath,
369                        Util::IODeserialize& deser )
370 {
371     bool result;
372     result  = GenericAVC::AvDevice::deserialize( basePath, deser );
373     return result;
374 }
375
376 Glib::ustring
377 AvDevice::getCachePath()
378 {
379     Glib::ustring cachePath;
380     char* pCachePath;
381
382     string path = CACHEDIR;
383     if ( path.size() && path[0] == '~' ) {
384         path.erase( 0, 1 ); // remove ~
385         path.insert( 0, getenv( "HOME" ) ); // prepend the home path
386     }
387
388     if ( asprintf( &pCachePath, "%s/cache/",  path.c_str() ) < 0 ) {
389         debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
390         cachePath == "/var/cache/libffado/";
391     } else {
392         cachePath = pCachePath;
393         free( pCachePath );
394     }
395     return cachePath;
396 }
397
398 bool
399 AvDevice::loadFromCache()
400 {
401     Glib::ustring sDevicePath = getCachePath() + m_pConfigRom->getGuidString();
402
403     char* configId;
404     asprintf(&configId, "%08x", getConfigurationId() );
405     if ( !configId ) {
406         debugError( "could not create id string\n" );
407         return false;
408     }
409
410     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
411     free( configId );
412     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
413
414     struct stat buf;
415     if ( stat( sFileName.c_str(), &buf ) != 0 ) {
416         debugOutput( DEBUG_LEVEL_NORMAL,  "\"%s\" does not exist\n",  sFileName.c_str() );
417         return false;
418     } else {
419         if ( !S_ISREG( buf.st_mode ) ) {
420             debugOutput( DEBUG_LEVEL_NORMAL,  "\"%s\" is not a regular file\n",  sFileName.c_str() );
421             return false;
422         }
423     }
424
425     Util::XMLDeserialize deser( sFileName, getDebugLevel() );
426
427     bool result = deserialize( "", deser );
428     if ( result ) {
429         debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
430                      sFileName.c_str() );
431     }
432
433     return result;
434 }
435
436 bool
437 AvDevice::saveCache()
438 {
439     // the path looks like this:
440     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
441     string tmp_path = getCachePath() + m_pConfigRom->getGuidString();
442
443     // the following piece should do something like
444     // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
445     vector<string> tokens;
446     tokenize( tmp_path, tokens, "/" );
447     string path;
448     for ( vector<string>::const_iterator it = tokens.begin();
449           it != tokens.end();
450           ++it )
451     {
452         path +=  "/" + *it;
453
454         struct stat buf;
455         if ( stat( path.c_str(), &buf ) == 0 ) {
456             if ( !S_ISDIR( buf.st_mode ) ) {
457                 debugError( "\"%s\" is not a directory\n",  path.c_str() );
458                 return false;
459             }
460         } else {
461             if (  mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
462                 debugError( "Could not create \"%s\" directory\n", path.c_str() );
463                 return false;
464             }
465         }
466     }
467
468     // come up with an unique file name for the current settings
469     char* configId;
470     asprintf(&configId, "%08x", BeBoB::AvDevice::getConfigurationId() );
471     if ( !configId ) {
472         debugError( "Could not create id string\n" );
473         return false;
474     }
475     string filename = path + "/" + configId + ".xml";
476     free( configId );
477     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
478
479     Util::XMLSerialize ser( filename );
480     return serialize( "", ser );
481 }
482
483 } // end of namespace
Note: See TracBrowser for help on using the browser.