root/branches/libffado-2.0/src/fireworks/fireworks_device.cpp

Revision 1288, 26.6 kB (checked in by ppalmers, 16 years ago)

implement samplerate control through the mixer panels. disabled by default due to potential issues with rediscovery and a running jackd

Line 
1 /*
2  * Copyright (C) 2005-2008 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 2 of the License, or
12  * (at your option) version 3 of the License.
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 #include "efc/efc_cmds_flash.h"
30
31 #include "audiofire/audiofire_device.h"
32
33 #include "libieee1394/configrom.h"
34 #include "libieee1394/ieee1394service.h"
35
36 #include "config.h"
37
38 #include "fireworks/fireworks_control.h"
39
40 #include "libutil/PosixMutex.h"
41
42 #include "IntelFlashMap.h"
43
44 #define ECHO_FLASH_ERASE_TIMEOUT_MILLISECS 2000
45
46 #include <sstream>
47 using namespace std;
48
49 // FireWorks is the platform used and developed by ECHO AUDIO
50 namespace FireWorks {
51
52 Device::Device(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
53     : GenericAVC::AvDevice( d, configRom)
54     , m_poll_lock( new Util::PosixMutex() )
55     , m_efc_discovery_done ( false )
56     , m_MixerContainer ( NULL )
57 {
58     debugOutput( DEBUG_LEVEL_VERBOSE, "Created FireWorks::Device (NodeID %d)\n",
59                  getConfigRom().getNodeId() );
60 }
61
62 Device::~Device()
63 {
64     destroyMixer();
65 }
66
67 void
68 Device::showDevice()
69 {
70     debugOutput(DEBUG_LEVEL_VERBOSE, "This is a FireWorks::Device\n");
71     if ( !m_efc_discovery_done) {
72         if (!discoverUsingEFC()) {
73             debugError("EFC discovery failed\n");
74         }
75     }
76     m_HwInfo.showEfcCmd();
77     GenericAVC::AvDevice::showDevice();
78 }
79
80 bool
81 Device::probe( ConfigRom& configRom, bool generic )
82 {
83     if(generic) {
84         // try an EFC command
85         EfcOverAVCCmd cmd( configRom.get1394Service() );
86         cmd.setCommandType( AVC::AVCCommand::eCT_Control );
87         cmd.setNodeId( configRom.getNodeId() );
88         cmd.setSubunitType( AVC::eST_Unit  );
89         cmd.setSubunitId( 0xff );
90         cmd.setVerbose( configRom.getVerboseLevel() );
91
92         EfcHardwareInfoCmd hwInfo;
93         hwInfo.setVerboseLevel(configRom.getVerboseLevel());
94         cmd.m_cmd = &hwInfo;
95
96         if ( !cmd.fire()) {
97             return false;
98         }
99
100         if ( cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
101             return false;
102         }
103         if ( hwInfo.m_header.retval != EfcCmd::eERV_Ok
104              && hwInfo.m_header.retval != EfcCmd::eERV_FlashBusy) {
105              debugError( "EFC command failed\n" );
106              return false;
107         }
108         return true;
109     } else {
110         unsigned int vendorId = configRom.getNodeVendorId();
111         unsigned int modelId = configRom.getModelId();
112    
113         GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_fireworks.txt" );
114         if ( vendorModel.parse() ) {
115             return vendorModel.isPresent( vendorId, modelId );
116         }
117         return false;
118     }
119 }
120
121 bool
122 Device::discover()
123 {
124     unsigned int vendorId = getConfigRom().getNodeVendorId();
125     unsigned int modelId = getConfigRom().getModelId();
126
127     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_fireworks.txt" );
128     if ( vendorModel.parse() ) {
129         m_model = vendorModel.find( vendorId, modelId );
130     }
131
132     if (!GenericAVC::VendorModel::isValid(m_model)) {
133         debugWarning("Using generic ECHO Audio FireWorks support for unsupported device '%s %s'\n",
134             getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
135     } else {
136         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
137                 m_model.vendor_name.c_str(), m_model.model_name.c_str());
138     }
139
140     // get the info from the EFC
141     if ( !discoverUsingEFC() ) {
142         debugError( "Could not discover using EFC\n" );
143         return false;
144     }
145
146     // discover AVC-wise
147     if ( !GenericAVC::AvDevice::discover() ) {
148         debugError( "Could not discover GenericAVC::AvDevice\n" );
149         return false;
150     }
151
152     if(!buildMixer()) {
153         debugWarning("Could not build mixer\n");
154     }
155
156     return true;
157 }
158
159 bool
160 Device::discoverUsingEFC()
161 {
162     m_efc_discovery_done = false;
163     m_HwInfo.setVerboseLevel(getDebugLevel());
164
165     if (!doEfcOverAVC(m_HwInfo)) {
166         debugError("Could not read hardware capabilities\n");
167         return false;
168     }
169
170     // save the EFC version, since some stuff
171     // depends on this
172     m_efc_version = m_HwInfo.m_header.version;
173
174     if (!updatePolledValues()) {
175         debugError("Could not update polled values\n");
176         return false;
177     }
178
179     m_efc_discovery_done = true;
180     return true;
181 }
182
183 FFADODevice *
184 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
185 {
186     unsigned int vendorId = configRom->getNodeVendorId();
187 //     unsigned int modelId = configRom->getModelId();
188
189     switch(vendorId) {
190         case FW_VENDORID_ECHO: return new ECHO::AudioFire(d, configRom );
191         default: return new Device(d, configRom );
192     }
193 }
194
195 bool
196 Device::doEfcOverAVC(EfcCmd &c) {
197     EfcOverAVCCmd cmd( get1394Service() );
198     cmd.setCommandType( AVC::AVCCommand::eCT_Control );
199     cmd.setNodeId( getConfigRom().getNodeId() );
200     cmd.setSubunitType( AVC::eST_Unit  );
201     cmd.setSubunitId( 0xff );
202
203     cmd.setVerbose( getDebugLevel() );
204     cmd.m_cmd = &c;
205
206     if ( !cmd.fire()) {
207         debugError( "EfcOverAVCCmd command failed\n" );
208         c.showEfcCmd();
209         return false;
210     }
211
212     if ( cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
213         debugError( "EfcOverAVCCmd not accepted\n" );
214         return false;
215     }
216
217     if (   c.m_header.retval != EfcCmd::eERV_Ok
218         && c.m_header.retval != EfcCmd::eERV_FlashBusy) {
219         debugError( "EFC command failed\n" );
220         c.showEfcCmd();
221         return false;
222     }
223
224     return true;
225 }
226
227 bool
228 Device::buildMixer()
229 {
230     bool result=true;
231     debugOutput(DEBUG_LEVEL_VERBOSE, "Building a FireWorks mixer...\n");
232    
233     destroyMixer();
234    
235     // create the mixer object container
236     m_MixerContainer = new Control::Container(this, "Mixer");
237
238     if (!m_MixerContainer) {
239         debugError("Could not create mixer container...\n");
240         return false;
241     }
242
243     // create control objects for the audiofire
244
245     // matrix mix controls
246     result &= m_MixerContainer->addElement(
247         new MonitorControl(*this, MonitorControl::eMC_Gain, "MonitorGain"));
248
249     result &= m_MixerContainer->addElement(
250         new MonitorControl(*this, MonitorControl::eMC_Mute, "MonitorMute"));
251
252     result &= m_MixerContainer->addElement(
253         new MonitorControl(*this, MonitorControl::eMC_Solo, "MonitorSolo"));
254
255     result &= m_MixerContainer->addElement(
256         new MonitorControl(*this, MonitorControl::eMC_Pan, "MonitorPan"));
257
258     // Playback mix controls
259     for (unsigned int ch=0;ch<m_HwInfo.m_nb_1394_playback_channels;ch++) {
260         std::ostringstream node_name;
261         node_name << "PC" << ch;
262        
263         result &= m_MixerContainer->addElement(
264             new BinaryControl(*this, eMT_PlaybackMix, eMC_Mute, ch, 0, node_name.str()+"Mute"));
265         result &= m_MixerContainer->addElement(
266             new BinaryControl(*this, eMT_PlaybackMix, eMC_Solo, ch, 0, node_name.str()+"Solo"));
267         result &= m_MixerContainer->addElement(
268             new SimpleControl(*this, eMT_PlaybackMix, eMC_Gain, ch, node_name.str()+"Gain"));
269     }
270    
271     // Physical output mix controls
272     for (unsigned int ch=0;ch<m_HwInfo.m_nb_phys_audio_out;ch++) {
273         std::ostringstream node_name;
274         node_name << "OUT" << ch;
275        
276         result &= m_MixerContainer->addElement(
277             new BinaryControl(*this, eMT_PhysicalOutputMix, eMC_Mute, ch, 0, node_name.str()+"Mute"));
278         result &= m_MixerContainer->addElement(
279             new BinaryControl(*this, eMT_PhysicalOutputMix, eMC_Nominal, ch, 1, node_name.str()+"Nominal"));
280         result &= m_MixerContainer->addElement(
281             new SimpleControl(*this, eMT_PhysicalOutputMix, eMC_Gain, ch, node_name.str()+"Gain"));
282     }
283    
284     // Physical input mix controls
285     for (unsigned int ch=0;ch<m_HwInfo.m_nb_phys_audio_in;ch++) {
286         std::ostringstream node_name;
287         node_name << "IN" << ch;
288        
289         // result &= m_MixerContainer->addElement(
290         //     new BinaryControl(*this, eMT_PhysicalInputMix, eMC_Pad, ch, 0, node_name.str()+"Pad"));
291         result &= m_MixerContainer->addElement(
292             new BinaryControl(*this, eMT_PhysicalInputMix, eMC_Nominal, ch, 1, node_name.str()+"Nominal"));
293     }
294
295     // add hardware information controls
296     m_HwInfoContainer = new Control::Container(this, "HwInfo");
297     result &= m_HwInfoContainer->addElement(
298         new HwInfoControl(*this, HwInfoControl::eHIF_PhysicalAudioOutCount, "PhysicalAudioOutCount"));
299     result &= m_HwInfoContainer->addElement(
300         new HwInfoControl(*this, HwInfoControl::eHIF_PhysicalAudioInCount, "PhysicalAudioInCount"));
301     result &= m_HwInfoContainer->addElement(
302         new HwInfoControl(*this, HwInfoControl::eHIF_1394PlaybackCount, "1394PlaybackCount"));
303     result &= m_HwInfoContainer->addElement(
304         new HwInfoControl(*this, HwInfoControl::eHIF_1394RecordCount, "1394RecordCount"));
305     result &= m_HwInfoContainer->addElement(
306         new HwInfoControl(*this, HwInfoControl::eHIF_GroupOutCount, "GroupOutCount"));
307     result &= m_HwInfoContainer->addElement(
308         new HwInfoControl(*this, HwInfoControl::eHIF_GroupInCount, "GroupInCount"));
309     result &= m_HwInfoContainer->addElement(
310         new HwInfoControl(*this, HwInfoControl::eHIF_PhantomPower, "PhantomPower"));
311
312     // add a save settings control
313     result &= this->addElement(
314         new MultiControl(*this, MultiControl::eT_SaveSession, "SaveSettings"));
315
316     // add an identify control
317     result &= this->addElement(
318         new MultiControl(*this, MultiControl::eT_Identify, "Identify"));
319
320     // spdif mode control
321     result &= this->addElement(
322         new SpdifModeControl(*this, "SpdifMode"));
323
324     // check for IO config controls and add them if necessary
325     if(m_HwInfo.hasMirroring()) {
326         result &= this->addElement(
327             new IOConfigControl(*this, eCR_Mirror, "ChannelMirror"));
328     }
329     if(m_HwInfo.hasSoftwarePhantom()) {
330         result &= this->addElement(
331             new IOConfigControl(*this, eCR_Phantom, "PhantomPower"));
332     }
333
334     if (!result) {
335         debugWarning("One or more control elements could not be created.");
336         // clean up those that couldn't be created
337         destroyMixer();
338         return false;
339     }
340
341     if (!addElement(m_MixerContainer)) {
342         debugWarning("Could not register mixer to device\n");
343         // clean up
344         destroyMixer();
345         return false;
346     }
347
348     if (!addElement(m_HwInfoContainer)) {
349         debugWarning("Could not register hwinfo to device\n");
350         // clean up
351         destroyMixer();
352         return false;
353     }
354
355     // load the session block
356     if (!loadSession()) {
357         debugWarning("Could not load session\n");
358     }
359
360     return true;
361 }
362
363 bool
364 Device::destroyMixer()
365 {
366     debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n");
367
368     if (m_MixerContainer == NULL) {
369         debugOutput(DEBUG_LEVEL_VERBOSE, "no mixer to destroy...\n");
370     } else {
371         if (!deleteElement(m_MixerContainer)) {
372             debugError("Mixer present but not registered to the avdevice\n");
373             return false;
374         }
375
376         // remove and delete (as in free) child control elements
377         m_MixerContainer->clearElements(true);
378         delete m_MixerContainer;
379         m_MixerContainer = NULL;
380     }
381
382     if (m_HwInfoContainer == NULL) {
383         debugOutput(DEBUG_LEVEL_VERBOSE, "no hwinfo to destroy...\n");
384     } else {
385         if (!deleteElement(m_HwInfoContainer)) {
386             debugError("HwInfo present but not registered to the avdevice\n");
387             return false;
388         }
389
390         // remove and delete (as in free) child control elements
391         m_HwInfoContainer->clearElements(true);
392         delete m_HwInfoContainer;
393         m_HwInfoContainer = NULL;
394     }
395     return true;
396 }
397
398 bool
399 Device::saveSession()
400 {
401     // save the session block
402 //     if ( !updateSession() ) {
403 //         debugError( "Could not update session\n" );
404 //     } else {
405         if ( !m_session.saveToDevice(*this) ) {
406             debugError( "Could not save session block\n" );
407         }
408 //     }
409
410     return true;
411 }
412
413 bool
414 Device::loadSession()
415 {
416     if ( !m_session.loadFromDevice(*this) ) {
417         debugError( "Could not load session block\n" );
418         return false;
419     }
420     return true;
421 }
422
423 bool
424 Device::updatePolledValues() {
425     Util::MutexLockHelper lock(*m_poll_lock);
426     return doEfcOverAVC(m_Polled);
427 }
428
429 #define ECHO_CHECK_AND_ADD_SR(v, x) \
430     { if(x >= m_HwInfo.m_min_sample_rate && x <= m_HwInfo.m_max_sample_rate) \
431       v.push_back(x); }
432 std::vector<int>
433 Device::getSupportedSamplingFrequencies()
434 {
435     std::vector<int> frequencies;
436     ECHO_CHECK_AND_ADD_SR(frequencies, 22050);
437     ECHO_CHECK_AND_ADD_SR(frequencies, 24000);
438     ECHO_CHECK_AND_ADD_SR(frequencies, 32000);
439     ECHO_CHECK_AND_ADD_SR(frequencies, 44100);
440     ECHO_CHECK_AND_ADD_SR(frequencies, 48000);
441     ECHO_CHECK_AND_ADD_SR(frequencies, 88200);
442     ECHO_CHECK_AND_ADD_SR(frequencies, 96000);
443     ECHO_CHECK_AND_ADD_SR(frequencies, 176400);
444     ECHO_CHECK_AND_ADD_SR(frequencies, 192000);
445     return frequencies;
446 }
447
448 FFADODevice::ClockSourceVector
449 Device::getSupportedClockSources() {
450     FFADODevice::ClockSourceVector r;
451
452     if (!m_efc_discovery_done) {
453         debugError("EFC discovery not done yet!\n");
454         return r;
455     }
456
457     uint32_t active_clock=getClock();
458
459     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_INTERNAL)) {
460         debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock supported\n");
461         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_INTERNAL);
462         s.active=(active_clock == EFC_CMD_HW_CLOCK_INTERNAL);
463         if (s.type != eCT_Invalid) r.push_back(s);
464     }
465     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SYTMATCH)) {
466         debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match clock supported\n");
467         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SYTMATCH);
468         s.active=(active_clock == EFC_CMD_HW_CLOCK_SYTMATCH);
469         if (s.type != eCT_Invalid) r.push_back(s);
470     }
471     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_WORDCLOCK)) {
472         debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock supported\n");
473         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_WORDCLOCK);
474         s.active=(active_clock == EFC_CMD_HW_CLOCK_WORDCLOCK);
475         if (s.type != eCT_Invalid) r.push_back(s);
476     }
477     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SPDIF)) {
478         debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock supported\n");
479         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SPDIF);
480         s.active=(active_clock == EFC_CMD_HW_CLOCK_SPDIF);
481         if (s.type != eCT_Invalid) r.push_back(s);
482     }
483     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_1)) {
484         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock supported\n");
485         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_1);
486         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_1);
487         if (s.type != eCT_Invalid) r.push_back(s);
488     }
489     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_2)) {
490         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock supported\n");
491         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_2);
492         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_2);
493         if (s.type != eCT_Invalid) r.push_back(s);
494     }
495     return r;
496 }
497
498 bool
499 Device::isClockValid(uint32_t id) {
500     // always valid
501     if (id==EFC_CMD_HW_CLOCK_INTERNAL) return true;
502
503     // the polled values are used to detect
504     // whether clocks are valid
505     if (!updatePolledValues()) {
506         debugError("Could not update polled values\n");
507         return false;
508     }
509     return EFC_CMD_HW_CHECK_FLAG(m_Polled.m_status,id);
510 }
511
512 bool
513 Device::setActiveClockSource(ClockSource s) {
514     bool result;
515
516     debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
517
518     if(!isClockValid(s.id)) {
519         debugError("Clock not valid\n");
520         return false;
521     }
522
523     result=setClock(s.id);
524
525     // From the ECHO sources:
526     // "If this is a 1200F and the sample rate is being set via EFC, then
527     // send the "phy reconnect command" so the device will vanish and reappear
528     // with a new descriptor."
529
530 //     EfcPhyReconnectCmd rccmd;
531 //     if(!doEfcOverAVC(rccmd)) {
532 //         debugError("Phy reconnect failed\n");
533 //     } else {
534 //         // sleep for one second such that the phy can get reconnected
535 //         sleep(1);
536 //     }
537
538     return result;
539 }
540
541 FFADODevice::ClockSource
542 Device::getActiveClockSource() {
543     ClockSource s;
544     uint32_t active_clock=getClock();
545     s=clockIdToClockSource(active_clock);
546     s.active=true;
547     return s;
548 }
549
550 FFADODevice::ClockSource
551 Device::clockIdToClockSource(uint32_t clockid) {
552     ClockSource s;
553     debugOutput(DEBUG_LEVEL_VERBOSE, "clock id: %lu\n", clockid);
554
555     // the polled values are used to detect
556     // whether clocks are valid
557     if (!updatePolledValues()) {
558         debugError("Could not update polled values\n");
559         return s;
560     }
561
562     switch (clockid) {
563         case EFC_CMD_HW_CLOCK_INTERNAL:
564             debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock\n");
565             s.type=eCT_Internal;
566             s.description="Internal sync";
567             break;
568
569         case EFC_CMD_HW_CLOCK_SYTMATCH:
570             debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match\n");
571             s.type=eCT_SytMatch;
572             s.description="SYT Match";
573             break;
574
575         case EFC_CMD_HW_CLOCK_WORDCLOCK:
576             debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock\n");
577             s.type=eCT_WordClock;
578             s.description="Word Clock";
579             break;
580
581         case EFC_CMD_HW_CLOCK_SPDIF:
582             debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock\n");
583             s.type=eCT_SPDIF;
584             s.description="SPDIF";
585             break;
586
587         case EFC_CMD_HW_CLOCK_ADAT_1:
588             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock\n");
589             s.type=eCT_ADAT;
590             s.description="ADAT 1";
591             break;
592
593         case EFC_CMD_HW_CLOCK_ADAT_2:
594             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock\n");
595             s.type=eCT_ADAT;
596             s.description="ADAT 2";
597             break;
598
599         default:
600             debugError("Invalid clock id: %d\n",clockid);
601             return s; // return an invalid ClockSource
602     }
603
604     s.id=clockid;
605     s.valid=isClockValid(clockid);
606
607     return s;
608 }
609
610 uint32_t
611 Device::getClock() {
612     EfcGetClockCmd gccmd;
613     if (!doEfcOverAVC(gccmd)) {
614         debugError("Could not get clock info\n");
615         return EFC_CMD_HW_CLOCK_UNSPECIFIED;
616     }
617     debugOutput(DEBUG_LEVEL_VERBOSE, "Active clock: 0x%08lX\n",gccmd.m_clock);
618     gccmd.showEfcCmd();
619
620     return gccmd.m_clock;
621 }
622
623 bool
624 Device::setClock(uint32_t id) {
625     EfcGetClockCmd gccmd;
626     if (!doEfcOverAVC(gccmd)) {
627         debugError("Could not get clock info\n");
628         return false;
629     }
630     debugOutput(DEBUG_LEVEL_VERBOSE, "Set clock: 0x%08lX\n", id);
631
632     EfcSetClockCmd sccmd;
633     sccmd.m_clock=id;
634     sccmd.m_samplerate=gccmd.m_samplerate;
635     sccmd.m_index=0;
636     if (!doEfcOverAVC(sccmd)) {
637         debugError("Could not set clock info\n");
638         return false;
639     }
640     return true;
641 }
642
643 bool
644 Device::lockFlash(bool lock) {
645     EfcFlashLockCmd cmd;
646     cmd.m_lock = lock;
647
648     if(!doEfcOverAVC(cmd)) {
649         debugError("Flash lock failed\n");
650         return false;
651     }
652     return true;
653 }
654
655 bool
656 Device::writeFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
657
658     if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
659         debugError("bogus start/len: 0x%08X / %u\n", start, len);
660         return false;
661     }
662     if(start & 0x03) {
663         debugError("start address not quadlet aligned: 0x%08X\n", start);
664         return false;
665     }
666
667     uint32_t start_addr = start;
668     uint32_t stop_addr = start + len*4;
669     uint32_t *target_buffer = buffer;
670
671     EfcFlashWriteCmd cmd;
672     // write EFC_FLASH_SIZE_BYTES at a time
673     for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
674         cmd.m_address = start_addr;
675         unsigned int quads_to_write = (stop_addr - start_addr)/4;
676         if (quads_to_write > EFC_FLASH_SIZE_QUADS) {
677             quads_to_write = EFC_FLASH_SIZE_QUADS;
678         }
679         cmd.m_nb_quadlets = quads_to_write;
680         for(unsigned int i=0; i<quads_to_write; i++) {
681             cmd.m_data[i] = *target_buffer;
682             target_buffer++;
683         }
684         if(!doEfcOverAVC(cmd)) {
685             debugError("Flash write failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_write);
686             return false;
687         }
688     }
689     return true;
690 }
691
692 bool
693 Device::readFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
694
695     if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
696         debugError("bogus start/len: 0x%08X / %u\n", start, len);
697         return false;
698     }
699     if(start & 0x03) {
700         debugError("start address not quadlet aligned: 0x%08X\n", start);
701         return false;
702     }
703
704     uint32_t start_addr = start;
705     uint32_t stop_addr = start + len*4;
706     uint32_t *target_buffer = buffer;
707
708     EfcFlashReadCmd cmd;
709     // read EFC_FLASH_SIZE_BYTES at a time
710     for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
711         unsigned int quads_to_read = (stop_addr - start_addr)/4;
712         if (quads_to_read > EFC_FLASH_SIZE_QUADS) {
713             quads_to_read = EFC_FLASH_SIZE_QUADS;
714         }
715         uint32_t quadlets_read = 0;
716         int ntries = 10000;
717         do {
718             cmd.m_address = start_addr + quadlets_read*4;
719             unsigned int new_to_read = quads_to_read - quadlets_read;
720             cmd.m_nb_quadlets = new_to_read;
721             if(!doEfcOverAVC(cmd)) {
722                 debugError("Flash read failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_read);
723                 return false;
724             }
725             if(cmd.m_nb_quadlets != new_to_read) {
726                 debugOutput(DEBUG_LEVEL_VERBOSE,
727                             "Flash read didn't return enough data (%u/%u) \n",
728                             cmd.m_nb_quadlets, new_to_read);
729                 // continue trying
730             }
731             quadlets_read += cmd.m_nb_quadlets;
732
733             // copy content
734             for(unsigned int i=0; i<cmd.m_nb_quadlets; i++) {
735                 *target_buffer = cmd.m_data[i];
736                 target_buffer++;
737             }
738         } while(quadlets_read < quads_to_read && ntries--);
739         if(ntries==0) {
740             debugError("deadlock while reading flash\n");
741             return false;
742         }
743     }
744     return true;
745 }
746
747 bool
748 Device::eraseFlash(uint32_t addr) {
749     if(addr & 0x03) {
750         debugError("start address not quadlet aligned: 0x%08X\n", addr);
751         return false;
752     }
753     EfcFlashEraseCmd cmd;
754     cmd.m_address = addr;
755     if(!doEfcOverAVC(cmd)) {
756         if (cmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
757             return true;
758         }
759         debugError("Flash erase failed for block 0x%08X\n", addr);
760         return false;
761     }
762     return true;
763 }
764
765 bool
766 Device::eraseFlashBlocks(uint32_t start_address, unsigned int nb_quads)
767 {
768     uint32_t blocksize_bytes;
769     uint32_t blocksize_quads;
770     unsigned int quads_left = nb_quads;
771     bool success = true;
772
773     const unsigned int max_nb_tries = 10;
774     unsigned int nb_tries = 0;
775
776     do {
777         // the erase block size is fixed by the HW, and depends
778         // on the flash section we're in
779         if (start_address < MAINBLOCKS_BASE_OFFSET_BYTES)
780                 blocksize_bytes = PROGRAMBLOCK_SIZE_BYTES;
781         else
782                 blocksize_bytes = MAINBLOCK_SIZE_BYTES;
783         start_address &= ~(blocksize_bytes - 1);
784         blocksize_quads = blocksize_bytes / 4;
785
786         uint32_t verify[blocksize_quads];
787
788         // corner case: requested to erase less than one block
789         if (blocksize_quads > quads_left) {
790             blocksize_quads = quads_left;
791         }
792
793         // do the actual erase
794         if (!eraseFlash(start_address)) {
795             debugWarning("Could not erase flash block at 0x%08X\n", start_address);
796             success = false;
797         } else {
798             // wait for the flash to become ready again
799             if (!waitForFlash(ECHO_FLASH_ERASE_TIMEOUT_MILLISECS)) {
800                 debugError("Wait for flash timed out at address 0x%08X\n", start_address);
801                 return false;
802             }
803
804             // verify that the block is empty as an extra precaution
805             if (!readFlash(start_address, blocksize_quads, verify)) {
806                 debugError("Could not read flash block at 0x%08X\n", start_address);
807                 return false;
808             }
809
810             // everything should be 0xFFFFFFFF if the erase was successful
811             for (unsigned int i = 0; i < blocksize_quads; i++) {
812                 if (0xFFFFFFFF != verify[i]) {
813                     debugWarning("Flash erase verification failed.\n");
814                     success = false;
815                     break;
816                 }
817             }
818         }
819
820         if (success) {
821             start_address += blocksize_bytes;
822             quads_left -= blocksize_quads;
823             nb_tries = 0;
824         } else {
825             nb_tries++;
826         }
827         if (nb_tries > max_nb_tries) {
828             debugError("Needed too many tries to erase flash at 0x%08X\n", start_address);
829             return false;
830         }
831     } while (quads_left > 0);
832
833     return true;
834 }
835
836 bool
837 Device::waitForFlash(unsigned int msecs)
838 {
839     bool ready;
840
841     EfcFlashGetStatusCmd statusCmd;
842     const unsigned int time_to_sleep_usecs = 10000;
843     int wait_cycles = msecs * 1000 / time_to_sleep_usecs;
844
845     do {
846         if (!doEfcOverAVC(statusCmd)) {
847             debugError("Could not read flash status\n");
848             return false;
849         }
850         if (statusCmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
851             ready = false;
852         } else {
853             ready = statusCmd.m_ready;
854         }
855         usleep(time_to_sleep_usecs);
856     } while (!ready && wait_cycles--);
857
858     if(wait_cycles == 0) {
859         debugError("Timeout while waiting for flash\n");
860         return false;
861     }
862
863     return ready;
864 }
865
866 uint32_t
867 Device::getSessionBase()
868 {
869     EfcFlashGetSessionBaseCmd cmd;
870     if(!doEfcOverAVC(cmd)) {
871         debugError("Could not get session base address\n");
872         return 0; // FIXME: arbitrary
873     }
874     return cmd.m_address;
875 }
876
877 } // FireWorks
Note: See TracBrowser for help on using the browser.