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

Revision 1234, 17.7 kB (checked in by holin, 15 years ago)

fix gcc 4.3 compile errors and some warnings (largely from Adrian Knoth)

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 "fireworks_firmware.h"
26 #include "efc/efc_avc_cmd.h"
27 #include "efc/efc_cmd.h"
28 #include "efc/efc_cmds_flash.h"
29
30 #include "libieee1394/configrom.h"
31 #include "libieee1394/vendor_model_ids.h"
32
33 #include <string>
34 #include <sstream>
35 #include <iostream>
36 #include <fstream>
37 #include <cstring>
38
39 #define ECHO_FLASH_ERASE_TIMEOUT_MILLISECS 2000
40
41 #define DAT_EXTENSION "dat"
42
43 // device id's
44 #define AUDIOFIRE2                      0x000af2
45 #define AUDIOFIRE4                      0x000af4
46 #define AUDIOFIRE8                      0x000af8
47 #define AUDIOFIRE12                     0x00af12
48 #define AUDIOFIRE12HD           0x0af12d
49 #define FWHDMI                          0x00afd1
50 #define ONYX400F                        0x00400f
51 #define ONYX1200F                       0x01200f
52 #define FIREWORKS8                      0x0000f8
53
54 using namespace std;
55
56 template <class T>
57 bool from_string(T& t,
58                  const std::string& s,
59                  std::ios_base& (*f)(std::ios_base&))
60 {
61   std::istringstream iss(s);
62   return !(iss >> f >> t).fail();
63 }
64
65 // These classes provide support for reading/writing the firmware on
66 // echo fireworks based devices
67 namespace FireWorks {
68
69 IMPL_DEBUG_MODULE( Firmware, Firmware, DEBUG_LEVEL_NORMAL );
70 IMPL_DEBUG_MODULE( FirmwareUtil, FirmwareUtil, DEBUG_LEVEL_NORMAL );
71
72 // the firmware class
73
74 // some generic string generation functions
75 const char *Firmware::eDatTypeToString(const enum Firmware::eDatType type) {
76     switch (type) {
77         case eDT_DspCode:
78             return "Dsp Code";
79         case eDT_IceLynxCode:
80             return "IceLynx Code";
81         case eDT_Data:
82             return "Data";
83         case eDT_FPGACode:
84             return "FPGA Code";
85         case eDT_DeviceName:
86             return "Device Name";
87         default:
88             return "invalid";
89     }
90 }
91
92 const enum Firmware::eDatType Firmware::intToeDatType(int type) {
93     switch (type) {
94         case (int)eDT_DspCode: return eDT_DspCode;
95         case (int)eDT_IceLynxCode: return eDT_IceLynxCode;
96         case (int)eDT_Data: return eDT_Data;
97         case (int)eDT_FPGACode: return eDT_FPGACode;
98         case (int)eDT_DeviceName: return eDT_DeviceName;
99         default:
100             return eDT_Invalid;
101     }
102 }
103
104 Firmware::Firmware()
105 : m_source( "none" )
106 , m_Type ( eDT_Invalid )
107 , m_flash_offset_address ( 0 )
108 , m_length_quads ( 0 )
109 , m_CRC32 ( 0 )
110 , m_checksum ( 0 )
111 , m_version ( 0 )
112 , m_append_crc ( false )
113 , m_footprint_quads ( 0 )
114 , m_data( NULL )
115 , m_valid( false )
116 {
117 }
118
119 Firmware::Firmware(const Firmware& f) {
120     debugOutput(DEBUG_LEVEL_VERBOSE, "copy constructor\n");
121     m_source = f.m_source;
122     m_Type = f.m_Type;
123     m_flash_offset_address = f.m_flash_offset_address;
124     m_length_quads = f.m_length_quads;
125     m_CRC32 = f.m_CRC32;
126     m_checksum = f.m_checksum;
127     m_version = f.m_version;
128     m_append_crc = f.m_append_crc;
129     m_footprint_quads = f.m_footprint_quads;
130     m_valid = f.m_valid;
131     m_data = new uint32_t[m_length_quads];
132
133     memcpy(m_data, f.m_data, m_length_quads*sizeof(uint32_t));
134 }
135
136 Firmware& Firmware::operator=(const Firmware& f) {
137     debugOutput(DEBUG_LEVEL_VERBOSE, "assignment\n");
138     if (this != &f) {  // make sure not same object
139         // assign new vars
140         m_source = f.m_source;
141         m_Type = f.m_Type;
142         m_flash_offset_address = f.m_flash_offset_address;
143         m_length_quads = f.m_length_quads;
144         m_CRC32 = f.m_CRC32;
145         m_checksum = f.m_checksum;
146         m_version = f.m_version;
147         m_append_crc = f.m_append_crc;
148         m_footprint_quads = f.m_footprint_quads;
149         m_valid = f.m_valid;
150
151         // replace dynamic data
152         delete [] m_data;
153         m_data = new uint32_t[m_length_quads];
154         memcpy(m_data, f.m_data, m_length_quads*sizeof(uint32_t));
155     }
156     return *this;    // Return ref for multiple assignment
157 }
158
159 Firmware::~Firmware()
160 {
161     if (m_data) delete[] m_data;
162 }
163
164 void
165 Firmware::show()
166 {
167     #ifdef DEBUG
168     debugOutput(DEBUG_LEVEL_NORMAL, "Firmware from %s\n", m_source.c_str());
169     debugOutput(DEBUG_LEVEL_NORMAL, " Valid?               : %s\n", (m_valid?"Yes":"No"));
170     debugOutput(DEBUG_LEVEL_NORMAL, " Type                 : %s\n", eDatTypeToString(m_Type));
171     if (m_Type == eDT_Invalid) return;
172
173     unsigned int version_major = (m_version & 0xFF000000) >> 24;
174     unsigned int version_minor = (m_version & 0x00FF0000) >> 16;
175     unsigned int version_build = (m_version & 0x0000FFFF);
176     debugOutput(DEBUG_LEVEL_NORMAL, " Address Offset       : 0x%08lX\n", m_flash_offset_address);
177     debugOutput(DEBUG_LEVEL_NORMAL, " Length (Quadlets)    : 0x%08lX\n", m_length_quads);
178     debugOutput(DEBUG_LEVEL_NORMAL, " CRC 32               : 0x%08lX\n", m_CRC32);
179     debugOutput(DEBUG_LEVEL_NORMAL, " Checksum             : 0x%08lX\n", m_checksum);
180     debugOutput(DEBUG_LEVEL_NORMAL, " Firmware version     : %02u.%02u.%02u (0x%08X)\n",
181                                     version_major, version_minor, version_build, m_version);
182     debugOutput(DEBUG_LEVEL_NORMAL, " Append CRC           : %s\n", (m_append_crc?"Yes":"No"));
183     debugOutput(DEBUG_LEVEL_NORMAL, " Footprint (Quadlets) : 0x%08lX\n", m_footprint_quads);
184     #endif
185 }
186
187 bool
188 Firmware::operator==(const Firmware& f)
189 {
190     debugOutput(DEBUG_LEVEL_VERBOSE, "Comparing header...\n");
191     if(m_flash_offset_address != f.m_flash_offset_address) {
192         debugOutput(DEBUG_LEVEL_VERBOSE,
193                     "Flash address differs: %08X != %08X\n",
194                     m_flash_offset_address, f.m_flash_offset_address);
195         return false;
196     }
197     if(m_length_quads != f.m_length_quads) {
198         debugOutput(DEBUG_LEVEL_VERBOSE,
199                     "Flash length differs: %08X != %08X\n",
200                     m_length_quads, f.m_length_quads);
201         return false;
202     }
203     if(m_data == NULL && f.m_data == NULL) {
204         debugOutput(DEBUG_LEVEL_VERBOSE,
205                     "both firmwares have no data\n");
206         return true;
207     }
208     if(m_data == NULL || f.m_data == NULL) {
209         debugOutput(DEBUG_LEVEL_VERBOSE,
210                     "one of the firmwares has no data: %p != %p\n",
211                     m_data, f.m_data);
212         return false;
213     }
214    
215     debugOutput(DEBUG_LEVEL_VERBOSE, "Comparing data...\n");
216     bool retval = true;
217     for(unsigned int i=0; i<m_length_quads; i++) {
218         if(m_data[i] != f.m_data[i]) {
219             debugOutput(DEBUG_LEVEL_VERBOSE,
220                         " POS 0x%08X: %08X != %08X\n",
221                         i, m_data[i], f.m_data[i]);
222             retval = false;
223         }
224     }
225     return retval;
226 }
227
228 bool
229 Firmware::loadFile(std::string filename)
230 {
231     debugOutput(DEBUG_LEVEL_VERBOSE, "Loading firmware from file %s\n", filename.c_str());
232     fstream fwfile;
233    
234     debugOutput(DEBUG_LEVEL_VERBOSE, " Loading file...\n");
235     fwfile.open( filename.c_str(), ios::in | ios::ate);
236     if ( !fwfile.is_open() ) {
237         debugError("Could not open file.\n");
238         return false;
239     }
240     // get file size
241     int size;
242     size = (int)fwfile.tellg();
243    
244     if( size > ECHO_FIRMWARE_FILE_MAX_LENGTH_BYTES) {
245         debugError("File too large (%d bytes).\n", size);
246         return false;
247     }
248    
249     debugOutput(DEBUG_LEVEL_VERBOSE, " Checking magic...\n");
250     // read magic
251     if( size < ECHO_FIRMWARE_MAGIC_LENGTH_BYTES) {
252         debugError("File too small (%d bytes) to contain the magic header.\n", size);
253         return false;
254     }
255    
256     fwfile.seekg (0, ios::beg);
257     getline(fwfile, m_magic);
258     // get rid of the DOS-Style end of line
259     string::size_type loc = m_magic.find( '\r' );
260     if( loc != string::npos ) {
261         m_magic.erase(loc);
262     }
263     loc = m_magic.find( '\n' );
264     if( loc != string::npos ) {
265         m_magic.erase(loc);
266     }
267    
268     // check the magic
269     if (m_magic != ECHO_FIRMWARE_MAGIC) {
270         debugError("Magic was '%s' but should have been '%s'\n",
271                     m_magic.c_str(), ECHO_FIRMWARE_MAGIC);
272         return false;
273     }
274
275     debugOutput(DEBUG_LEVEL_VERBOSE, "   magic OK...\n");
276    
277     debugOutput(DEBUG_LEVEL_VERBOSE, " Reading header...\n");
278     // read header
279     if( size < ECHO_FIRMWARE_MAGIC_LENGTH_BYTES + ECHO_FIRMWARE_HEADER_LENGTH_BYTES) {
280         debugError("File too small to contain the header.\n");
281         return false;
282     }
283    
284     for (int i=0; i < ECHO_FIRMWARE_HEADER_LENGTH_QUADLETS; i++) {
285         std::string buffer;
286         getline(fwfile, buffer);
287         // get rid of the DOS-Style end of line
288         string::size_type loc = buffer.find( '\r' );
289         if( loc != string::npos ) {
290             buffer.erase(loc);
291         }
292         loc = buffer.find( '\n' );
293         if( loc != string::npos ) {
294             buffer.erase(loc);
295         }
296        
297         if (!from_string<uint32_t>(m_header[i], buffer, std::hex)) {
298             debugWarning("Could not convert '%s' to uint32_t\n", buffer.c_str());
299             return false;
300         }
301        
302         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "   Header %02d: %08lX\n",
303                     i, m_header[i]);
304     }
305
306     m_Type                  = intToeDatType(m_header[0]);
307     m_flash_offset_address  = m_header[1];
308     m_length_quads          = m_header[2];
309     m_CRC32                 = m_header[3];
310     m_checksum              = m_header[4];
311     m_version               = m_header[5];
312     m_append_crc            = m_header[6] != 0;
313     m_footprint_quads       = m_header[7];
314     debugOutput(DEBUG_LEVEL_VERBOSE, "  header ok...\n");
315
316     debugOutput(DEBUG_LEVEL_VERBOSE, " Reading data...\n");
317     delete[] m_data;
318     m_data = new uint32_t[m_length_quads];
319     if(m_data == NULL) {
320         debugError("could not allocate memory for firmware\n");
321         return false;
322     }
323     for (uint32_t i=0; i < m_length_quads; i++) {
324         std::string buffer;
325         getline(fwfile, buffer);
326         // get rid of the DOS-Style end of line
327         string::size_type loc = buffer.find( '\r' );
328         if( loc != string::npos ) {
329             buffer.erase(loc);
330         }
331         loc = buffer.find( '\n' );
332         if( loc != string::npos ) {
333             buffer.erase(loc);
334         }
335        
336         if (!from_string<uint32_t>(m_data[i], buffer, std::hex)) {
337             debugWarning("Could not convert '%s' to uint32_t\n", buffer.c_str());
338             return false;
339         }
340        
341         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "   Data %02d: %08lX\n",
342                     i, m_data[i]);
343     }
344     debugOutput(DEBUG_LEVEL_VERBOSE, "  data ok...\n");
345     fwfile.close();
346
347     m_source = filename;
348     m_valid = true;
349     return true;
350 }
351
352 bool
353 Firmware::loadFromMemory(uint32_t *data, uint32_t addr, uint32_t len) {
354     m_valid = false;
355
356     // mark it as invalid for now
357     m_Type                  = eDT_Invalid;
358
359     // set some values (FIXME)
360     m_flash_offset_address  = addr;
361     m_length_quads          = len;
362     m_CRC32                 = 0;
363     m_checksum              = 0;
364     m_version               = 0;
365     m_append_crc            = false;
366     m_footprint_quads       = 0;
367
368     // delete any old data
369     delete[] m_data;
370     m_data = new uint32_t[len];
371     if(m_data == NULL) {
372         debugError("could not allocate memory for firmware\n");
373         return false;
374     }
375     // copy data
376     memcpy(m_data, data, len*sizeof(uint32_t));
377
378     return true;
379 }
380
381 uint32_t
382 Firmware::getWriteDataLen() {
383     uint32_t retval = 0;
384     if((m_append_crc != 0) && (m_length_quads < m_footprint_quads)) {
385         retval += m_footprint_quads;
386     } else {
387         retval += m_length_quads;
388     }
389     return retval;
390 }
391
392 bool
393 Firmware::getWriteData(uint32_t *buff) {
394     // copy the payload data
395     memcpy(buff, m_data, m_length_quads*4);
396     // if necessary, add crc/version
397     if((m_append_crc != 0) && (m_length_quads < m_footprint_quads)) {
398         debugOutput(DEBUG_LEVEL_VERBOSE, "appending CRC and version\n");
399         buff[m_footprint_quads - 1] = m_CRC32;
400         buff[m_footprint_quads - 2] = m_version;
401     }
402     return true;
403 }
404
405 void
406 Firmware::dumpData()
407 {
408     debugWarning("-- char dump --");
409     hexDump((unsigned char*)m_data, m_length_quads*4);
410 /*   
411     debugWarning("-- quadlet dump --");
412     hexDumpQuadlets(m_data, m_length_quads);*/
413
414 }
415
416
417 // the firmware loader helper class
418 const char *Af2Dats[] =
419 {
420         "Fireworks3"
421 };
422
423 const char *Af4Dats[] =
424 {
425         "Fireworks3"
426 };
427
428 const char *Af8Dats[] =
429 {
430         "bootstrap",
431         "audiofire8",
432         "audiofire8_E",
433         "FireworksARM"
434 };
435
436 const char *Af12Dats[] =
437 {
438         "bootstrap",
439         "audiofire12",
440         "audiofire12_E",
441         "FireworksARM"
442 };
443
444 FirmwareUtil::FirmwareUtil(FireWorks::Device& p)
445 : m_Parent(p)
446 {
447
448     struct dat_list datlists[4] =
449     {
450             { FW_VENDORID_ECHO, AUDIOFIRE2,     0x04010000, 1, Af2Dats },
451             { FW_VENDORID_ECHO, AUDIOFIRE4,     0x04010000, 1, Af4Dats },
452             { FW_VENDORID_ECHO, AUDIOFIRE8,     0x04010000, 4, Af8Dats },
453             { FW_VENDORID_ECHO, AUDIOFIRE12,    0x04010000, 4, Af12Dats }
454     };
455
456     assert(sizeof(datlists) <= sizeof(m_datlists));
457     memset(&m_datlists, 0, sizeof(m_datlists));
458     memcpy(&m_datlists, &datlists, sizeof(datlists));
459 }
460
461 FirmwareUtil::~FirmwareUtil()
462 {
463 }
464
465 bool
466 FirmwareUtil::isValidForDevice(Firmware f)
467 {
468     std::string src = f.getSourceString();
469
470     uint32_t vendor = m_Parent.getConfigRom().getNodeVendorId();
471     uint32_t model = m_Parent.getConfigRom().getModelId();
472
473     for (unsigned int i=0; i<ECHO_FIRMWARE_NUM_BOXTYPES; i++) {
474         if(m_datlists[i].boxtype == model
475            && m_datlists[i].vendorid == vendor)
476         {
477             for(int j=0; j<m_datlists[i].count; j++) {
478                 std::string cmpstring = m_datlists[i].filenames[j];
479                 cmpstring += ".dat";
480                 std::string::size_type loc = src.find( cmpstring, 0 );
481                 if( loc != std::string::npos ) {
482                     debugOutput(DEBUG_LEVEL_VERBOSE, "found filename\n");
483                     return true;
484                     break;
485                  }
486             }
487         }
488     }
489     debugOutput(DEBUG_LEVEL_VERBOSE, "file not for this device\n");
490     return false;
491 }
492
493 Firmware
494 FirmwareUtil::getFirmwareFromDevice(uint32_t start, uint32_t len)
495 {
496     if(len == 0) {
497         debugError("Invalid length: %u\n", len);
498         return Firmware();
499     }
500
501     uint32_t data[len];
502     Firmware f = Firmware();
503
504     if(!m_Parent.readFlash(start, len, data)) {
505         debugError("Flash read failed\n");
506         return f;
507     }
508
509     if(!f.loadFromMemory(data, start, len)) {
510         debugError("Could not load firmware from memory dump\n");
511     }
512
513     return f;
514 }
515
516 bool
517 FirmwareUtil::writeFirmwareToDevice(Firmware f)
518 {
519     uint32_t start_addr = f.getAddress();
520     uint32_t writelen = f.getWriteDataLen();
521     uint32_t buff[writelen * 4];
522     if (!f.getWriteData(buff)) {
523         debugError("Could not prepare data for writing to the device\n");
524         return false;
525     }
526     if(!m_Parent.writeFlash(start_addr, writelen, buff)) {
527         debugError("Writing to flash failed.\n");
528         return false;
529     }
530     return true;
531 }
532
533 bool
534 FirmwareUtil::eraseBlocks(uint32_t start_address, unsigned int nb_quads)
535 {
536     uint32_t blocksize_bytes;
537     uint32_t blocksize_quads;
538     unsigned int quads_left = nb_quads;
539     bool success = true;
540
541     const unsigned int max_nb_tries = 10;
542     unsigned int nb_tries = 0;
543
544     do {
545         // the erase block size is fixed by the HW, and depends
546         // on the flash section we're in
547         if (start_address < MAINBLOCKS_BASE_OFFSET_BYTES)
548                 blocksize_bytes = PROGRAMBLOCK_SIZE_BYTES;
549         else
550                 blocksize_bytes = MAINBLOCK_SIZE_BYTES;
551         start_address &= ~(blocksize_bytes - 1);
552         blocksize_quads = blocksize_bytes / 4;
553
554         uint32_t verify[blocksize_quads];
555
556         // corner case: requested to erase less than one block
557         if (blocksize_quads > quads_left) {
558             blocksize_quads = quads_left;
559         }
560
561         // do the actual erase
562         if (!m_Parent.eraseFlash(start_address)) {
563             debugWarning("Could not erase flash block at 0x%08X\n", start_address);
564             success = false;
565         } else {
566             // wait for the flash to become ready again
567             if (!m_Parent.waitForFlash(ECHO_FLASH_ERASE_TIMEOUT_MILLISECS)) {
568                 debugError("Wait for flash timed out at address 0x%08X\n", start_address);
569                 return false;
570             }
571
572             // verify that the block is empty as an extra precaution
573             if (!m_Parent.readFlash(start_address, blocksize_quads, verify)) {
574                 debugError("Could not read flash block at 0x%08X\n", start_address);
575                 return false;
576             }
577
578             // everything should be 0xFFFFFFFF if the erase was successful
579             for (unsigned int i = 0; i < blocksize_quads; i++) {
580                 if (0xFFFFFFFF != verify[i]) {
581                     debugWarning("Flash erase verification failed.\n");
582                     success = false;
583                     break;
584                 }
585             }
586         }
587
588         if (success) {
589             start_address += blocksize_bytes;
590             quads_left -= blocksize_quads;
591             nb_tries = 0;
592         } else {
593             nb_tries++;
594         }
595         if (nb_tries > max_nb_tries) {
596             debugError("Needed too many tries to erase flash at 0x%08X\n", start_address);
597             return false;
598         }
599     } while (quads_left > 0);
600    
601     return true;
602 }
603
604 void
605 FirmwareUtil::show()
606 {
607     debugOutput(DEBUG_LEVEL_NORMAL, "FirmwareUtil\n");
608 }
609
610 } // FireWorks
Note: See TracBrowser for help on using the browser.