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

Revision 639, 10.9 kB (checked in by ppalmers, 16 years ago)

- Introduce a generic infrastructure for FFADODevices to present the clock sources they support and their state
- Implement this infrastructure for BeBoB devices
- Implement this infrastructure for ECHO 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 // FireWorks is the platform used and developed by ECHO AUDIO
38 namespace FireWorks {
39
40 Device::Device( Ieee1394Service& ieee1394Service,
41                             std::auto_ptr<ConfigRom>( configRom ))
42     : GenericAVC::AvDevice( ieee1394Service, configRom)
43     , m_efc_discovery_done ( false )
44 {
45     debugOutput( DEBUG_LEVEL_VERBOSE, "Created FireWorks::Device (NodeID %d)\n",
46                  getConfigRom().getNodeId() );
47     pthread_mutex_init( &m_polled_mutex, 0 );
48 }
49
50 Device::~Device()
51 {
52 }
53
54 void
55 Device::showDevice()
56 {
57     debugOutput(DEBUG_LEVEL_VERBOSE, "This is a FireWorks::Device\n");
58     GenericAVC::AvDevice::showDevice();
59 }
60
61
62 bool
63 Device::probe( ConfigRom& configRom )
64 {
65     unsigned int vendorId = configRom.getNodeVendorId();
66     unsigned int modelId = configRom.getModelId();
67
68     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_fireworks.txt" );
69     if ( vendorModel.parse() ) {
70         vendorModel.printTable();
71         return vendorModel.isPresent( vendorId, modelId );
72     }
73
74     return false;
75 }
76
77 bool
78 Device::discover()
79 {
80     unsigned int vendorId = m_pConfigRom->getNodeVendorId();
81     unsigned int modelId = m_pConfigRom->getModelId();
82
83     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_fireworks.txt" );
84     if ( vendorModel.parse() ) {
85         m_model = vendorModel.find( vendorId, modelId );
86     }
87
88     if (!GenericAVC::VendorModel::isValid(m_model)) {
89         return false;
90     }
91     debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
92             m_model.vendor_name.c_str(), m_model.model_name.c_str());
93
94     // get the info from the EFC
95     if ( !discoverUsingEFC() ) {
96         debugError( "Could not discover using EFC\n" );
97         return false;
98     }
99
100     // discover AVC-wise
101     if ( !GenericAVC::AvDevice::discover() ) {
102         debugError( "Could not discover GenericAVC::AvDevice\n" );
103         return false;
104     }
105
106     return true;
107 }
108
109 bool
110 Device::discoverUsingEFC()
111 {
112     m_efc_discovery_done = false;
113
114     if (!doEfcOverAVC(m_HwInfo)) {
115         debugError("Could not read hardware capabilities\n");
116         return false;
117     }
118
119     // save the EFC version, since some stuff
120     // depends on this
121     m_efc_version = m_HwInfo.m_header.version;
122
123     if (!updatePolledValues()) {
124         debugError("Could not update polled values\n");
125         return false;
126     }
127
128     m_efc_discovery_done = true;
129     return true;
130 }
131
132 FFADODevice *
133 Device::createDevice( Ieee1394Service& ieee1394Service,
134                       std::auto_ptr<ConfigRom>( configRom ))
135 {
136     unsigned int vendorId = configRom->getNodeVendorId();
137     unsigned int modelId = configRom->getModelId();
138
139     switch(vendorId) {
140         case FW_VENDORID_ECHO: return new ECHO::AudioFire(ieee1394Service, configRom );
141         default: return new Device(ieee1394Service, configRom );
142     }
143 }
144
145 bool
146 Device::doEfcOverAVC(EfcCmd &c) {
147     EfcOverAVCCmd cmd( get1394Service() );
148     cmd.setCommandType( AVC::AVCCommand::eCT_Control );
149     cmd.setNodeId( getConfigRom().getNodeId() );
150     cmd.setSubunitType( AVC::eST_Unit  );
151     cmd.setSubunitId( 0xff );
152
153     cmd.setVerbose( getDebugLevel() );
154 //     cmd.setVerbose( DEBUG_LEVEL_VERY_VERBOSE );
155
156     cmd.m_cmd = &c;
157
158 //     c.showEfcCmd();
159
160     if ( !cmd.fire()) {
161         debugError( "EfcOverAVCCmd command failed\n" );
162         c.showEfcCmd();
163         return false;
164     }
165 //     c.showEfcCmd();
166
167     if (   c.m_header.retval != EfcCmd::eERV_Ok
168         && c.m_header.retval != EfcCmd::eERV_FlashBusy) {
169         debugError( "EFC command failed\n" );
170         c.showEfcCmd();
171         return false;
172     }
173
174     return true;
175 }
176
177 bool
178 Device::updatePolledValues() {
179     bool retval;
180
181     pthread_mutex_lock( &m_polled_mutex );
182     retval = doEfcOverAVC(m_Polled);
183     pthread_mutex_unlock( &m_polled_mutex );
184
185     return retval;
186 }
187
188 FFADODevice::ClockSourceVector
189 Device::getSupportedClockSources() {
190     FFADODevice::ClockSourceVector r;
191
192     if (!m_efc_discovery_done) {
193         debugError("EFC discovery not done yet!\n");
194         return r;
195     }
196
197     uint32_t active_clock=getClock();
198
199     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_INTERNAL)) {
200         debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock supported\n");
201         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_INTERNAL);
202         s.active=(active_clock == EFC_CMD_HW_CLOCK_INTERNAL);
203         if (s.type != eCT_Invalid) r.push_back(s);
204     }
205     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SYTMATCH)) {
206         debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match clock supported\n");
207         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SYTMATCH);
208         s.active=(active_clock == EFC_CMD_HW_CLOCK_SYTMATCH);
209         if (s.type != eCT_Invalid) r.push_back(s);
210     }
211     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_WORDCLOCK)) {
212         debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock supported\n");
213         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_WORDCLOCK);
214         s.active=(active_clock == EFC_CMD_HW_CLOCK_WORDCLOCK);
215         if (s.type != eCT_Invalid) r.push_back(s);
216     }
217     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SPDIF)) {
218         debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock supported\n");
219         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SPDIF);
220         s.active=(active_clock == EFC_CMD_HW_CLOCK_SPDIF);
221         if (s.type != eCT_Invalid) r.push_back(s);
222     }
223     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_1)) {
224         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock supported\n");
225         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_1);
226         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_1);
227         if (s.type != eCT_Invalid) r.push_back(s);
228     }
229     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_2)) {
230         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock supported\n");
231         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_2);
232         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_2);
233         if (s.type != eCT_Invalid) r.push_back(s);
234     }
235
236     return r;
237 }
238
239 bool
240 Device::isClockValid(uint32_t id) {
241     // always valid
242     if (id==EFC_CMD_HW_CLOCK_INTERNAL) return true;
243
244     // the polled values are used to detect
245     // whether clocks are valid
246     if (!updatePolledValues()) {
247         debugError("Could not update polled values\n");
248         return false;
249     }
250     return EFC_CMD_HW_CHECK_FLAG(m_Polled.m_status,id);
251 }
252
253 bool
254 Device::setActiveClockSource(ClockSource s) {
255     bool result;
256
257     debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
258
259     if(!isClockValid(s.id)) {
260         debugError("Clock not valid\n");
261         return false;
262     }
263
264     result=setClock(s.id);
265
266     // From the ECHO sources:
267     // "If this is a 1200F and the sample rate is being set via EFC, then
268     // send the "phy reconnect command" so the device will vanish and reappear
269     // with a new descriptor."
270
271 //     EfcPhyReconnectCmd rccmd;
272 //     if(!doEfcOverAVC(rccmd)) {
273 //         debugError("Phy reconnect failed");
274 //     } else {
275 //         // sleep for one second such that the phy can get reconnected
276 //         sleep(1);
277 //     }
278
279     return result;
280 }
281
282 FFADODevice::ClockSource
283 Device::getActiveClockSource() {
284     ClockSource s;
285     uint32_t active_clock=getClock();
286     s=clockIdToClockSource(active_clock);
287     s.active=true;
288     return s;
289 }
290
291 FFADODevice::ClockSource
292 Device::clockIdToClockSource(uint32_t clockid) {
293     ClockSource s;
294     debugOutput(DEBUG_LEVEL_VERBOSE, "clock id: %lu\n", clockid);
295
296     // the polled values are used to detect
297     // whether clocks are valid
298     if (!updatePolledValues()) {
299         debugError("Could not update polled values\n");
300         return s;
301     }
302
303     switch (clockid) {
304         case EFC_CMD_HW_CLOCK_INTERNAL:
305             debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock\n");
306             s.type=eCT_Internal;
307             s.description="Internal sync";
308             break;
309
310         case EFC_CMD_HW_CLOCK_SYTMATCH:
311             debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match\n");
312             s.type=eCT_SytMatch;
313             s.description="SYT Match";
314             break;
315
316         case EFC_CMD_HW_CLOCK_WORDCLOCK:
317             debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock\n");
318             s.type=eCT_WordClock;
319             s.description="Word Clock";
320             break;
321
322         case EFC_CMD_HW_CLOCK_SPDIF:
323             debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock\n");
324             s.type=eCT_SPDIF;
325             s.description="SPDIF";
326             break;
327
328         case EFC_CMD_HW_CLOCK_ADAT_1:
329             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock\n");
330             s.type=eCT_ADAT;
331             s.description="ADAT 1";
332             break;
333
334         case EFC_CMD_HW_CLOCK_ADAT_2:
335             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock\n");
336             s.type=eCT_ADAT;
337             s.description="ADAT 2";
338             break;
339
340         default:
341             debugError("Invalid clock id: %d\n",clockid);
342             return s; // return an invalid ClockSource
343     }
344
345     s.id=clockid;
346     s.valid=isClockValid(clockid);
347
348     return s;
349 }
350
351 uint32_t
352 Device::getClock() {
353     EfcGetClockCmd gccmd;
354     if (!doEfcOverAVC(gccmd)) {
355         debugError("Could not get clock info\n");
356         return EFC_CMD_HW_CLOCK_UNSPECIFIED;
357     }
358     debugOutput(DEBUG_LEVEL_VERBOSE, "Active clock: 0x%08lX\n",gccmd.m_clock);
359     gccmd.showEfcCmd();
360
361     return gccmd.m_clock;
362 }
363
364 bool
365 Device::setClock(uint32_t id) {
366     EfcGetClockCmd gccmd;
367     if (!doEfcOverAVC(gccmd)) {
368         debugError("Could not get clock info\n");
369         return false;
370     }
371     debugOutput(DEBUG_LEVEL_VERBOSE, "Set clock: 0x%08lX\n", id);
372
373     EfcSetClockCmd sccmd;
374     sccmd.m_clock=id;
375     sccmd.m_samplerate=gccmd.m_samplerate;
376     sccmd.m_index=0;
377     if (!doEfcOverAVC(sccmd)) {
378         debugError("Could not set clock info\n");
379         return false;
380     }
381     return true;
382 }
383
384 } // FireWorks
Note: See TracBrowser for help on using the browser.