root/trunk/libffado/src/fireworks/fireworks_device.cpp

Revision 1254, 20.0 kB (checked in by ppalmers, 14 years ago)

split config.h into config/version/debug_config to allow for faster compilation (splits dependencies)

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 "config.h"
25
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"
32
33 #include "audiofire/audiofire_device.h"
34
35 #include "libieee1394/configrom.h"
36 #include "libieee1394/ieee1394service.h"
37
38 #include "fireworks/fireworks_control.h"
39
40 #include "libutil/PosixMutex.h"
41
42 #include <sstream>
43 using namespace std;
44
45 // FireWorks is the platform used and developed by ECHO AUDIO
46 namespace FireWorks {
47
48 Device::Device(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
49     : GenericAVC::AvDevice( d, configRom)
50     , m_poll_lock( new Util::PosixMutex() )
51     , m_efc_discovery_done ( false )
52     , m_MixerContainer ( NULL )
53 {
54     debugOutput( DEBUG_LEVEL_VERBOSE, "Created FireWorks::Device (NodeID %d)\n",
55                  getConfigRom().getNodeId() );
56 }
57
58 Device::~Device()
59 {
60     destroyMixer();
61 }
62
63 void
64 Device::showDevice()
65 {
66     debugOutput(DEBUG_LEVEL_VERBOSE, "This is a FireWorks::Device\n");
67     if ( !m_efc_discovery_done) {
68         if (!discoverUsingEFC()) {
69             debugError("EFC discovery failed\n");
70         }
71     }
72     m_HwInfo.showEfcCmd();
73     GenericAVC::AvDevice::showDevice();
74 }
75
76 bool
77 Device::probe( ConfigRom& configRom, bool generic )
78 {
79     if(generic) {
80         // try an EFC command
81         EfcOverAVCCmd cmd( configRom.get1394Service() );
82         cmd.setCommandType( AVC::AVCCommand::eCT_Control );
83         cmd.setNodeId( configRom.getNodeId() );
84         cmd.setSubunitType( AVC::eST_Unit  );
85         cmd.setSubunitId( 0xff );
86         cmd.setVerbose( configRom.getVerboseLevel() );
87
88         EfcHardwareInfoCmd hwInfo;
89         hwInfo.setVerboseLevel(configRom.getVerboseLevel());
90         cmd.m_cmd = &hwInfo;
91
92         if ( !cmd.fire()) {
93             return false;
94         }
95
96         if ( cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
97             return false;
98         }
99         if ( hwInfo.m_header.retval != EfcCmd::eERV_Ok
100              && hwInfo.m_header.retval != EfcCmd::eERV_FlashBusy) {
101              debugError( "EFC command failed\n" );
102              return false;
103         }
104         return true;
105     } else {
106         unsigned int vendorId = configRom.getNodeVendorId();
107         unsigned int modelId = configRom.getModelId();
108
109         GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_fireworks.txt" );
110         if ( vendorModel.parse() ) {
111             return vendorModel.isPresent( vendorId, modelId );
112         }
113         return false;
114     }
115 }
116
117 bool
118 Device::discover()
119 {
120     unsigned int vendorId = getConfigRom().getNodeVendorId();
121     unsigned int modelId = getConfigRom().getModelId();
122
123     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_fireworks.txt" );
124     if ( vendorModel.parse() ) {
125         m_model = vendorModel.find( vendorId, modelId );
126     }
127
128     if (!GenericAVC::VendorModel::isValid(m_model)) {
129         debugWarning("Using generic ECHO Audio FireWorks support for unsupported device '%s %s'\n",
130             getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
131     } else {
132         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
133                 m_model.vendor_name.c_str(), m_model.model_name.c_str());
134     }
135
136     // get the info from the EFC
137     if ( !discoverUsingEFC() ) {
138         debugError( "Could not discover using EFC\n" );
139         return false;
140     }
141
142     // discover AVC-wise
143     if ( !GenericAVC::AvDevice::discover() ) {
144         debugError( "Could not discover GenericAVC::AvDevice\n" );
145         return false;
146     }
147
148     if(!buildMixer()) {
149         debugWarning("Could not build mixer\n");
150     }
151
152     return true;
153 }
154
155 bool
156 Device::discoverUsingEFC()
157 {
158     m_efc_discovery_done = false;
159     m_HwInfo.setVerboseLevel(getDebugLevel());
160
161     if (!doEfcOverAVC(m_HwInfo)) {
162         debugError("Could not read hardware capabilities\n");
163         return false;
164     }
165
166     // save the EFC version, since some stuff
167     // depends on this
168     m_efc_version = m_HwInfo.m_header.version;
169
170     if (!updatePolledValues()) {
171         debugError("Could not update polled values\n");
172         return false;
173     }
174
175     m_efc_discovery_done = true;
176     return true;
177 }
178
179 FFADODevice *
180 Device::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
181 {
182     unsigned int vendorId = configRom->getNodeVendorId();
183 //     unsigned int modelId = configRom->getModelId();
184
185     switch(vendorId) {
186         case FW_VENDORID_ECHO: return new ECHO::AudioFire(d, configRom );
187         default: return new Device(d, configRom );
188     }
189 }
190
191 bool
192 Device::doEfcOverAVC(EfcCmd &c) {
193     EfcOverAVCCmd cmd( get1394Service() );
194     cmd.setCommandType( AVC::AVCCommand::eCT_Control );
195     cmd.setNodeId( getConfigRom().getNodeId() );
196     cmd.setSubunitType( AVC::eST_Unit  );
197     cmd.setSubunitId( 0xff );
198
199     cmd.setVerbose( getDebugLevel() );
200     cmd.m_cmd = &c;
201
202     if ( !cmd.fire()) {
203         debugError( "EfcOverAVCCmd command failed\n" );
204         c.showEfcCmd();
205         return false;
206     }
207
208     if ( cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
209         debugError( "EfcOverAVCCmd not accepted\n" );
210         return false;
211     }
212
213     if (   c.m_header.retval != EfcCmd::eERV_Ok
214         && c.m_header.retval != EfcCmd::eERV_FlashBusy) {
215         debugError( "EFC command failed\n" );
216         c.showEfcCmd();
217         return false;
218     }
219
220     return true;
221 }
222
223 bool
224 Device::buildMixer()
225 {
226     bool result=true;
227     debugOutput(DEBUG_LEVEL_VERBOSE, "Building a FireWorks mixer...\n");
228    
229     destroyMixer();
230    
231     // create the mixer object container
232     m_MixerContainer = new Control::Container(this, "Mixer");
233
234     if (!m_MixerContainer) {
235         debugError("Could not create mixer container...\n");
236         return false;
237     }
238
239     // create control objects for the audiofire
240
241     // matrix mix controls
242     result &= m_MixerContainer->addElement(
243         new MonitorControl(*this, MonitorControl::eMC_Gain, "MonitorGain"));
244
245     result &= m_MixerContainer->addElement(
246         new MonitorControl(*this, MonitorControl::eMC_Mute, "MonitorMute"));
247
248     result &= m_MixerContainer->addElement(
249         new MonitorControl(*this, MonitorControl::eMC_Solo, "MonitorSolo"));
250
251     result &= m_MixerContainer->addElement(
252         new MonitorControl(*this, MonitorControl::eMC_Pan, "MonitorPan"));
253
254     // Playback mix controls
255     for (unsigned int ch=0;ch<m_HwInfo.m_nb_1394_playback_channels;ch++) {
256         std::ostringstream node_name;
257         node_name << "PC" << ch;
258        
259         result &= m_MixerContainer->addElement(
260             new BinaryControl(*this, eMT_PlaybackMix, eMC_Mute, ch, 0, node_name.str()+"Mute"));
261         result &= m_MixerContainer->addElement(
262             new SimpleControl(*this, eMT_PlaybackMix, eMC_Gain, ch, node_name.str()+"Gain"));
263     }
264    
265     // Physical output mix controls
266     for (unsigned int ch=0;ch<m_HwInfo.m_nb_phys_audio_out;ch++) {
267         std::ostringstream node_name;
268         node_name << "OUT" << ch;
269        
270         result &= m_MixerContainer->addElement(
271             new BinaryControl(*this, eMT_PhysicalOutputMix, eMC_Mute, ch, 0, node_name.str()+"Mute"));
272         result &= m_MixerContainer->addElement(
273             new BinaryControl(*this, eMT_PhysicalOutputMix, eMC_Nominal, ch, 1, node_name.str()+"Nominal"));
274         result &= m_MixerContainer->addElement(
275             new SimpleControl(*this, eMT_PhysicalOutputMix, eMC_Gain, ch, node_name.str()+"Gain"));
276     }
277    
278     // check for IO config controls and add them if necessary
279     if(m_HwInfo.hasMirroring()) {
280         result &= m_MixerContainer->addElement(
281             new IOConfigControl(*this, eCR_Mirror, "ChannelMirror"));
282     }
283     if(m_HwInfo.hasSoftwarePhantom()) {
284         result &= m_MixerContainer->addElement(
285             new IOConfigControl(*this, eCR_Phantom, "PhantomPower"));
286     }
287
288     if (!result) {
289         debugWarning("One or more control elements could not be created.");
290         // clean up those that couldn't be created
291         destroyMixer();
292         return false;
293     }
294
295     if (!addElement(m_MixerContainer)) {
296         debugWarning("Could not register mixer to device\n");
297         // clean up
298         destroyMixer();
299         return false;
300     }
301
302     return true;
303 }
304
305 bool
306 Device::destroyMixer()
307 {
308     debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n");
309
310     if (m_MixerContainer == NULL) {
311         debugOutput(DEBUG_LEVEL_VERBOSE, "no mixer to destroy...\n");
312         return true;
313     }
314
315     if (!deleteElement(m_MixerContainer)) {
316         debugError("Mixer present but not registered to the avdevice\n");
317         return false;
318     }
319
320     // remove and delete (as in free) child control elements
321     m_MixerContainer->clearElements(true);
322     delete m_MixerContainer;
323     return true;
324 }
325
326
327 bool
328 Device::updatePolledValues() {
329     Util::MutexLockHelper lock(*m_poll_lock);
330     return doEfcOverAVC(m_Polled);
331 }
332
333 FFADODevice::ClockSourceVector
334 Device::getSupportedClockSources() {
335     FFADODevice::ClockSourceVector r;
336
337     if (!m_efc_discovery_done) {
338         debugError("EFC discovery not done yet!\n");
339         return r;
340     }
341
342     uint32_t active_clock=getClock();
343
344     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_INTERNAL)) {
345         debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock supported\n");
346         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_INTERNAL);
347         s.active=(active_clock == EFC_CMD_HW_CLOCK_INTERNAL);
348         if (s.type != eCT_Invalid) r.push_back(s);
349     }
350     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SYTMATCH)) {
351         debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match clock supported\n");
352         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SYTMATCH);
353         s.active=(active_clock == EFC_CMD_HW_CLOCK_SYTMATCH);
354         if (s.type != eCT_Invalid) r.push_back(s);
355     }
356     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_WORDCLOCK)) {
357         debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock supported\n");
358         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_WORDCLOCK);
359         s.active=(active_clock == EFC_CMD_HW_CLOCK_WORDCLOCK);
360         if (s.type != eCT_Invalid) r.push_back(s);
361     }
362     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_SPDIF)) {
363         debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock supported\n");
364         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_SPDIF);
365         s.active=(active_clock == EFC_CMD_HW_CLOCK_SPDIF);
366         if (s.type != eCT_Invalid) r.push_back(s);
367     }
368     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_1)) {
369         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock supported\n");
370         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_1);
371         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_1);
372         if (s.type != eCT_Invalid) r.push_back(s);
373     }
374     if(EFC_CMD_HW_CHECK_FLAG(m_HwInfo.m_supported_clocks, EFC_CMD_HW_CLOCK_ADAT_2)) {
375         debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock supported\n");
376         ClockSource s=clockIdToClockSource(EFC_CMD_HW_CLOCK_ADAT_2);
377         s.active=(active_clock == EFC_CMD_HW_CLOCK_ADAT_2);
378         if (s.type != eCT_Invalid) r.push_back(s);
379     }
380     return r;
381 }
382
383 bool
384 Device::isClockValid(uint32_t id) {
385     // always valid
386     if (id==EFC_CMD_HW_CLOCK_INTERNAL) return true;
387
388     // the polled values are used to detect
389     // whether clocks are valid
390     if (!updatePolledValues()) {
391         debugError("Could not update polled values\n");
392         return false;
393     }
394     return EFC_CMD_HW_CHECK_FLAG(m_Polled.m_status,id);
395 }
396
397 bool
398 Device::setActiveClockSource(ClockSource s) {
399     bool result;
400
401     debugOutput(DEBUG_LEVEL_VERBOSE, "setting clock source to id: %d\n",s.id);
402
403     if(!isClockValid(s.id)) {
404         debugError("Clock not valid\n");
405         return false;
406     }
407
408     result=setClock(s.id);
409
410     // From the ECHO sources:
411     // "If this is a 1200F and the sample rate is being set via EFC, then
412     // send the "phy reconnect command" so the device will vanish and reappear
413     // with a new descriptor."
414
415 //     EfcPhyReconnectCmd rccmd;
416 //     if(!doEfcOverAVC(rccmd)) {
417 //         debugError("Phy reconnect failed\n");
418 //     } else {
419 //         // sleep for one second such that the phy can get reconnected
420 //         sleep(1);
421 //     }
422
423     return result;
424 }
425
426 FFADODevice::ClockSource
427 Device::getActiveClockSource() {
428     ClockSource s;
429     uint32_t active_clock=getClock();
430     s=clockIdToClockSource(active_clock);
431     s.active=true;
432     return s;
433 }
434
435 FFADODevice::ClockSource
436 Device::clockIdToClockSource(uint32_t clockid) {
437     ClockSource s;
438     debugOutput(DEBUG_LEVEL_VERBOSE, "clock id: %lu\n", clockid);
439
440     // the polled values are used to detect
441     // whether clocks are valid
442     if (!updatePolledValues()) {
443         debugError("Could not update polled values\n");
444         return s;
445     }
446
447     switch (clockid) {
448         case EFC_CMD_HW_CLOCK_INTERNAL:
449             debugOutput(DEBUG_LEVEL_VERBOSE, "Internal clock\n");
450             s.type=eCT_Internal;
451             s.description="Internal sync";
452             break;
453
454         case EFC_CMD_HW_CLOCK_SYTMATCH:
455             debugOutput(DEBUG_LEVEL_VERBOSE, "Syt Match\n");
456             s.type=eCT_SytMatch;
457             s.description="SYT Match";
458             break;
459
460         case EFC_CMD_HW_CLOCK_WORDCLOCK:
461             debugOutput(DEBUG_LEVEL_VERBOSE, "WordClock\n");
462             s.type=eCT_WordClock;
463             s.description="Word Clock";
464             break;
465
466         case EFC_CMD_HW_CLOCK_SPDIF:
467             debugOutput(DEBUG_LEVEL_VERBOSE, "SPDIF clock\n");
468             s.type=eCT_SPDIF;
469             s.description="SPDIF";
470             break;
471
472         case EFC_CMD_HW_CLOCK_ADAT_1:
473             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 1 clock\n");
474             s.type=eCT_ADAT;
475             s.description="ADAT 1";
476             break;
477
478         case EFC_CMD_HW_CLOCK_ADAT_2:
479             debugOutput(DEBUG_LEVEL_VERBOSE, "ADAT 2 clock\n");
480             s.type=eCT_ADAT;
481             s.description="ADAT 2";
482             break;
483
484         default:
485             debugError("Invalid clock id: %d\n",clockid);
486             return s; // return an invalid ClockSource
487     }
488
489     s.id=clockid;
490     s.valid=isClockValid(clockid);
491
492     return s;
493 }
494
495 uint32_t
496 Device::getClock() {
497     EfcGetClockCmd gccmd;
498     if (!doEfcOverAVC(gccmd)) {
499         debugError("Could not get clock info\n");
500         return EFC_CMD_HW_CLOCK_UNSPECIFIED;
501     }
502     debugOutput(DEBUG_LEVEL_VERBOSE, "Active clock: 0x%08lX\n",gccmd.m_clock);
503     gccmd.showEfcCmd();
504
505     return gccmd.m_clock;
506 }
507
508 bool
509 Device::setClock(uint32_t id) {
510     EfcGetClockCmd gccmd;
511     if (!doEfcOverAVC(gccmd)) {
512         debugError("Could not get clock info\n");
513         return false;
514     }
515     debugOutput(DEBUG_LEVEL_VERBOSE, "Set clock: 0x%08lX\n", id);
516
517     EfcSetClockCmd sccmd;
518     sccmd.m_clock=id;
519     sccmd.m_samplerate=gccmd.m_samplerate;
520     sccmd.m_index=0;
521     if (!doEfcOverAVC(sccmd)) {
522         debugError("Could not set clock info\n");
523         return false;
524     }
525     return true;
526 }
527
528 bool
529 Device::lockFlash(bool lock) {
530     EfcFlashLockCmd cmd;
531     cmd.m_lock = lock;
532
533     if(!doEfcOverAVC(cmd)) {
534         debugError("Flash lock failed\n");
535         return false;
536     }
537     return true;
538 }
539
540 bool
541 Device::writeFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
542
543     if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
544         debugError("bogus start/len: 0x%08X / %u\n", start, len);
545         return false;
546     }
547     if(start & 0x03) {
548         debugError("start address not quadlet aligned: 0x%08X\n", start);
549         return false;
550     }
551
552     uint32_t start_addr = start;
553     uint32_t stop_addr = start + len*4;
554     uint32_t *target_buffer = buffer;
555
556     EfcFlashWriteCmd cmd;
557     // write EFC_FLASH_SIZE_BYTES at a time
558     for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
559         cmd.m_address = start_addr;
560         unsigned int quads_to_write = (stop_addr - start_addr)/4;
561         if (quads_to_write > EFC_FLASH_SIZE_QUADS) {
562             quads_to_write = EFC_FLASH_SIZE_QUADS;
563         }
564         cmd.m_nb_quadlets = quads_to_write;
565         for(unsigned int i=0; i<quads_to_write; i++) {
566             cmd.m_data[i] = *target_buffer;
567             target_buffer++;
568         }
569         if(!doEfcOverAVC(cmd)) {
570             debugError("Flash write failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_write);
571             return false;
572         }
573     }
574     return true;
575 }
576
577 bool
578 Device::readFlash(uint32_t start, uint32_t len, uint32_t* buffer) {
579
580     if(len <= 0 || 0xFFFFFFFF - len*4 < start) {
581         debugError("bogus start/len: 0x%08X / %u\n", start, len);
582         return false;
583     }
584     if(start & 0x03) {
585         debugError("start address not quadlet aligned: 0x%08X\n", start);
586         return false;
587     }
588
589     uint32_t start_addr = start;
590     uint32_t stop_addr = start + len*4;
591     uint32_t *target_buffer = buffer;
592
593     EfcFlashReadCmd cmd;
594     // read EFC_FLASH_SIZE_BYTES at a time
595     for(start_addr = start; start_addr < stop_addr; start_addr += EFC_FLASH_SIZE_BYTES) {
596         unsigned int quads_to_read = (stop_addr - start_addr)/4;
597         if (quads_to_read > EFC_FLASH_SIZE_QUADS) {
598             quads_to_read = EFC_FLASH_SIZE_QUADS;
599         }
600         uint32_t quadlets_read = 0;
601         int ntries = 10000;
602         do {
603             cmd.m_address = start_addr + quadlets_read*4;
604             unsigned int new_to_read = quads_to_read - quadlets_read;
605             cmd.m_nb_quadlets = new_to_read;
606             if(!doEfcOverAVC(cmd)) {
607                 debugError("Flash read failed for block 0x%08X (%d quadlets)\n", start_addr, quads_to_read);
608                 return false;
609             }
610             if(cmd.m_nb_quadlets != new_to_read) {
611                 debugOutput(DEBUG_LEVEL_VERBOSE,
612                             "Flash read didn't return enough data (%u/%u) \n",
613                             cmd.m_nb_quadlets, new_to_read);
614                 // continue trying
615             }
616             quadlets_read += cmd.m_nb_quadlets;
617
618             // copy content
619             for(unsigned int i=0; i<cmd.m_nb_quadlets; i++) {
620                 *target_buffer = cmd.m_data[i];
621                 target_buffer++;
622             }
623         } while(quadlets_read < quads_to_read && ntries--);
624         if(ntries==0) {
625             debugError("deadlock while reading flash\n");
626             return false;
627         }
628     }
629     return true;
630 }
631
632 bool
633 Device::eraseFlash(uint32_t addr) {
634     if(addr & 0x03) {
635         debugError("start address not quadlet aligned: 0x%08X\n", addr);
636         return false;
637     }
638     EfcFlashEraseCmd cmd;
639     cmd.m_address = addr;
640     if(!doEfcOverAVC(cmd)) {
641         if (cmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
642             return true;
643         }
644         debugError("Flash erase failed for block 0x%08X\n", addr);
645         return false;
646     }
647     return true;
648 }
649
650 bool
651 Device::waitForFlash(unsigned int msecs)
652 {
653     bool ready;
654
655     EfcFlashGetStatusCmd statusCmd;
656     const unsigned int time_to_sleep_usecs = 10000;
657     int wait_cycles = msecs * 1000 / time_to_sleep_usecs;
658
659     do {
660         if (!doEfcOverAVC(statusCmd)) {
661             debugError("Could not read flash status\n");
662             return false;
663         }
664         if (statusCmd.m_header.retval == EfcCmd::eERV_FlashBusy) {
665             ready = false;
666         } else {
667             ready = statusCmd.m_ready;
668         }
669         usleep(time_to_sleep_usecs);
670     } while (!ready && wait_cycles--);
671
672     if(wait_cycles == 0) {
673         debugError("Timeout while waiting for flash\n");
674         return false;
675     }
676
677     return ready;
678 }
679
680 } // FireWorks
Note: See TracBrowser for help on using the browser.