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

Revision 648, 14.3 kB (checked in by ppalmers, 15 years ago)

rename saffire pro device implementation file to ease normal saffire implementation

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