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

Revision 665, 14.4 kB (checked in by ppalmers, 16 years ago)

Implement support for Phantom power on the fireworks devices

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