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

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

fix initialization bug

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