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

Revision 583, 16.6 kB (checked in by ppalmers, 16 years ago)

- Clean up the FFADODevice constructor to remove the nodeid that

can be retrieved from the configrom.

- Implement new method of creating devices: a device is supposed

to implement the createDevice static method that should return
an instance of itself or a subclass of itself. This should ease
support for manufacturer specific customizations since we don't
have to put them into the device manager class.

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.h"
31 #include "bebob/terratec/terratec.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 "libavc/util/avc_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 static GenericAVC::VendorModelEntry supportedDeviceList[] =
57 {
58     {0x00000f, 0x00010065, "Mackie", "Onyx Firewire"},
59
60     {0x0003db, 0x00010048, "Apogee Electronics", "Rosetta 200"},
61
62     {0x0007f5, 0x00010048, "BridgeCo", "RD Audio1"},
63
64     {0x000a92, 0x00010000, "PreSonus", "FIREBOX"},
65     {0x000a92, 0x00010066, "PreSonus", "FirePOD"},
66
67     {0x000aac, 0x00000003, "TerraTec Electronic GmbH", "Phase 88 FW"},
68     {0x000aac, 0x00000004, "TerraTec Electronic GmbH", "Phase X24 FW (model version 4)"},
69     {0x000aac, 0x00000007, "TerraTec Electronic GmbH", "Phase X24 FW (model version 7)"},
70
71     {0x000f1b, 0x00010064, "ESI", "Quatafire 610"},
72
73     {0x00130e, 0x00000000, "Focusrite", "Saffire (LE)"},
74     {0x00130e, 0x00000003, "Focusrite", "Saffire Pro26IO"},
75     {0x00130e, 0x00000006, "Focusrite", "Saffire Pro10IO"},
76
77     {0x0040ab, 0x00010048, "EDIROL", "FA-101"},
78     {0x0040ab, 0x00010049, "EDIROL", "FA-66"},
79
80     {0x000d6c, 0x00010062, "M-Audio", "FW Solo"},
81     {0x000d6c, 0x00010081, "M-Audio", "NRV10"},
82 };
83
84 AvDevice::AvDevice( Ieee1394Service& ieee1394service,
85                     std::auto_ptr< ConfigRom >( configRom ) )
86     : GenericAVC::AvDevice( ieee1394service, configRom )
87     , m_Mixer ( NULL )
88 {
89     debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::AvDevice (NodeID %d)\n",
90                  configRom->getNodeId() );
91 }
92
93 AvDevice::~AvDevice()
94 {
95     if(m_Mixer != NULL) {
96         delete m_Mixer;
97     }
98 }
99
100 void
101 AvDevice::showDevice()
102 {
103     debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
104     GenericAVC::AvDevice::showDevice();
105     flushDebugOutput();
106 }
107
108 AVC::Subunit*
109 AvDevice::createSubunit(AVC::Unit& unit,
110                         AVC::ESubunitType type,
111                         AVC::subunit_t id )
112 {
113     AVC::Subunit* s=NULL;
114     switch (type) {
115         case eST_Audio:
116             s=new BeBoB::SubunitAudio(unit, id );
117             break;
118         case eST_Music:
119             s=new BeBoB::SubunitMusic(unit, id );
120             break;
121         default:
122             s=NULL;
123             break;
124     }
125     if(s) s->setVerboseLevel(getDebugLevel());
126     return s;
127 }
128
129
130 AVC::Plug *
131 AvDevice::createPlug( AVC::Unit* unit,
132                       AVC::Subunit* subunit,
133                       AVC::function_block_type_t functionBlockType,
134                       AVC::function_block_type_t functionBlockId,
135                       AVC::Plug::EPlugAddressType plugAddressType,
136                       AVC::Plug::EPlugDirection plugDirection,
137                       AVC::plug_id_t plugId )
138 {
139
140     Plug *p= new BeBoB::Plug( unit,
141                               subunit,
142                               functionBlockType,
143                               functionBlockId,
144                               plugAddressType,
145                               plugDirection,
146                               plugId );
147     if (p) p->setVerboseLevel(getDebugLevel());
148     return p;
149 }
150
151 bool
152 AvDevice::probe( ConfigRom& configRom )
153 {
154     unsigned int vendorId = configRom.getNodeVendorId();
155     unsigned int modelId = configRom.getModelId();
156
157     //GenericAVC::VendorModel vendorModel( "/home/wagi/src/libffado/src/bebob/ffado_driver_bebob.txt" );
158
159     for ( unsigned int i = 0;
160           i < ( sizeof( supportedDeviceList )/sizeof( GenericAVC::VendorModelEntry ) );
161           ++i )
162     {
163         if ( ( supportedDeviceList[i].vendor_id == vendorId )
164              && ( supportedDeviceList[i].model_id == modelId ) )
165         {
166             return true;
167         }
168     }
169     return false;
170 }
171
172 FFADODevice *
173 AvDevice::createDevice( Ieee1394Service& ieee1394Service,
174                         std::auto_ptr<ConfigRom>( configRom ))
175 {
176     return new AvDevice(ieee1394Service, configRom );
177 }
178
179 bool
180 AvDevice::discover()
181 {
182     unsigned int vendorId = m_pConfigRom->getNodeVendorId();
183     unsigned int modelId = m_pConfigRom->getModelId();
184
185     for ( unsigned int i = 0;
186           i < ( sizeof( supportedDeviceList )/sizeof( GenericAVC::VendorModelEntry ) );
187           ++i )
188     {
189         if ( ( supportedDeviceList[i].vendor_id == vendorId )
190              && ( supportedDeviceList[i].model_id == modelId )
191            )
192         {
193             m_model = &(supportedDeviceList[i]);
194             break;
195         }
196     }
197
198     if (m_model != NULL) {
199         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
200                 m_model->vendor_name, m_model->model_name);
201     } else return false;
202
203     if ( !Unit::discover() ) {
204         debugError( "Could not discover unit\n" );
205         return false;
206     }
207
208     if((getAudioSubunit( 0 ) == NULL)) {
209         debugError( "Unit doesn't have an Audio subunit.\n");
210         return false;
211     }
212     if((getMusicSubunit( 0 ) == NULL)) {
213         debugError( "Unit doesn't have a Music subunit.\n");
214         return false;
215     }
216
217     // create a Mixer
218     // this removes the mixer if it already exists
219     // note: a mixer self-registers to it's parent
220     if(m_Mixer != NULL) {
221         delete m_Mixer;
222     }
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     return true;
232 }
233
234 bool
235 AvDevice::propagatePlugInfo() {
236     // we don't have to propagate since we discover things
237     // another way
238     debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
239     return true;
240 }
241
242
243 int
244 AvDevice::getConfigurationIdSampleRate()
245 {
246     ExtendedStreamFormatCmd extStreamFormatCmd( *m_p1394Service );
247     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
248                                      getNodeId() );
249     extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
250                                                     PlugAddress::ePAM_Unit,
251                                                     unitPlugAddress ) );
252
253     extStreamFormatCmd.setNodeId( getNodeId() );
254     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
255     extStreamFormatCmd.setVerbose( true );
256
257     if ( !extStreamFormatCmd.fire() ) {
258         debugError( "Stream format command failed\n" );
259         return false;
260     }
261
262     FormatInformation* formatInfo =
263         extStreamFormatCmd.getFormatInformation();
264     FormatInformationStreamsCompound* compoundStream
265         = dynamic_cast< FormatInformationStreamsCompound* > (
266             formatInfo->m_streams );
267     if ( compoundStream ) {
268         debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
269                     compoundStream->m_samplingFrequency );
270         return compoundStream->m_samplingFrequency;
271     }
272
273     debugError( "Could not retrieve sample rate\n" );
274     return 0;
275 }
276
277 int
278 AvDevice::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
279 {
280     ExtendedPlugInfoCmd extPlugInfoCmd( *m_p1394Service );
281     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
282                                      getNodeId() );
283     extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
284                                                 PlugAddress::ePAM_Unit,
285                                                 unitPlugAddress ) );
286     extPlugInfoCmd.setNodeId( getNodeId() );
287     extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
288     extPlugInfoCmd.setVerbose( true );
289     ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
290         ExtendedPlugInfoInfoType::eIT_NoOfChannels );
291     extendedPlugInfoInfoType.initialize();
292     extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
293
294     if ( !extPlugInfoCmd.fire() ) {
295         debugError( "Number of channels command failed\n" );
296         return false;
297     }
298
299     ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
300     if ( infoType
301          && infoType->m_plugNrOfChns )
302     {
303         debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
304                     infoType->m_plugNrOfChns->m_nrOfChannels );
305         return infoType->m_plugNrOfChns->m_nrOfChannels;
306     }
307
308     debugError( "Could not retrieve number of channels\n" );
309     return 0;
310 }
311
312 int
313 AvDevice::getConfigurationIdSyncMode()
314 {
315     SignalSourceCmd signalSourceCmd( *m_p1394Service );
316     SignalUnitAddress signalUnitAddr;
317     signalUnitAddr.m_plugId = 0x01;
318     signalSourceCmd.setSignalDestination( signalUnitAddr );
319     signalSourceCmd.setNodeId( getNodeId() );
320     signalSourceCmd.setSubunitType( eST_Unit  );
321     signalSourceCmd.setSubunitId( 0xff );
322
323     signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
324
325     if ( !signalSourceCmd.fire() ) {
326         debugError( "Number of channels command failed\n" );
327         return false;
328     }
329
330     SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
331     SignalSubunitAddress* pSyncPlugSubunitAddress
332         = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
333     if ( pSyncPlugSubunitAddress ) {
334         debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
335                     ( pSyncPlugSubunitAddress->m_subunitType << 3
336                       | pSyncPlugSubunitAddress->m_subunitId ) << 8
337                     | pSyncPlugSubunitAddress->m_plugId );
338
339         return ( pSyncPlugSubunitAddress->m_subunitType << 3
340                  | pSyncPlugSubunitAddress->m_subunitId ) << 8
341             | pSyncPlugSubunitAddress->m_plugId;
342     }
343
344     debugError( "Could not retrieve sync mode\n" );
345     return 0;
346 }
347
348 int
349 AvDevice::getConfigurationId()
350 {
351     // create a unique configuration id.
352     int id = 0;
353     id = getConfigurationIdSampleRate();
354     id |= ( getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input )
355             + getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) ) << 8;
356     id |= getConfigurationIdSyncMode() << 16;
357
358     return id;
359 }
360
361
362 template <typename T> bool serializeVector( Glib::ustring path,
363                                             Util::IOSerialize& ser,
364                                             const T& vec )
365 {
366     bool result = true; // if vec.size() == 0
367     int i = 0;
368     for ( typename T::const_iterator it = vec.begin(); it != vec.end(); ++it ) {
369         std::ostringstream strstrm;
370         strstrm << path << i;
371         result &= ( *it )->serialize( strstrm.str() + "/", ser );
372         i++;
373     }
374     return result;
375 }
376
377 template <typename T, typename VT> bool deserializeVector( Glib::ustring path,
378                                                            Util::IODeserialize& deser,
379                                                            Unit& avDevice,
380                                                            VT& vec )
381 {
382     int i = 0;
383     bool bFinished = false;
384     do {
385         std::ostringstream strstrm;
386         strstrm << path << i << "/";
387         T* ptr = T::deserialize( strstrm.str(),
388                                  deser,
389                                  avDevice );
390         if ( ptr ) {
391             vec.push_back( ptr );
392             i++;
393         } else {
394             bFinished = true;
395         }
396     } while ( !bFinished );
397
398     return true;
399 }
400
401 bool
402 AvDevice::serialize( Glib::ustring basePath,
403                      Util::IOSerialize& ser ) const
404 {
405
406     bool result;
407     result  = m_pConfigRom->serialize( basePath + "m_pConfigRom/", ser );
408     result &= ser.write( basePath + "m_verboseLevel", getDebugLevel() );
409     result &= m_pPlugManager->serialize( basePath + "Plug", ser ); // serialize all av plugs
410     result &= serializeVector( basePath + "PlugConnection", ser, m_plugConnections );
411     result &= serializeVector( basePath + "Subunit", ser, m_subunits );
412     #warning broken at echoaudio merge
413     //result &= serializeSyncInfoVector( basePath + "SyncInfo", ser, m_syncInfos );
414
415     int i = 0;
416     for ( SyncInfoVector::const_iterator it = m_syncInfos.begin();
417           it != m_syncInfos.end();
418           ++it )
419     {
420         const SyncInfo& info = *it;
421         if ( m_activeSyncInfo == &info ) {
422             result &= ser.write( basePath + "m_activeSyncInfo",  i );
423             break;
424         }
425         i++;
426     }
427
428     result &= serializeOptions( basePath + "Options", ser );
429
430 //     result &= ser.write( basePath + "m_id", id );
431
432     return result;
433 }
434
435 AvDevice*
436 AvDevice::deserialize( Glib::ustring basePath,
437                        Util::IODeserialize& deser,
438                        Ieee1394Service& ieee1394Service )
439 {
440
441 //     ConfigRom *configRom =
442 //         ConfigRom::deserialize( basePath + "m_pConfigRom/", deser, ieee1394Service );
443 //
444 //     if ( !configRom ) {
445 //         return NULL;
446 //     }
447 //
448 //     AvDevice* pDev = new AvDevice(
449 //         std::auto_ptr<ConfigRom>(configRom),
450 //         ieee1394Service, configRom->getNodeId());
451 //
452 //     if ( pDev ) {
453 //         bool result;
454 //         int verboseLevel;
455 //         result  = deser.read( basePath + "m_verboseLevel", verboseLevel );
456 //         setDebugLevel( verboseLevel );
457 //
458 //         result &= AVC::Unit::deserialize(basePath, pDev, deser, ieee1394Service);
459 //
460 //         result &= deserializeOptions( basePath + "Options", deser, *pDev );
461 //     }
462 //
463 //     return pDev;
464     return NULL;
465 }
466
467 Glib::ustring
468 AvDevice::getCachePath()
469 {
470     Glib::ustring cachePath;
471     char* pCachePath;
472     if ( asprintf( &pCachePath, "%s/cache/libffado/",  CACHEDIR ) < 0 ) {
473         debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
474         cachePath == "/var/cache/libffado/";
475     } else {
476         cachePath = pCachePath;
477         free( pCachePath );
478     }
479     return cachePath;
480 }
481
482 bool
483 AvDevice::loadFromCache()
484 {
485 /*    Glib::ustring sDevicePath = getCachePath() + m_pConfigRom->getGuidString();
486
487     char* configId;
488     asprintf(&configId, "%08x", getConfigurationId() );
489     if ( !configId ) {
490         debugError( "could not create id string\n" );
491         return false;
492     }
493
494     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
495     free( configId );
496     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
497
498     Util::XMLDeserialize deser( sFileName, m_verboseLevel );
499
500     bool result = deserialize( "", deser );
501     if ( result ) {
502         debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
503                      sFileName.c_str() );
504     }
505
506     return result;*/
507     return false;
508 }
509
510 bool
511 AvDevice::saveCache()
512 {
513 //     // the path looks like this:
514 //     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
515 //
516 //     Glib::ustring sDevicePath = getCachePath() + m_pConfigRom->getGuidString();
517 //     struct stat buf;
518 //     if ( stat( sDevicePath.c_str(), &buf ) == 0 ) {
519 //         if ( !S_ISDIR( buf.st_mode ) ) {
520 //             debugError( "\"%s\" is not a directory\n",  sDevicePath.c_str() );
521 //             return false;
522 //         }
523 //     } else {
524 //         if (  mkdir( sDevicePath.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
525 //             debugError( "Could not create \"%s\" directory\n", sDevicePath.c_str() );
526 //             return false;
527 //         }
528 //     }
529 //
530 //     char* configId;
531 //     asprintf(&configId, "%08x", BeBoB::AvDevice::getConfigurationId() );
532 //     if ( !configId ) {
533 //         debugError( "Could not create id string\n" );
534 //         return false;
535 //     }
536 //     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
537 //     free( configId );
538 //     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
539 //
540 //     Util::XMLSerialize ser( sFileName );
541 //     return serialize( "", ser );
542     return false;
543 }
544
545 } // end of namespace
Note: See TracBrowser for help on using the browser.