root/trunk/libffado/src/fireworks/fireworks_device.cpp

Revision 750, 14.5 kB (checked in by ppalmers, 16 years ago)

Code refactoring. Tries to simplify things and tries to put all code where it belongs.

Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
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 3 of the License, or
12  * (at your option) any later version.
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 "fireworks_device.h"
25 #include "efc/efc_avc_cmd.h"
26 #include "efc/efc_cmd.h"
27 #include "efc/efc_cmds_hardware.h"
28 #include "efc/efc_cmds_hardware_ctrl.h"
29
30 #include "audiofire/audiofire_device.h"
31
32 #include "libieee1394/configrom.h"
33 #include "libieee1394/ieee1394service.h"
34
35 #include "config.h"
36
37 #include "fireworks/fireworks_control.h"
38
39 #include <sstream>
40 using namespace std;
41
42 // FireWorks is the platform used and developed by ECHO AUDIO
43 namespace FireWorks {
44
45 Device::Device(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
46     : GenericAVC::AvDevice( d, configRom)
47     , m_efc_discovery_done ( false )
48     , m_MixerContainer ( NULL )
49 {
50     debugOutput( DEBUG_LEVEL_VERBOSE, "Created FireWorks::Device (NodeID %d)\n",
51                  getConfigRom().getNodeId() );
52     pthread_mutex_init( &m_polled_mutex, 0 );
53 }
54
55 Device::~Device()
56 {
57     destroyMixer();
58 }
59
60 void
61 Device::showDevice()
62 {
63     debugOutput(DEBUG_LEVEL_VERBOSE, "This is a FireWorks::Device\n");
64     if ( !m_efc_discovery_done) {
65         if (!discoverUsingEFC()) {
66             debugError("EFC discovery failed\n");
67         }
68     }
69     m_HwInfo.showEfcCmd();
70     GenericAVC::AvDevice::showDevice();
71 }
72
73
74 bool
75 Device::probe( ConfigRom& configRom )
76 {
77     unsigned int vendorId = configRom.getNodeVendorId();
78     unsigned int modelId = configRom.getModelId();
79
80     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_fireworks.txt" );
81     if ( vendorModel.parse() ) {
82         return vendorModel.isPresent( vendorId, modelId );
83     }
84     return false;
85 }
86
87 bool
88 Device::discover()
89 {
90     unsigned int vendorId = getConfigRom().getNodeVendorId();
91     unsigned int modelId = getConfigRom().getModelId();
92
93     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_fireworks.txt" );
94     if ( vendorModel.parse() ) {
95         m_model = vendorModel.find( vendorId, modelId );
96     }
97
98     if (!GenericAVC::VendorModel::isValid(m_model)) {
99         return false;
100     }
101     debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
102             m_model.vendor_name.c_str(), m_model.model_name.c_str());
103
104     // get the info from the EFC
105     if ( !discoverUsingEFC() ) {
106         debugError( "Could not discover using EFC\n" );
107         return false;
108     }
109
110     // discover AVC-wise
111     if ( !GenericAVC::AvDevice::discover() ) {
112         debugError( "Could not discover GenericAVC::AvDevice\n" );
113         return false;
114     }
115
116     if(!buildMixer()) {
117         debugWarning("Could not build mixer\n");
118     }
119
120     return true;
121 }
122
123 bool
124 Device::discoverUsingEFC()
125 {
126     m_efc_discovery_done = false;
127     m_HwInfo.setVerboseLevel(getDebugLevel());
128
129     if (!doEfcOverAVC(m_HwInfo)) {
130         debugError("Could not read hardware capabilities\n");
131         return false;
132     }
133
134     // save the EFC version, since some stuff
135     // depends on this
136     m_efc_version = m_HwInfo.m_header.version;
137
138     if (!updatePolledValues()) {
139         debugError("Could not update polled values\n");
140         return false;
141     }
142
143     m_efc_discovery_done = true;
144     return true;
145 }
146
147 FFADODevice *
148 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
149 {
150     unsigned int vendorId = configRom->getNodeVendorId();
151 //     unsigned int modelId = configRom->getModelId();
152
153     switch(vendorId) {
154         case FW_VENDORID_ECHO: return new ECHO::AudioFire(d, configRom );
155         default: return new Device(d, configRom );
156     }
157 }
158
159 bool
160 Device::doEfcOverAVC(EfcCmd &c) {
161     EfcOverAVCCmd cmd( get1394Service() );
162     cmd.setCommandType( AVC::AVCCommand::eCT_Control );
163     cmd.setNodeId( getConfigRom().getNodeId() );
164     cmd.setSubunitType( AVC::eST_Unit  );
165     cmd.setSubunitId( 0xff );
166
167     cmd.setVerbose( getDebugLevel() );
168     cmd.m_cmd = &c;
169
170     if ( !cmd.fire()) {
171         debugError( "EfcOverAVCCmd command failed\n" );
172         c.showEfcCmd();
173         return false;
174     }
175
176     if ( cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
177         debugError( "EfcOverAVCCmd not accepted\n" );
178         return false;
179     }
180
181     if (   c.m_header.retval != EfcCmd::eERV_Ok
182         && c.m_header.retval != EfcCmd::eERV_FlashBusy) {
183         debugError( "EFC command failed\n" );
184         c.showEfcCmd();
185         return false;
186     }
187
188     return true;
189 }
190
191 bool
192 Device::buildMixer()
193 {
194     bool result=true;
195     debugOutput(DEBUG_LEVEL_VERBOSE, "Building a FireWorks mixer...\n");
196    
197     destroyMixer();
198    
199     // create the mixer object container
200     m_MixerContainer = new Control::Container("Mixer");
201
202     if (!m_MixerContainer) {
203         debugError("Could not create mixer container...\n");
204         return false;
205     }
206
207     // create control objects for the audiofire
208
209     // matrix mix controls
210     result &= m_MixerContainer->addElement(
211         new MonitorControl(*this, MonitorControl::eMC_Gain, "MonitorGain"));
212
213     result &= m_MixerContainer->addElement(
214         new MonitorControl(*this, MonitorControl::eMC_Mute, "MonitorMute"));
215
216     result &= m_MixerContainer->addElement(
217         new MonitorControl(*this, MonitorControl::eMC_Solo, "MonitorSolo"));
218
219     result &= m_MixerContainer->addElement(
220         new MonitorControl(*this, MonitorControl::eMC_Pan, "MonitorPan"));
221
222     // Playback mix controls
223     for (unsigned int ch=0;ch<m_HwInfo.m_nb_1394_playback_channels;ch++) {
224         std::ostringstream node_name;
225         node_name << "PC" << ch;
226        
227         result &= m_MixerContainer->addElement(
228             new BinaryControl(*this, eMT_PlaybackMix, eMC_Mute, ch, 0, node_name.str()+"Mute"));
229         result &= m_MixerContainer->addElement(
230             new SimpleControl(*this, eMT_PlaybackMix, eMC_Gain, ch, node_name.str()+"Gain"));
231     }
232    
233     // Physical output mix controls
234     for (unsigned int ch=0;ch<m_HwInfo.m_nb_phys_audio_out;ch++) {
235         std::ostringstream node_name;
236         node_name << "OUT" << ch;
237        
238         result &= m_MixerContainer->addElement(
239             new BinaryControl(*this, eMT_PhysicalOutputMix, eMC_Mute, ch, 0, node_name.str()+"Mute"));
240         result &= m_MixerContainer->addElement(
241             new BinaryControl(*this, eMT_PhysicalOutputMix, eMC_Nominal, ch, 1, node_name.str()+"Nominal"));
242         result &= m_MixerContainer->addElement(
243             new SimpleControl(*this, eMT_PhysicalOutputMix, eMC_Gain, ch, node_name.str()+"Gain"));
244     }
245    
246     // check for IO config controls and add them if necessary
247     if(m_HwInfo.hasMirroring()) {
248         result &= m_MixerContainer->addElement(
249             new IOConfigControl(*this, eCR_Mirror, "ChannelMirror"));
250     }
251     if(m_HwInfo.hasSoftwarePhantom()) {
252         result &= m_MixerContainer->addElement(
253             new IOConfigControl(*this, eCR_Phantom, "PhantomPower"));
254     }
255
256     if (!result) {
257         debugWarning("One or more control elements could not be created.");
258         // clean up those that couldn't be created
259         destroyMixer();
260         return false;
261     }
262
263     if (!addElement(m_MixerContainer)) {
264         debugWarning("Could not register mixer to device\n");
265         // clean up
266         destroyMixer();
267         return false;
268     }
269
270     return true;
271 }
272
273 bool
274 Device::destroyMixer()
275 {
276     debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n");
277
278     if (m_MixerContainer == NULL) {
279         debugOutput(DEBUG_LEVEL_VERBOSE, "no mixer to destroy...\n");
280         return true;
281     }
282
283     if (!deleteElement(m_MixerContainer)) {
284         debugError("Mixer present but not registered to the avdevice\n");
285         return false;
286     }
287
288     // remove and delete (as in free) child control elements
289     m_MixerContainer->clearElements(true);
290     delete m_MixerContainer;
291     return true;
292 }
293
294
295 bool
296 Device::updatePolledValues() {
297     bool retval;
298
299     pthread_mutex_lock( &m_polled_mutex );
300     retval = doEfcOverAVC(m_Polled);
301     pthread_mutex_unlock( &m_polled_mutex );
302
303     return retval;
304 }
305
306 FFADODevice::ClockSourceVector
307 Device::getSupportedClockSources() {
308     FFADODevice::ClockSourceVector r;
309
310     if (!m_efc_discovery_done) {
311         debugError("EFC discovery not done yet!\n");
312         return r;
313     }
314
315     uint32_t active_clock=getClock();
316
317     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_INTERNAL)) {
318         debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock supported\n");
319         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_INTERNAL);
320         s.active=(active_clock == EFC_CMD_HW_CLOCK_INTERNAL);
321         if (s.type != eCT_Invalid) r.push_back(s);
322     }
323     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SYTMATCH)) {
324         debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match clock supported\n");
325         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SYTMATCH);
326         s.active=(active_clock == EFC_CMD_HW_CLOCK_SYTMATCH);
327         if (s.type != eCT_Invalid) r.push_back(s);
328     }
329     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_WORDCLOCK)) {
330         debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock supported\n");
331         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_WORDCLOCK);
332         s.active=(active_clock == EFC_CMD_HW_CLOCK_WORDCLOCK);
333         if (s.type != eCT_Invalid) r.push_back(s);
334     }
335     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SPDIF)) {
336         debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock supported\n");
337         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SPDIF);
338         s.active=(active_clock == EFC_CMD_HW_CLOCK_SPDIF);
339         if (s.type != eCT_Invalid) r.push_back(s);
340     }
341     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_1)) {
342         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock supported\n");
343         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_1);
344         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_1);
345         if (s.type != eCT_Invalid) r.push_back(s);
346     }
347     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_2)) {
348         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock supported\n");
349         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_2);
350         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_2);
351         if (s.type != eCT_Invalid) r.push_back(s);
352     }
353     return r;
354 }
355
356 bool
357 Device::isClockValid(uint32_t id) {
358     // always valid
359     if (id==EFC_CMD_HW_CLOCK_INTERNAL) return true;
360
361     // the polled values are used to detect
362     // whether clocks are valid
363     if (!updatePolledValues()) {
364         debugError("Could not update polled values\n");
365         return false;
366     }
367     return EFC_CMD_HW_CHECK_FLAG(m_Polled.m_status,id);
368 }
369
370 bool
371 Device::setActiveClockSource(ClockSource s) {
372     bool result;
373
374     debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
375
376     if(!isClockValid(s.id)) {
377         debugError("Clock not valid\n");
378         return false;
379     }
380
381     result=setClock(s.id);
382
383     // From the ECHO sources:
384     // "If this is a 1200F and the sample rate is being set via EFC, then
385     // send the "phy reconnect command" so the device will vanish and reappear
386     // with a new descriptor."
387
388 //     EfcPhyReconnectCmd rccmd;
389 //     if(!doEfcOverAVC(rccmd)) {
390 //         debugError("Phy reconnect failed");
391 //     } else {
392 //         // sleep for one second such that the phy can get reconnected
393 //         sleep(1);
394 //     }
395
396     return result;
397 }
398
399 FFADODevice::ClockSource
400 Device::getActiveClockSource() {
401     ClockSource s;
402     uint32_t active_clock=getClock();
403     s=clockIdToClockSource(active_clock);
404     s.active=true;
405     return s;
406 }
407
408 FFADODevice::ClockSource
409 Device::clockIdToClockSource(uint32_t clockid) {
410     ClockSource s;
411     debugOutput(DEBUG_LEVEL_VERBOSE, "clock id: %lu\n", clockid);
412
413     // the polled values are used to detect
414     // whether clocks are valid
415     if (!updatePolledValues()) {
416         debugError("Could not update polled values\n");
417         return s;
418     }
419
420     switch (clockid) {
421         case EFC_CMD_HW_CLOCK_INTERNAL:
422             debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock\n");
423             s.type=eCT_Internal;
424             s.description="Internal sync";
425             break;
426
427         case EFC_CMD_HW_CLOCK_SYTMATCH:
428             debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match\n");
429             s.type=eCT_SytMatch;
430             s.description="SYT Match";
431             break;
432
433         case EFC_CMD_HW_CLOCK_WORDCLOCK:
434             debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock\n");
435             s.type=eCT_WordClock;
436             s.description="Word Clock";
437             break;
438
439         case EFC_CMD_HW_CLOCK_SPDIF:
440             debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock\n");
441             s.type=eCT_SPDIF;
442             s.description="SPDIF";
443             break;
444
445         case EFC_CMD_HW_CLOCK_ADAT_1:
446             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock\n");
447             s.type=eCT_ADAT;
448             s.description="ADAT 1";
449             break;
450
451         case EFC_CMD_HW_CLOCK_ADAT_2:
452             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock\n");
453             s.type=eCT_ADAT;
454             s.description="ADAT 2";
455             break;
456
457         default:
458             debugError("Invalid clock id: %d\n",clockid);
459             return s; // return an invalid ClockSource
460     }
461
462     s.id=clockid;
463     s.valid=isClockValid(clockid);
464
465     return s;
466 }
467
468 uint32_t
469 Device::getClock() {
470     EfcGetClockCmd gccmd;
471     if (!doEfcOverAVC(gccmd)) {
472         debugError("Could not get clock info\n");
473         return EFC_CMD_HW_CLOCK_UNSPECIFIED;
474     }
475     debugOutput(DEBUG_LEVEL_VERBOSE, "Active clock: 0x%08lX\n",gccmd.m_clock);
476     gccmd.showEfcCmd();
477
478     return gccmd.m_clock;
479 }
480
481 bool
482 Device::setClock(uint32_t id) {
483     EfcGetClockCmd gccmd;
484     if (!doEfcOverAVC(gccmd)) {
485         debugError("Could not get clock info\n");
486         return false;
487     }
488     debugOutput(DEBUG_LEVEL_VERBOSE, "Set clock: 0x%08lX\n", id);
489
490     EfcSetClockCmd sccmd;
491     sccmd.m_clock=id;
492     sccmd.m_samplerate=gccmd.m_samplerate;
493     sccmd.m_index=0;
494     if (!doEfcOverAVC(sccmd)) {
495         debugError("Could not set clock info\n");
496         return false;
497     }
498     return true;
499 }
500
501 } // FireWorks
Note: See TracBrowser for help on using the browser.