fireworks: Remove useless execution of command for polled values
[ffado.git] / libffado / src / fireworks / fireworks_device.cpp
blob0123e93c2305a5fe03864e13f2b8f136257f3687
1 /*
2 * Copyright (C) 2005-2008 by Pieter Palmers
4 * This file is part of FFADO
5 * FFADO = Free Firewire (pro-)audio drivers for linux
7 * FFADO is based upon FreeBoB.
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.
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.
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/>.
24 // #include "config.h"
25 #include "devicemanager.h"
26 #include "fireworks_device.h"
27 #include "efc/efc_avc_cmd.h"
28 #include "efc/efc_cmd.h"
29 #include "efc/efc_cmds_hardware.h"
30 #include "efc/efc_cmds_hardware_ctrl.h"
31 #include "efc/efc_cmds_flash.h"
33 #include "audiofire/audiofire_device.h"
35 #include "libieee1394/configrom.h"
36 #include "libieee1394/ieee1394service.h"
38 #include "fireworks/fireworks_control.h"
40 #include "libutil/PosixMutex.h"
41 #include "libutil/SystemTimeSource.h"
43 #include "IntelFlashMap.h"
45 #define ECHO_FLASH_ERASE_TIMEOUT_MILLISECS 2000
46 #define FIREWORKS_MIN_FIRMWARE_VERSION 0x04080000
48 #include <sstream>
49 #include <unistd.h>
50 using namespace std;
52 // FireWorks is the platform used and developed by ECHO AUDIO
53 namespace FireWorks {
55 Device::Device(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
56 : GenericAVC::Device( d, configRom)
57 , m_poll_lock( new Util::PosixMutex("DEVPOLL") )
58 , m_efc_discovery_done ( false )
59 , m_MixerContainer ( NULL )
60 , m_HwInfoContainer ( NULL )
62 debugOutput( DEBUG_LEVEL_VERBOSE, "Created FireWorks::Device (NodeID %d)\n",
63 getConfigRom().getNodeId() );
66 Device::~Device()
68 destroyMixer();
71 void
72 Device::showDevice()
74 debugOutput(DEBUG_LEVEL_VERBOSE, "This is a FireWorks::Device\n");
75 if ( !m_efc_discovery_done) {
76 if (!discoverUsingEFC()) {
77 debugError("EFC discovery failed\n");
80 m_HwInfo.showEfcCmd();
81 GenericAVC::Device::showDevice();
84 bool
85 Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
87 if(generic) {
88 // try an EFC command
89 EfcOverAVCCmd cmd( configRom.get1394Service() );
90 cmd.setCommandType( AVC::AVCCommand::eCT_Control );
91 cmd.setNodeId( configRom.getNodeId() );
92 cmd.setSubunitType( AVC::eST_Unit );
93 cmd.setSubunitId( 0xff );
94 cmd.setVerbose( configRom.getVerboseLevel() );
96 EfcHardwareInfoCmd hwInfo;
97 hwInfo.setVerboseLevel(configRom.getVerboseLevel());
98 cmd.m_cmd = &hwInfo;
100 if ( !cmd.fire()) {
101 return false;
104 if ( cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
105 return false;
107 if ( hwInfo.m_header.retval != EfcCmd::eERV_Ok
108 && hwInfo.m_header.retval != EfcCmd::eERV_FlashBusy) {
109 debugError( "EFC command failed\n" );
110 return false;
112 return true;
113 } else {
114 unsigned int vendorId = configRom.getNodeVendorId();
115 unsigned int modelId = configRom.getModelId();
116 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
117 return c.isValid(vme) && vme.driver == Util::Configuration::eD_FireWorks;
121 bool
122 Device::discover()
124 unsigned int vendorId = getConfigRom().getNodeVendorId();
125 unsigned int modelId = getConfigRom().getModelId();
127 Util::Configuration &c = getDeviceManager().getConfiguration();
128 Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
130 if (c.isValid(vme) && vme.driver == Util::Configuration::eD_FireWorks) {
131 debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
132 vme.vendor_name.c_str(),
133 vme.model_name.c_str());
134 } else {
135 debugWarning("Using generic ECHO Audio FireWorks support for unsupported device '%s %s'\n",
136 getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
139 // get the info from the EFC
140 if ( !discoverUsingEFC() ) {
141 return false;
144 // discover AVC-wise
145 if ( !GenericAVC::Device::discoverGeneric() ) {
146 debugError( "Could not discover GenericAVC::Device\n" );
147 return false;
150 if(!buildMixer()) {
151 debugWarning("Could not build mixer\n");
154 return true;
157 bool
158 Device::discoverUsingEFC()
160 m_efc_discovery_done = false;
161 m_HwInfo.setVerboseLevel(getDebugLevel());
163 if (!doEfcOverAVC(m_HwInfo)) {
164 debugError("Could not read hardware capabilities\n");
165 return false;
168 // check the firmware version
169 if (m_HwInfo.m_arm_version < FIREWORKS_MIN_FIRMWARE_VERSION) {
170 debugError("Firmware version %u.%u (rev %u) not recent enough. FFADO requires at least version %u.%u (rev %u).\n",
171 (m_HwInfo.m_arm_version >> 24) & 0xFF,
172 (m_HwInfo.m_arm_version >> 16) & 0xFF,
173 (m_HwInfo.m_arm_version >> 0) & 0xFFFF,
174 (FIREWORKS_MIN_FIRMWARE_VERSION >> 24) & 0xFF,
175 (FIREWORKS_MIN_FIRMWARE_VERSION >> 16) & 0xFF,
176 (FIREWORKS_MIN_FIRMWARE_VERSION >> 0) & 0xFFFF
178 return false;
181 // save the EFC version, since some stuff
182 // depends on this
183 m_efc_version = m_HwInfo.m_header.version;
185 m_current_clock = -1;
187 m_efc_discovery_done = true;
188 return true;
191 FFADODevice *
192 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
194 unsigned int vendorId = configRom->getNodeVendorId();
195 // unsigned int modelId = configRom->getModelId();
197 switch(vendorId) {
198 case FW_VENDORID_ECHO: return new ECHO::AudioFire(d, configRom );
199 default: return new Device(d, configRom );
203 bool Device::doEfcOverAVC(EfcCmd &c)
205 EfcOverAVCCmd cmd( get1394Service() );
206 cmd.setCommandType( AVC::AVCCommand::eCT_Control );
207 cmd.setNodeId( getConfigRom().getNodeId() );
208 cmd.setSubunitType( AVC::eST_Unit );
209 cmd.setSubunitId( 0xff );
211 cmd.setVerbose( getDebugLevel() );
212 cmd.m_cmd = &c;
214 if (!cmd.fire()) {
215 debugError( "EfcOverAVCCmd command failed\n" );
216 c.showEfcCmd();
217 return false;
220 if ( cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
221 debugError( "EfcOverAVCCmd not accepted\n" );
222 return false;
225 if ( c.m_header.retval != EfcCmd::eERV_Ok
226 && c.m_header.retval != EfcCmd::eERV_FlashBusy) {
227 debugError( "EFC command failed\n" );
228 c.showEfcCmd();
229 return false;
232 return true;
235 bool
236 Device::buildMixer()
238 bool result=true;
239 debugOutput(DEBUG_LEVEL_VERBOSE, "Building a FireWorks mixer...\n");
241 destroyMixer();
243 // create the mixer object container
244 m_MixerContainer = new Control::Container(this, "Mixer");
246 if (!m_MixerContainer) {
247 debugError("Could not create mixer container...\n");
248 return false;
251 // create control objects for the audiofire
253 // matrix mix controls
254 result &= m_MixerContainer->addElement(
255 new MonitorControl(*this, MonitorControl::eMC_Gain, "MonitorGain"));
257 result &= m_MixerContainer->addElement(
258 new MonitorControl(*this, MonitorControl::eMC_Mute, "MonitorMute"));
260 result &= m_MixerContainer->addElement(
261 new MonitorControl(*this, MonitorControl::eMC_Solo, "MonitorSolo"));
263 result &= m_MixerContainer->addElement(
264 new MonitorControl(*this, MonitorControl::eMC_Pan, "MonitorPan"));
266 // Playback mix controls
267 for (unsigned int ch=0;ch<m_HwInfo.m_nb_1394_playback_channels;ch++) {
268 std::ostringstream node_name;
269 node_name << "PC" << ch;
271 result &= m_MixerContainer->addElement(
272 new BinaryControl(*this, eMT_PlaybackMix, eMC_Mute, ch, 0, node_name.str()+"Mute"));
273 result &= m_MixerContainer->addElement(
274 new BinaryControl(*this, eMT_PlaybackMix, eMC_Solo, ch, 0, node_name.str()+"Solo"));
275 result &= m_MixerContainer->addElement(
276 new SimpleControl(*this, eMT_PlaybackMix, eMC_Gain, ch, node_name.str()+"Gain"));
279 // Physical output mix controls
280 for (unsigned int ch=0;ch<m_HwInfo.m_nb_phys_audio_out;ch++) {
281 std::ostringstream node_name;
282 node_name << "OUT" << ch;
284 result &= m_MixerContainer->addElement(
285 new BinaryControl(*this, eMT_PhysicalOutputMix, eMC_Mute, ch, 0, node_name.str()+"Mute"));
286 result &= m_MixerContainer->addElement(
287 new BinaryControl(*this, eMT_PhysicalOutputMix, eMC_Nominal, ch, 1, node_name.str()+"Nominal"));
288 result &= m_MixerContainer->addElement(
289 new SimpleControl(*this, eMT_PhysicalOutputMix, eMC_Gain, ch, node_name.str()+"Gain"));
292 // Physical input mix controls
293 for (unsigned int ch=0;ch<m_HwInfo.m_nb_phys_audio_in;ch++) {
294 std::ostringstream node_name;
295 node_name << "IN" << ch;
297 // result &= m_MixerContainer->addElement(
298 // new BinaryControl(*this, eMT_PhysicalInputMix, eMC_Pad, ch, 0, node_name.str()+"Pad"));
299 result &= m_MixerContainer->addElement(
300 new BinaryControl(*this, eMT_PhysicalInputMix, eMC_Nominal, ch, 1, node_name.str()+"Nominal"));
303 // add hardware information controls
304 m_HwInfoContainer = new Control::Container(this, "HwInfo");
305 result &= m_HwInfoContainer->addElement(
306 new HwInfoControl(*this, HwInfoControl::eHIF_PhysicalAudioOutCount, "PhysicalAudioOutCount"));
307 result &= m_HwInfoContainer->addElement(
308 new HwInfoControl(*this, HwInfoControl::eHIF_PhysicalAudioInCount, "PhysicalAudioInCount"));
309 result &= m_HwInfoContainer->addElement(
310 new HwInfoControl(*this, HwInfoControl::eHIF_1394PlaybackCount, "1394PlaybackCount"));
311 result &= m_HwInfoContainer->addElement(
312 new HwInfoControl(*this, HwInfoControl::eHIF_1394RecordCount, "1394RecordCount"));
313 result &= m_HwInfoContainer->addElement(
314 new HwInfoControl(*this, HwInfoControl::eHIF_GroupOutCount, "GroupOutCount"));
315 result &= m_HwInfoContainer->addElement(
316 new HwInfoControl(*this, HwInfoControl::eHIF_GroupInCount, "GroupInCount"));
317 result &= m_HwInfoContainer->addElement(
318 new HwInfoControl(*this, HwInfoControl::eHIF_PhantomPower, "PhantomPower"));
319 result &= m_HwInfoContainer->addElement(
320 new HwInfoControl(*this, HwInfoControl::eHIF_OpticalInterface, "OpticalInterface"));
321 result &= m_HwInfoContainer->addElement(
322 new HwInfoControl(*this, HwInfoControl::eHIF_PlaybackRouting, "PlaybackRouting"));
324 // add a save settings control
325 result &= this->addElement(
326 new MultiControl(*this, MultiControl::eT_SaveSession, "SaveSettings"));
328 // add an identify control
329 result &= this->addElement(
330 new MultiControl(*this, MultiControl::eT_Identify, "Identify"));
332 // spdif mode control
333 result &= this->addElement(
334 new SpdifModeControl(*this, "SpdifMode"));
336 // check for IO config controls and add them if necessary
337 if(m_HwInfo.hasMirroring()) {
338 result &= this->addElement(
339 new IOConfigControl(*this, eCR_Mirror, "ChannelMirror"));
341 if(m_HwInfo.hasOpticalInterface()) {
342 result &= this->addElement(
343 new IOConfigControl(*this, eCR_DigitalInterface, "DigitalInterface"));
345 if(m_HwInfo.hasSoftwarePhantom()) {
346 result &= this->addElement(
347 new IOConfigControl(*this, eCR_Phantom, "PhantomPower"));
349 if(m_HwInfo.hasPlaybackRouting()) {
350 result &= this->addElement(
351 new PlaybackRoutingControl(*this, "PlaybackRouting"));
354 if (!result) {
355 debugWarning("One or more control elements could not be created.");
356 // clean up those that couldn't be created
357 destroyMixer();
358 return false;
361 if (!addElement(m_MixerContainer)) {
362 debugWarning("Could not register mixer to device\n");
363 // clean up
364 destroyMixer();
365 return false;
368 if (!addElement(m_HwInfoContainer)) {
369 debugWarning("Could not register hwinfo to device\n");
370 // clean up
371 destroyMixer();
372 return false;
375 // load the session block
376 if (!loadSession()) {
377 debugWarning("Could not load session\n");
380 return true;
383 bool
384 Device::destroyMixer()
386 debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n");
388 if (m_MixerContainer == NULL) {
389 debugOutput(DEBUG_LEVEL_VERBOSE, "no mixer to destroy...\n");
390 } else {
391 if (!deleteElement(m_MixerContainer)) {
392 debugError("Mixer present but not registered to the avdevice\n");
393 return false;
396 // remove and delete (as in free) child control elements
397 m_MixerContainer->clearElements(true);
398 delete m_MixerContainer;
399 m_MixerContainer = NULL;
402 if (m_HwInfoContainer == NULL) {
403 debugOutput(DEBUG_LEVEL_VERBOSE, "no hwinfo to destroy...\n");
404 } else {
405 if (!deleteElement(m_HwInfoContainer)) {
406 debugError("HwInfo present but not registered to the avdevice\n");
407 return false;
410 // remove and delete (as in free) child control elements
411 m_HwInfoContainer->clearElements(true);
412 delete m_HwInfoContainer;
413 m_HwInfoContainer = NULL;
415 return true;
418 bool
419 Device::saveSession()
421 // save the session block
422 // if ( !updateSession() ) {
423 // debugError( "Could not update session\n" );
424 // } else {
425 if ( !m_session.saveToDevice(*this) ) {
426 debugError( "Could not save session block\n" );
428 // }
430 return true;
433 bool
434 Device::loadSession()
436 if ( !m_session.loadFromDevice(*this) ) {
437 debugError( "Could not load session block\n" );
438 return false;
440 return true;
443 bool
444 Device::updatePolledValues() {
445 Util::MutexLockHelper lock(*m_poll_lock);
446 return doEfcOverAVC(m_Polled);
449 #define ECHO_CHECK_AND_ADD_SR(v, x) \
450 { if(x >= m_HwInfo.m_min_sample_rate && x <= m_HwInfo.m_max_sample_rate) \
451 v.push_back(x); }
452 std::vector<int>
453 Device::getSupportedSamplingFrequencies()
455 std::vector<int> frequencies;
456 ECHO_CHECK_AND_ADD_SR(frequencies, 22050);
457 ECHO_CHECK_AND_ADD_SR(frequencies, 24000);
458 ECHO_CHECK_AND_ADD_SR(frequencies, 32000);
459 ECHO_CHECK_AND_ADD_SR(frequencies, 44100);
460 ECHO_CHECK_AND_ADD_SR(frequencies, 48000);
461 ECHO_CHECK_AND_ADD_SR(frequencies, 88200);
462 ECHO_CHECK_AND_ADD_SR(frequencies, 96000);
463 ECHO_CHECK_AND_ADD_SR(frequencies, 176400);
464 ECHO_CHECK_AND_ADD_SR(frequencies, 192000);
465 return frequencies;
468 FFADODevice::ClockSourceVector
469 Device::getSupportedClockSources() {
470 FFADODevice::ClockSourceVector r;
472 if (!m_efc_discovery_done) {
473 debugError("EFC discovery not done yet!\n");
474 return r;
477 uint32_t active_clock=getClock();
479 if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_INTERNAL)) {
480 debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock supported\n");
481 ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_INTERNAL);
482 s.active=(active_clock == EFC_CMD_HW_CLOCK_INTERNAL);
483 if (s.type != eCT_Invalid) r.push_back(s);
485 if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SYTMATCH)) {
486 debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match clock supported\n");
487 ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SYTMATCH);
488 s.active=(active_clock == EFC_CMD_HW_CLOCK_SYTMATCH);
489 if (s.type != eCT_Invalid) r.push_back(s);
491 if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_WORDCLOCK)) {
492 debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock supported\n");
493 ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_WORDCLOCK);
494 s.active=(active_clock == EFC_CMD_HW_CLOCK_WORDCLOCK);
495 if (s.type != eCT_Invalid) r.push_back(s);
497 if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SPDIF)) {
498 debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock supported\n");
499 ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SPDIF);
500 s.active=(active_clock == EFC_CMD_HW_CLOCK_SPDIF);
501 if (s.type != eCT_Invalid) r.push_back(s);
503 if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_1)) {
504 debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock supported\n");
505 ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_1);
506 s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_1);
507 if (s.type != eCT_Invalid) r.push_back(s);
509 if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_2)) {
510 debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock supported\n");
511 ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_2);
512 s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_2);
513 if (s.type != eCT_Invalid) r.push_back(s);
515 return r;
518 bool
519 Device::isClockValid(uint32_t id) {
520 // always valid
521 if (id==EFC_CMD_HW_CLOCK_INTERNAL)
522 return true;
524 // the polled values tell thether each clock source is detected or not
525 if (!updatePolledValues()) {
526 debugError("Could not update polled values\n");
527 return false;
529 return EFC_CMD_HW_CHECK_FLAG(m_Polled.m_status,id);
532 bool
533 Device::setActiveClockSource(ClockSource s) {
534 bool result;
536 debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
538 if(!isClockValid(s.id)) {
539 debugError("Clock not valid\n");
540 return false;
543 result = setClock(s.id);
545 // From the ECHO sources:
546 // "If this is a 1200F and the sample rate is being set via EFC, then
547 // send the "phy reconnect command" so the device will vanish and reappear
548 // with a new descriptor."
550 // EfcPhyReconnectCmd rccmd;
551 // if(!doEfcOverAVC(rccmd)) {
552 // debugError("Phy reconnect failed\n");
553 // } else {
554 // // sleep for one second such that the phy can get reconnected
555 // sleep(1);
556 // }
558 return result;
561 FFADODevice::ClockSource
562 Device::getActiveClockSource() {
563 ClockSource s;
564 uint32_t active_clock=getClock();
565 s=clockIdToClockSource(active_clock);
566 s.active=true;
567 return s;
570 FFADODevice::ClockSource
571 Device::clockIdToClockSource(uint32_t clockid) {
572 ClockSource s;
573 debugOutput(DEBUG_LEVEL_VERBOSE, "clock id: %u\n", clockid);
575 switch (clockid) {
576 case EFC_CMD_HW_CLOCK_INTERNAL:
577 debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock\n");
578 s.type=eCT_Internal;
579 s.description="Internal sync";
580 break;
582 case EFC_CMD_HW_CLOCK_SYTMATCH:
583 debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match\n");
584 s.type=eCT_SytMatch;
585 s.description="SYT Match";
586 break;
588 case EFC_CMD_HW_CLOCK_WORDCLOCK:
589 debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock\n");
590 s.type=eCT_WordClock;
591 s.description="Word Clock";
592 break;
594 case EFC_CMD_HW_CLOCK_SPDIF:
595 debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock\n");
596 s.type=eCT_SPDIF;
597 s.description="SPDIF";
598 break;
600 case EFC_CMD_HW_CLOCK_ADAT_1:
601 debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock\n");
602 s.type=eCT_ADAT;
603 s.description="ADAT 1";
604 break;
606 case EFC_CMD_HW_CLOCK_ADAT_2:
607 debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock\n");
608 s.type=eCT_ADAT;
609 s.description="ADAT 2";
610 break;
612 default:
613 debugError("Invalid clock id: %d\n",clockid);
614 return s; // return an invalid ClockSource
617 s.id=clockid;
618 s.valid=isClockValid(clockid);
620 return s;
623 uint32_t Device::getClock()
625 uint32_t clock;
627 EfcGetClockCmd gccmd;
628 if (!doEfcOverAVC(gccmd)) {
629 debugError("Could not get clock info\n");
630 /* fallback to cache */
631 if (m_current_clock >= 0)
632 clock = m_current_clock;
633 /* fallback to internal */
634 else if (setClock(EFC_CMD_HW_CLOCK_INTERNAL))
635 clock = EFC_CMD_HW_CLOCK_INTERNAL;
636 /* fatal error */
637 else
638 clock = EFC_CMD_HW_CLOCK_UNSPECIFIED;
639 } else
640 clock = gccmd.m_clock;
642 debugOutput(DEBUG_LEVEL_VERBOSE, "Active clock: 0x%08X\n", clock);
643 gccmd.showEfcCmd();
645 return clock;
648 bool Device::setClock(uint32_t id)
650 int sampling_rate = getSamplingFrequency();
651 if (!sampling_rate)
652 return false;
654 debugOutput(DEBUG_LEVEL_VERBOSE, "Set clock: 0x%08X\n", id);
656 EfcSetClockCmd sccmd;
657 sccmd.m_clock=id;
658 sccmd.m_samplerate= sampling_rate;
659 sccmd.m_index=0;
660 if (!doEfcOverAVC(sccmd)) {
661 debugError("Could not set clock info\n");
662 return false;
665 m_current_clock = id;
666 return true;
669 bool
670 Device::lockFlash(bool lock) {
671 // some hardware doesn't need/support flash lock
672 if (m_HwInfo.hasDSP()) {
673 debugOutput(DEBUG_LEVEL_VERBOSE, "flash lock not needed\n");
674 return true;
677 EfcFlashLockCmd cmd;
678 cmd.m_lock = lock;
680 if(!doEfcOverAVC(cmd)) {
681 debugError("Flash lock failed\n");
682 return false;
684 return true;
687 bool
688 Device::writeFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
690 if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
691 debugError("bogus start/len: 0x%08X / %u\n", start, len);
692 return false;
694 if(start & 0x03) {
695 debugError("start address not quadlet aligned: 0x%08X\n", start);
696 return false;
699 uint32_t start_addr = start;
700 uint32_t stop_addr = start + len*4;
701 uint32_t *target_buffer = buffer;
703 EfcFlashWriteCmd cmd;
704 // write EFC_FLASH_SIZE_BYTES at a time
705 for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
706 cmd.m_address = start_addr;
707 unsigned int quads_to_write = (stop_addr - start_addr)/4;
708 if (quads_to_write > EFC_FLASH_SIZE_QUADS) {
709 quads_to_write = EFC_FLASH_SIZE_QUADS;
711 cmd.m_nb_quadlets = quads_to_write;
712 for(unsigned int i=0; i<quads_to_write; i++) {
713 cmd.m_data[i] = *target_buffer;
714 target_buffer++;
716 if(!doEfcOverAVC(cmd)) {
717 debugError("Flash write failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_write);
718 return false;
721 return true;
724 bool
725 Device::readFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
727 if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
728 debugError("bogus start/len: 0x%08X / %u\n", start, len);
729 return false;
731 if(start & 0x03) {
732 debugError("start address not quadlet aligned: 0x%08X\n", start);
733 return false;
736 uint32_t start_addr = start;
737 uint32_t stop_addr = start + len*4;
738 uint32_t *target_buffer = buffer;
740 EfcFlashReadCmd cmd;
741 // read EFC_FLASH_SIZE_BYTES at a time
742 for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
743 unsigned int quads_to_read = (stop_addr - start_addr)/4;
744 if (quads_to_read > EFC_FLASH_SIZE_QUADS) {
745 quads_to_read = EFC_FLASH_SIZE_QUADS;
747 uint32_t quadlets_read = 0;
748 int ntries = 10000;
749 do {
750 cmd.m_address = start_addr + quadlets_read*4;
751 unsigned int new_to_read = quads_to_read - quadlets_read;
752 cmd.m_nb_quadlets = new_to_read;
753 if(!doEfcOverAVC(cmd)) {
754 debugError("Flash read failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_read);
755 return false;
757 if(cmd.m_nb_quadlets != new_to_read) {
758 debugOutput(DEBUG_LEVEL_VERBOSE,
759 "Flash read didn't return enough data (%u/%u) \n",
760 cmd.m_nb_quadlets, new_to_read);
761 // continue trying
763 quadlets_read += cmd.m_nb_quadlets;
765 // copy content
766 for(unsigned int i=0; i<cmd.m_nb_quadlets; i++) {
767 *target_buffer = cmd.m_data[i];
768 target_buffer++;
770 } while(quadlets_read < quads_to_read && ntries--);
771 if(ntries==0) {
772 debugError("deadlock while reading flash\n");
773 return false;
776 return true;
779 bool
780 Device::eraseFlash(uint32_t addr) {
781 if(addr & 0x03) {
782 debugError("start address not quadlet aligned: 0x%08X\n", addr);
783 return false;
785 EfcFlashEraseCmd cmd;
786 cmd.m_address = addr;
787 if(!doEfcOverAVC(cmd)) {
788 if (cmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
789 return true;
791 debugError("Flash erase failed for block 0x%08X\n", addr);
792 return false;
794 return true;
797 bool
798 Device::eraseFlashBlocks(uint32_t start_address, unsigned int nb_quads)
800 uint32_t blocksize_bytes;
801 uint32_t blocksize_quads;
802 unsigned int quads_left = nb_quads;
803 bool success = true;
805 const unsigned int max_nb_tries = 10;
806 unsigned int nb_tries = 0;
808 do {
809 // the erase block size is fixed by the HW, and depends
810 // on the flash section we're in
811 if (start_address < MAINBLOCKS_BASE_OFFSET_BYTES)
812 blocksize_bytes = PROGRAMBLOCK_SIZE_BYTES;
813 else
814 blocksize_bytes = MAINBLOCK_SIZE_BYTES;
815 start_address &= ~(blocksize_bytes - 1);
816 blocksize_quads = blocksize_bytes / 4;
818 uint32_t verify[blocksize_quads];
820 // corner case: requested to erase less than one block
821 if (blocksize_quads > quads_left) {
822 blocksize_quads = quads_left;
825 // do the actual erase
826 if (!eraseFlash(start_address)) {
827 debugWarning("Could not erase flash block at 0x%08X\n", start_address);
828 success = false;
829 } else {
830 // wait for the flash to become ready again
831 if (!waitForFlash(ECHO_FLASH_ERASE_TIMEOUT_MILLISECS)) {
832 debugError("Wait for flash timed out at address 0x%08X\n", start_address);
833 return false;
836 // verify that the block is empty as an extra precaution
837 if (!readFlash(start_address, blocksize_quads, verify)) {
838 debugError("Could not read flash block at 0x%08X\n", start_address);
839 return false;
842 // everything should be 0xFFFFFFFF if the erase was successful
843 for (unsigned int i = 0; i < blocksize_quads; i++) {
844 if (0xFFFFFFFF != verify[i]) {
845 debugWarning("Flash erase verification failed.\n");
846 success = false;
847 break;
852 if (success) {
853 start_address += blocksize_bytes;
854 quads_left -= blocksize_quads;
855 nb_tries = 0;
856 } else {
857 nb_tries++;
859 if (nb_tries > max_nb_tries) {
860 debugError("Needed too many tries to erase flash at 0x%08X\n", start_address);
861 return false;
863 } while (quads_left > 0);
865 return true;
868 bool
869 Device::waitForFlash(unsigned int msecs)
871 bool ready;
873 EfcFlashGetStatusCmd statusCmd;
874 const unsigned int time_to_sleep_usecs = 10000;
875 int wait_cycles = msecs * 1000 / time_to_sleep_usecs;
877 do {
878 if (!doEfcOverAVC(statusCmd)) {
879 debugError("Could not read flash status\n");
880 return false;
882 if (statusCmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
883 ready = false;
884 } else {
885 ready = statusCmd.m_ready;
887 usleep(time_to_sleep_usecs);
888 } while (!ready && wait_cycles--);
890 if(wait_cycles == 0) {
891 debugError("Timeout while waiting for flash\n");
892 return false;
895 return ready;
898 uint32_t
899 Device::getSessionBase()
901 EfcFlashGetSessionBaseCmd cmd;
902 if(!doEfcOverAVC(cmd)) {
903 debugError("Could not get session base address\n");
904 return 0; // FIXME: arbitrary
906 return cmd.m_address;
910 Device::getSamplingFrequency()
912 int sampling_rate;
914 EfcGetClockCmd gccmd;
915 if (!doEfcOverAVC(gccmd)) {
916 /* fallback to 'input/output plug signal format' command */
917 sampling_rate = GenericAVC::Device::getSamplingFrequency();
918 if (!sampling_rate) {
919 debugError("Could not get sample rate\n");
920 return false;
922 return sampling_rate;
924 return gccmd.m_samplerate;
926 bool
927 Device::setSamplingFrequency(int s)
929 uint32_t clock = getClock();
930 if (clock == EFC_CMD_HW_CLOCK_UNSPECIFIED)
931 return false;
933 debugOutput(DEBUG_LEVEL_VERBOSE, "Set samplerate: %d\n", s);
935 EfcSetClockCmd sccmd;
936 sccmd.m_clock = clock;
937 sccmd.m_samplerate = s;
938 sccmd.m_index = 0;
939 if (!doEfcOverAVC(sccmd)) {
940 /* fallback to 'input/output plug signal format' command */
941 if (!GenericAVC::Device::setSamplingFrequency(s)) {
942 debugError("Could not set sample rate\n");
943 return false;
946 return true;
950 } // FireWorks