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

Revision 1284, 26.0 kB (checked in by ppalmers, 16 years ago)

rewrite the audiofire mixer, is now generic for all audiofire devices

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 FFADODevice::ClockSourceVector
430 Device::getSupportedClockSources() {
431     FFADODevice::ClockSourceVector r;
432
433     if (!m_efc_discovery_done) {
434         debugError("EFC discovery not done yet!\n");
435         return r;
436     }
437
438     uint32_t active_clock=getClock();
439
440     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_INTERNAL)) {
441         debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock supported\n");
442         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_INTERNAL);
443         s.active=(active_clock == EFC_CMD_HW_CLOCK_INTERNAL);
444         if (s.type != eCT_Invalid) r.push_back(s);
445     }
446     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SYTMATCH)) {
447         debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match clock supported\n");
448         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SYTMATCH);
449         s.active=(active_clock == EFC_CMD_HW_CLOCK_SYTMATCH);
450         if (s.type != eCT_Invalid) r.push_back(s);
451     }
452     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_WORDCLOCK)) {
453         debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock supported\n");
454         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_WORDCLOCK);
455         s.active=(active_clock == EFC_CMD_HW_CLOCK_WORDCLOCK);
456         if (s.type != eCT_Invalid) r.push_back(s);
457     }
458     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SPDIF)) {
459         debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock supported\n");
460         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SPDIF);
461         s.active=(active_clock == EFC_CMD_HW_CLOCK_SPDIF);
462         if (s.type != eCT_Invalid) r.push_back(s);
463     }
464     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_1)) {
465         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock supported\n");
466         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_1);
467         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_1);
468         if (s.type != eCT_Invalid) r.push_back(s);
469     }
470     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_2)) {
471         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock supported\n");
472         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_2);
473         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_2);
474         if (s.type != eCT_Invalid) r.push_back(s);
475     }
476     return r;
477 }
478
479 bool
480 Device::isClockValid(uint32_t id) {
481     // always valid
482     if (id==EFC_CMD_HW_CLOCK_INTERNAL) return true;
483
484     // the polled values are used to detect
485     // whether clocks are valid
486     if (!updatePolledValues()) {
487         debugError("Could not update polled values\n");
488         return false;
489     }
490     return EFC_CMD_HW_CHECK_FLAG(m_Polled.m_status,id);
491 }
492
493 bool
494 Device::setActiveClockSource(ClockSource s) {
495     bool result;
496
497     debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
498
499     if(!isClockValid(s.id)) {
500         debugError("Clock not valid\n");
501         return false;
502     }
503
504     result=setClock(s.id);
505
506     // From the ECHO sources:
507     // "If this is a 1200F and the sample rate is being set via EFC, then
508     // send the "phy reconnect command" so the device will vanish and reappear
509     // with a new descriptor."
510
511 //     EfcPhyReconnectCmd rccmd;
512 //     if(!doEfcOverAVC(rccmd)) {
513 //         debugError("Phy reconnect failed\n");
514 //     } else {
515 //         // sleep for one second such that the phy can get reconnected
516 //         sleep(1);
517 //     }
518
519     return result;
520 }
521
522 FFADODevice::ClockSource
523 Device::getActiveClockSource() {
524     ClockSource s;
525     uint32_t active_clock=getClock();
526     s=clockIdToClockSource(active_clock);
527     s.active=true;
528     return s;
529 }
530
531 FFADODevice::ClockSource
532 Device::clockIdToClockSource(uint32_t clockid) {
533     ClockSource s;
534     debugOutput(DEBUG_LEVEL_VERBOSE, "clock id: %lu\n", clockid);
535
536     // the polled values are used to detect
537     // whether clocks are valid
538     if (!updatePolledValues()) {
539         debugError("Could not update polled values\n");
540         return s;
541     }
542
543     switch (clockid) {
544         case EFC_CMD_HW_CLOCK_INTERNAL:
545             debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock\n");
546             s.type=eCT_Internal;
547             s.description="Internal sync";
548             break;
549
550         case EFC_CMD_HW_CLOCK_SYTMATCH:
551             debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match\n");
552             s.type=eCT_SytMatch;
553             s.description="SYT Match";
554             break;
555
556         case EFC_CMD_HW_CLOCK_WORDCLOCK:
557             debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock\n");
558             s.type=eCT_WordClock;
559             s.description="Word Clock";
560             break;
561
562         case EFC_CMD_HW_CLOCK_SPDIF:
563             debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock\n");
564             s.type=eCT_SPDIF;
565             s.description="SPDIF";
566             break;
567
568         case EFC_CMD_HW_CLOCK_ADAT_1:
569             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock\n");
570             s.type=eCT_ADAT;
571             s.description="ADAT 1";
572             break;
573
574         case EFC_CMD_HW_CLOCK_ADAT_2:
575             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock\n");
576             s.type=eCT_ADAT;
577             s.description="ADAT 2";
578             break;
579
580         default:
581             debugError("Invalid clock id: %d\n",clockid);
582             return s; // return an invalid ClockSource
583     }
584
585     s.id=clockid;
586     s.valid=isClockValid(clockid);
587
588     return s;
589 }
590
591 uint32_t
592 Device::getClock() {
593     EfcGetClockCmd gccmd;
594     if (!doEfcOverAVC(gccmd)) {
595         debugError("Could not get clock info\n");
596         return EFC_CMD_HW_CLOCK_UNSPECIFIED;
597     }
598     debugOutput(DEBUG_LEVEL_VERBOSE, "Active clock: 0x%08lX\n",gccmd.m_clock);
599     gccmd.showEfcCmd();
600
601     return gccmd.m_clock;
602 }
603
604 bool
605 Device::setClock(uint32_t id) {
606     EfcGetClockCmd gccmd;
607     if (!doEfcOverAVC(gccmd)) {
608         debugError("Could not get clock info\n");
609         return false;
610     }
611     debugOutput(DEBUG_LEVEL_VERBOSE, "Set clock: 0x%08lX\n", id);
612
613     EfcSetClockCmd sccmd;
614     sccmd.m_clock=id;
615     sccmd.m_samplerate=gccmd.m_samplerate;
616     sccmd.m_index=0;
617     if (!doEfcOverAVC(sccmd)) {
618         debugError("Could not set clock info\n");
619         return false;
620     }
621     return true;
622 }
623
624 bool
625 Device::lockFlash(bool lock) {
626     EfcFlashLockCmd cmd;
627     cmd.m_lock = lock;
628
629     if(!doEfcOverAVC(cmd)) {
630         debugError("Flash lock failed\n");
631         return false;
632     }
633     return true;
634 }
635
636 bool
637 Device::writeFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
638
639     if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
640         debugError("bogus start/len: 0x%08X / %u\n", start, len);
641         return false;
642     }
643     if(start & 0x03) {
644         debugError("start address not quadlet aligned: 0x%08X\n", start);
645         return false;
646     }
647
648     uint32_t start_addr = start;
649     uint32_t stop_addr = start + len*4;
650     uint32_t *target_buffer = buffer;
651
652     EfcFlashWriteCmd cmd;
653     // write EFC_FLASH_SIZE_BYTES at a time
654     for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
655         cmd.m_address = start_addr;
656         unsigned int quads_to_write = (stop_addr - start_addr)/4;
657         if (quads_to_write > EFC_FLASH_SIZE_QUADS) {
658             quads_to_write = EFC_FLASH_SIZE_QUADS;
659         }
660         cmd.m_nb_quadlets = quads_to_write;
661         for(unsigned int i=0; i<quads_to_write; i++) {
662             cmd.m_data[i] = *target_buffer;
663             target_buffer++;
664         }
665         if(!doEfcOverAVC(cmd)) {
666             debugError("Flash write failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_write);
667             return false;
668         }
669     }
670     return true;
671 }
672
673 bool
674 Device::readFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
675
676     if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
677         debugError("bogus start/len: 0x%08X / %u\n", start, len);
678         return false;
679     }
680     if(start & 0x03) {
681         debugError("start address not quadlet aligned: 0x%08X\n", start);
682         return false;
683     }
684
685     uint32_t start_addr = start;
686     uint32_t stop_addr = start + len*4;
687     uint32_t *target_buffer = buffer;
688
689     EfcFlashReadCmd cmd;
690     // read EFC_FLASH_SIZE_BYTES at a time
691     for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
692         unsigned int quads_to_read = (stop_addr - start_addr)/4;
693         if (quads_to_read > EFC_FLASH_SIZE_QUADS) {
694             quads_to_read = EFC_FLASH_SIZE_QUADS;
695         }
696         uint32_t quadlets_read = 0;
697         int ntries = 10000;
698         do {
699             cmd.m_address = start_addr + quadlets_read*4;
700             unsigned int new_to_read = quads_to_read - quadlets_read;
701             cmd.m_nb_quadlets = new_to_read;
702             if(!doEfcOverAVC(cmd)) {
703                 debugError("Flash read failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_read);
704                 return false;
705             }
706             if(cmd.m_nb_quadlets != new_to_read) {
707                 debugOutput(DEBUG_LEVEL_VERBOSE,
708                             "Flash read didn't return enough data (%u/%u) \n",
709                             cmd.m_nb_quadlets, new_to_read);
710                 // continue trying
711             }
712             quadlets_read += cmd.m_nb_quadlets;
713
714             // copy content
715             for(unsigned int i=0; i<cmd.m_nb_quadlets; i++) {
716                 *target_buffer = cmd.m_data[i];
717                 target_buffer++;
718             }
719         } while(quadlets_read < quads_to_read && ntries--);
720         if(ntries==0) {
721             debugError("deadlock while reading flash\n");
722             return false;
723         }
724     }
725     return true;
726 }
727
728 bool
729 Device::eraseFlash(uint32_t addr) {
730     if(addr & 0x03) {
731         debugError("start address not quadlet aligned: 0x%08X\n", addr);
732         return false;
733     }
734     EfcFlashEraseCmd cmd;
735     cmd.m_address = addr;
736     if(!doEfcOverAVC(cmd)) {
737         if (cmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
738             return true;
739         }
740         debugError("Flash erase failed for block 0x%08X\n", addr);
741         return false;
742     }
743     return true;
744 }
745
746 bool
747 Device::eraseFlashBlocks(uint32_t start_address, unsigned int nb_quads)
748 {
749     uint32_t blocksize_bytes;
750     uint32_t blocksize_quads;
751     unsigned int quads_left = nb_quads;
752     bool success = true;
753
754     const unsigned int max_nb_tries = 10;
755     unsigned int nb_tries = 0;
756
757     do {
758         // the erase block size is fixed by the HW, and depends
759         // on the flash section we're in
760         if (start_address < MAINBLOCKS_BASE_OFFSET_BYTES)
761                 blocksize_bytes = PROGRAMBLOCK_SIZE_BYTES;
762         else
763                 blocksize_bytes = MAINBLOCK_SIZE_BYTES;
764         start_address &= ~(blocksize_bytes - 1);
765         blocksize_quads = blocksize_bytes / 4;
766
767         uint32_t verify[blocksize_quads];
768
769         // corner case: requested to erase less than one block
770         if (blocksize_quads > quads_left) {
771             blocksize_quads = quads_left;
772         }
773
774         // do the actual erase
775         if (!eraseFlash(start_address)) {
776             debugWarning("Could not erase flash block at 0x%08X\n", start_address);
777             success = false;
778         } else {
779             // wait for the flash to become ready again
780             if (!waitForFlash(ECHO_FLASH_ERASE_TIMEOUT_MILLISECS)) {
781                 debugError("Wait for flash timed out at address 0x%08X\n", start_address);
782                 return false;
783             }
784
785             // verify that the block is empty as an extra precaution
786             if (!readFlash(start_address, blocksize_quads, verify)) {
787                 debugError("Could not read flash block at 0x%08X\n", start_address);
788                 return false;
789             }
790
791             // everything should be 0xFFFFFFFF if the erase was successful
792             for (unsigned int i = 0; i < blocksize_quads; i++) {
793                 if (0xFFFFFFFF != verify[i]) {
794                     debugWarning("Flash erase verification failed.\n");
795                     success = false;
796                     break;
797                 }
798             }
799         }
800
801         if (success) {
802             start_address += blocksize_bytes;
803             quads_left -= blocksize_quads;
804             nb_tries = 0;
805         } else {
806             nb_tries++;
807         }
808         if (nb_tries > max_nb_tries) {
809             debugError("Needed too many tries to erase flash at 0x%08X\n", start_address);
810             return false;
811         }
812     } while (quads_left > 0);
813
814     return true;
815 }
816
817 bool
818 Device::waitForFlash(unsigned int msecs)
819 {
820     bool ready;
821
822     EfcFlashGetStatusCmd statusCmd;
823     const unsigned int time_to_sleep_usecs = 10000;
824     int wait_cycles = msecs * 1000 / time_to_sleep_usecs;
825
826     do {
827         if (!doEfcOverAVC(statusCmd)) {
828             debugError("Could not read flash status\n");
829             return false;
830         }
831         if (statusCmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
832             ready = false;
833         } else {
834             ready = statusCmd.m_ready;
835         }
836         usleep(time_to_sleep_usecs);
837     } while (!ready && wait_cycles--);
838
839     if(wait_cycles == 0) {
840         debugError("Timeout while waiting for flash\n");
841         return false;
842     }
843
844     return ready;
845 }
846
847 uint32_t
848 Device::getSessionBase()
849 {
850     EfcFlashGetSessionBaseCmd cmd;
851     if(!doEfcOverAVC(cmd)) {
852         debugError("Could not get session base address\n");
853         return 0; // FIXME: arbitrary
854     }
855     return cmd.m_address;
856 }
857
858 } // FireWorks
Note: See TracBrowser for help on using the browser.