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

Revision 1290, 26.8 kB (checked in by ppalmers, 16 years ago)

add CRC calculation, support saving of session block. fix AF8/AF12 bug on locking flash.

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     // some hardware doesn't need/support flash lock
646     if (m_HwInfo.hasDSP()) {
647         debugOutput(DEBUG_LEVEL_VERBOSE, "flash lock not needed\n");
648         return true;
649     }
650
651     EfcFlashLockCmd cmd;
652     cmd.m_lock = lock;
653
654     if(!doEfcOverAVC(cmd)) {
655         debugError("Flash lock failed\n");
656         return false;
657     }
658     return true;
659 }
660
661 bool
662 Device::writeFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
663
664     if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
665         debugError("bogus start/len: 0x%08X / %u\n", start, len);
666         return false;
667     }
668     if(start & 0x03) {
669         debugError("start address not quadlet aligned: 0x%08X\n", start);
670         return false;
671     }
672
673     uint32_t start_addr = start;
674     uint32_t stop_addr = start + len*4;
675     uint32_t *target_buffer = buffer;
676
677     EfcFlashWriteCmd cmd;
678     // write EFC_FLASH_SIZE_BYTES at a time
679     for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
680         cmd.m_address = start_addr;
681         unsigned int quads_to_write = (stop_addr - start_addr)/4;
682         if (quads_to_write > EFC_FLASH_SIZE_QUADS) {
683             quads_to_write = EFC_FLASH_SIZE_QUADS;
684         }
685         cmd.m_nb_quadlets = quads_to_write;
686         for(unsigned int i=0; i<quads_to_write; i++) {
687             cmd.m_data[i] = *target_buffer;
688             target_buffer++;
689         }
690         if(!doEfcOverAVC(cmd)) {
691             debugError("Flash write failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_write);
692             return false;
693         }
694     }
695     return true;
696 }
697
698 bool
699 Device::readFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
700
701     if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
702         debugError("bogus start/len: 0x%08X / %u\n", start, len);
703         return false;
704     }
705     if(start & 0x03) {
706         debugError("start address not quadlet aligned: 0x%08X\n", start);
707         return false;
708     }
709
710     uint32_t start_addr = start;
711     uint32_t stop_addr = start + len*4;
712     uint32_t *target_buffer = buffer;
713
714     EfcFlashReadCmd cmd;
715     // read EFC_FLASH_SIZE_BYTES at a time
716     for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
717         unsigned int quads_to_read = (stop_addr - start_addr)/4;
718         if (quads_to_read > EFC_FLASH_SIZE_QUADS) {
719             quads_to_read = EFC_FLASH_SIZE_QUADS;
720         }
721         uint32_t quadlets_read = 0;
722         int ntries = 10000;
723         do {
724             cmd.m_address = start_addr + quadlets_read*4;
725             unsigned int new_to_read = quads_to_read - quadlets_read;
726             cmd.m_nb_quadlets = new_to_read;
727             if(!doEfcOverAVC(cmd)) {
728                 debugError("Flash read failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_read);
729                 return false;
730             }
731             if(cmd.m_nb_quadlets != new_to_read) {
732                 debugOutput(DEBUG_LEVEL_VERBOSE,
733                             "Flash read didn't return enough data (%u/%u) \n",
734                             cmd.m_nb_quadlets, new_to_read);
735                 // continue trying
736             }
737             quadlets_read += cmd.m_nb_quadlets;
738
739             // copy content
740             for(unsigned int i=0; i<cmd.m_nb_quadlets; i++) {
741                 *target_buffer = cmd.m_data[i];
742                 target_buffer++;
743             }
744         } while(quadlets_read < quads_to_read && ntries--);
745         if(ntries==0) {
746             debugError("deadlock while reading flash\n");
747             return false;
748         }
749     }
750     return true;
751 }
752
753 bool
754 Device::eraseFlash(uint32_t addr) {
755     if(addr & 0x03) {
756         debugError("start address not quadlet aligned: 0x%08X\n", addr);
757         return false;
758     }
759     EfcFlashEraseCmd cmd;
760     cmd.m_address = addr;
761     if(!doEfcOverAVC(cmd)) {
762         if (cmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
763             return true;
764         }
765         debugError("Flash erase failed for block 0x%08X\n", addr);
766         return false;
767     }
768     return true;
769 }
770
771 bool
772 Device::eraseFlashBlocks(uint32_t start_address, unsigned int nb_quads)
773 {
774     uint32_t blocksize_bytes;
775     uint32_t blocksize_quads;
776     unsigned int quads_left = nb_quads;
777     bool success = true;
778
779     const unsigned int max_nb_tries = 10;
780     unsigned int nb_tries = 0;
781
782     do {
783         // the erase block size is fixed by the HW, and depends
784         // on the flash section we're in
785         if (start_address < MAINBLOCKS_BASE_OFFSET_BYTES)
786                 blocksize_bytes = PROGRAMBLOCK_SIZE_BYTES;
787         else
788                 blocksize_bytes = MAINBLOCK_SIZE_BYTES;
789         start_address &= ~(blocksize_bytes - 1);
790         blocksize_quads = blocksize_bytes / 4;
791
792         uint32_t verify[blocksize_quads];
793
794         // corner case: requested to erase less than one block
795         if (blocksize_quads > quads_left) {
796             blocksize_quads = quads_left;
797         }
798
799         // do the actual erase
800         if (!eraseFlash(start_address)) {
801             debugWarning("Could not erase flash block at 0x%08X\n", start_address);
802             success = false;
803         } else {
804             // wait for the flash to become ready again
805             if (!waitForFlash(ECHO_FLASH_ERASE_TIMEOUT_MILLISECS)) {
806                 debugError("Wait for flash timed out at address 0x%08X\n", start_address);
807                 return false;
808             }
809
810             // verify that the block is empty as an extra precaution
811             if (!readFlash(start_address, blocksize_quads, verify)) {
812                 debugError("Could not read flash block at 0x%08X\n", start_address);
813                 return false;
814             }
815
816             // everything should be 0xFFFFFFFF if the erase was successful
817             for (unsigned int i = 0; i < blocksize_quads; i++) {
818                 if (0xFFFFFFFF != verify[i]) {
819                     debugWarning("Flash erase verification failed.\n");
820                     success = false;
821                     break;
822                 }
823             }
824         }
825
826         if (success) {
827             start_address += blocksize_bytes;
828             quads_left -= blocksize_quads;
829             nb_tries = 0;
830         } else {
831             nb_tries++;
832         }
833         if (nb_tries > max_nb_tries) {
834             debugError("Needed too many tries to erase flash at 0x%08X\n", start_address);
835             return false;
836         }
837     } while (quads_left > 0);
838
839     return true;
840 }
841
842 bool
843 Device::waitForFlash(unsigned int msecs)
844 {
845     bool ready;
846
847     EfcFlashGetStatusCmd statusCmd;
848     const unsigned int time_to_sleep_usecs = 10000;
849     int wait_cycles = msecs * 1000 / time_to_sleep_usecs;
850
851     do {
852         if (!doEfcOverAVC(statusCmd)) {
853             debugError("Could not read flash status\n");
854             return false;
855         }
856         if (statusCmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
857             ready = false;
858         } else {
859             ready = statusCmd.m_ready;
860         }
861         usleep(time_to_sleep_usecs);
862     } while (!ready && wait_cycles--);
863
864     if(wait_cycles == 0) {
865         debugError("Timeout while waiting for flash\n");
866         return false;
867     }
868
869     return ready;
870 }
871
872 uint32_t
873 Device::getSessionBase()
874 {
875     EfcFlashGetSessionBaseCmd cmd;
876     if(!doEfcOverAVC(cmd)) {
877         debugError("Could not get session base address\n");
878         return 0; // FIXME: arbitrary
879     }
880     return cmd.m_address;
881 }
882
883 } // FireWorks
Note: See TracBrowser for help on using the browser.