]> git.openfabrics.org - ~adrianc/mstflint.git/commitdiff
r1954: support more flash types
authorMichael S. Tsirkin <mst@mellanox.co.il>
Sun, 6 Mar 2005 16:03:35 +0000 (16:03 +0000)
committerMichael S. Tsirkin <mst@mellanox.co.il>
Sun, 6 Mar 2005 16:03:35 +0000 (16:03 +0000)
flint.cpp

index 3434e1a10c410ed55c5e5899af0bfd6a7f65a8f0..1adaddad96f8c52993d5cf7c51e0e8f014ffb4d5 100644 (file)
--- a/flint.cpp
+++ b/flint.cpp
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- *  Version: $Id: flint.cpp,v 1.60 2004/10/31 14:02:51 orenk Exp $
+ *  Version: $Id: flint.cpp,v 1.89 2005/03/06 15:55:53 mtsirkin Exp $
  *
  */
 
+//MTCR needs to be first since it needs to define all kind of
+//macros which affect standard headers.
+
 #include "mtcr.h"
 
 #include <ctype.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <assert.h>
-#include <alloca.h>
 
+
+#include <alloca.h>
 #include <netinet/in.h>
 #include <endian.h>
 #include <byteswap.h>
-
 #include <unistd.h>
+
+#include <signal.h>
+
 #ifndef O_BINARY
-#define  O_BINARY 0
+    #define  O_BINARY 0
 #endif
 
+#include <memory>
+#include <vector>
+
 #ifndef DEV_MST_EXAMPLE1
-#define DEV_MST_EXAMPLE1 "/dev/mst/mt23108_pci_cr0"
+    #define DEV_MST_EXAMPLE1 "/dev/mst/mt23108_pci_cr0"
 #endif
 
 #ifndef DEV_MST_EXAMPLE2
-#define DEV_MST_EXAMPLE2 "/dev/mst/mt23108_pciconf0"
+    #define DEV_MST_EXAMPLE2 "/dev/mst/mt23108_pciconf0"
 #endif
 
 #ifndef FLINT_NAME
-#ifdef __GNUC__
-#define FLINT_NAME "%1$s"
-#else
-#define FLINT_NAME "./flint"
-#endif
+    #ifdef __GNUC__
+        #define FLINT_NAME "%1$s"
+    #else
+        #define FLINT_NAME "./flint"
+    #endif
 #endif
 
 namespace std {}; using namespace std;
 
-
 char* _versionID = "VERSION_ID_HERE";
-char* _cvsID     = "$Revision: 1.60 $";
+
+char* _cvsID     = "$Revision: 1.89 $";
+
+#ifndef __be32_to_cpu
+    #define __be32_to_cpu(x) ntohl(x)
+#endif
+#ifndef __cpu_to_be32
+    #define __cpu_to_be32(x) htonl(x)
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    #ifndef __cpu_to_le32
+        #define  __cpu_to_le32(x) (x)
+    #endif
+    #ifndef __le32_to_cpu
+        #define  __le32_to_cpu(x) (x)
+    #endif
+#elif __BYTE_ORDER == __BIG_ENDIAN
+    #ifndef __cpu_to_le32
+        #define  __cpu_to_le32(x) bswap_32(x)
+    #endif
+    #ifndef __le32_to_cpu
+        #define  __le32_to_cpu(x) bswap_32(x)
+    #endif
+#else
+    #ifndef __cpu_to_le32
+        #define  __cpu_to_le32(x) bswap_32(__cpu_to_be32(x))
+    #endif
+    #ifndef __le32_to_cpu
+        #define  __le32_to_cpu(x) __be32_to_cpu(bswap_32(x))
+    #endif
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    #ifndef __cpu_to_le16
+        #define  __cpu_to_le16(x) (x)
+    #endif
+    #ifndef __le16_to_cpu
+        #define  __le16_to_cpu(x) (x)
+    #endif
+#elif __BYTE_ORDER == __BIG_ENDIAN
+    #ifndef __cpu_to_le16
+        #define  __cpu_to_le16(x) bswap_16(x)
+    #endif
+    #ifndef __le16_to_cpu
+        #define  __le16_to_cpu(x) bswap_16(x)
+    #endif
+#else
+    #ifndef __cpu_to_le16
+        #define  __cpu_to_le16(x) bswap_16(__cpu_to_be16(x))
+    #endif
+    #ifndef __le16_to_cpu
+        #define  __le16_to_cpu(x) __be16_to_cpu(bswap_16(x))
+    #endif
+#endif
+
 
 ////////////////////////////////////////////////////////////////////////
 //                                                                    //
@@ -90,18 +153,18 @@ char* _cvsID     = "$Revision: 1.60 $";
 //                                                                    //
 ////////////////////////////////////////////////////////////////////////
 typedef struct guid {
-       u_int32_t h;
-       u_int32_t l;
+    u_int32_t h;
+    u_int32_t l;
 } guid_t;
 
 static inline void be_guid_to_cpu(guid_t* to, guid_t* from) {
-       to->h=__be32_to_cpu(from->h);
-       to->l=__be32_to_cpu(from->l);
+    to->h=__be32_to_cpu(from->h);
+    to->l=__be32_to_cpu(from->l);
 }
 
 static inline void cpu_to_be_guid(guid_t* to, guid_t* from) {
-       to->h=__cpu_to_be32(from->h);
-       to->l=__cpu_to_be32(from->l);
+    to->h=__cpu_to_be32(from->h);
+    to->l=__cpu_to_be32(from->l);
 }
 
 #define GUID_FORMAT "%8.8x%8.8x"
@@ -168,44 +231,59 @@ static inline void cpu_to_be_guid(guid_t* to, guid_t* from) {
 
 #if  1
 
-#define MWRITE4(offs,val) do { \
+    #define MWRITE4(offs,val) do { \
     if (mwrite4(_mf, offs, val) != 4) return false; } while (0)
-#define MREAD4(offs,val) do { \
+    #define MREAD4(offs,val) do { \
    if (mread4(_mf, offs, val) != 4) return false; } while (0)
 
 #else
 
-#define MWRITE4(offs,val) do { \
+    #define MWRITE4(offs,val) do { \
     printf("%08x <- %08x\n", (u_int32_t)offs, (u_int32_t)val); \
     if (mwrite4(_mf, offs, val) != 4) return false; } while (0)
-#define MREAD4(offs,val) do { \
+    #define MREAD4(offs,val) do { \
     if (mread4(_mf, offs, val) != 4) return false; \
      printf("%08x -> %08x\n", (u_int32_t)offs, (u_int32_t)(*(val))); \
     } while (0)
 
 #endif
 
-enum { SIGNATURE=0x5a445a44};
+enum {
+    SIGNATURE=0x5a445a44
+};
 struct PS {
     u_int32_t fi_addr;
     u_int32_t fi_size;
     u_int32_t signature;
     u_int32_t fw_reserved[5];
-    u_int32_t vsd[56];
+    u_int32_t vsd[52];
+    u_int32_t psid[4];
     u_int32_t branch_to;
     u_int32_t crc016;
 };
-enum { H_FIRST=1, H_DDR=1, H_CNF=2, H_JMP=3, H_EMT=4, H_ROM=5, H_GUID=6,
-       H_BOARD_ID=7, H_LAST=7 };
+enum {
+    H_FIRST = 1, 
+    H_DDR   = 1, 
+    H_CNF   = 2,
+    H_JMP   = 3,
+    H_EMT   = 4,
+    H_ROM   = 5,
+    H_GUID  = 6,
+    H_BOARD_ID=7, 
+    H_LAST  =7 
+};
+
 struct GPH {
     u_int32_t type;
     u_int32_t size;
     u_int32_t param;
     u_int32_t next;
 };
+
 const u_int32_t BOARD_ID_BSN_LEN=64;
 const u_int32_t BOARD_ID_BID_LEN=32;
 const u_int32_t BOARD_ID_PID=7;
+
 struct BOARD_ID {
     char      bsn[BOARD_ID_BSN_LEN];
     char      bid[BOARD_ID_BID_LEN];
@@ -231,21 +309,30 @@ bool _byte_write = false;
 
 void report(const char *format, ...)
 #ifdef __GNUC__
-    __attribute__ ((format (printf, 1, 2)))
+__attribute__ ((format (printf, 1, 2)))
 #endif
-    ;
+;
 void report(const char *format, ...)
 {
     va_list  args;
 
-    if (!_silent)
-    {
+    if (!_silent) {
         va_start(args, format);
         vprintf(format, args);
         va_end(args);
     }
 } // report
 
+static u_int32_t log2up (u_int32_t in) {
+    u_int32_t i;
+    for (i = 0; i < 32; i++) {
+        if (in <= (u_int32_t)(1 << i))
+            break;
+    }
+
+    return i;
+}
+
 
 ////////////////////////////////////////////////////////////////////////
 //                                                                    //
@@ -254,13 +341,12 @@ void report(const char *format, ...)
 // ****************************************************************** //
 //                                                                    //
 ////////////////////////////////////////////////////////////////////////
-class Crc16
-{
+class Crc16 {
 public:
-    Crc16(bool d = false) : _debug(d) { clear();       }
-    u_int16_t      get()              { return _crc;   }
-    void           clear()            { _crc = 0xffff; }
-    void           operator<<(u_int32_t val) { add(val); }
+    Crc16(bool d = false) : _debug(d) { clear();}
+    u_int16_t      get()              { return _crc;}
+    void           clear()            { _crc = 0xffff;}
+    void           operator<<(u_int32_t val) { add(val);}
     void           add(u_int32_t val);
     void           finish();
 private:
@@ -273,8 +359,7 @@ void Crc16::add(u_int32_t o)
 {
     if (_debug)
         printf("Crc16::add(%08x)\n", o);
-    for (int i=0; i<32; i++)
-    {
+    for (int i=0; i<32; i++) {
         if (_crc & 0x8000)
             _crc = (u_int16_t) ((((_crc<<1) | (o>>31)) ^  0x100b) & 0xffff);
         else
@@ -287,8 +372,7 @@ void Crc16::add(u_int32_t o)
 ////////////////////////////////////////////////////////////////////////
 void Crc16::finish()
 {
-    for (int i=0; i<16; i++)
-    {
+    for (int i=0; i<16; i++) {
         if (_crc & 0x8000)
             _crc=((_crc<<1)  ^  0x100b) & 0xffff;
         else
@@ -301,6 +385,69 @@ void Crc16::finish()
 } // Crc16::finish
 
 
+//////////////////////////////////////////////////////////////////////
+//
+//  class u_int32_ba (bit access):
+//  A uint wrapper which allows easy access to bit/range of bits.
+//
+//  Usage example:
+//     u_int32_ba a;
+//     Read_Word( Table.reg ,&a);
+//     int upper_byte = a.range(31,24);
+//     if (a[15])
+//        cout << " Bit 15 is 1 \n";
+//     else
+//        cout << " Bit 15 is 0 \n";
+//
+//     u_int32_ba b;
+//     b.range(15,12) = 0xa;
+//     b[31]          = 1;     // b == 0x8000a000
+//     Write_Word( Table.reg ,b);
+//
+//////////////////////////////////////////////////////////////////////
+
+
+class u_int32_ba {
+public:
+    u_int32_ba(u_int32_t i = 0) :
+    _bits(i),
+    _rbits(_bits),
+    _sptr(0),
+    _eptr(31)    {}
+
+    u_int32_ba  operator[](u_int32_t idx) {return range(idx,idx);}
+    u_int32_ba& operator= (u_int32_t i)   {_rbits = ((i << _sptr) & mask()) | (_rbits & ~mask()); return *this;}
+    u_int32_t*  operator& ()              {return &_bits;}
+    operator    u_int32_t ()              {return((mask() & _rbits) >> _sptr);}
+
+    u_int32_ba  range     (u_int8_t eptr, 
+                           u_int8_t sptr) {return u_int32_ba(*this,eptr,sptr);}
+
+private:
+    u_int32_ba(u_int32_ba& other, u_int8_t eptr, u_int8_t sptr) :
+    _bits(other._bits),
+    _rbits(other._bits),
+    _sptr(sptr),
+    _eptr(eptr) {}
+
+    u_int32_t  mask       () {
+        u_int32_t s_msk = (u_int32_t)-1; // start mask
+        u_int32_t e_msk = (u_int32_t)-1; // end mask
+
+        s_msk = (s_msk << _sptr);
+        e_msk = (_eptr >= (sizeof(_bits)*8-1)) ? e_msk : ~(e_msk << (_eptr+1));
+
+        return(s_msk & e_msk);
+    };
+
+    u_int32_t  _bits;
+    u_int32_t& _rbits;
+
+    u_int8_t   _sptr;
+    u_int8_t   _eptr;
+};
+
+
 ////////////////////////////////////////////////////////////////////////
 //                                                                    //
 // ****************************************************************** //
@@ -311,12 +458,11 @@ void Crc16::finish()
 //#define FUJITSU_BYTE_MODE
 
 // Common base class for Flash and for FImage
-class FBase
-{
+class FBase {
 public:
     FBase() :_err(0)         {}
 
-    virtual bool open(const char *)                        = 0;
+    virtual bool open(const char *, bool)                  = 0;
     virtual void close()                                   = 0;
     virtual bool read(u_int32_t addr, u_int32_t *data)     = 0;
     virtual bool read(u_int32_t addr, void *data, int len,
@@ -326,206 +472,211 @@ public:
 
     char *_err;
 
-    enum { MAX_FLASH = 4*1048576 };
-protected:
+    enum {
+        MAX_FLASH = 4*1048576
+    };
+
     char _msg[1024];
 };
 
 // Flash image (RO)
-class FImage : public FBase
-{
+class FImage : public FBase {
 public:
     FImage() : _buf(0) {}
-    virtual ~FImage() { close(); }
+    virtual ~FImage() { close();}
 
-    u_int32_t    *getBuf()      { return _buf; }
-    u_int32_t    getBufLength() { return _len; }
-    virtual bool open(const char *fname);
+    u_int32_t    *getBuf()      { return _buf;}
+    u_int32_t    getBufLength() { return _len;}
+    virtual bool open(const char *fname, bool read_only = false);
     virtual void close();
     virtual bool read(u_int32_t addr, u_int32_t *data);
     virtual bool read(u_int32_t addr, void *data, int len, bool verbose=false);
 
     virtual u_int32_t get_sector_size();
-    
+
 private:
     u_int32_t *_buf;
     u_int32_t _len;
 };
 
 // Flash access (R/W)
-class Flash : public FBase
-{
-public:
-    Flash();
-    virtual ~Flash()  { close(); };
 
-    enum {
-       CS_INTEL = 0x01,
-       CS_AMD   = 0x02,
-    };
+//
+// Flash classes heirarchy:
+//
+//
+//    Flash { CmdSet (abstract) }
+//      |
+//      | 
+//      +----> ParallelFlash { CmdSetAmd, CmdSetIntel }
+//      |
+//      |
+//      |----> SerialFlash
+//                  |
+//               +--------> SpiFlash { CmdSetStSpi }
+//               |
+//               +- - - - > LpcFlash (currently not uset - not implemented)
+//
+//
+//    Flash Interface:
+//      - open
+//      - close
+//      - read
+//      - detect type (and allocate CmdSet accordingly)  
+//
+//
+//    Flash Class HAS A command set.
+//
+//    CmdSet Interface:
+//      - write 
+//      - erase_sector
+//
+//    Q: Why is diferentiation needed for both flash type and CmdSet ?
+//    A: Read operation is done in the same way for all flash devices of
+//       the same type (serial or parallel). This is a basic requirement 
+//       from the flash, since the HCA HW reads from flash at boot, and 
+//       the way it reads can not be change. 
+//       However, Write and Erase operations protocol varies between flash 
+//       vendors.
+//       The term 'command set' is taken from the Common Flash Interface (CFI)
+//       specification.
+//
+//
+//    Flash Allocation flow:
+//
+//    1. Main checks device type, and allocates Flash sub class accordingly.
+//    2. In Flash.open() , get_cmd_set() is called. this function checks flash
+//       type, gets flash attributes (size, sector size) and allocates CmdSet.
+//
+//       
 
 
-    u_int32_t  curr_sector;
 
-    virtual bool open(const char *device);
-    virtual void close();
-    virtual bool read(u_int32_t addr, u_int32_t *data);
-    virtual bool read(u_int32_t addr, void *data, int len, bool verbose=false);
-    
-    virtual u_int32_t get_sector_size() { return _cfi.erase_block[0].sector_size;}
-    
-
-    bool         query_cfi();
-    bool         unlock_bypass(bool unlock);
-    bool         erase_sector(u_int32_t addr);
-    bool         write(u_int32_t addr, u_int32_t data);
-    bool         write(u_int32_t addr, void *data, int cnt,
-                       bool noerase = false, bool noverify = false);
-    bool         write_image(u_int32_t addr, void *data, int cnt,
-                             bool report=false);
-    bool         lazy_FailSafe_burn(void *data, int cnt, bool need_report);
-    bool         FailSafe_burn(void *data, int cnt, bool need_report);
-    bool         repair(const int from, const int to, bool need_report);
-    bool         FailSafe_burn_internal(void *data, int cnt, bool need_report);
+// 
+//
+//
+class Flash : public FBase {
+public:
+    Flash(u_int32_t log2_bank_size) :  
+    _mf(0), 
+    _cmd_set(NULL), 
+    _curr_bank(0xffffffff),
+    _log2_bank_size(log2_bank_size) 
+    {}
 
-private:
-    mfile        *_mf;
-    u_int32_t    _curr_bank;
-    u_int32_t    _dir;
-    u_int32_t    _pol;
-    u_int32_t    _mod;
-    u_int32_t    _data;
-    bool         _use_scr;
+    virtual ~Flash()  { close();};
 
-    bool         set_bank(u_int32_t bank);
-    bool         write_internal(u_int32_t addr, u_int8_t data);
+    // FBase Interface
 
-    enum FlashCmds { IDLE=0, READ4=(1<<29), WRITE1=(2<<29) };
-    enum { TRANS = 4096 };
-    enum { BANK_SHIFT = 19,     BANK_MASK = 0xfff80000 };
-    enum { FLASH    = 0xf01a4, ADDR_MSK=0x7ffffUL, CMD_MASK=0xe0000000UL };
-    u_int32_t USE_SCR;
-    enum { LEN_MSK = 0x3ff, LEN_SHIFT = 19};
-    enum { CPUMODE  = 0xf0150, CPUMODE_MSK=0xc0000000UL, CPUMODE_SHIFT=30 };
-    enum { SEMAP63    = 0xf03fc, GPIO_DIR_L = 0xf008c, GPIO_POL_L = 0xf0094,
-           GPIO_MOD_L = 0xf009c, GPIO_DAT_L = 0xf0084,
-           GPIO_DATACLEAR_L = 0xf00d4, GPIO_DATASET_L = 0xf00dc };
+    virtual bool open          (const char *device,
+                                bool read_only = false);
 
-    // FLASH constants
-    enum { FLASH_CMD_CNT  = 5000,    // Number of reads till flash cmd is zeroed
-           ERASE_DELAY    = 200000,  // Delay between reads when wating for sector erase
-           ERASE_CNT      = 80,      // Maximal number of reads when wating for sector erase
-           READ_CNT_FAST  = 5000,    // Number of fast reads after write byte
-           READ_CNT_SLOW  = 50,      // Number of slow reads after write byte
-           READ_DELAY     = 100000,  // Delay between slow reads after write byte
-           WR_REPORT_FAST = 256,     // Report frequency when write (fast interfaces)
-           WR_REPORT_SLOW = 4,       // Report frequency when write (slow interfaces)
-           RD_REPORT_FAST = 4096,    // Report frequency when read (fast interfaces)
-           RD_REPORT_SLOW = 64,      // Report frequency when read (slow interfaces)
-           GPIO_SEM_TRIES = 10240,   // Number of tries to obtain a GPIO sem.
-          MAX_WRITE_BUFFER_SIZE = 32// Max buffer size for buffer write devices
-    };
+    virtual void close         ();
 
+    virtual bool read          (u_int32_t addr, 
+                                u_int32_t *data)            = NULL;
 
-    class CmdSet {
-    public:
-       CmdSet                     (Flash& f) : _f(f) {}
-        virtual ~CmdSet            ()                 {}
+    virtual bool read          (u_int32_t addr, 
+                                void*     data, 
+                                int       len, 
+                                bool      verbose = false);
+    //
+    // Flash Interface
+    //
 
-        virtual bool write         (u_int32_t addr, 
-                                   void*     data, 
-                                   int       cnt,
-                                   bool      noerase  = false, 
-                                   bool      noverify = false)  = 0;
+    virtual u_int32_t 
+    get_sector_size        ()                           {return _cfi_data.erase_block[0].sector_size;}
 
-       //virtual bool unlock_bypass (bool      unlock)            = 0;
-       virtual bool erase_sector  (u_int32_t addr)              = 0;
+    virtual bool wait_ready    (const char* msg = NULL)     = NULL;
 
-       virtual bool reset          ()                           = 0;
 
-    protected:
+    // Write and Erase functions are performed by the Command Set
 
-       Flash& _f;
-    };
+    virtual bool erase_sector  (u_int32_t addr)             {if (!set_bank(addr)) return false;return _cmd_set->erase_sector(addr);}
 
+    virtual bool write         (u_int32_t addr, 
+                                void*     data, 
+                                int       cnt,
+                                bool      noerase = false, 
+                                bool      noverify = false) {return _cmd_set->write(addr, data, cnt, noerase, noverify);}
 
+    virtual bool write         (u_int32_t addr, 
+                                u_int32_t data);
 
-    //
-    // AMD's Am29LV033C command set
-    //
-    class CmdSet0002 : public CmdSet {
-    public:
-       CmdSet0002                 (Flash& f  ) : CmdSet(f) {}
+    bool         print_cfi_info();
 
-        virtual bool write         (u_int32_t addr, 
-                                   void*     data, 
-                                   int       cnt,
-                                   bool      noerase  = false, 
-                                   bool      noverify = false);
 
-       virtual bool erase_sector  (u_int32_t addr);
-       virtual bool reset         ();
-    private:
+    enum {
+        TRANS = 4096
+    };
+
+#ifndef _MSC_VER
+protected:
+#endif
 
-       //bool         unlock_bypass (bool      unlock);
+    // FLASH constants
+    enum FlashConstant {
+        FLASH_CMD_CNT  = 5000,    // Number of reads till flash cmd is zeroed
+        ERASE_DELAY    = 200000,  // Delay between reads when wating for sector erase
+        ERASE_CNT      = 80,      // Maximal number of reads when wating for sector erase
+        READ_CNT_FAST  = 5000,    // Number of fast reads after write byte
+        READ_CNT_SLOW  = 50,      // Number of slow reads after write byte
+        READ_DELAY     = 100000,  // Delay between slow reads after write byte
+        WR_REPORT_FAST = 256,     // Report frequency when write (fast interfaces)
+        WR_REPORT_SLOW = 4,       // Report frequency when write (slow interfaces)
+        RD_REPORT_FAST = 4096,    // Report frequency when read (fast interfaces)
+        RD_REPORT_SLOW = 64,      // Report frequency when read (slow interfaces)
+        GPIO_SEM_TRIES = 10240,   // Number of tries to obtain a GPIO sem.
+        MAX_WRITE_BUFFER_SIZE = 32// Max buffer size for buffer write devices
     };
 
-    //
-    // Intel's 28F320J3 x8 command set, using buffer writes
-    //
-    class CmdSet0001 : public CmdSet {
-    public:
-       enum FlashCommand { 
-           FC_ReadID      = 0x90,
-           FC_Read        = 0xFF,
-           FC_Erase       = 0x20,
-           FC_Confirm     = 0xD0,
-           FC_Clear       = 0x50,
-           FC_Write       = 0x40,
-           FC_LoadPB      = 0xE0,
-           FC_PBWrite     = 0x0C,
-           FC_Status      = 0x70,
-           FC_Suspend     = 0xB0,
-           FC_Resume      = 0xD0,
-           FC_ReadESR     = 0x71,
-           FC_QueryCFI    = 0x98,
-           FC_SCSErase    = 0x28,
-           FC_SCSWrite    = 0xE8
-       };
-
-       enum FlashStatus { 
-           FS_Ready       = 0x80,
-           FS_Suspended   = 0x40,
-           FS_Error       = 0x3E,
-           FS_BlockError  = 0x3F
-       };
-
-       CmdSet0001                 (Flash& f) : CmdSet(f) {}
 
-        virtual bool write         (u_int32_t addr, 
-                                   void*     data, 
-                                   int       cnt,
-                                   bool      noerase  = false, 
-                                   bool      noverify = false);
+    enum CrAddres {
+        GPIO_DIR_L     = 0xf008c, 
+        GPIO_POL_L     = 0xf0094,
+        GPIO_MOD_L     = 0xf009c,
+        GPIO_DAT_L     = 0xf0084,
+        GPIO_DATACLEAR_L = 0xf00d4, 
+        GPIO_DATASET_L   = 0xf00dc,
 
-       virtual bool erase_sector  (u_int32_t addr);
-       virtual bool reset         ();
+        SEMAP63        = 0xf03fc
     };
 
+    virtual bool lock           (bool retry=true);
+    virtual bool unlock         ();
 
-    //
-    // Intel's 28F320J3 x8 command set, using byte write (For debug only).
-    //
-    class CmdSet0001WriteByte : public CmdSet0001 {
+    virtual bool init_gpios    ()                           = NULL;
+
+    virtual bool get_cmd_set   ()                           = NULL;
+
+    bool set_bank      (u_int32_t addr);
+
+    virtual bool write_internal(u_int32_t addr, 
+                                u_int8_t  data)             = NULL;
+
+    bool         write_internal(u_int32_t addr, 
+                                u_int8_t* data, 
+                                u_int32_t cnt);
+
+    class CmdSet {
     public:
-       CmdSet0001WriteByte        (Flash& f) : CmdSet0001(f) {}
+        CmdSet                     () : _curr_sector(0xffffffff) {}
+        virtual ~CmdSet            ()                 {}
 
         virtual bool write         (u_int32_t addr, 
-                                   void*     data, 
-                                   int       cnt,
-                                   bool      noerase  = false, 
-                                   bool      noverify = false);
+                                    void*     data, 
+                                    int       cnt,
+                                    bool      noerase  = false, 
+                                    bool      noverify = false)  = NULL;
+
+        //virtual bool unlock_bypass (bool      unlock)            = NULL;
+        virtual bool erase_sector  (u_int32_t addr)              = NULL;
+
+        virtual bool reset         ()                            = NULL;
+
+    protected:
 
+        u_int32_t    _curr_sector; 
     };
 
 
@@ -537,508 +688,1592 @@ private:
     //
 
     struct cfi_query {
-       u_int8_t  manuf_id;
-       u_int8_t  device_id;
-
-       char      query_string[4];              // Should be 'QRY' 
-       u_int16_t oem_command_set;              // Command set 
-       u_int16_t primary_table_address;        // Addy of entended table 
-       u_int16_t alt_command_set;              // Alt table 
-       u_int16_t alt_table_address;            // Alt table addy 
-       float     vcc_min;                      // Vcc minimum 
-       float     vcc_max;                      // Vcc maximum 
-       float     vpp_min;                      // Vpp minimum, if supported 
-       float     vpp_max;                      // Vpp maximum, if supported 
-       int       timeout_single_write;         // Time of single write 
-       int       timeout_buffer_write;         // Time of buffer write 
-       int       timeout_block_erase;          // Time of sector erase 
-       int       timeout_chip_erase;           // Time of chip erase 
-       int       max_timeout_single_write;     // Max time of single write 
-       int       max_timeout_buffer_write;     // Max time of buffer write 
-       int       max_timeout_block_erase;      // Max time of sector erase 
-       int       max_timeout_chip_erase;       // Max time of chip erase 
-       long      device_size;                  // Device size in bytes 
-       u_int16_t interface_description;        // Interface description 
-       int       max_multi_byte_write;         // Time of multi-byte write 
-       int       num_erase_blocks;             // Number of sector defs. 
-       struct {
-           unsigned long sector_size;          // Byte size of sector 
-           int           num_sectors;          // Num sectors of this size 
-           u_int32_t     sector_mask;          // Sector mask 
-       } erase_block[8];                       // Max of 256, but 8 is good 
-
-       // AMD SPECIFIC
-       char primary_extended_query[4];         // Vendor specific info here 
-       u_int16_t major_version;                // Major code version 
-       u_int16_t minor_version;                // Minor code version 
-       u_int8_t  sensitive_unlock;             // Is byte sensitive unlock? 
-       u_int8_t  erase_suspend;                // Capable of erase suspend? 
-       u_int8_t  sector_protect;               // Can Sector protect? 
-       u_int8_t  sector_temp_unprotect;        // Can we temporarily unprotect? 
-       u_int8_t  protect_scheme;               // Scheme of unprotection 
-       u_int8_t  is_simultaneous;              // Is a smulataneous part? 
-       u_int8_t  is_burst;                     // Is a burst mode part? 
-       u_int8_t  is_page;                      // Is a page mode part? 
+        u_int8_t  manuf_id;
+        u_int8_t  device_id;
+
+        char      query_string[4];      // Should be 'QRY' 
+        u_int16_t oem_command_set;              // Command set 
+        u_int16_t primary_table_address;        // Addy of entended table 
+        u_int16_t alt_command_set;              // Alt table 
+        u_int16_t alt_table_address;            // Alt table addy 
+        float     vcc_min;                      // Vcc minimum 
+        float     vcc_max;          // Vcc maximum 
+        float     vpp_min;          // Vpp minimum, if supported 
+        float     vpp_max;          // Vpp maximum, if supported 
+        int       timeout_single_write;         // Time of single write 
+        int       timeout_buffer_write;         // Time of buffer write 
+        int       timeout_block_erase;          // Time of sector erase 
+        int       timeout_chip_erase;       // Time of chip erase 
+        int       max_timeout_single_write;     // Max time of single write 
+        int       max_timeout_buffer_write;     // Max time of buffer write 
+        int       max_timeout_block_erase;  // Max time of sector erase 
+        int       max_timeout_chip_erase;   // Max time of chip erase 
+        long      device_size;              // Device size in bytes 
+        u_int16_t interface_description;    // Interface description 
+        int       max_multi_byte_write;         // Time of multi-byte write 
+        int       num_erase_blocks;     // Number of sector defs. 
+        struct {
+            unsigned long sector_size;          // Byte size of sector 
+            int           num_sectors;      // Num sectors of this size 
+            u_int32_t     sector_mask;          // Sector mask 
+        } erase_block[8];               // Max of 256, but 8 is good 
+
+        // AMD SPECIFIC
+        char primary_extended_query[4];         // Vendor specific info here 
+        u_int16_t major_version;        // Major code version 
+        u_int16_t minor_version;        // Minor code version 
+        u_int8_t  sensitive_unlock;     // Is byte sensitive unlock? 
+        u_int8_t  erase_suspend;        // Capable of erase suspend? 
+        u_int8_t  sector_protect;       // Can Sector protect? 
+        u_int8_t  sector_temp_unprotect;    // Can we temporarily unprotect? 
+        u_int8_t  protect_scheme;       // Scheme of unprotection 
+        u_int8_t  is_simultaneous;      // Is a smulataneous part? 
+        u_int8_t  is_burst;         // Is a burst mode part? 
+        u_int8_t  is_page;          // Is a page mode part? 
     };
 
-    u_int16_t extract_word   ( const u_int8_t* pb, int data_width)  {
-       assert (data_width == 1 || data_width == 2);
-       u_int16_t ret = *pb | ((*(pb + data_width)) << 8);
-       return ret;
-    }
-
-    bool get_cfi        (       cfi_query *query);
     bool print_cfi_info ( const cfi_query *q );
 
-    cfi_query   _cfi;
-    CmdSet*     _cmd_set;
 
+    virtual bool set_bank_int  (u_int32_t bank)              = NULL;
+    u_int32_t    bank_mask     ()                 {return((1 << _log2_bank_size) -1 );}
+
+    mfile        *_mf;
+
+    cfi_query    _cfi_data;
+    CmdSet*      _cmd_set;
+
+    u_int32_t    _curr_bank;
+    u_int32_t    _log2_bank_size;
 };
 
-////////////////////////////////////////////////////////////////////////
-bool FImage::open(const char *fname)
-{
-    struct stat        stat_buf;
-    int                r_cnt;
 
-    int fd = ::open(fname, O_RDONLY | O_BINARY);
-    if (fd < 0)
-    {
-        sprintf(_msg, "Can't open file \"%s\" - %s\n", fname,
-                strerror(errno));
-        _err = &_msg[0];
-        return false;
-    }
-    if (fstat(fd, &stat_buf) < 0)
-    {
-        sprintf(_msg, "Can't stat file \"%s\" - %s\n", fname,
-                strerror(errno));
-        _err = &_msg[0];
-        return false;
-    }
-    //printf("%ld / 0x%lx\n", stat_buf.st_size, stat_buf.st_size);
-    if (stat_buf.st_size & 0x3)
-    {
-        _err = "Image size should be 4-bytes aligned.";
-        return false;
-    }
+class ParallelFlash : public Flash {
+public:
+    ParallelFlash();
+    ~ParallelFlash() {close();}
 
-    _buf = new u_int32_t[stat_buf.st_size/4];
-    if ((r_cnt = ::read(fd, _buf, stat_buf.st_size)) != stat_buf.st_size)
-    {
-        if (r_cnt < 0)
-            sprintf(_msg, "Read error on file \"%s\" - %s\n",
-                    fname, strerror(errno));
-        else
-            sprintf(_msg, "Read error on file \"%s\" - read only %d bytes (from %ld)\n",
-                    fname, r_cnt, (unsigned long)stat_buf.st_size);
-        _err = &_msg[0];
-        return false;
-    }
+    enum {
+        CS_INTEL = 0x01,
+        CS_AMD   = 0x02,
+    };
 
-    _len = stat_buf.st_size;
-    ::close(fd);
-    return true;
-} // FImage::open
+    // FBase Interface
 
-////////////////////////////////////////////////////////////////////////
-void FImage::close()
-{
-    delete [] _buf;
-    _buf = 0;
-} // FImage::close
+//    virtual bool open          (const char *device,
+//                             bool read_only = false);
 
-////////////////////////////////////////////////////////////////////////
-bool FImage::read(u_int32_t addr, u_int32_t *data)
-{
-    if (addr & 0x3)
-    {
-        _err = "Address should be 4-bytes aligned.";
-        return false;
-    }
-    if (!_buf)
-    {
-        _err = "Not opened";
-        return false;
-    }
-    if (addr > _len-4)
-    {
-        sprintf(_msg, "Address (0x%x) is out of image limits\n", addr);
-        _err = &_msg[0];
-        return false;
-    }
-    *data = _buf[addr/4];
-    return true;
-} // FImage::read
+    virtual void close         ();
 
-////////////////////////////////////////////////////////////////////////
-bool FImage::read(u_int32_t addr, void *data, int len, bool)
-{
-    if (addr & 0x3)
-    {
-        _err = "Address should be 4-bytes aligned.";
-        return false;
-    }
-    if (len & 0x3)
-    {
-        _err = "Length should be 4-bytes aligned.";
-        return false;
-    }
-    if (!_buf)
-    {
-        _err = "Not opened";
-        return false;
-    }
 
-    u_int32_t *p = (u_int32_t *)data;
-    for (int i=0; i<len/4; i++)
-    {
-        if (!read(addr, p++))
-            return false;
-        addr += 4;
-    }
-    return true;
-} // FImage::read
+    virtual bool read          (u_int32_t addr, 
+                                u_int32_t *data);
 
-////////////////////////////////////////////////////////////////////////
-u_int32_t FImage::get_sector_size() 
-{      
-    u_int32_t log2_sector_sz_ptr;
-    u_int32_t log2_sector_sz;
-    u_int32_t signature;
+    virtual bool read          (u_int32_t addr, 
+                                void*     data, 
+                                int       len, 
+                                bool      verbose=false) {return Flash::read(addr, data, len, verbose);}
 
-    read(0x24, &signature);
-    TOCPU1(signature);
-    if (signature == SIGNATURE)
-    {
-       // full image:
-       read(0x14, &log2_sector_sz_ptr);
-       TOCPU1(log2_sector_sz_ptr);
-       log2_sector_sz_ptr &= 0xffff;
+    virtual bool wait_ready    (const char* msg = NULL);
 
-       read(0x30 + log2_sector_sz_ptr, &log2_sector_sz);
-       TOCPU1(log2_sector_sz);
-       log2_sector_sz &= 0xffff;
+    bool                        unlock_bypass (bool unlock);
 
-       return (1 << log2_sector_sz);
+#ifndef _MSC_VER
+protected:
+#endif
 
-    } else {
-       return 0;
-    }
-}
+    virtual bool init_gpios    ();
 
+    virtual bool get_cmd_set   ();
 
-////////////////////////////////////////////////////////////////////////
-Flash::Flash() : curr_sector(0xffffffff), _mf(0), _curr_bank(0xffffffff), _cmd_set(0)
-{
-    char *use_scr_p = getenv("FLINT_USE_SCRATCHPAD");
+    virtual bool set_bank_int  (u_int32_t bank);
 
-    if (use_scr_p)
-    {
-        char *endp;
+    virtual bool write_internal(u_int32_t addr, 
+                                u_int8_t  data);
 
-        USE_SCR = strtoul(use_scr_p, &endp, 0);
-        if (*endp)
-        {
-            printf("Invalid FLINT_USE_SCRATCHPAD syntax (%s). Must be integer.",
-                   use_scr_p);
-            _use_scr = false;
-        }
-        else
-        {
-            printf("Burning via SCRATCHPAD interface by addr 0x%x\n", USE_SCR);
-            _use_scr = true;
-        }
-    }
-    else
-        _use_scr = false;
-} // Flash::Flash
+    enum FlashCmds {
+        IDLE           = 0, 
+        READ4          = (1<<29), 
+        WRITE1         = (2<<29) 
+    };
 
+    enum {
+        BANK_SHIFT     = 19,     
+        BANK_MASK      = 0xfff80000 
+    };                 
 
-////////////////////////////////////////////////////////////////////////
-bool Flash::open(const char *device)
-{
-    // Open device
-    _mf = mopen(device);
-    if (!_mf)
-    {
-        _err = strerror(errno);
-        return false;
-    }
-    _curr_bank = 0xffffffff;
+    enum {
+        FLASH          =    0xf01a4, 
+        ADDR_MSK       =    0x7ffffUL, 
+        CMD_MASK       = 0xe0000000UL 
+    };
 
-    // Obtain GPIO Semaphore
-    u_int32_t cnt=0;
-    u_int32_t word;
-    do {
-        if (++cnt > GPIO_SEM_TRIES)
-        {
-            _err = "cannot obtain GPIO semaphore (63)";
-            return false;
-        }
-        MREAD4(SEMAP63, &word);
-    } while (word);
+    enum {
+        LEN_MSK        = 0x3ff, 
+        LEN_SHIFT      = 19
+    };
 
-    // Save old values
-    MREAD4(GPIO_DIR_L, &_dir);
-    MREAD4(GPIO_POL_L, &_pol);
-    MREAD4(GPIO_MOD_L, &_mod);
-    MREAD4(GPIO_DAT_L, &_data);
+    enum {
+        CPUMODE_MSK    = 0xc0000000UL, 
+        CPUMODE_SHIFT  = 30 
+    };
 
-    // Set Direction=1, Polarity=0, Mode=0 for 3 GPIO lower bits
-    u_int32_t dir = _dir | 0x70;
-    u_int32_t pol = _pol & ~0x70;
-    u_int32_t mod = _mod & ~0x70;
-    MWRITE4(GPIO_DIR_L, dir);
-    MWRITE4(GPIO_POL_L, pol);
-    MWRITE4(GPIO_MOD_L, mod);
+    enum CrAddres {
+        CPUMODE        = 0xf0150
+    };
 
-    // Set CPUMODE
-    MREAD4(CPUMODE, &word);
-    word &= ~CPUMODE_MSK;
-    word |= 1 << CPUMODE_SHIFT;
-    MWRITE4(CPUMODE, word);
 
     //
-    // CFI Query
+    // AMD's Am29LV033C command set
     //
-    if (!get_cfi(&_cfi))
-       return false;
+    class CmdSetAmd : public Flash::CmdSet {
+    public:
+        CmdSetAmd                  (ParallelFlash& f  ) : _f(f) {}
+
+        virtual bool write         (u_int32_t addr, 
+                                    void*     data, 
+                                    int       cnt,
+                                    bool      noerase  = false, 
+                                    bool      noverify = false);
+
+        virtual bool erase_sector  (u_int32_t addr);
+        virtual bool reset         ();
+
+    protected:
+        ParallelFlash& _f;
+
+
+        //bool         unlock_bypass (bool      unlock);
+    };
+
 
     //
-    // Some sanity checks:
+    // Intel's 28F320J3 x8 command set, using buffer writes
     //
+    class CmdSetIntel : public Flash::CmdSet {
+    public:
+        enum FlashCommand {
+            FC_ReadID      = 0x90,
+            FC_Read        = 0xFF,
+            FC_Erase       = 0x20,
+            FC_Confirm     = 0xD0,
+            FC_Clear       = 0x50,
+            FC_Write       = 0x40,
+            FC_LoadPB      = 0xE0,
+            FC_PBWrite     = 0x0C,
+            FC_Status      = 0x70,
+            FC_Suspend     = 0xB0,
+            FC_Resume      = 0xD0,
+            FC_ReadESR     = 0x71,
+            FC_QueryCFI    = 0x98,
+            FC_SCSErase    = 0x28,
+            FC_SCSWrite    = 0xE8
+        };
+
+        enum FlashStatus {
+            FS_Ready       = 0x80,
+            FS_Suspended   = 0x40,
+            FS_Error       = 0x3E,
+            FS_BlockError  = 0x3F
+        };
+
+        CmdSetIntel                (ParallelFlash& f  ) : _f(f) {}
 
-    if (_cfi.max_multi_byte_write > MAX_WRITE_BUFFER_SIZE) {
-       _err = "Device write buffer is larger than the supported size.";
-       return false;
-    }
+        virtual bool write         (u_int32_t addr, 
+                                    void*     data, 
+                                    int       cnt,
+                                    bool      noerase  = false, 
+                                    bool      noverify = false);
 
-    if (_cfi.num_erase_blocks > 1) {
-       _err = "Device has more than one sector size - not supported by this tool";
-       return false;
-    }
+        virtual bool erase_sector  (u_int32_t addr);
+        virtual bool reset         ();
+
+    protected:
+        ParallelFlash& _f;
+    };
 
     //
-    // Sellect CmdSet
+    // Intel's 28F320J3 x8 command set, using byte write (For debug only).
     //
+    class CmdSetIntelWriteByte : public CmdSetIntel {
+    public:
+        CmdSetIntelWriteByte       (ParallelFlash& f) : CmdSetIntel(f) {}
 
-    switch (_cfi.oem_command_set) {
-    case CS_INTEL:
-       if (_byte_write || _cfi.max_multi_byte_write == 0)
-           _cmd_set = new CmdSet0001WriteByte(*this);
-       else 
-           _cmd_set = new CmdSet0001(*this);
-       break;
-    case CS_AMD: 
-       _cmd_set = new CmdSet0002(*this);
-       break;
+        virtual bool write         (u_int32_t addr, 
+                                    void*     data, 
+                                    int       cnt,
+                                    bool      noerase  = false, 
+                                    bool      noverify = false);
 
-    default:
-       _err = "Unknown CFI command set";
-       return false;
+    };
+
+    bool get_cfi                (cfi_query *query);
+
+    u_int16_t extract_word   ( const u_int8_t* pb, int data_width)  {
+        assert (data_width == 1 || data_width == 2);
+        u_int16_t ret = *pb | ((*(pb + data_width)) << 8);
+        return ret;
     }
 
-    // Reset flash
-    return _cmd_set->reset();
+    u_int32_t     USE_SCR;
+    bool         _use_scr;
 
-} // Flash::open
+    // Place holders to keep GPIO data for restoring after closing flash.
+    u_int32_t    _dir;
+    u_int32_t    _pol;
+    u_int32_t    _mod;
+    u_int32_t    _data;
 
-////////////////////////////////////////////////////////////////////////
-void Flash::close()
-{
-    if (!_mf)
-        return;
+};
 
-    delete _cmd_set;
 
-    if (_unlock_bypass) {
-       unlock_bypass(false);
-    }
+class SerialFlash : public Flash {
+public:
+    SerialFlash() : Flash(20) {}
 
-    // Restore origin values
-    mwrite4(_mf, GPIO_DIR_L, _dir);
-    mwrite4(_mf, GPIO_POL_L, _pol);
-    mwrite4(_mf, GPIO_MOD_L, _mod);
-    mwrite4(_mf, GPIO_DAT_L, _data);
+    enum CrAddres {
+        FLASH_GW     = 0xf0400,
+        FLASH_ADDR   = 0xf0404,
+        FLASH_DATA   = 0xf0408,
+        FLASH_CS     = 0xf0418,
 
-    // Free GPIO Semaphore
-    mwrite4(_mf, SEMAP63, 0);
+        GPIO_LOCK    = 0xf00ec
+    };
 
-    mclose(_mf);
-    _mf = 0;
-    _curr_bank = 0xffffffff;
+    enum BitOffset {
+        READ_OP      = 0,
+        ADDR_INCR    = 1,
 
-} // Flash::close
+        LPC_STOP     = 3,
+        SPI_NO_DATA  = 4,
+        SPI_NO_ADDR  = 5,
+        SPI_SPECIAL  = 6,
+
+        MSIZE_S      = 8,
+        MSIZE_E      = 10,
+
+        STATUS_S     = 26,
+        STATUS_E     = 29,
+
+        BUSY         = 30,
+
+        SPI_ADDR_S   = 0,
+        SPI_ADDR_E   = 23,
+
+        SPI_CMD_S    = 24,
+        SPI_CMD_E    = 31,
+
+        SPI_GPIO_S   = 5,
+        SPI_GPIO_E   = 7
+    };
+
+
+protected:
+
+    virtual bool write_internal(u_int32_t addr, 
+                                u_int8_t  data);
+
+};
+
+bool SerialFlash::write_internal (u_int32_t addr, 
+                                  u_int8_t  data)  {addr = 0; data = 0; return true;}
+
+
+class SpiFlash : public SerialFlash {
+public:
+    SpiFlash() {}
+    ~SpiFlash() {close();}
+
+
+    // FBase Interface
+
+    virtual void close         ();
+
+    virtual bool read          (u_int32_t addr, 
+                                u_int32_t *data);
+
+    virtual bool read          (u_int32_t addr, 
+                                void*     data, 
+                                int       len, 
+                                bool      verbose=false) {return Flash::read(addr, data, len, verbose);}
+
+    virtual bool wait_ready    (const char* msg);
+
+protected:
+
+    virtual bool init_gpios    ();
+
+    virtual bool get_cmd_set   ();
+
+    virtual bool set_bank_int  (u_int32_t bank);
+
+
+    //
+    // ST's M25P80 command set
+    //
+    class CmdSetStSpi : public Flash::CmdSet {
+    public:
+        CmdSetStSpi                (SpiFlash& f  ) : _f(f) , _mf(f._mf){}
 
+        virtual bool write         (u_int32_t addr, 
+                                    void*     data, 
+                                    int       cnt,
+                                    bool      noerase  = false, 
+                                    bool      noverify = false);
+
+        virtual bool erase_sector  (u_int32_t addr);
+
+        virtual bool reset         ()                {return true;}
+
+        enum FlashCommand {
+            FC_SE    = 0xD8,
+            FC_PP    = 0x02,
+            FC_RDSR  = 0x05,
+            FC_WREN  = 0x06,
+            FC_READ  = 0x03,
+            FC_RDID  = 0x09
+        }; 
+
+
+    protected:
+        bool         write_block   (u_int32_t block_addr, 
+                                    void*     block_data, 
+                                    u_int32_t block_size);
+
+        bool         wait_wip      (u_int32_t delay, 
+                                    u_int32_t retrys, 
+                                    u_int32_t fast_retry = 0);
+
+        bool         write_enable  ();
+
+
+        SpiFlash& _f;
+        mfile*    _mf;
+
+    };
+
+    bool fill_cfi                  (cfi_query *query);
+
+};
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// FImage Class Implementation
+//
 ////////////////////////////////////////////////////////////////////////
-bool Flash::set_bank(u_int32_t bank)
+bool FImage::open(const char *fname, bool read_only)
 {
-    if (!_mf)
-    {
-        _err = "Not opened";
+    struct stat        stat_buf;
+    int                r_cnt;
+
+    read_only = true;  // FImage can be opened only for read
+
+    int fd = ::open(fname, O_RDONLY | O_BINARY, 0);
+    if (fd < 0) {
+        sprintf(_msg, "Can't open file \"%s\" - %s\n", fname,
+                strerror(errno));
+        _err = &_msg[0];
+        return false;
+    }
+    if (fstat(fd, &stat_buf) < 0) {
+        sprintf(_msg, "Can't stat file \"%s\" - %s\n", fname,
+                strerror(errno));
+        _err = &_msg[0];
+        return false;
+    }
+    //printf("%ld / 0x%lx\n", stat_buf.st_size, stat_buf.st_size);
+    if (stat_buf.st_size & 0x3) {
+        _err = "Image size should be 4-bytes aligned.";
         return false;
     }
 
-    //printf("\n*** Flash::set_bank(0x%lx) : 0x%lx\n", bank, (bank >> 19) & 0x07);
-    MWRITE4(GPIO_DATACLEAR_L, 0x70);
-    MWRITE4(GPIO_DATASET_L, (bank >> (BANK_SHIFT-4)) & 0x70);
+    _buf = new u_int32_t[stat_buf.st_size/4];
+    if ((r_cnt = ::read(fd, _buf, stat_buf.st_size)) != stat_buf.st_size) {
+        if (r_cnt < 0)
+            sprintf(_msg, "Read error on file \"%s\" - %s\n",
+                    fname, strerror(errno));
+        else
+            sprintf(_msg, "Read error on file \"%s\" - read only %d bytes (from %ld)\n",
+                    fname, r_cnt, (unsigned long)stat_buf.st_size);
+        _err = &_msg[0];
+        return false;
+    }
+
+    _len = stat_buf.st_size;
+    ::close(fd);
     return true;
-} // Flash::set_bank
+} // FImage::open
 
 ////////////////////////////////////////////////////////////////////////
-bool Flash::read(u_int32_t addr, u_int32_t *data)
+void FImage::close()
 {
-    if (!_mf)
-    {
-        _err = "Not opened";
-        return false;
-    }
+    delete [] _buf;
+    _buf = 0;
+} // FImage::close
 
-    u_int32_t cmd;
-    if (addr & 0x3)
-    {
+////////////////////////////////////////////////////////////////////////
+bool FImage::read(u_int32_t addr, u_int32_t *data)
+{
+    if (addr & 0x3) {
         _err = "Address should be 4-bytes aligned.";
         return false;
     }
-
-    u_int32_t bank = addr & 0xfff80000;
-    if (bank != _curr_bank)
-    {
-        _curr_bank = bank;
-        if (!set_bank(bank))
-            return false;
+    if (!_buf) {
+        _err = "Not opened";
+        return false;
     }
-
-    MWRITE4(FLASH, READ4 | (addr & ADDR_MSK));
-    u_int32_t cnt = 0;
-    do
-    {
-        // Timeout checks
-        if (++cnt > FLASH_CMD_CNT)
-        {
-            _err = "Flash gateway timeout: CMD doesn't become zero";
-            return false;
-        }
-
-        MREAD4(FLASH, &cmd);
-
-    } while(cmd & CMD_MASK);
-    MREAD4(FLASH+4, &cmd);
-    cmd = __be32_to_cpu(cmd);
-    memcpy(data, &cmd, sizeof(u_int32_t));
-
+    if (addr > _len-4) {
+        sprintf(_msg, "Address (0x%x) is out of image limits\n", addr);
+        _err = &_msg[0];
+        return false;
+    }
+    *data = _buf[addr/4];
     return true;
-} // Flash::read
+} // FImage::read
 
 ////////////////////////////////////////////////////////////////////////
-bool Flash::read(u_int32_t addr, void *data, int len, bool verbose)
+bool FImage::read(u_int32_t addr, void *data, int len, bool)
 {
-    u_int32_t  perc = 0xffffffff;
-
-    if (addr & 0x3)
-    {
+    if (addr & 0x3) {
         _err = "Address should be 4-bytes aligned.";
         return false;
     }
-    if (len & 0x3)
-    {
+    if (len & 0x3) {
         _err = "Length should be 4-bytes aligned.";
         return false;
     }
-
-    // Report
-    if (verbose)
-    {
-        printf("000%%");
-        fflush(stdout);
+    if (!_buf) {
+        _err = "Not opened";
+        return false;
     }
 
     u_int32_t *p = (u_int32_t *)data;
-    for (int i=0; i<len/4; i++)
-    {
+    for (int i=0; i<len/4; i++) {
         if (!read(addr, p++))
             return false;
         addr += 4;
-
-        // Report
-        if (verbose)
-        {
-            u_int32_t new_perc = (i * 100) / len;
-            if (new_perc != perc)
-            {
-                printf("\b\b\b\b%03d%%", new_perc);
-                fflush(stdout);
-                perc = new_perc;
-            }
-        }
     }
+    return true;
+} // FImage::read
 
-    // Report
-    if (verbose)
-    {
-        printf("\b\b\b\b100%%");
-        fflush(stdout);
+////////////////////////////////////////////////////////////////////////
+u_int32_t FImage::get_sector_size() 
+{   
+    u_int32_t log2_sector_sz_ptr;
+    u_int32_t log2_sector_sz;
+    u_int32_t signature;
+
+    read(0x24, &signature);
+    TOCPU1(signature);
+    if (signature == SIGNATURE) {
+        // full image:
+        read(0x14, &log2_sector_sz_ptr);
+        TOCPU1(log2_sector_sz_ptr);
+        log2_sector_sz_ptr &= 0xffff;
+
+        read(0x30 + log2_sector_sz_ptr, &log2_sector_sz);
+        TOCPU1(log2_sector_sz);
+        log2_sector_sz &= 0xffff;
+
+        return(1 << log2_sector_sz);
+
+    } else {
+        return 0;
     }
+}
 
-    return true;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Flash Class Implementation
+//
+////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////
+bool Flash::open(const char *device, bool read_only)
+{
+
+    // Open device
+    _mf = mopen(device);
+    if (!_mf) {
+        _err = strerror(errno);
+        return false;
+    }
+
+    if (!lock())
+        return false;
+
+    if (!init_gpios())
+        return false;
+
+    if (!read_only) {
+        if (!get_cmd_set())
+            return false;
+
+        // Reset flash
+        return _cmd_set->reset(); 
+    }
+
+    return true;
+} // Flash::open
+
+////////////////////////////////////////////////////////////////////////
+void Flash::close()
+{
+    if (!_mf)
+        return;
+
+    delete _cmd_set;
+
+    // ??? Check if unlock should be before delete _cmd_set
+    unlock();
+
+    mclose(_mf); 
+    _mf = 0;
+
+} // Flash::close
+
+
+bool Flash::lock(bool retry) {
+
+    retry = false; // compiler - REMOVE ???
+
+    // Obtain GPIO Semaphore
+    u_int32_t cnt=0;
+    u_int32_t word;
+    do {
+        if (++cnt > GPIO_SEM_TRIES) {
+            _err = "cannot obtain Flash semaphore (63)";
+            return false;
+        }
+        MREAD4(SEMAP63, &word);
+    } while (word);
+
+    return true;
+}
+
+
+bool Flash::unlock() {
+
+    // Free GPIO Semaphore
+    mwrite4(_mf, SEMAP63, 0);
+    return true;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+bool Flash::read(u_int32_t addr, void *data, int len, bool verbose)
+{
+    u_int32_t  perc = 0xffffffff;
+
+    if (addr & 0x3) {
+        _err = "Address should be 4-bytes aligned.";
+        return false;
+    }
+    if (len & 0x3) {
+        _err = "Length should be 4-bytes aligned.";
+        return false;
+    }
+
+    // Report
+    if (verbose) {
+        printf("000%%");
+        fflush(stdout);
+    }
+
+    u_int32_t *p = (u_int32_t *)data;
+    for (int i=0; i<len/4; i++) {
+        if (!read(addr, p++))
+            return false;
+        addr += 4;
+
+        // Report
+        if (verbose) {
+            u_int32_t new_perc = (i * 100) / len;
+            if (new_perc != perc) {
+                printf("\b\b\b\b%03d%%", new_perc);
+                fflush(stdout);
+                perc = new_perc;
+            }
+        }
+    }
+
+    // Report
+    if (verbose) {
+        printf("\b\b\b\b100%%");
+        fflush(stdout);
+    }
+
+    return true;
 } // Flash::read
 
+
+////////////////////////////////////////////////////////////////////////
+bool Flash::write(u_int32_t addr, u_int32_t data)
+{
+    if (!_mf) {
+        _err = "Not opened";
+        return false;
+    }
+    if (addr & 0x3) {
+        _err = "Address should be 4-bytes aligned.";
+        return false;
+    }
+
+    u_int32_t word;
+
+    // TODO: Rewrite using get_sector_size() only
+    u_int32_t sector = addr & _cfi_data.erase_block[0].sector_mask;
+    u_int32_t word_in_sector = (addr & ~_cfi_data.erase_block[0].sector_mask)/sizeof(u_int32_t);
+
+    if (!read(addr, &word))
+        return false;
+    if (word == data)
+        return true;   // already there
+
+       vector<u_int32_t> buff(get_sector_size()/sizeof(u_int32_t));
+    if (!read(sector, &buff[0] , get_sector_size()))
+        return false;
+    buff[word_in_sector] = data;
+    return write(sector, &buff[0], get_sector_size());
+} // Flash::write
+
+////////////////////////////////////////////////////////////////////////
+
+inline
+bool Flash::set_bank      (u_int32_t addr) {
+    u_int32_t bank = (addr >> _log2_bank_size);
+
+    if (bank != _curr_bank ) {
+        if (!set_bank_int(bank))
+            return false;
+
+        _curr_bank = bank;
+    }
+
+    return true;
+}
+
+
+// A smaple function which loops through and prints out the data
+// contained in the CFI query structure.  Should ONLY be called
+// after init_flash 
+
+bool Flash::print_cfi_info()
+{
+
+    const cfi_query *q = &_cfi_data;
+
+    int i=0;
+    printf("\n");
+
+    char* head_fmt = "%-50s ";
+
+    printf(head_fmt, "CFI Query String Read:");
+    printf("[%s]\n", (char *) q->query_string);
+
+    printf(head_fmt, "Primary table address at offset:");
+    printf("[0x%2x] hex.\n", q->primary_table_address);
+
+    printf(head_fmt, "Manufacturer ID, Device ID:");
+    printf("[0x%02x,0x%02x] hex.\n", q->manuf_id, q->device_id );
+
+    printf(head_fmt, "Command set:");
+    printf("[0x%04x] hex.\n", q->oem_command_set);
+
+    printf(head_fmt, "Write buffer:");
+    printf("[%d] bytes\n", q->max_multi_byte_write );
+
+    printf("\n----Voltage and Signal Timing Parameters-------------------\n");
+    printf(head_fmt, "Vcc operating voltage:");
+    printf("[%2.3f] to [%2.3f] Volts\n", q->vcc_min, q->vcc_max);
+
+
+    printf(head_fmt, "Vpp operating voltage:");
+    if (q->vpp_min == 0.0)
+        printf("Device does not support Vpp voltage.\n");
+    else {
+        printf("[%2.3f] to [%2.3f] Volts\n", q->vpp_min, q->vpp_max);
+    }
+
+    printf(head_fmt, "Typical timeout for single write (micro-sec):");
+    printf("[%8i]us\n", q->timeout_single_write);
+
+
+
+    printf(head_fmt,"Typical timeout for single write (micro-sec):");
+    if (q->timeout_buffer_write == 0x00)
+        printf("Buffer writes not supported in this device.\n");
+    else {
+        printf("[%8i]us\n" ,q->timeout_buffer_write);
+    }
+
+    printf(head_fmt, "Typical timeout for block erase (milli-sec):", q->timeout_block_erase);
+    printf("[%8i]ms\n", q->timeout_block_erase);
+
+    printf(head_fmt, "Typical timeout for chip erase (milli-sec):");
+    if (q->timeout_chip_erase == 0x00)
+        printf("Not supported in this device.\n");
+    else {
+        printf("[%8i]ms\n", q->timeout_single_write);
+    }
+
+    printf(head_fmt, "Maximum timeout for single write (micro-sec) :");
+    printf("[%8i]us\n", q->max_timeout_single_write);
+
+    printf(head_fmt, "Maximum timeout for buffer write (micro-sec) :");
+    if (q->max_timeout_buffer_write == 0x00)
+        printf("Not supported in this device.\n");
+    else {
+        printf("[%8i]us\n", q->max_timeout_buffer_write);
+    }
+
+    printf(head_fmt, "Maximum timeout for block erase (milli-sec) :");
+    printf("[%8i]ms\n", q->max_timeout_block_erase);
+
+    printf(head_fmt, "Maximum timeout for chip erase (milli-sec) :");
+    if (q->max_timeout_chip_erase == 0x00)
+        printf("Not supported in this device.\n");
+    else {
+        printf("[%8i]ms\n", q->max_timeout_chip_erase);
+    }
+
+
+
+
+    printf("\n----Sector Organization Parameters-------------------\n\n");
+
+    printf(head_fmt, "Device size:");
+    printf("[%8li] bytes, or [%2i] Mbit\n",
+           q->device_size, 
+           (int) (q->device_size/((long)0x20000)));
+
+    printf(head_fmt, "Number of erase block regions:");
+    printf("%d\n",q->num_erase_blocks);
+
+    for (i=0; i<q->num_erase_blocks; i++) {
+        printf("  Size:[%8lx] bytes, Mask [%08x], [Number:[%4i]\n",
+               q->erase_block[i].sector_size,
+               q->erase_block[i].sector_mask,
+               q->erase_block[i].num_sectors);
+    }
+
+    printf("\n----Primary Vendor-Specific Extended Parameters----\n\n");
+
+    printf(head_fmt, "CFI Extended String Read:");
+    printf("[%s]\n", (char *) q->primary_extended_query);
+
+    printf(head_fmt, "Major version:", q->major_version);
+    printf("[%3x]\n", q->major_version);
+
+    printf(head_fmt, "Minor version:", q->minor_version);
+    printf("[%3x]\n", q->minor_version);
+
+    printf(head_fmt, "Sensitive Unlock:", q->sensitive_unlock);
+    printf("[%3x]\n", q->sensitive_unlock);
+
+    printf(head_fmt, "Erase Suspend:", q->erase_suspend);
+    printf("[%3x]\n", q->erase_suspend);
+
+    printf(head_fmt, "Sector Protect:", q->sector_protect);
+    printf("[%3x]\n", q->sector_protect);
+
+    printf(head_fmt, "Temporary Sector Unprotect:", q->sector_temp_unprotect);
+    printf("[%3x]\n", q->sector_temp_unprotect);
+
+    printf(head_fmt, "Protection Scheme:", q->protect_scheme);
+    printf("[%3x]\n", q->protect_scheme);
+
+    printf(head_fmt, "Is simultaneous? :", q->is_simultaneous);
+    printf("[%3x]\n", q->is_simultaneous);
+
+    printf(head_fmt, "Is Burst capable? :", q->is_burst);
+    printf("[%3x]\n", q->is_burst);
+
+    printf(head_fmt, "Is Page capable? :", q->is_page);
+    printf("[%3x]\n", q->is_page);
+
+    printf("Done.\n\n");
+
+    return true;
+} // Flash::print_cfi_info()
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// ParallelFlash Class Implementation
+//
+////////////////////////////////////////////////////////////////////////
+
+ParallelFlash::ParallelFlash() : Flash(19)
+{
+    char *use_scr_p = getenv("FLINT_USE_SCRATCHPAD");
+
+    if (use_scr_p) {
+        char *endp;
+
+        USE_SCR = strtoul(use_scr_p, &endp, 0);
+        if (*endp) {
+            printf("Invalid FLINT_USE_SCRATCHPAD syntax (%s). Must be integer.",
+                   use_scr_p);
+            _use_scr = false;
+        } else {
+            printf("Burning via SCRATCHPAD interface by addr 0x%x\n", USE_SCR);
+            _use_scr = true;
+        }
+    } else
+        _use_scr = false;
+} // Flash::Flash
+
+
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::init_gpios() {
+
+    // Save old values
+    MREAD4(GPIO_DIR_L, &_dir);
+    MREAD4(GPIO_POL_L, &_pol);
+    MREAD4(GPIO_MOD_L, &_mod);
+    MREAD4(GPIO_DAT_L, &_data);
+
+    // Set Direction=1, Polarity=0, Mode=0 for 3 GPIO lower bits
+    u_int32_t dir = _dir | 0x70;
+    u_int32_t pol = _pol & ~0x70;
+    u_int32_t mod = _mod & ~0x70;
+    MWRITE4(GPIO_DIR_L, dir);
+    MWRITE4(GPIO_POL_L, pol);
+    MWRITE4(GPIO_MOD_L, mod);
+
+    // Set CPUMODE
+    u_int32_t word;
+    MREAD4(CPUMODE, &word);
+    word &= ~CPUMODE_MSK;
+    word |= 1 << CPUMODE_SHIFT;
+    MWRITE4(CPUMODE, word);
+
+    return true;
+}
+
+void ParallelFlash::close() {
+    if (_unlock_bypass) {
+        unlock_bypass(false);
+    }
+
+    // Restore origin values
+    mwrite4(_mf, GPIO_DIR_L, _dir);
+    mwrite4(_mf, GPIO_POL_L, _pol);
+    mwrite4(_mf, GPIO_MOD_L, _mod);
+    mwrite4(_mf, GPIO_DAT_L, _data);
+
+    _curr_bank = 0xffffffff;
+
+    Flash::close();
+}
+
+
+bool ParallelFlash::get_cmd_set() {
+
+    //
+    // CFI Query
+    //
+    if (!get_cfi(&_cfi_data))
+        return false;
+
+    //
+    // Some sanity checks:
+    //
+
+    if (_cfi_data.max_multi_byte_write > MAX_WRITE_BUFFER_SIZE) {
+        _err = "Device write buffer is larger than the supported size.";
+        return false;
+    }
+
+    if (_cfi_data.num_erase_blocks > 1) {
+        _err = "Device has more than one sector size - not supported by this tool";
+        return false;
+    }
+
+    //
+    // Sellect CmdSet
+    //
+
+    switch (_cfi_data.oem_command_set) {
+    case CS_INTEL:
+        if (_byte_write || _cfi_data.max_multi_byte_write == 0)
+            _cmd_set = new CmdSetIntelWriteByte(*this);
+        else
+            _cmd_set = new CmdSetIntel(*this);
+        break;
+    case CS_AMD: 
+        _cmd_set =     new CmdSetAmd(*this);
+        break;
+
+    default:
+        _err = "Unknown CFI command set";
+        return false;
+    }
+
+    return true;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::set_bank_int(u_int32_t bank)
+{
+    if (!_mf) {
+        _err = "Not opened";
+        return false;
+    }
+
+    //printf("\n*** Flash::set_bank(0x%lx) : 0x%lx\n", bank, (bank >> 19) & 0x07);
+    MWRITE4(GPIO_DATACLEAR_L, 0x70);
+    MWRITE4(GPIO_DATASET_L, (bank << 4) & 0x70);
+
+    return true;
+} // Flash::ParallelFlashGw::set_bank_int
+
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::wait_ready(const char* msg) {
+    u_int32_t cnt = 0;
+    u_int32_t cmd;
+    do {
+        // Timeout checks
+        if (++cnt > FLASH_CMD_CNT) {
+            sprintf(_msg, "Flash gateway timeout: %s", msg);
+            _err = _msg;
+            return false;
+        }
+
+        MREAD4(FLASH, &cmd);
+
+    } while (cmd & CMD_MASK);
+
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::read(u_int32_t addr, u_int32_t *data)
+{
+    if (!_mf) {
+        _err = "Not opened";
+        return false;
+    }
+
+    u_int32_t cmd;
+    if (addr & 0x3) {
+        _err = "Address should be 4-bytes aligned.";
+        return false;
+    }
+
+    if (!set_bank(addr))
+        return false;
+
+
+    MWRITE4(FLASH, READ4 | (addr & ADDR_MSK));
+
+    if (!wait_ready("Read"))
+        return false;
+
+    MREAD4(FLASH+4, &cmd);
+    cmd = __cpu_to_be32(cmd);
+    memcpy(data, &cmd, sizeof(u_int32_t));
+
+    return true;
+} // Flash::read
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::write_internal(u_int32_t addr, u_int8_t data)
+{
+    MWRITE4(FLASH+4, data << 24);
+    MWRITE4(FLASH, WRITE1 | (addr & ADDR_MSK));
+
+    if (!wait_ready("Write"))
+        return false;
+
+    return true;
+} // Flash::write_internal
+
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::unlock_bypass(bool unlock) {
+
+    if (unlock) {
+        // unlock bypass
+
+        if (!write_internal(0x555, 0xaa))
+            return false;
+        if (!write_internal(0x2aa, 0x55))
+            return false;
+        if (!write_internal(0x555, 0x20))
+            return false;
+    } else {
+        // unlock reset
+        if (!write_internal(0x555, 0x90))
+            return false;
+        if (!write_internal(0x2aa, 0x00))
+            return false;
+    }
+    return true;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::CmdSetAmd::write(u_int32_t addr, void *data, int cnt,
+                                     bool noerase, bool noverify)
+{
+    if (!_f._mf) {
+        _f._err = "Not opened";
+        return false;
+    }
+    if (addr & 0x3) {
+        _f._err = "Address should be 4-bytes aligned.";
+        return false;
+    }
+
+    char         *p = (char *)data;
+
+    for (int i=0; i<cnt; i++,addr++) {
+        u_int32_t  word;
+        u_int8_t   act, exp;
+        int        cnt1 = 0;
+
+        if (!_f.set_bank(addr))
+            return false;
+
+        if (!noerase) {
+            u_int32_t sector = (addr / _f.get_sector_size()) * _f.get_sector_size();
+            if (sector != _curr_sector) {
+                _curr_sector = sector;
+                if (!erase_sector(_curr_sector))
+                    return false;
+            }
+        }
+
+        if (_no_burn)
+            continue;
+
+        if (_f._use_scr) {
+
+            //
+            // Special burning interface via Scratchpad
+            // ----------------------------------------
+            //
+            u_int32_t cmd;
+            u_int32_t data = (*p++ & 0xff) << 24;
+            data |= (*p++ & 0xff) << 16;
+            data |= (*p++ & 0xff) << 8;
+            data |= (*p++ & 0xff);
+            if (mwrite4(_f._mf, _f.USE_SCR+4 , data) != 4) return false;
+            if (mwrite4(_f._mf, _f.USE_SCR ,   WRITE1 | (3 << LEN_SHIFT) | (addr & ADDR_MSK)) != 4) return false;
+            do {
+                int  loop_cnt = 0;
+                // Timeout checks
+                if (++loop_cnt > FLASH_CMD_CNT) {
+                    _f._err = "Use scratchpad: CMD doesn't become zero";
+                    return false;
+                }
+                if (mread4(_f._mf, _f.USE_SCR , &cmd) != 4) return false;
+
+            } while (cmd & CMD_MASK);
+            i += 3;
+            addr += 3;
+        } else if ((u_int8_t)(*p) != 0xff) {
+
+#ifdef FUJITSU_BYTE_MODE
+            if (!_f.write_internal(0xaaa, 0xaa))
+                return false;
+            if (!_f.write_internal(0x555, 0x55))
+                return false;
+            if (!_f.write_internal(0xaaa, 0xa0))
+                return false;
+#else // FUJITSU_WORD_MODE
+            if (!_unlock_bypass) {
+                if (!_f.write_internal(0x555, 0xaa))
+                    return false;
+                if (!_f.write_internal(0x2aa, 0x55))
+                    return false;
+            }
+
+            if (!_f.write_internal(0x555, 0xa0))
+                return false;
+#endif
+
+            if (!_f.write_internal(addr, *p++))
+                return false;
+
+            do {
+                // Timeout checks
+                if (++cnt1 > READ_CNT_FAST)
+                    usleep(READ_DELAY);
+                if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW) {
+                    _f._err = "Flash write error - read value didn't stabilized.";
+                    return false;
+                }
+
+                if (!_f.read(addr & ~3, &word))
+                    return false;
+
+                word = __be32_to_cpu(word);
+                act = (u_int8_t) ((word >> ((3 - (addr & 3)) * 8)) & 0xff);
+                exp = *(p-1) & 0xff;
+                //if (act != exp)
+                //    printf("write: %08x - exp:%02x act:%02x /%08x/\n",
+                //           addr, exp & 0xff, act & 0xff, word);
+            } while (!noverify && act != exp);      
+
+        } else {
+            p++;
+        }
+    } 
+    return true;
+} // flash_write
+
+
+
+bool ParallelFlash::CmdSetIntelWriteByte::write(u_int32_t addr, void *data, int cnt,
+                                                bool noerase, bool noverify)
+{
+    if (!_f._mf) {
+        _f._err = "Not opened";
+        return false;
+    }
+    if (addr & 0x3) {
+        _f._err = "Address should be 4-bytes aligned.";
+        return false;
+    }
+
+    char         *p = (char *)data;
+
+    for (int i=0; i<cnt; i++,addr++) {
+        u_int32_t  status;
+        u_int8_t   act, exp;
+        int        cnt1 = 0;
+
+        if (!_f.set_bank(addr))
+            return false;
+
+        if (!noerase) {
+            u_int32_t sector = (addr / _f.get_sector_size()) * _f.get_sector_size();
+            if (sector != _curr_sector) {
+                _curr_sector = sector;
+                if (!erase_sector(_curr_sector))
+                    return false;
+            }
+        }
+
+        if (_no_burn)
+            continue;
+
+        if ((u_int8_t)(*p) != 0xff) {
+            // Write byte
+            if (!_f.write_internal(addr, FC_Write))
+                return false;
+
+            if (!_f.write_internal(addr, *p++))
+                return false;
+
+            do {
+                // Timeout checks
+                if (++cnt1 > READ_CNT_FAST)
+                    usleep(READ_DELAY);
+                if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW) {
+                    _f._err = "Flash write error - timeout waiting for ready after write.";
+                    return false;
+                }
+
+                // TODO - Move to read single for Arbel
+                if (!_f.read(addr & ~3, &status))
+                    return false;
+
+                //if (act != exp)
+                //    printf("write: %08x - exp:%02x act:%02x /%08x/\n",
+                //           addr, exp & 0xff, act & 0xff, word);
+            } while ((status & FS_Ready) == 0);
+
+            if (status & FS_Error) {
+                _f._err = "Flash write error - error staus detected.";
+                return false;
+            }
+
+            if (!noverify) {
+                u_int32_t word;
+                if (!reset())
+                    return false;
+                // TODO - Move to read single for Arbel
+                if (!_f.read(addr & ~3, &word))
+                    return false;
+
+                word = __be32_to_cpu(word);
+                act = (u_int8_t) ((word >> ((3 - (addr & 3)) * 8)) & 0xff);
+                exp = *(p-1) & 0xff;
+
+                if (act != exp) {
+                    printf("write: %08x - exp:%02x act:%02x /%08x/\n",
+                           addr, exp & 0xff, act & 0xff, word);
+
+                    _f._err = "Write verification failed";
+                    return false;
+                }
+            }
+
+        } else {
+            p++;
+        }
+    }
+
+    if (!reset())
+        return false;
+
+    return true;
+} // flash_write
+
+///////////////////////////////////////////////////////////////////////////
+
+//
+// Use the buffer write capability.
+//
+bool ParallelFlash::CmdSetIntel::write(u_int32_t addr, void *data, int cnt,
+                                       bool noerase, bool noverify)
+{
+    if (!_f._mf) {
+        _f._err = "Not opened";
+        return false;
+    }
+    if (addr & 0x3) {
+        _f._err = "Address should be 4-bytes aligned.";
+        return false;
+    }
+
+    u_int8_t         *p = (u_int8_t *)data;
+
+    u_int32_t block_size = _f._cfi_data.max_multi_byte_write;
+    u_int32_t block_mask = ~(block_size - 1 );
+
+    // TODO - Check MAX_WRITE_BUFFER_SIZE against block_size in open (or here)
+    u_int8_t  tmp_buff[MAX_WRITE_BUFFER_SIZE];
+
+    while (cnt) {
+
+        u_int32_t prefix_pad_size = 0;
+        u_int32_t suffix_pad_size = 0;
+
+        u_int32_t block_addr = addr & block_mask;
+        u_int32_t data_size  = block_size;
+
+        u_int8_t* write_data = p;
+
+
+        //
+        // First and last cycles (can be the same one) may not be block aligned.
+        // Check the status, and copy data to a padded temp bufer if not alligned.
+        // (there's an option to write partial buffer, but Intel reference code always
+        // writes full buffer, with pads if needed. I do the dame ...)
+        //
+
+        prefix_pad_size = addr - block_addr;
+
+        if ((addr & block_mask) == ((addr + cnt) & block_mask)) {
+            suffix_pad_size = block_size - ((addr + cnt) % block_size);
+        }
+
+        if (suffix_pad_size || prefix_pad_size) {
+            memset(tmp_buff, 0xff, block_size);
+
+            data_size -= prefix_pad_size;
+            data_size -= suffix_pad_size;
+
+            memcpy(tmp_buff + prefix_pad_size, p , data_size);
+
+            write_data = tmp_buff;
+        }
+
+        int        cnt1 = 0;
+
+        //
+        // Bank setup.
+        //
+        if (!_f.set_bank(addr))
+            return false;
+
+        if (!noerase) {
+            u_int32_t sector = (addr / _f.get_sector_size()) * _f.get_sector_size();
+            if (sector != _curr_sector) {
+                _curr_sector = sector;
+                if (!erase_sector(_curr_sector))
+                    return false;
+            }
+        }
+
+        if (_no_burn)
+            continue;
+
+        //
+        // Check to see if there's something to do
+        //
+        bool all_ffs = true;
+        for (u_int32_t i = 0; i < block_size ; i++) {
+            if (write_data[i] != 0xff) {
+                all_ffs = false;
+                break;
+            }
+        }
+
+        if (!all_ffs) {
+
+            u_int32_t status;
+            cnt1 = 0;
+            do {
+                // Get Write buffer
+                if (!_f.write_internal(block_addr, FC_SCSWrite))
+                    return false;
+
+                if (cnt1 > ((READ_CNT_FAST + READ_CNT_SLOW) * 4)) {
+                    //printf("-D- status = %08x\n", status);
+                    reset();
+                    _f._err = "Flash write error - Write buffer not ready.";  
+                    return false;
+                }
+
+                cnt1++;
+
+                if (!_f.read(block_addr, &status))
+                    return false;
+
+            } while (!(status & FS_Ready));
+
+            if (status & FS_Error) {
+                _f._err = "Flash write error - Error getting write buffer";
+                return false;
+            }
+
+            // word count (allways full buffer, coded as cull buffer size -1)
+            if (!_f.write_internal(block_addr, block_size - 1))
+                return false;
+
+            // Write data to buffer
+            for (u_int32_t i = 0; i < block_size ; i++ ) {
+                if (!_f.write_internal(block_addr + i, write_data[i]))
+                    return false;
+            }
+
+            // write confirm
+            if (!_f.write_internal(block_addr, FC_Confirm))
+                return false;
+
+            cnt1 = 0;
+            do {
+                // Timeout checks
+                if (++cnt1 > READ_CNT_FAST)
+                    usleep(READ_DELAY);
+                if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW) {
+                    reset();
+                    _f._err = "Flash write error - Write buffer status timeout";
+                    return false;
+                }
+
+                // TODO - Move to read single for Arbel
+                if (!_f.read(block_addr, &status))
+                    return false;
+
+                //if (act != exp)
+                //    printf("write: %08x - exp:%02x act:%02x /%08x/\n",
+                //           addr, exp & 0xff, act & 0xff, word);
+            } while ((status & 0x80) == 0);
+
+            //
+            // TODO: Status checks.
+            //
+
+            if (!noverify) {
+                u_int8_t verify_buffer[MAX_WRITE_BUFFER_SIZE];
+                if (!reset())
+                    return false;
+
+                if (!_f.read(addr, verify_buffer, data_size))
+                    return false;
+
+                for (u_int32_t i = 0 ; i < data_size ; i++) {
+                    if (verify_buffer[i] != write_data[i + prefix_pad_size]) {
+                        printf("write: %08x - exp:%02x act:%02x\n",
+                               addr + i, 
+                               write_data[i + prefix_pad_size] , 
+                               verify_buffer[i]);
+
+                        _f._err = "Write verification failed";
+                        return false;
+                    }
+                }  
+            }
+        }
+
+
+        //
+        // loop advance
+        //
+
+        addr += data_size;
+        p    += data_size;
+        cnt  -= data_size;
+    }
+
+    if (!reset())
+        return false;
+
+    return true;
+} // flash_write
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::CmdSetAmd::reset() {
+    if (!_f.write_internal(0x555, 0xf0)) {
+        _f._err = "Device reset failed";
+        return false;
+    }
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////
+bool ParallelFlash::CmdSetAmd::erase_sector(u_int32_t addr)
+{
+    u_int32_t word = 0;
+    int       cnt  = 0;
+
+    if (_no_erase)
+        return true;
+
+    // Just to insure zeroes because erase completion waits for ones
+    if (!write(addr, &word, sizeof(word), true))
+        return false;
+
+    // erase sector sequence
+#ifdef FUJITSU_BYTE_MODE
+    if (!_f.write_internal(0xaaa, 0xaa))
+        return false;
+    if (!_f.write_internal(0x555, 0x55))
+        return false;
+    if (!_f.write_internal(0xaaa, 0x80))
+        return false;
+    if (!_f.write_internal(0xaaa, 0xaa))
+        return false;
+    if (!_f.write_internal(0x555, 0x55))
+        return false;
+    if (!_f.write_internal(addr, 0x30))
+        return false;
+#else // FUJITSU_WORD_MODE 
+    if (_unlock_bypass) {
+        // release unlock bypass before erase sector
+        if (!_f.unlock_bypass(false)) return false;
+    }
+
+    if (!_f.write_internal(0x555, 0xaa))
+        return false;
+    if (!_f.write_internal(0x2aa, 0x55))
+        return false;
+    if (!_f.write_internal(0x555, 0x80))
+        return false;
+    if (!_f.write_internal(0x555, 0xaa))
+        return false;
+    if (!_f.write_internal(0x2aa, 0x55))
+        return false;
+    if (!_f.write_internal(addr, 0x30))
+        return false;
+
+#endif
+
+    // Wait while erase completes
+    do {
+        // Timeout checks
+        if (++cnt > ERASE_CNT) {
+            _f._err = "Flash erase sector timeout";
+            return false;
+        }
+        if (!_f.read(addr, &word))
+            return false;
+
+        //printf("erase_sector: addr:%08lx, %08x\n", addr, word);
+        usleep(ERASE_DELAY);
+    } while (word != 0xffffffff);
+
+
+
+#ifdef FUJITSU_BYTE_MODE
+    // TODO: Need to check unlock bypass option for FUJITSU flash
+#else // FUJITSU_WORD_MODE 
+
+    if (_unlock_bypass) {
+        // release unlock bypass before erase sector
+//     if (!_f.unlock_bypass(true)) return false; 
+    }
+
+#endif
+
+
+    return true;
+} // Flash::erase_sector
+
+////////////////////////////////////////////////////////////////////////
+
+bool ParallelFlash::CmdSetIntel::reset() {
+    if (!_f.write_internal(0x555, FC_Read)) {
+        _f._err = "Device reset failed";
+        return false;
+    }
+    return true;
+}
+
 ////////////////////////////////////////////////////////////////////////
-bool Flash::write_internal(u_int32_t addr, u_int8_t data)
+bool ParallelFlash::CmdSetIntel::erase_sector(u_int32_t addr)
 {
-    u_int32_t    cmd;
-    int          cnt = 0;
+    u_int32_t    status = 0;
+    int          cnt    = 0;
 
-    MWRITE4(FLASH+4, data << 24);
-    MWRITE4(FLASH, WRITE1 | (addr & ADDR_MSK));
-    do
-    {
-        // Timeout checks
-        if (++cnt > FLASH_CMD_CNT)
-        {
-            _err = "Flash gateway timeout: CMD doesn't become zero";
-            return false;
-        }
+    if (_no_erase)
+        return true;
 
-        MREAD4(FLASH, &cmd);
+    // Just to insure zeroes because erase completion waits for ones
+    //if (!write(addr, &word, sizeof(word), true))
+    //    return false;
 
-    } while(cmd & CMD_MASK);
-    return true;
-} // Flash::write_internal
+    // Erase command
+    if (!_f.write_internal(addr, FC_Erase))
+        return false;
 
+    // Erase confirm
+    if (!_f.write_internal(addr, FC_Confirm))
+        return false;
 
-////////////////////////////////////////////////////////////////////////
-bool Flash::unlock_bypass(bool unlock) {
+    usleep(ERASE_DELAY);
+
+    // Wait while erase completes
+    do {
+        // Timeout checks
+        if (++cnt > ERASE_CNT) {
+            _f._err = "Flash erase sector timeout";
+            return false;
+        }
+        if (!_f.read(addr, &status))
+            return false;
 
-     if (unlock) {
-       // unlock bypass
+        //printf("CmdSetIntel::erase_sector: addr:%08lx, %08x\n", addr, word);
+        usleep(ERASE_DELAY);
+    } while ((status & FS_Ready) == 0);
 
-       if (!write_internal(0x555, 0xaa))
-           return false;
-       if (!write_internal(0x2aa, 0x55))
-           return false;
-       if (!write_internal(0x555, 0x20))
-           return false; 
-    } else {
-       // unlock reset
-       if (!write_internal(0x555, 0x90))
-           return false;
-       if (!write_internal(0x2aa, 0x00))
-           return false; 
+    if (status & FS_Error) {
+        _f._err = "Status register detected erase error";
+        return false;
     }
-    return true;
-}
-////////////////////////////////////////////////////////////////////////
-bool Flash::query_cfi() {    
-    return print_cfi_info(&_cfi); 
-}
 
-////////////////////////////////////////////////////////////////////////
+    // Reset
+    if (!reset())
+        return false;
 
-//
-// AMD SOURCE
-//
+    return true;
+} // ParallelFlash::CmdSetIntel::erase_sector
 
 //*******************************************************************
 // flash_get_cfi() is the main CFI workhorse function.  Due to it's  
@@ -1050,13 +2285,12 @@ bool Flash::query_cfi() {
 // calculations are done using bit-shifts when possible              
 //*******************************************************************
 
-
-bool Flash::get_cfi(struct cfi_query *query)
+bool ParallelFlash::get_cfi(struct cfi_query *query)
 {
 
     enum {
-       TOTAL_QUERY_SIZE    = 1024,
-       EXTENDED_QUERY_SIZE =   12 
+        TOTAL_QUERY_SIZE    = 1024,
+        EXTENDED_QUERY_SIZE =   12 
     };
 
     u_int8_t fwp[TOTAL_QUERY_SIZE]; // flash window 
@@ -1069,51 +2303,51 @@ bool Flash::get_cfi(struct cfi_query *query)
     // Initial house-cleaning 
     memset(fwp, 0xff, TOTAL_QUERY_SIZE);
 
-    for(i=0; i < 8; i++) {
-       query->erase_block[i].sector_size = 0;
-       query->erase_block[i].num_sectors = 0;
-    }  query->erase_block[i].sector_mask = 0;
+    for (i=0; i < 8; i++) {
+        query->erase_block[i].sector_size = 0;
+        query->erase_block[i].num_sectors = 0;
+    }   query->erase_block[i].sector_mask = 0;
 
     // reset
     if (!write_internal(0x55, 0xff))
-       return false;
-      
-     // CFI QUERY 
+        return false;
+
+    // CFI QUERY 
     if (!write_internal(0x55, 0x98))
-       return false;
+        return false;
 
     char query_str_x8[4];
     char query_str_x16asx8[4];
 
     if (!read(0x10, query_str_x8, 0x4))
-       return false;
+        return false;
 
     if (!read(0x20, query_str_x16asx8, 0x4))
-       return false;
+        return false;
 
     query_str_x8[3]       = '\0';
     query_str_x16asx8[3]  = '\0';
 
-    if        ( strncmp( query_str_x8 ,      "QRY" ,3 ) == 0) { 
-       // x8 CFI flash (AMD)
-       query_base = 1;
+    if ( strncmp( query_str_x8 ,      "QRY" ,3 ) == 0) {
+        // x8 CFI flash (AMD)
+        query_base = 1;
     } else if ( strncmp( query_str_x16asx8 , "QQR" ,3 ) == 0) {
-       // x16 CFI flash worqing in x8 mode (Intel)
-       query_base = 2;
+        // x16 CFI flash worqing in x8 mode (Intel)
+        query_base = 2;
     } else {
-    
-       printf(" Received CFI query from addr 0x10: [%s]\n", query_str_x8 );
-       printf(" Received CFI query from addr 0x20: [%s]\n", query_str_x16asx8);
-       _err = "Failed CFI query";
-       return false;
+
+        printf(" Received CFI query from addr 0x10: [%s]\n", query_str_x8 );
+        printf(" Received CFI query from addr 0x20: [%s]\n", query_str_x16asx8);
+
+        _err = "Failed CFI query";
+        return false;
     } 
 
     if (!read(0x0, fwp, 0x4)) // Dev ID
-       return false;
+        return false;
 
     if (!read(query_base * 0x10, fwp + query_base * 0x10, query_base * 0x20))
-       return false;
+        return false;
 
     query->manuf_id              = fwp[query_base * 0];
     query->device_id             = fwp[query_base * 1];
@@ -1127,1031 +2361,957 @@ bool Flash::get_cfi(struct cfi_query *query)
     query->primary_table_address = extract_word(fwp + query_base * 0x15, query_base); // Important one! 
     query->alt_command_set       = extract_word(fwp + query_base * 0x17, query_base);
     query->alt_table_address     = extract_word(fwp + query_base * 0x19, query_base);
-    
+
     // We will do some bit translation to give the following values
     // numerical meaning in terms of C 'float' numbers 
-    
+
     volts = ((fwp[query_base * 0x1B] & 0xF0) >> 4);
     milli = ( fwp[query_base * 0x1B] & 0x0F);
     query->vcc_min = (float) (volts + ((float)milli/10));
-    
+
     volts = ((fwp[query_base * 0x1C] & 0xF0) >> 4);
     milli = ( fwp[query_base * 0x1C] & 0x0F);
     query->vcc_max = (float) (volts + ((float)milli/10));
-    
+
     volts = ((fwp[query_base * 0x1D] & 0xF0) >> 4);
     milli = ( fwp[query_base * 0x1D] & 0x0F);
     query->vpp_min = (float) (volts + ((float)milli/10));
-    
+
     volts = ((fwp[query_base * 0x1E] & 0xF0) >> 4);
     milli = ( fwp[query_base * 0x1E] & 0x0F);
     query->vpp_max = (float) (volts + ((float)milli/10));
-    
+
     // Let's not drag in the libm library to calculate powers
     // for something as simple as 2^(power)
     // Use a bit shift instead - it's faster 
 
     temp = fwp[query_base * 0x1F];
     query->timeout_single_write = (1 << temp);
-    
+
     temp = fwp[query_base * 0x20];
     if (temp != 0x00)
-       query->timeout_buffer_write = (1 << temp);
+        query->timeout_buffer_write = (1 << temp);
     else
-       query->timeout_buffer_write = 0x00;
-    
+        query->timeout_buffer_write = 0x00;
+
     temp = 0;
     temp = fwp[query_base * 0x21];
     query->timeout_block_erase = (1 << temp);
-    
+
     temp = fwp[query_base * 0x22];
     if (temp != 0x00)
-       query->timeout_chip_erase = (1 << temp);
+        query->timeout_chip_erase = (1 << temp);
     else
-       query->timeout_chip_erase = 0x00;
-    
+        query->timeout_chip_erase = 0x00;
+
     temp = fwp[query_base * 0x23];
     query->max_timeout_single_write = (1 << temp) *
-       query->timeout_single_write;
-    
+                                      query->timeout_single_write;
+
     temp = fwp[query_base * 0x24];
     if (temp != 0x00)
-       query->max_timeout_buffer_write = (1 << temp) *
-       query->timeout_buffer_write;
+        query->max_timeout_buffer_write = (1 << temp) *
+                                          query->timeout_buffer_write;
     else
-       query->max_timeout_buffer_write = 0x00;
-    
+        query->max_timeout_buffer_write = 0x00;
+
     temp = fwp[query_base * 0x25];
     query->max_timeout_block_erase = (1 << temp) *
-       query->timeout_block_erase;
-    
+                                     query->timeout_block_erase;
+
     temp = fwp[query_base * 0x26];
     if (temp != 0x00)
-       query->max_timeout_chip_erase = (1 << temp) *
-       query->timeout_chip_erase;
+        query->max_timeout_chip_erase = (1 << temp) *
+                                        query->timeout_chip_erase;
     else
-       query->max_timeout_chip_erase = 0x00;
-    
+        query->max_timeout_chip_erase = 0x00;
+
     temp = fwp[query_base * 0x27];
     query->device_size = (long) (((long)1) << temp);
-    
+
     query->interface_description = extract_word(fwp + query_base * 0x28, query_base);
-    
+
     temp = fwp[query_base * 0x2A];
     if (temp != 0x00)
-       query->max_multi_byte_write = (1 << temp);
+        query->max_multi_byte_write = (1 << temp);
     else
-       query->max_multi_byte_write = 0;
-    
+        query->max_multi_byte_write = 0;
+
     query->num_erase_blocks = fwp[query_base * 0x2C];
 
-    if (!read(query_base * 0x2C, fwp + query_base * 0x2C ,query_base * 4 * (query->num_erase_blocks + 1))) 
-       return false;
+    if (!read(query_base * 0x2C, fwp + query_base * 0x2C ,query_base * 4 * (query->num_erase_blocks + 1)))
+        return false;
+
+    for (i=0; i < query->num_erase_blocks; i++) {
+        query->erase_block[i].num_sectors = extract_word(fwp + query_base * (0x2D+(4*i)), query_base);
+        query->erase_block[i].num_sectors++;
+
+        query->erase_block[i].sector_size = (long) 256 *
+                                            ( (long)256 * fwp[(query_base * (0x30+(4*i)))] +
+                                              fwp[(query_base * (0x2F+(4*i)))] );
+
+        query->erase_block[i].sector_mask = ~(query->erase_block[i].sector_size - 1);
+    }
+
+    // Store primary table offset in variable for clarity 
+    offset = query->primary_table_address;
+
+    if ((offset + EXTENDED_QUERY_SIZE) * query_base > TOTAL_QUERY_SIZE) {
+        _err = "Primary extended query larger than TOTAL_QUERY_SIZE";
+        return false;
+    }
+
+
+    // DEBUG: 
+    //printf("Raw Cfi query:\n");
+    //for (u_int32_t i = 0x10 * query_base ; i <= (0x30 * query_base); i+= query_base) {
+    //printf("0x%02x: %02x\n", i/query_base, fwp[i]);
+    //}
+
+    u_int32_t dw_aligned_offs = (((offset * query_base) >> 2 ) << 2);
+
+    if (!read(dw_aligned_offs , fwp + dw_aligned_offs  , EXTENDED_QUERY_SIZE * query_base))
+        return false;
+
+    query->primary_extended_query[0] = fwp[query_base * (offset)];
+    query->primary_extended_query[1] = fwp[query_base * (offset + 1)];
+    query->primary_extended_query[2] = fwp[query_base * (offset + 2)];
+    query->primary_extended_query[3] = '\0';
+
+    if ( query->primary_extended_query[0] != 'P' &&
+         query->primary_extended_query[1] != 'R' &&
+         query->primary_extended_query[2] != 'I') {
+        _err = "Bad primary table address";
+        return false;
+    }
+
+    query->major_version = fwp[query_base * (offset + 3)];
+    query->minor_version = fwp[query_base * (offset + 4)];
+
+    query->sensitive_unlock      = (u_int8_t) (fwp[query_base * (offset+5)] & 0x0F);
+    query->erase_suspend         = (u_int8_t) (fwp[query_base * (offset+6)] & 0x0F);
+    query->sector_protect        = (u_int8_t) (fwp[query_base * (offset+7)] & 0x0F);
+    query->sector_temp_unprotect = (u_int8_t) (fwp[query_base * (offset+8)] & 0x0F);
+    query->protect_scheme        = (u_int8_t) (fwp[query_base * (offset+9)] & 0x0F);
+    query->is_simultaneous       = (u_int8_t) (fwp[query_base * (offset+10)] & 0x0F);
+    query->is_burst              = (u_int8_t) (fwp[query_base * (offset+11)] & 0x0F);
+    query->is_page               = (u_int8_t) (fwp[query_base * (offset+12)] & 0x0F);
+
+    return true;
+} 
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SpiFlash Class Implementation
+//
+////////////////////////////////////////////////////////////////////////
+
+bool SpiFlash::init_gpios() {
+
+    //
+    // Set Multi SPI CS to output and 0.
+    // Assuming 4 flashes. If there are less than 4 flashes and there's
+    // a write attempt, it will fail.
+    //
+
+    u_int32_t       num_of_spis = 4;
+    u_int32_t       spi_en      = (1 << (num_of_spis - 1 ) ) -1;
+
+    u_int32_ba      dir;
+    u_int32_ba      mod; 
+    u_int32_ba      pol;
+
+    // No need to set the data - SPI GW CS does that in HW
+    //MREAD4(GPIO_DAT_L, &data);
+
+    MREAD4(GPIO_DIR_L, &dir);
+    MREAD4(GPIO_POL_L, &pol);
+    MREAD4(GPIO_MOD_L, &mod);
+
+    dir.range (SPI_GPIO_E, SPI_GPIO_S) = spi_en;
+    pol.range (SPI_GPIO_E, SPI_GPIO_S) = ~spi_en;
+    mod.range(SPI_GPIO_E, SPI_GPIO_S) = ~spi_en;
+
+    // unlock gpio
+    MWRITE4(GPIO_LOCK , 0xaaaa);
+
+    MWRITE4(GPIO_DIR_L, dir); 
+    MWRITE4(GPIO_POL_L, pol); 
+    MWRITE4(GPIO_MOD_L, mod); 
+
+    return true;
+}
+
+void SpiFlash::close() {
+    // Chip reset does not reset the chip sellect - Make sure after reset
+    // boot loads FW from SPI 0.
+    set_bank(0);
+
+    // unlock gpio
+    mwrite4(_mf, GPIO_LOCK , 0xaaaa);
+}
+
+bool SpiFlash::get_cmd_set   () {
+
+    // TODO: Implement ...
+
+    //
+    // Read device ID and allocate command set accordingly.
+    //
+
+    _cmd_set = new CmdSetStSpi(*this);
+
+    //
+    // Initiate some CFI fields to mimic cfi query procedure of parallel flash:
+    //
+
+    _cfi_data.max_multi_byte_write       = 16;   // In SPI context, this is the transaction size. Max is 16.
+    _cfi_data.num_erase_blocks           = 1;
+    _cfi_data.erase_block[0].sector_size = 64 * 1024;
+    _cfi_data.erase_block[0].sector_mask = ~(_cfi_data.erase_block[0].sector_size - 1);
+
+    return true;
+}
+
+
+bool SpiFlash::set_bank_int(u_int32_t bank)
+{
+    if (!_mf) {
+        _err = "Not opened";
+        return false;
+    }
+
+    // TODO: Check number of banks in open!
+    if (bank > 3) {
+        _err = "Tried to set bank > 3";
+        return false;
+    }
+
+    //printf("\n*** Flash::set_bank(0x%lx) : 0x%lx\n", bank, (bank >> 19) & 0x07);
+    u_int32_ba flash_cs;
+    flash_cs.range(31,30) = bank;
+    MWRITE4(FLASH_CS, flash_cs);  
+
+    return true;
+} // Flash::SpiFlash::set_bank
+
+
+////////////////////////////////////////////////////////////////////////
+bool SpiFlash::wait_ready(const char* msg)
+{
+    u_int32_ba gw_cmd = 0;
+    u_int32_t cnt = 0;
+    do {
+        // Timeout checks
+        if (++cnt > FLASH_CMD_CNT) {
+            sprintf(_msg, "Flash gateway timeout: %s.", msg);
+            _err = _msg;
+            return false;
+        }
+
+        MREAD4(FLASH_GW, &gw_cmd);
+
+    } while (gw_cmd[BUSY]);
+
+    return true;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+bool SpiFlash::read(u_int32_t addr, u_int32_t *data)
+{
+    if (!_mf) {
+        _err = "Not opened";
+        return false;
+    }
+
+    if (addr & 0x3) {
+        _err = "Address should be 4-bytes aligned.";
+        return false;
+    }
+
+    if (!set_bank(addr))
+        return false;
+
+
+    //
+    // Prepare command word
+    //
+
+    u_int32_ba gw_cmd;
+    u_int32_ba gw_addr;
+
+    gw_cmd[BUSY]                   = 1;
+    gw_cmd[READ_OP]                = 1;
+    //gw_cmd[ADDR_INCR]              = 0;
+
+    gw_cmd.range(MSIZE_E, MSIZE_S) = 2;
+
+    gw_addr.range(SPI_ADDR_E, SPI_ADDR_S) = addr & bank_mask();
+
+    MWRITE4(FLASH_ADDR, gw_addr);
+    MWRITE4(FLASH_GW,   gw_cmd);
+
+    if (!wait_ready("Read"))
+        return false;
+
+    MREAD4(FLASH_DATA, data);
+
+    *data = __cpu_to_be32(*data);
+
+    return true;
+} // SpiFlash::read
+
+
+//
+// TODO: Unify all the block handling code with the CmdSet001 write.
+//
+
+bool SpiFlash::CmdSetStSpi::write (u_int32_t addr, 
+                                   void*     data, 
+                                   int       cnt,
+                                   bool      noerase, 
+                                   bool      noverify) {
+
+    if (!_f._mf) {
+        _f._err = "Not opened";
+        return false;
+    }
+    if (addr & 0x3) {
+        _f._err = "Address should be 4-bytes aligned.";
+        return false;
+    }
+
+    u_int8_t         *p = (u_int8_t *)data;
+
+    u_int32_t block_size = _f._cfi_data.max_multi_byte_write;
+    u_int32_t block_mask = ~(block_size - 1 );
+
+    // TODO - Check MAX_WRITE_BUFFER_SIZE against block_size in open (or here)
+    u_int8_t  tmp_buff[MAX_WRITE_BUFFER_SIZE];
+
+    while (cnt) {
+
+        u_int32_t prefix_pad_size = 0;
+        u_int32_t suffix_pad_size = 0;
+
+        u_int32_t block_addr = addr & block_mask;
+        u_int32_t data_size  = block_size;
+
+        u_int8_t* block_data = p;
+
+
+        //
+        // First and last cycles (can be the same one) may not be block aligned.
+        // Check the status, and copy data to a padded temp bufer if not alligned.
+        // (there's an option to write partial buffer, but Intel reference code always
+        // writes full buffer, with pads if needed. I do the dame ...)
+        //
+
+        prefix_pad_size = addr - block_addr;
+
+        if ((addr & block_mask) == ((addr + cnt) & block_mask)) {
+            suffix_pad_size = block_size - ((addr + cnt) % block_size);
+        }
+
+        if (suffix_pad_size || prefix_pad_size) {
+            memset(tmp_buff, 0xff, block_size);
+
+            data_size -= prefix_pad_size;
+            data_size -= suffix_pad_size;
+
+            memcpy(tmp_buff + prefix_pad_size, p , data_size);
+
+            block_data = tmp_buff;
+        }
+
+        //
+        // Bank setup.
+        //
+        if (!_f.set_bank(addr))
+            return false;
+
+        if (!noerase) {
+            u_int32_t sector = (addr / _f.get_sector_size()) * _f.get_sector_size();
+            if (sector != _curr_sector) {
+                _curr_sector = sector;
+                if (!erase_sector(_curr_sector))
+                    return false;
+            }
+        }
 
-    for(i=0; i < query->num_erase_blocks; i++) {
-       query->erase_block[i].num_sectors = extract_word(fwp + query_base * (0x2D+(4*i)), query_base);
-       query->erase_block[i].num_sectors++;
-       
-       query->erase_block[i].sector_size = (long) 256 *
-           ( (long)256 * fwp[(query_base * (0x30+(4*i)))] +
-             fwp[(query_base * (0x2F+(4*i)))] );
+        if (_no_burn)
+            continue;
 
-       query->erase_block[i].sector_mask = ~(query->erase_block[i].sector_size - 1);
-    }
+        //
+        // Check to see if there's something to do
+        //
+        bool all_ffs = true;
+        for (u_int32_t i = 0; i < block_size ; i++) {
+            if (block_data[i] != 0xff) {
+                all_ffs = false;
+                break;
+            }
+        }
 
-    // Store primary table offset in variable for clarity 
-    offset = query->primary_table_address;
+        if (!all_ffs) {
 
-    if ((offset + EXTENDED_QUERY_SIZE) * query_base > TOTAL_QUERY_SIZE) {
-       _err = "Primary extended query larger than TOTAL_QUERY_SIZE";
-       return false;
-    }
+            write_block(block_addr, block_data, block_size);
 
+            if (!noverify) {
+                u_int8_t verify_buffer[MAX_WRITE_BUFFER_SIZE];
+                if (!reset())
+                    return false;
 
-    // DEBUG: 
-    //printf("Raw Cfi query:\n");
-    //for (u_int32_t i = 0x10 * query_base ; i <= (0x30 * query_base); i+= query_base) {
-       //printf("0x%02x: %02x\n", i/query_base, fwp[i]);
-    //}
+                if (!_f.read(addr, verify_buffer, data_size))
+                    return false;
 
-    u_int32_t dw_aligned_offs = (((offset * query_base) >> 2 ) << 2);
+                for (u_int32_t i = 0 ; i < data_size ; i++) {
+                    if (verify_buffer[i] != block_data[i + prefix_pad_size]) {
+                        printf("write: %08x - exp:%02x act:%02x\n",
+                               addr + i, 
+                               block_data[i + prefix_pad_size] , 
+                               verify_buffer[i]);
 
-    if (!read(dw_aligned_offs , fwp + dw_aligned_offs  , EXTENDED_QUERY_SIZE * query_base)) 
-       return false;
-    
-    query->primary_extended_query[0] = fwp[query_base * (offset)];
-    query->primary_extended_query[1] = fwp[query_base * (offset + 1)];
-    query->primary_extended_query[2] = fwp[query_base * (offset + 2)];
-    query->primary_extended_query[3] = '\0';
-    
-    if( query->primary_extended_query[0] != 'P' &&
-       query->primary_extended_query[1] != 'R' &&
-       query->primary_extended_query[2] != 'I') {
-       _err = "Bad primary table address";
-       return false;
-    }
-    
-    query->major_version = fwp[query_base * (offset + 3)];
-    query->minor_version = fwp[query_base * (offset + 4)];
-    
-    query->sensitive_unlock      = (u_int8_t) (fwp[query_base * (offset+5)] & 0x0F);
-    query->erase_suspend         = (u_int8_t) (fwp[query_base * (offset+6)] & 0x0F);
-    query->sector_protect        = (u_int8_t) (fwp[query_base * (offset+7)] & 0x0F);
-    query->sector_temp_unprotect = (u_int8_t) (fwp[query_base * (offset+8)] & 0x0F);
-    query->protect_scheme        = (u_int8_t) (fwp[query_base * (offset+9)] & 0x0F);
-    query->is_simultaneous       = (u_int8_t) (fwp[query_base * (offset+10)] & 0x0F);
-    query->is_burst              = (u_int8_t) (fwp[query_base * (offset+11)] & 0x0F);
-    query->is_page               = (u_int8_t) (fwp[query_base * (offset+12)] & 0x0F);
-    
-    return true;
-} 
+                        _f._err = "Write verification failed";
+                        return false;
+                    }
+                }  
+            }
+        }
 
 
-// A smaple function which loops through and prints out the data
-// contained in the CFI query structure.  Should ONLY be called
-// after init_flash 
+        //
+        // loop advance
+        //
 
-bool Flash::print_cfi_info( const cfi_query *q )
-{
-  int i=0;
-  printf("\n");
+        addr += data_size;
+        p    += data_size;
+        cnt  -= data_size;
+    }
 
-  char* head_fmt = "%-50s ";
+    if (!reset())
+        return false;
 
-  printf(head_fmt, "CFI Query String Read:");
-  printf("[%s]\n", (char *) q->query_string);
+    return true;
+} 
 
-  printf(head_fmt, "Primary table address at offset:");
-  printf("[0x%2x] hex.\n", q->primary_table_address);
+bool SpiFlash::CmdSetStSpi::erase_sector(u_int32_t addr)
+{
 
-  printf(head_fmt, "Manufacturer ID, Device ID:");
-  printf("[0x%02x,0x%02x] hex.\n", q->manuf_id, q->device_id );
+    if (_no_erase)
+        return true;
 
-  printf(head_fmt, "Command set:");
-  printf("[0x%04x] hex.\n", q->oem_command_set);
+    u_int32_ba gw_cmd;
+    u_int32_ba gw_addr;
 
-  printf(head_fmt, "Write buffer:");
-  printf("[%d] bytes\n", q->max_multi_byte_write );
 
-  printf("\n----Voltage and Signal Timing Parameters-------------------\n");
-  printf(head_fmt, "Vcc operating voltage:");
-  printf("[%2.3f] to [%2.3f] Volts\n", q->vcc_min, q->vcc_max);
+    if (!write_enable())
+        return false;
 
+    //
+    // Erase sector command:
+    //
 
-  printf(head_fmt, "Vpp operating voltage:");
-  if(q->vpp_min == 0.0)
-        printf("Device does not support Vpp voltage.\n");
-  else {
-        printf("[%2.3f] to [%2.3f] Volts\n", q->vpp_min, q->vpp_max);
-  }
+    gw_cmd[BUSY]                   = 1;
+    gw_cmd[SPI_SPECIAL]            = 1;
+    gw_cmd[SPI_NO_DATA]            = 1;
 
-  printf(head_fmt, "Typical timeout for single write (micro-sec):");
-  printf("[%8i]us\n", q->timeout_single_write);
+    gw_addr.range(SPI_CMD_E,  SPI_CMD_S)  = FC_SE;
+    gw_addr.range(SPI_ADDR_E, SPI_ADDR_S) = addr & _f.bank_mask();
 
+    MWRITE4(FLASH_ADDR, gw_addr);
+    MWRITE4(FLASH_GW,   gw_cmd);
 
-  
-  printf(head_fmt,"Typical timeout for single write (micro-sec):");
-  if(q->timeout_buffer_write == 0x00)
-        printf("Buffer writes not supported in this device.\n");
-  else {
-        printf("[%8i]us\n" ,q->timeout_buffer_write);
-  }
+    if (!_f.wait_ready("ES"))
+        return false;
 
-  printf(head_fmt, "Typical timeout for block erase (milli-sec):", q->timeout_block_erase);
-  printf("[%8i]ms\n", q->timeout_block_erase);
+    //
+    // Wait for erase completion
+    //
 
-  printf(head_fmt, "Typical timeout for chip erase (milli-sec):");
-  if(q->timeout_chip_erase == 0x00)
-        printf("Not supported in this device.\n");
-  else {
-        printf("[%8i]ms\n", q->timeout_single_write);
-  }
+    if (!wait_wip(ERASE_DELAY, ERASE_CNT))
+        return false;
 
-  printf(head_fmt, "Maximum timeout for single write (micro-sec) :");
-  printf("[%8i]us\n", q->max_timeout_single_write);
+    return true;
+} // Flash::erase_sector
 
-  printf(head_fmt, "Maximum timeout for buffer write (micro-sec) :");
-  if(q->max_timeout_buffer_write == 0x00)
-      printf("Not supported in this device.\n");
-  else {
-      printf("[%8i]us\n", q->max_timeout_buffer_write);
-  }
 
-  printf(head_fmt, "Maximum timeout for block erase (milli-sec) :");
-  printf("[%8i]ms\n", q->max_timeout_block_erase);
 
-  printf(head_fmt, "Maximum timeout for chip erase (milli-sec) :");
-  if(q->max_timeout_chip_erase == 0x00)
-      printf("Not supported in this device.\n");
-  else {
-      printf("[%8i]ms\n", q->max_timeout_chip_erase);
-  }
+bool SpiFlash::CmdSetStSpi::write_block(u_int32_t block_addr, 
+                                        void*     block_data, 
+                                        u_int32_t block_size) {
 
+    u_int32_ba gw_cmd;
+    u_int32_ba gw_addr;
 
-  
+    // sanity check ??? remove ???
+    if (block_size != (u_int32_t)_f._cfi_data.max_multi_byte_write) {
+        _f._err = "Block write of wrong block size";
+        return false;
+    }
 
-  printf("\n----Sector Organization Parameters-------------------\n\n");
+    if (!write_enable())
+        return false;
 
-  printf(head_fmt, "Device size:");
-  printf("[%8li] bytes, or [%2i] Mbit\n",
-        q->device_size, 
-        (int) (q->device_size/((long)0x20000)));
+    //
+    // Write the data block
+    //
 
-  printf(head_fmt, "Number of erase block regions:");
-  printf("%d\n",q->num_erase_blocks);
 
-  for(i=0; i<q->num_erase_blocks; i++) {
-        printf("  Size:[%8lx] bytes, Mask [%08x], [Number:[%4i]\n",
-               q->erase_block[i].sector_size,
-               q->erase_block[i].sector_mask,
-               q->erase_block[i].num_sectors);
-  }
+    gw_cmd[BUSY]                   = 1;
+    gw_cmd[SPI_SPECIAL]            = 1;
 
-  printf("\n----Primary Vendor-Specific Extended Parameters----\n\n");
+    gw_cmd.range(MSIZE_E, MSIZE_S) = log2up(block_size);
 
-  printf(head_fmt, "CFI Extended String Read:");
-  printf("[%s]\n", (char *) q->primary_extended_query);
+    gw_addr.range(SPI_CMD_E,  SPI_CMD_S)  = FC_PP;
+    gw_addr.range(SPI_ADDR_E, SPI_ADDR_S) = block_addr & _f.bank_mask();
 
-  printf(head_fmt, "Major version:", q->major_version);
-  printf("[%3x]\n", q->major_version);
+    MWRITE4(FLASH_ADDR, gw_addr);
 
-  printf(head_fmt, "Minor version:", q->minor_version);
-  printf("[%3x]\n", q->minor_version);
+    // Data:
+    for (u_int32_t offs = 0 ; offs < block_size ; offs += 4) {
+        // NOTE: !!! To much swapping around the data. !!!
+        // Flash GW in sinai eats full DWords with byte0 as high data.
+        // TODO: Swap on writes in Parallel flash. Save double swapping for serial flash. 
+        u_int32_t word = *((u_int32_t*)((u_int8_t*)block_data + offs));
+        word = __be32_to_cpu(word);
+        MWRITE4(FLASH_DATA + offs, word );
+    }
 
-  printf(head_fmt, "Sensitive Unlock:", q->sensitive_unlock);
-  printf("[%3x]\n", q->sensitive_unlock);
+    MWRITE4(FLASH_GW,   gw_cmd);
 
-  printf(head_fmt, "Erase Suspend:", q->erase_suspend);
-  printf("[%3x]\n", q->erase_suspend);
+    if (!_f.wait_ready("PP command"))
+        return false;
 
-  printf(head_fmt, "Sector Protect:", q->sector_protect);
-  printf("[%3x]\n", q->sector_protect);
+    //
+    // Wait for end of write in flash (WriteInProgress = 0):
+    //
 
-  printf(head_fmt, "Temporary Sector Unprotect:", q->sector_temp_unprotect);
-  printf("[%3x]\n", q->sector_temp_unprotect);
+    if (!wait_wip(READ_DELAY, READ_CNT_SLOW + READ_CNT_FAST, READ_CNT_FAST))
+        return false;
 
-  printf(head_fmt, "Protection Scheme:", q->protect_scheme);
-  printf("[%3x]\n", q->protect_scheme);
+    return true;
+}
 
-  printf(head_fmt, "Is simultaneous? :", q->is_simultaneous);
-  printf("[%3x]\n", q->is_simultaneous);
 
-  printf(head_fmt, "Is Burst capable? :", q->is_burst);
-  printf("[%3x]\n", q->is_burst);
+bool SpiFlash::CmdSetStSpi::write_enable() {
 
-  printf(head_fmt, "Is Page capable? :", q->is_page);
-  printf("[%3x]\n", q->is_page);
+    u_int32_ba gw_cmd;
+    u_int32_ba gw_addr;
 
-  printf("Done.\n\n");
+    //
+    // Write enable:
+    //
 
-  return true;
-}
+    gw_cmd[BUSY]                   = 1;
+    gw_cmd[SPI_NO_ADDR]            = 1;
+    gw_cmd[SPI_NO_DATA]            = 1;
+    gw_cmd[SPI_SPECIAL]            = 1;
 
-////////////////////////////////////////////////////////////////////////
-bool Flash::erase_sector(u_int32_t addr)
-{
-    return _cmd_set->erase_sector(addr);
-}
+    gw_addr.range(SPI_CMD_E,  SPI_CMD_S)  = FC_WREN;
 
+    MWRITE4(FLASH_ADDR, gw_addr);
+    MWRITE4(FLASH_GW,   gw_cmd);
 
-////////////////////////////////////////////////////////////////////////
+    if (!_f.wait_ready("WREN command"))
+        return false;
 
-bool Flash::CmdSet0002::reset() {
-    if (!_f.write_internal(0x555, 0xf0)) {
-       _f._err = "Device reset failed";
-       return false;
-    }
     return true;
 }
 
-////////////////////////////////////////////////////////////////////////
-bool Flash::CmdSet0002::erase_sector(u_int32_t addr)
-{
-    u_int32_t word = 0;
-    int          cnt = 0;
+bool SpiFlash::CmdSetStSpi::wait_wip(u_int32_t delay, u_int32_t retrys, u_int32_t fast_retrys  ) {
 
-    if (_no_erase)
-        return true;
 
-    // Just to insure zeroes because erase completion waits for ones
-    if (!write(addr, &word, sizeof(word), true))
-        return false;
+    u_int32_ba gw_cmd;
+    u_int32_ba gw_data;
+    u_int32_ba gw_addr;
 
-    // erase sector sequence
-#ifdef FUJITSU_BYTE_MODE
-    if (!_f.write_internal(0xaaa, 0xaa))
-        return false;
-    if (!_f.write_internal(0x555, 0x55))
-        return false;
-    if (!_f.write_internal(0xaaa, 0x80))
-        return false;
-    if (!_f.write_internal(0xaaa, 0xaa))
-        return false;
-    if (!_f.write_internal(0x555, 0x55))
-        return false;
-    if (!_f.write_internal(addr, 0x30))
-        return false;
-#else // FUJITSU_WORD_MODE 
-    if (_unlock_bypass) {
-       // release unlock bypass before erase sector
-       if (!_f.unlock_bypass(false)) return false; 
-    }
-      
-    if (!_f.write_internal(0x555, 0xaa))
-        return false;
-    if (!_f.write_internal(0x2aa, 0x55))
-        return false;
-    if (!_f.write_internal(0x555, 0x80))
-        return false;
-    if (!_f.write_internal(0x555, 0xaa))
-        return false;
-    if (!_f.write_internal(0x2aa, 0x55))
-        return false;
-    if (!_f.write_internal(addr, 0x30))
-        return false;
+    u_int32_t cnt = 0;
 
-#endif
+    //
+    // Read SR:
+    //
 
-    // Wait while erase completes
-    do
-    {
-        // Timeout checks
-        if (++cnt > ERASE_CNT)
-        {
-            _f._err = "Flash erase sector timeout";
-            return false;
-        }
-        if (!_f.read(addr, &word))
-            return false;
+    gw_cmd[BUSY]                   = 1;
+    gw_cmd[READ_OP]                = 1;
+    gw_cmd[SPI_NO_ADDR]            = 1;
+    gw_cmd[SPI_SPECIAL]            = 1;
 
-        //printf("erase_sector: addr:%08lx, %08x\n", addr, word);
-        usleep(ERASE_DELAY);
-    } while (word != 0xffffffff);
+    gw_addr.range(SPI_CMD_E,  SPI_CMD_S)  = FC_RDSR;
 
+    do {
 
+        if (++cnt > fast_retrys)
+            usleep(delay);
+        if (cnt > retrys) {
+            reset();
+            _f._err = "Flash write error - Write In Progress bit didn't clear.";
+            return false;
+        }
 
-#ifdef FUJITSU_BYTE_MODE
-    // TODO: Need to check unlock bypass option for FUJITSU flash
-#else // FUJITSU_WORD_MODE 
+        MWRITE4(FLASH_ADDR, gw_addr);
+        MWRITE4(FLASH_GW,   gw_cmd);
 
-    if (_unlock_bypass) {
-       // release unlock bypass before erase sector
-       if (!_f.unlock_bypass(true)) return false; 
-    }
+        if (!_f.wait_ready("RDSR"))
+            return false;
 
-#endif
+        MREAD4(FLASH_DATA, &gw_data);
 
+    } while (gw_data[24]); // WIP bit in status reg - Note byte 0 is in bits 31-24 of data word.
 
     return true;
-} // Flash::erase_sector
+}
+
 
+////////////////////////////////////////////////////////////////////////
+//
+// Burn Operations functions
+//
 ////////////////////////////////////////////////////////////////////////
 
-bool Flash::CmdSet0001::reset() {
-    if (!_f.write_internal(0x555, FC_Read)) {
-       _f._err = "Device reset failed";
-       return false;
+
+//
+// Asks user a yes/no question. 
+// Returns true if user chose Y, false if user chose N.
+//
+bool ask_user(const char* msg) {
+    printf(msg);
+    if (_assume_yes)
+        printf("y\n");
+    else {
+        fflush(stdout);
+        char c = getchar();
+        if (c != '\n')
+            while (getchar() != '\n');
+
+        if (c != 'y')
+            return false;
     }
     return true;
 }
 
-////////////////////////////////////////////////////////////////////////
-bool Flash::CmdSet0001::erase_sector(u_int32_t addr)
+bool write_image(Flash& f, u_int32_t addr, void *data, int cnt, bool need_report)
 {
-    u_int32_t    status = 0;
-    int          cnt    = 0;
-
-    if (_no_erase)
-        return true;
+    u_int8_t   *p = (u_int8_t *)data;
+    u_int32_t  curr_addr = addr;
+    u_int32_t  towrite = cnt;
+    u_int32_t  perc = 0xffffffff;
 
-    // Just to insure zeroes because erase completion waits for ones
-    //if (!write(addr, &word, sizeof(word), true))
-    //    return false;
+    //f.curr_sector = 0xffffffff;  // Erase sector first time
+    if (need_report) {
+        printf("000%%");
+        fflush(stdout);
+    }
 
-    // Erase command
-    if (!_f.write_internal(addr, FC_Erase))
-        return false;
+    while (towrite) {
+        // Write
+        int trans = (towrite > (int)Flash::TRANS) ? (int)Flash::TRANS : towrite;
+        if (!f.write(curr_addr, p, trans))
+            return false;
+        p += trans;
+        curr_addr += trans;
+        towrite -= trans;
 
-    // Erase confirm
-    if (!_f.write_internal(addr, FC_Confirm))
-        return false;
+        // Report
+        if (need_report) {
+            u_int32_t new_perc = ((cnt - towrite) * 100) / cnt;
+            if (new_perc != perc) {
+                printf("\b\b\b\b%03d%%", new_perc);
+                fflush(stdout);
+                perc = new_perc;
+            }
+        }
+    }
 
-    usleep(ERASE_DELAY);
+    if (need_report) {
+        printf("\b\b\b\b100%%");
+        fflush(stdout);
+    }
 
-    // Wait while erase completes
-    do
-    {
-        // Timeout checks
-        if (++cnt > ERASE_CNT)
-        {
-            _f._err = "Flash erase sector timeout";
-            return false;
-        }
-        if (!_f.read(addr, &status))
-            return false;
+    return true;
+} //  Flash::write_image
 
-        //printf("CmdSet0001::erase_sector: addr:%08lx, %08x\n", addr, word);
-        usleep(ERASE_DELAY);
-    } while ((status & FS_Ready) == 0);
 
-    if (status & FS_Error) {
-       _f._err = "Status register detected erase error";
-       return false;
-    }
+////////////////////////////////////////////////////////////////////////
+bool WriteSignature(Flash& f, u_int32_t image_idx, u_int32_t sig) {
+    u_int32_t sect_size = f.get_sector_size();
 
-    // Reset
-    if (!reset())
-       return false;
+    if (!f.write( sect_size * (image_idx + 1)  + 8, &sig, 4, true, false))
+        return false;
 
     return true;
-} // Flash::erase_sector
-
+}
 
 
 ////////////////////////////////////////////////////////////////////////
-bool Flash::write(u_int32_t addr, u_int32_t data)
+bool repair(Flash& f, const int from, const int to, bool need_report)
 {
-    if (!_mf)
-    {
-        _err = "Not opened";
+
+    u_int32_t sect_size = f.get_sector_size();
+
+    report("Repairing: Copy %s image to %s     - ", from ? "secondary" : "primary" ,
+           to ? "secondary" : "primary");
+
+    // Valid image pointer
+    u_int32_t im_ptr;
+    if (!f.read(sect_size * (from+1), &im_ptr)) {
+        report("FAILED\n\n");
         return false;
     }
-    if (addr & 0x3)
-    {
-        _err = "Address should be 4-bytes aligned.";
+    TOCPU1(im_ptr);
+
+    // Valid image size in bytes
+    u_int32_t im_size_b;
+    if (!f.read(sect_size * (from+1) + 4, &im_size_b)) {
+        report("FAILED\n\n");
         return false;
     }
+    TOCPU1(im_size_b);
 
-    u_int32_t word;
-    u_int32_t sector = addr & _cfi.erase_block[0].sector_mask;
-    u_int32_t word_in_sector = (addr & ~_cfi.erase_block[0].sector_mask)/sizeof(u_int32_t);
+    // Valid image size in sectors
+    u_int32_t im_size_s = (im_size_b + sect_size - 1) / sect_size;
 
-    if (!read(addr, &word))
-        return false;
-    if (word == data)
-        return true;   // already there
+    // Address to copy valid image
+    u_int32_t write_to = (!to) ? sect_size * 3 : sect_size * (3 + im_size_s);
 
-    u_int32_t buff[get_sector_size()/sizeof(u_int32_t)];
-    if (!read(sector, buff, get_sector_size()))
+    // f.read valid image
+    report("READ FW ");
+    fflush(stdout);
+    char *buf = new char[im_size_b];
+    if (!f.read(im_ptr, buf, im_size_b, need_report)) {
+        report("FAILED\n\n");
+        delete [] buf;
         return false;
-    buff[word_in_sector] = data;
-    return write(sector, buff, get_sector_size());
-} // Flash::write
-
-
-////////////////////////////////////////////////////////////////////////
-bool Flash::write(u_int32_t addr, void *data, int cnt,
-                             bool noerase, bool noverify)
-{
-    return _cmd_set->write(addr, data, cnt, noerase, noverify);
-}
+    }
 
-////////////////////////////////////////////////////////////////////////
-bool Flash::CmdSet0002::write(u_int32_t addr, void *data, int cnt,
-                             bool noerase, bool noverify)
-{
-    if (!_f._mf)
-    {
-        _f._err = "Not opened";
+    // Copy it to right place
+    report(" WRITE FW ");
+    fflush(stdout);
+    if (!write_image(f, write_to, buf, im_size_b, need_report)) {
+        report("FAILED\n\n");
+        delete [] buf;
         return false;
     }
-    if (addr & 0x3)
-    {
-        _f._err = "Address should be 4-bytes aligned.";
+    delete [] buf;
+
+    // Read valid sector
+    u_int32_t sect[sizeof(PS)/4];
+    report(" READ %s ", from ? "SPS" : "PPS");
+    if (!f.read(from ? sect_size*2 : sect_size, sect, sizeof(sect) , need_report)) {
+        report("FAILED\n\n");
         return false;
     }
 
-    char         *p = (char *)data;
-
-    for (int i=0; i<cnt; i++,addr++)
-    {
-        u_int32_t  word;
-        u_int8_t   act, exp;
-        int        cnt1 = 0;
+    // Set new image address
+    // ++++++
+    sect[0] = __be32_to_cpu(write_to);
 
-       u_int32_t bank = addr & BANK_MASK;
-       if (bank != _f._curr_bank)
-       {
-           _f._curr_bank = bank;
-           if (!_f.set_bank(bank))
-               return false;
-       }
-       
-       if (!noerase)
-       {
-           u_int32_t sector = addr & _f._cfi.erase_block[0].sector_mask;
-           if (sector != _f.curr_sector)
-           {
-               _f.curr_sector = sector;
-               if (!erase_sector(_f.curr_sector))
-                   return false;
-           }
-       }
-       
-       if (_no_burn)
-           continue;
-       
-       if (_f._use_scr)
-       {
-
-          //
-          // Special burning interface via Scratchpad
-           // ----------------------------------------
-           //
-           u_int32_t cmd;
-           u_int32_t data = (*p++ & 0xff) << 24;
-           data |= (*p++ & 0xff) << 16;
-           data |= (*p++ & 0xff) << 8;
-           data |= (*p++ & 0xff);
-           if (mwrite4(_f._mf, _f.USE_SCR+4 , data) != 4) return false; 
-           if (mwrite4(_f._mf, _f.USE_SCR ,   WRITE1 | (3 << LEN_SHIFT) | (addr & ADDR_MSK)) != 4) return false; 
-           do
-           {
-               int  loop_cnt = 0;
-               // Timeout checks
-               if (++loop_cnt > FLASH_CMD_CNT)
-               {
-                   _f._err = "Use scratchpad: CMD doesn't become zero";
-                   return false;
-               }
-               if (mread4(_f._mf, _f.USE_SCR , &cmd) != 4) return false; 
-               
-           } while(cmd & CMD_MASK);
-           i += 3;
-           addr += 3;
-       }
-       else if ((u_int8_t)(*p) != 0xff)
-       {
-           
-#ifdef FUJITSU_BYTE_MODE
-           if (!_f.write_internal(0xaaa, 0xaa))
-               return false;
-           if (!_f.write_internal(0x555, 0x55))
-               return false;
-           if (!_f.write_internal(0xaaa, 0xa0))
-               return false;
-#else // FUJITSU_WORD_MODE
-           if (!_unlock_bypass) { 
-               if (!_f.write_internal(0x555, 0xaa))
-                   return false;
-               if (!_f.write_internal(0x2aa, 0x55))
-                   return false;
-           }
-
-           if (!_f.write_internal(0x555, 0xa0))
-               return false;
-#endif
+    // Calculate new CRC
+    // ++++++
+    Crc16 crc;
 
-           if (!_f.write_internal(addr, *p++))
-               return false;
-
-           do
-           {
-               // Timeout checks
-               if (++cnt1 > READ_CNT_FAST)
-                   usleep(READ_DELAY);
-               if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW)
-               {
-                   _f._err = "Flash write error - read value doesn't stabilized.";
-                   return false;
-               }
-               
-               if (!_f.read(addr & ~3, &word))
-                   return false;
-               
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               act = (u_int8_t) ((word >> ((addr & 3) * 8)) & 0xff);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               act = (u_int8_t) ((word >> ((3 - (addr & 3)) * 8)) & 0xff);
-#endif
-               exp = *(p-1) & 0xff;
-               //if (act != exp)
-               //    printf("write: %08x - exp:%02x act:%02x /%08x/\n",
-               //           addr, exp & 0xff, act & 0xff, word);
-           } while (!noverify && act != exp);          
-           
-       } else {
-           p++;
-       }
-    } 
-    return true;
-} // flash_write
+    for (u_int32_t i = 0; i < (sizeof(sect)/4 - 1) ; i++) {
+        crc << __be32_to_cpu(sect[i]);
+    }
+    crc.finish();
 
+    sect[sizeof(sect)/4 - 1] = __be32_to_cpu(crc.get());
 
+    // Corrupt signature
+    u_int32_t valid_signature = sect[2];
+    sect[2] = 0xffffffff;
 
-bool Flash::CmdSet0001WriteByte::write(u_int32_t addr, void *data, int cnt,
-                                      bool noerase, bool noverify)
-{
-    if (!_f._mf)
-    {
-        _f._err = "Not opened";
+    // Write it to invalid sector
+    report(" WRITE %s ", to ? "SPS" : "PPS");
+    if (!write_image(f, to ? sect_size*2 : sect_size, sect, sect_size, need_report)) {
+        report("FAILED\n\n");
         return false;
     }
-    if (addr & 0x3)
-    {
-        _f._err = "Address should be 4-bytes aligned.";
+
+    // Validate signature
+    report(" SIGNATURE ");
+    if (!WriteSignature(f, to, valid_signature)) {
+        report("FAILED\n\n");
         return false;
     }
 
-    char         *p = (char *)data;
-
-    for (int i=0; i<cnt; i++,addr++)
-    {
-        u_int32_t  status;
-        u_int8_t   act, exp;
-        int        cnt1 = 0;
+    report("OK\n");
+    return true;
+} // Flash::repair
 
-       u_int32_t bank = addr & BANK_MASK;
-       if (bank != _f._curr_bank)
-       {
-           _f._curr_bank = bank;
-           if (!_f.set_bank(bank))
-               return false;
-       }
-       
-       if (!noerase)
-       {
-           u_int32_t sector = addr & _f._cfi.erase_block[0].sector_mask;
-           if (sector != _f.curr_sector)
-           {
-               _f.curr_sector = sector;
-               if (!erase_sector(_f.curr_sector))
-                   return false;
-           }
-       }
-       
-       if (_no_burn)
-           continue;
-       
-       if ((u_int8_t)(*p) != 0xff)
-       {
-           // Write byte
-           if (!_f.write_internal(addr, FC_Write))
-               return false;
-
-           if (!_f.write_internal(addr, *p++))
-               return false;
-
-           do
-           {
-               // Timeout checks
-               if (++cnt1 > READ_CNT_FAST)
-                   usleep(READ_DELAY);
-               if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW)
-               {
-                   _f._err = "Flash write error - timeout waiting for ready after write.";
-                   return false;
-               }
-
-               // TODO - Move to read single for Arbel
-               if (!_f.read(addr & ~3, &status))
-                   return false;
-               
-               //if (act != exp)
-               //    printf("write: %08x - exp:%02x act:%02x /%08x/\n",
-               //           addr, exp & 0xff, act & 0xff, word);
-           } while ((status & FS_Ready) == 0);
-
-           if (status & FS_Error) {
-               _f._err = "Flash write error - error staus detected.";
-               return false;
-           }
-
-           if (!noverify) {
-               u_int32_t word;
-               if (!reset()) 
-                   return false;
-               // TODO - Move to read single for Arbel
-               if (!_f.read(addr & ~3, &word))
-                   return false;
-               
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               act = (u_int8_t) ((word >> ((addr & 3) * 8)) & 0xff);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               act = (u_int8_t) ((word >> ((3 - (addr & 3)) * 8)) & 0xff);
-#endif
-               exp = *(p-1) & 0xff;
 
-               if (act != exp) {  
-                   printf("write: %08x - exp:%02x act:%02x /%08x/\n",
-                          addr, exp & 0xff, act & 0xff, word);
 
-                   _f._err = "Write verification failed";
-                   return false;
-               }
-           }
-           
-       } else {
-           p++;
-       }
-    }
 
-    if (!reset()) 
-       return false;
-    
-    return true;
-} // flash_write
 
-///////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+bool FailSafe_burn_image(Flash&       f, 
+                         void         *data, 
+                         int          ps_addr, 
+                         const char*  image_name, 
+                         int          image_addr,
+                         int          image_size,
+                         bool         need_report) {
+
+    u_int8_t* data8 = (u_int8_t*) data;
+    u_int32_t sect_size = f.get_sector_size();
+
+    report("Burning %-9s FW image without signatures  - ", image_name);
+    fflush(stdout);
 
-//
-// Use the buffer write capability.
-//
-bool Flash::CmdSet0001::write(u_int32_t addr, void *data, int cnt,
-                                      bool noerase, bool noverify)
-{
-    if (!_f._mf)
-    {
-        _f._err = "Not opened";
-        return false;
-    }
-    if (addr & 0x3)
-    {
-        _f._err = "Address should be 4-bytes aligned.";
+    // Invalidate signature
+    u_int32_t zeros = 0;
+    if (!f.write(ps_addr + 8, &zeros, 4, true, false)) {
+        report("FAILED (Invalidating signature)\n\n");
         return false;
     }
 
-    u_int8_t         *p = (u_int8_t *)data;
-
-    u_int32_t block_size = _f._cfi.max_multi_byte_write;
-    u_int32_t block_mask = ~(block_size - 1 );
+    // Burn image (from new offset)
 
-    // TODO - Check MAX_WRITE_BUFFER_SIZE against block_size in open (or here)
-    u_int8_t  tmp_buff[MAX_WRITE_BUFFER_SIZE];
+    // Both burnt images are taken from the first image in the file - both images in file are identical.
+    // (future binary releases may contain a single image).
+    if (!write_image(f, image_addr, data8 + sect_size * 3, image_size, need_report)) {
+        report("FAILED\n\n");
+        return false;
+    }
+    report("\b\b\b\bOK  \n");
+    report("Restoring %-9s signature                  - ", image_name); 
+    fflush(stdout);
 
-    while (cnt) {
+    // Burn PS
+    if (!write_image(f, ps_addr, data8 + ps_addr, sect_size, false)) {
+        report("FAILED\n\n");
+        return false;
+    }
 
-       u_int32_t prefix_pad_size = 0;
-       u_int32_t suffix_pad_size = 0;
+    // Validate signature
+    u_int32_t sig = SIGNATURE;
+    TOCPU1(sig);
+    if (!f.write(ps_addr + 8, &sig, 4, true, false)) {
+        report("FAILED\n\n");
+        return false;
+    }
 
-       u_int32_t block_addr = addr & block_mask;
-       u_int32_t data_size  = block_size;
+    report("OK  \n");
 
-       u_int8_t* write_data = p;
+    return true;
+}   
 
 
-       //
-       // First and last cycles (can be the same one) may not be block aligned.
-       // Check the status, and copy data to a padded temp bufer if not alligned.
-       // (there's an option to write partial buffer, but Intel reference code always
-       // writes full buffer, with pads if needed. I do the dame ...)
-       //
+////////////////////////////////////////////////////////////////////////
+bool FailSafe_burn_internal(Flash& f, void *data, int cnt, bool need_report)
+{
+    u_int32_t *data32 = (u_int32_t *)data;
 
-       prefix_pad_size = addr - block_addr;
+    u_int32_t sect_size = f.get_sector_size();
 
-       if ((addr & block_mask) == ((addr + cnt) & block_mask)) {
-           suffix_pad_size = block_size - ((addr + cnt) % block_size);
-       }
+    // Extract Primary/Secondary image pointers and lengths
+    u_int32_t prim_ptr = data32[sect_size / 4];
+    u_int32_t prim_len = data32[sect_size / 4 + 1];
+    u_int32_t scnd_ptr = data32[(sect_size * 2) / 4];
+    u_int32_t scnd_len = data32[(sect_size * 2) / 4 + 1];
+    TOCPU1(prim_ptr);
+    TOCPU1(prim_len);
+    TOCPU1(scnd_ptr);
+    TOCPU1(scnd_len);
+    if ((cnt < (int)(prim_ptr + prim_len)) || (cnt < (int)(scnd_ptr + scnd_len))) {
+        f._err = "Invalid image: too small.";
+        return false;
+    }
+    if (prim_len != scnd_len) {
+        f._err = "Invalid image: two FW images should be in a same size.";
+        return false;
+    }
 
-       if (suffix_pad_size || prefix_pad_size) {
-           memset(tmp_buff, 0xff, block_size);
+    // Image size from flash
+    u_int32_t old_im_size;
+    if (!f.read(sect_size + 4, &old_im_size)) {
+        report("FAILED\n\n");
+        return false;
+    }
+    TOCPU1(old_im_size);
 
-           data_size -= prefix_pad_size;
-           data_size -= suffix_pad_size;
+    u_int32_t prim_order;
+    u_int32_t scnd_order;
 
-           memcpy(tmp_buff + prefix_pad_size, p , data_size);
+    u_int32_t ps_addr[2];
+    u_int32_t image_addr[2];
+    char*     image_name[2];
 
-           write_data = tmp_buff;
-       }
 
-        int        cnt1 = 0;
+    if (prim_len > old_im_size) {
+        scnd_order = 0;
+        prim_order = 1;
+    } else {
+        prim_order = 0;    
+        scnd_order = 1;
+    }
 
-       //
-       // Bank setup.
-       //
-       u_int32_t bank = addr & BANK_MASK;
-       if (bank != _f._curr_bank)
-       {
-           _f._curr_bank = bank;
-           if (!_f.set_bank(bank))
-               return false;
-       }
-       
-       if (!noerase)
-       {
-           u_int32_t sector = addr & _f._cfi.erase_block[0].sector_mask;
-           if (sector != _f.curr_sector)
-           {
-               _f.curr_sector = sector;
-               if (!erase_sector(_f.curr_sector))
-                   return false;
-           }
-       }
-       
-       if (_no_burn)
-           continue;
-
-       //
-       // Check to see if there's something to do
-       //
-       bool all_ffs = true;
-       for (u_int32_t i = 0; i < block_size ; i++) {
-           if (write_data[i] != 0xff) {
-               all_ffs = false;
-               break;
-           }
-       }
-
-       if (!all_ffs)
-       {
-
-           u_int32_t status;
-           cnt1 = 0;
-           do {
-               // Get Write buffer
-               if (!_f.write_internal(block_addr, FC_SCSWrite))
-                    return false;
-
-               if (cnt1 > ((READ_CNT_FAST + READ_CNT_SLOW) * 4))
-               {
-                   printf("-D- status = %08x\n", status);
-                   reset();
-                   _f._err = "Flash write error - Write buffer not ready.";  
-                   return false;
-               }
-
-               cnt1++;
-
-               if (!_f.read(block_addr, &status)) 
-                   return false;
-
-           } while (!(status & FS_Ready));
-
-           if (status & FS_Error) {
-               _f._err = "Flash write error - Error getting write buffer";
-               return false;
-           }
-
-           // word count (allways full buffer, coded as cull buffer size -1)
-           if (!_f.write_internal(block_addr, block_size - 1))
-               return false;
-
-           // Write data to buffer
-           for (u_int32_t i = 0; i < block_size ; i++ ) {
-               if (!_f.write_internal(block_addr + i, write_data[i]))
-                   return false;
-           }
-
-           // write confirm
-           if (!_f.write_internal(block_addr, FC_Confirm))
-               return false;
-
-           cnt1 = 0;
-           do
-           {
-               // Timeout checks
-               if (++cnt1 > READ_CNT_FAST)
-                   usleep(READ_DELAY);
-               if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW)
-               {
-                   reset();
-                   _f._err = "Flash write error - Write buffer status timeout";
-                   return false;
-               }
-
-               // TODO - Move to read single for Arbel
-               if (!_f.read(block_addr, &status))
-                   return false;
-               
-               //if (act != exp)
-               //    printf("write: %08x - exp:%02x act:%02x /%08x/\n",
-               //           addr, exp & 0xff, act & 0xff, word);
-           } while ((status & 0x80) == 0);
-
-           //
-           // TODO: Status checks.
-           //
-
-           if (!noverify) {
-               u_int8_t verify_buffer[MAX_WRITE_BUFFER_SIZE];
-               if (!reset()) 
-                   return false;
-               
-               if (!_f.read(addr, verify_buffer, data_size))
-                   return false;
-
-               for (u_int32_t i = 0 ; i < data_size ; i++) {
-                   if (verify_buffer[i] != write_data[i + prefix_pad_size]) {
-                       printf("write: %08x - exp:%02x act:%02x\n",
-                              addr + i, 
-                              write_data[i + prefix_pad_size] , 
-                              verify_buffer[i]);
-   
-                       _f._err = "Write verification failed";
-                       return false;
-                   }
-               }  
-           }    
-       }
-
-
-       //
-       // loop advance
-       //
-
-       addr += data_size;
-       p    += data_size;
-       cnt  -= data_size;
-    }
-
-    if (!reset()) 
-       return false;
-    
-    return true;
-} // flash_write
+    image_name[scnd_order] = "Secondary";
+    image_addr[scnd_order] = scnd_ptr;
+    ps_addr   [scnd_order] = sect_size * 2;
 
-////////////////////////////////////////////////////////////////////////
-bool Flash::write_image(u_int32_t addr, void *data, int cnt, bool need_report)
-{
-    u_int8_t   *p = (u_int8_t *)data;
-    u_int32_t  curr_addr = addr;
-    u_int32_t  towrite = cnt;
-    u_int32_t  perc = 0xffffffff;
+    image_name[prim_order] = "Primary";
+    image_addr[prim_order] = prim_ptr;
+    ps_addr   [prim_order] = sect_size; 
 
-    curr_sector = 0xffffffff;  // Erase sector first time
-    if (need_report)
-    {
-        printf("000%%");
-        fflush(stdout);
-    }
 
-    while (towrite)
-    {
-        // Write
-        int trans = (towrite > (int)TRANS) ? (int)TRANS : towrite;
-        if (!write(curr_addr, p, trans))
+    for (int i = 0 ; i < 2 ; i++) {
+        if (!FailSafe_burn_image(f, data, ps_addr[i], image_name[i], image_addr[i], prim_len, need_report)) {
             return false;
-        p += trans;
-        curr_addr += trans;
-        towrite -= trans;
-
-        // Report
-        if (need_report)
-        {
-            u_int32_t new_perc = ((cnt - towrite) * 100) / cnt;
-            if (new_perc != perc)
-            {
-                printf("\b\b\b\b%03d%%", new_perc);
-                fflush(stdout);
-                perc = new_perc;
-            }
         }
     }
 
-    if (need_report)
-    {
-        printf("\b\b\b\b100%%");
-        fflush(stdout);
-    }
-
     return true;
-} //  Flash::write_image
+}
+
+
 
 ////////////////////////////////////////////////////////////////////////
-bool Flash::FailSafe_burn(void *data, int cnt, bool need_report)
+bool FailSafe_burn(Flash& f, void *data, int size, bool single_image_burn, bool need_report)
 {
     u_int32_t *data32 = (u_int32_t *)data;
     u_int8_t  *data8 =  (u_int8_t *)data;
 
+       u_int32_t i;
+
+    u_int32_t sect_size = f.get_sector_size();
+
     report("\nRead and verify Invariant Sector               - ");
     fflush(stdout);
 
     // Once more check signature - the Inv.Sector signature should be OK
     u_int32_t signature;
-    if (!read(0x24, &signature))
-    {
+    if (!f.read(0x24, &signature)) {
         report("FAILED\n\n");
         return false;
     }
     TOCPU1(signature);
-    if (signature != SIGNATURE)
-    {
-        _err = "Flash has wrong signature in Invariant Sector.";
+    if (signature != SIGNATURE) {
+        f._err = "Flash has wrong signature in Invariant Sector.";
         report("FAILED\n\n");
         return false;
     }
 
     // Now check Invariant sector contents
-    u_int32_t buf1[get_sector_size()/4];
-    if (cnt < (int)get_sector_size() * 3)
-    {
-        _err = "Image is too small.";
+    vector<u_int32_t> buf1(sect_size/4);
+    if (size < (int)sect_size * 3) {
+        f._err = "Image is too small.";
         report("FAILED\n\n");
         return false;
     }
-    if (!read(0, buf1, get_sector_size()))
-    {
+    if (!f.read(0, &buf1[0] , sect_size)) {
         report("FAILED\n\n");
         return false;
     }
-    for (int i=0; i<(int)get_sector_size()/4; i++)
-    {
-        if (buf1[i] != data32[i]  &&  (data32[i] != 0 || buf1[i] != 0xffffffff))
-        {
-            sprintf(_msg, "Invariant sector doesn't match. Word #%d (0x%x)\n"
+    for (i=0; i < sect_size/4; i++) {
+        if (buf1[i] != data32[i]  &&  (data32[i] != 0 || buf1[i] != 0xffffffff)) {
+            sprintf(f._msg, "Invariant sector doesn't match. Word #%d (0x%x)\n"
                     "in image: 0x%08x, while in flash: 0x%08x",
                     i, i, data32[i], buf1[i]);
-            _err = &_msg[0];
+            f._err = &f._msg[0];
             report("FAILED\n\n");
             return false;
         }
@@ -2159,58 +3319,44 @@ bool Flash::FailSafe_burn(void *data, int cnt, bool need_report)
     report("OK\n");
 
     // Check signatures in image
-    u_int32_t actual_signature = data32[get_sector_size()/4 + 2];
+    u_int32_t actual_signature = data32[sect_size/4 + 2];
     u_int32_t signature_for_compare = actual_signature;
     TOCPU1(signature_for_compare);
-    if (signature_for_compare != SIGNATURE)
-    {
-        sprintf(_msg, "Wrong image: signature in PPS is 0x%08x (should be 0x%08x)",
+    if (signature_for_compare != SIGNATURE) {
+        sprintf(f._msg, "Wrong image: signature in PPS is 0x%08x (should be 0x%08x)",
                 signature_for_compare, SIGNATURE);
-        _err = &_msg[0];
+        f._err = &f._msg[0];
         return false;
     }
-    signature_for_compare = data32[(get_sector_size() * 2)/4 + 2];
+    signature_for_compare = data32[(sect_size * 2)/4 + 2];
     TOCPU1(signature_for_compare);
-    if (signature_for_compare != SIGNATURE)
-    {
-        sprintf(_msg, "Wrong image: signature in SPS is 0x%08x (should be 0x%08x)",
+    if (signature_for_compare != SIGNATURE) {
+        sprintf(f._msg, "Wrong image: signature in SPS is 0x%08x (should be 0x%08x)",
                 signature_for_compare, SIGNATURE);
-        _err = &_msg[0];
+        f._err = &f._msg[0];
         return false;
     }
 
     // Corrupt signatures in image
-    data32[get_sector_size()/4 + 2] = 0xffffffff;
-    data32[(get_sector_size() * 2)/4 + 2] = 0xffffffff;
+    data32[sect_size/4 + 2] = 0xffffffff;
+    data32[(sect_size * 2)/4 + 2] = 0xffffffff;
+
+    bool image_ok[2] = {false, false};
 
     // Check signatures on flash
     bool bad_first = false, bad_second = false;
     report("Read and verify PPS/SPS in flash               - ");
-    if (!read(get_sector_size() + 8, &signature_for_compare))
-    {
-        report("FAILED\n\n");
-        return false;
-    }
-    TOCPU1(signature_for_compare);
-    if (signature_for_compare != SIGNATURE)
-        bad_first = true;
-    if (!read(get_sector_size() * 2 + 8, &signature_for_compare))
-    {
-        report("FAILED\n\n");
-        return false;
-    }
-    TOCPU1(signature_for_compare);
-    if (signature_for_compare != SIGNATURE)
-        bad_second = true;
-
-    if (bad_first || bad_second) {
-       report("Error Detected\n");
-    } else {
-       report("OK\n");
+    for (i = 0 ; i < 2 ; i++) {
+        if (!f.read(sect_size * (i+1) + 8, &signature_for_compare)) {
+            report("FAILED\n\n");
+            return false;
+        }
+        TOCPU1(signature_for_compare);
+        if (signature_for_compare == SIGNATURE)
+            image_ok[i] = true;
     }
 
-    if (bad_first && bad_second)
-    {
+    if (bad_first && bad_second) {
         //
         // Both images are invalid in flash
         // --------------------------------
@@ -2220,8 +3366,7 @@ bool Flash::FailSafe_burn(void *data, int cnt, bool need_report)
         printf("\n    Do you want to continue ? (y/n) [n] : ");
         if (_assume_yes)
             printf("y\n");
-        else
-        {
+        else {
             fflush(stdout);
             char c = getchar();
             if (c != '\n')
@@ -2233,8 +3378,7 @@ bool Flash::FailSafe_burn(void *data, int cnt, bool need_report)
         // Burn all image
         report("Burn FW image without signatures - ");
         fflush(stdout);
-        if (!write_image(get_sector_size(), data8 + get_sector_size(), cnt - get_sector_size(), need_report))
-        {
+        if (!write_image(f, sect_size, data8 + sect_size, size - sect_size, need_report)) {
             report("FAILED\n\n");
             return false;
         }
@@ -2243,248 +3387,124 @@ bool Flash::FailSafe_burn(void *data, int cnt, bool need_report)
         // Restore signatures
         report("Restore right signatures         - ");
         fflush(stdout);
-        if (!write(get_sector_size() + 8, &actual_signature, 4, true, false))
-        {
+        if (!WriteSignature(f, 0, actual_signature)) {
             report("FAILED (PPS Signature)\n\n");
             return false;
         }
-        if (!write(get_sector_size() * 2 + 8, &actual_signature, 4, true, false))
-        {
+        if (!WriteSignature(f, 1, actual_signature)) {
             report("FAILED (SPS Signature)\n\n");
             return false;
         }
         report("OK\n");
         return true;
+    } else {
+        report("OK\n"); 
     }
-    else if (bad_first)
-    {
-        //
-        // Only first image is invalid in flash
-        //
-        if (!repair(1, 0, need_report))
-            return false;
-        return FailSafe_burn_internal(data, cnt, need_report);
-    }
-    else if (bad_second)
-    {
-        //
-        // Only second image is invalid in flash
-        //
-        if (!repair(0, 1, need_report))
-            return false;
-        return FailSafe_burn_internal(data, cnt, need_report);
-    }
-    else
-    {
-        //
-        // Both images are valid in flash
-        //
-        return FailSafe_burn_internal(data, cnt, need_report);
-    }
-
-    return true;
-} // Flash::FailSafe_burn
-
-////////////////////////////////////////////////////////////////////////
-bool Flash::repair(const int from, const int to, bool need_report)
-{
-    report("Repairing: Copy %s image to %s     - ", from ? "secondary" : "primary" ,
-           to ? "secondary" : "primary");
 
-    // Valid image pointer
-    u_int32_t im_ptr;
-    if (!read(get_sector_size() * (from+1), &im_ptr))
-    {
-        report("FAILED\n\n");
-        return false;
-    }
-    TOCPU1(im_ptr);
+    if (single_image_burn == false) {
 
-    // Valid image size in bytes
-    u_int32_t im_size_b;
-    if (!read(get_sector_size() * (from+1) + 4, &im_size_b))
-    {
-        report("FAILED\n\n");
-        return false;
-    }
-    TOCPU1(im_size_b);
+        if (image_ok[0] == false || image_ok[1] == false) {
+            report("Error Detected\n");
 
-    // Valid image size in sectors
-    u_int32_t im_size_s = (im_size_b + get_sector_size() - 1) / get_sector_size();
+            int image_from;
+            int image_to;
 
-    // Address to copy valid image
-    u_int32_t write_to = (!to) ? get_sector_size() * 3 : get_sector_size() * (3 + im_size_s);
+            if (!image_ok[0]) {
+                image_from = 1;
+                image_to   = 0;
+            } else {
+                image_from = 0;
+                image_to   = 1;
+            }
 
-    // Read valid image
-    report("READ FW ");
-    fflush(stdout);
-    char *buf = new char[im_size_b];
-    if (!read(im_ptr, buf, im_size_b, need_report))
-    {
-        report("FAILED\n\n");
-        delete [] buf;
-        return false;
-    }
+            if (!repair(f, image_from, image_to, need_report))
+                return false;
 
-    // Copy it to right place
-    report(" WRITE FW ");
-    fflush(stdout);
-    if (!write_image(write_to, buf, im_size_b, need_report))
-    {
-        report("FAILED\n\n");
-        delete [] buf;
-        return false;
-    }
-    delete [] buf;
+        }
 
-    // Read valid sector
-    u_int32_t sect[get_sector_size()/4];
-    report(" READ %s ", from ? "SPS" : "PPS");
-    if (!read(from ? get_sector_size()*2 : get_sector_size(), sect, get_sector_size(), need_report))
-    {
-        report("FAILED\n\n");
-        return false;
-    }
+        //
+        // Both images are valid in flash
+        //
+        return FailSafe_burn_internal(f, data, size, need_report);
 
-    // Set new image address
-    // ++++++
+    } else {
 
-    // Calculate new CRC
-    // ++++++
+        //
+        // Single image burn:
+        //
 
-    // Corrupt signature
-    u_int32_t valid_signature = sect[2];
-    sect[2] = 0xffffffff;
+        // Extract Primary/Secondary image pointers and lengths
+        u_int32_t frst_image_addr = data32[sect_size / 4];
+        u_int32_t frst_image_size = data32[sect_size / 4 + 1];
+        TOCPU1(frst_image_addr);
+        TOCPU1(frst_image_size);
+
+        if (!image_ok[0] && image_ok[1]) {
+            // Second image is valid on flash.
+            // If the new image can fit in the first image gap, it would be
+            //   burnt as first image.
+            // Otherwise (new image too big), image on flash is copied from second to 
+            //   first image, and new image would be written as second.
+
+            // Image size from flash
+            u_int32_t scnd_image_addr;
+            if (!f.read(sect_size * 2 , &scnd_image_addr)) {
+                report("FAILED\n\n");
+                return false;
+            }
+            TOCPU1(scnd_image_addr);
 
-    // Write it to invalid sector
-    report(" WRITE %s ", to ? "SPS" : "PPS");
-    if (!write_image(to ? get_sector_size()*2 : get_sector_size(), sect, get_sector_size(), need_report))
-    {
-        report("FAILED\n\n");
-        return false;
-    }
+            if (frst_image_addr + frst_image_size > scnd_image_addr) {
+                // New image is too large - can't get in between first image start 
+                // and current (second) image - move current image to be first.
+                if (!repair(f, 1, 0, need_report))
+                    return false;
 
-    // Validate signature
-    report(" SIGNATURE ");
-    if (!write((to ? get_sector_size()*2 : get_sector_size()) + 8, &valid_signature, 4, true, false))
-    {
-        report("FAILED\n\n");
-        return false;
-    }
+                // Now 2 images are valid
+                image_ok[0] = true;
+            } else {
+                if (!FailSafe_burn_image(f, data, sect_size, "first", sect_size * 3, frst_image_size, need_report))
+                    return false;
 
-    report("OK\n");
-    return true;
-} // Flash::repair
+                if (!WriteSignature(f, 1, 0))
+                    return false;
 
-////////////////////////////////////////////////////////////////////////
-bool Flash::FailSafe_burn_internal(void *data, int cnt, bool need_report)
-{
-    u_int32_t *data32 = (u_int32_t *)data;
-    u_int8_t  *data8 =  (u_int8_t *)data;
+                return true;
+            }
+        }
 
-    // Extract Primary/Secondary image pointers and lengths
-    u_int32_t prim_ptr = data32[get_sector_size() / 4];
-    u_int32_t prim_len = data32[get_sector_size() / 4 + 1];
-    u_int32_t scnd_ptr = data32[(get_sector_size() * 2) / 4];
-    u_int32_t scnd_len = data32[(get_sector_size() * 2) / 4 + 1];
-    TOCPU1(prim_ptr);
-    TOCPU1(prim_len);
-    TOCPU1(scnd_ptr);
-    TOCPU1(scnd_len);
-    if ((cnt < (int)(prim_ptr + prim_len)) || (cnt < (int)(scnd_ptr + scnd_len)))
-    {
-        _err = "Invalid image: too small.";
-        return false;
-    }
-    if (prim_len != scnd_len)
-    {
-        _err = "Invalid image: two FW images should be in a same size.";
-        return false;
-    }
+        if (image_ok[0] && image_ok[1]) {
 
-    // Image size from flash
-    u_int32_t old_im_size;
-    if (!read(get_sector_size() + 4, &old_im_size))
-    {
-        report("FAILED\n\n");
-        return false;
-    }
-    TOCPU1(old_im_size);
+            // Invalidate second image 
+            if (!WriteSignature(f, 1, 0)) {
+                report("FAILED\n");
+                return false;
+            }
 
-    u_int32_t prim_order;
-    u_int32_t scnd_order;
+            image_ok[1] = false;
+        }
 
-    u_int32_t ps_addr[2];
-    u_int32_t image_addr[2];
-    char*     image_name[2];
+        if (image_ok[0] && !image_ok[1]) {
+            u_int32_t image_size_sect = ((frst_image_size - 1) / sect_size) + 1 ;
 
+            if (!FailSafe_burn_image(f, data, sect_size * 2, "second", sect_size * (3 + image_size_sect) , frst_image_size, need_report))
+                return false;
 
-    if (prim_len > old_im_size)
-    {
-       scnd_order = 0;
-       prim_order = 1;
-    }
-    else
-    {
-       prim_order = 0;    
-       scnd_order = 1;
-    }
+            // Invalidate first image 
+            if (!WriteSignature(f, 0, 0))
+                return false;
 
-    image_name[scnd_order] = "Secondary";
-    image_addr[scnd_order] = scnd_ptr;
-    ps_addr   [scnd_order] = get_sector_size() * 2;
-    
-    image_name[prim_order] = "Primary";
-    image_addr[prim_order] = prim_ptr;
-    ps_addr   [prim_order] = get_sector_size(); 
-    
-
-    for (int i = 0 ; i < 2 ; i++) 
-    {
-       report("Burning %-9s FW image without signatures  - ", image_name[i]);
-       fflush(stdout);
-               
-       // Invalidate signature
-       u_int32_t zeros = 0;
-       if (!write(ps_addr[i] + 8, &zeros, 4, true, false))
-       {
-           report("FAILED (Invalidating signature)\n\n");
-           return false;
-       }
-
-        // Burn image (from new offset)
-
-       // Both burnt images are taken from the first image in the file - both images in file are identical.
-       // (future binary releases may contain a single image).
-       if (!write_image(image_addr[i], data8 + get_sector_size() * 3, prim_len, need_report))
-       {
-           report("FAILED\n\n");
-           return false;
-       }
-       report("\b\b\b\bOK  \n");
-       report("Restoring %-9s signature                  - ", image_name[i]); 
-        fflush(stdout);
+            return true;
+        } else {
+            report("UNKNOWN FLASH STATE: Valid imagees = (%d,%d).\n", image_ok[0], image_ok[1] );
+            return false;
+        }
 
-       // Burn PS
-       if (!write_image(ps_addr[i], data8 + ps_addr[i], get_sector_size(), false)) {
-           report("FAILED\n\n");
-           return false;
-       }
-        
-       // Validate signature
-       u_int32_t sig = SIGNATURE;
-       TOCPU1(sig);
-       if (!write(ps_addr[i] + 8, &sig, 4, true, false))
-       {
-           report("FAILED\n\n");
-           return false;
-       }
-       
-       report("OK  \n");
     }
 
     return true;
-} // Flash::FailSafe_burn_internal
+}
+
 
 ////////////////////////////////////////////////////////////////////////
 //                                                                    //
@@ -2505,8 +3525,7 @@ bool checkBoot2(FBase& f, u_int32_t beg, u_int32_t offs,
     // Size
     READ4(f, offs+beg+4, &size, pr);
     TOCPU1(size);
-    if (size > 1048576 || size < 4)
-    {
+    if (size > 1048576 || size < 4) {
         report("%s /0x%08x/ - unexpected size (0x%x)\n", pr, offs+beg+4, size);
         return false;
     }
@@ -2522,8 +3541,7 @@ bool checkBoot2(FBase& f, u_int32_t beg, u_int32_t offs,
     CRC1n(crc, buff, size+4);
     crc.finish();
     u_int32_t crc_act = buff[size+3];
-    if (crc.get() != crc_act)
-    {
+    if (crc.get() != crc_act) {
         report("%s /0x%08x/ - wrong CRC (exp:0x%x, act:0x%x)\n",
                pr, offs+beg, crc.get(), crc_act);
         return false;
@@ -2558,22 +3576,18 @@ bool checkGen(FBase& f, u_int32_t beg,
     part_cnt++;
 
     // May be BOOT3?
-    if (gph.type < H_FIRST  ||  gph.type > H_LAST)
-    {
-        if (part_cnt > 2)
-        {
+    if (gph.type < H_FIRST  ||  gph.type > H_LAST) {
+        if (part_cnt > 2) {
             report("%s /0x%x/ - Invalid partition type (%d)\n",
                    pref, offs+beg, gph.type);
             return false;
-        }
-        else
+        } else
             return checkBoot2(f, beg, offs, next, pref);
     }
 
     // All partitions here
     offs += beg;
-    switch(gph.type)
-    {
+    switch (gph.type) {
     case H_DDR:
         size = gph.size * sizeof(u_int32_t);
         sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (DDR)",
@@ -2635,8 +3649,7 @@ bool checkGen(FBase& f, u_int32_t beg,
     u_int32_t crc_act;
     READ4(f, offs+sizeof(gph)+size, &crc_act, pr);
     TOCPU1(crc_act);
-    if (crc.get() != crc_act)
-    {
+    if (crc.get() != crc_act) {
         report("%s /0x%08x/ - wrong CRC (exp:0x%x, act:0x%x)\n",
                pr, offs, crc.get(), crc_act);
         return false;
@@ -2659,9 +3672,8 @@ bool checkPS(FBase& f, u_int32_t offs, u_int32_t& next, const char *pref)
     TOCPUBY(ps);
 
     // Signature
-    if (ps.signature != SIGNATURE)
-    {
-        report("%s Pointer Sector /0x%08x/ - wrong signature (%08x)\n",
+    if (ps.signature != SIGNATURE) {
+        report("%s Pointer Sector /0x%08x/ - invalid signature (%08x)\n",
                pref, offs, ps.signature);
         return false;
     }
@@ -2669,8 +3681,7 @@ bool checkPS(FBase& f, u_int32_t offs, u_int32_t& next, const char *pref)
     // CRC
     CRC1BY(crc, ps);
     crc.finish();
-    if (crc.get() != ps.crc016)
-    {
+    if (crc.get() != ps.crc016) {
         report("%s Pointer Sector /0x%08x/ - wrong CRC (exp:0x%x, act:0x%x)\n",
                pref, offs, ps.crc016, crc.get());
         return false;
@@ -2706,8 +3717,7 @@ bool Verify(FBase& f)
 
     READ4(f, 0x24, &signature, "Signature");
     TOCPU1(signature);
-    if (signature == SIGNATURE)
-    {
+    if (signature == SIGNATURE) {
         // Full image
         _image_is_full = true;
         report("\nFailsafe image:\n\n");
@@ -2718,9 +3728,7 @@ bool Verify(FBase& f)
         report("\n");
         if (checkPS(f, f.get_sector_size() * 2, scnd_ptr, "Secondary"))
             CHECKLS(f, scnd_ptr, "               ");
-    }
-    else
-    {
+    } else {
         // Short image
         _image_is_full = false;
         report("\nShort image:\n");
@@ -2778,8 +3786,7 @@ bool getBSN(char *s, guid_t *guid)
     for (i=0; i<5; i++)
         if (!isdigit(*p++))      // xxxxx
             BSN_RET;
-    if (*p == '-')               // - /optional/
-    {
+    if (*p == '-') {               // - /optional/
         p++;
         date_offs++;
     }
@@ -2793,8 +3800,7 @@ bool getBSN(char *s, guid_t *guid)
     while (isdigit(*q++))
         ndigits++;
 
-    switch (ndigits)
-    {
+    switch (ndigits) {
     case 6:
         p += 6;                  // skip ddmmyy
         break;
@@ -2811,8 +3817,7 @@ bool getBSN(char *s, guid_t *guid)
     for (i=0; i<3; i++)          // nnn
         if (!isdigit(*p++))
             BSN_RET;
-    if (*p)
-    {
+    if (*p) {
         cc_present = true;
         if (*p++ != '-')         // -
             BSN_RET;
@@ -2842,8 +3847,7 @@ bool getBSN(char *s, guid_t *guid)
     if (!num)
         BSN_RET1("Number (num) can't be zero");
     int cc = 1;
-    if (cc_present)
-    {
+    if (cc_present) {
         cc = BSN_subfield(s, 19+date_offs, 2);
         if (cc > 14)
             BSN_RET1("Chip number (cc) should not exceed 14");
@@ -2852,6 +3856,7 @@ bool getBSN(char *s, guid_t *guid)
     }
     u_int64_t id = ((((yy*12+mm-1)*31+ dd-1) * 1000) + num-1) * 112;
     id += (cc-1)*8;
+
     u_int64_t g = (COMPANY_ID << 40) | (TYPE << 32) | id;
     guid->h = (u_int32_t)(g>>32);
     guid->l = (u_int32_t)g;
@@ -2874,15 +3879,13 @@ bool getGUID(const char *s, guid_t *guid)
         str[j--] = s[i];
 
     l = strtoul(&str[8], &endp, 16);
-    if (*endp)
-    {
+    if (*endp) {
         printf("Invalid GUID syntax (low) (%s)\n", &str[8]);
         return false;
     }
     str[8] = '\0';
     h = strtoul(&str[0], &endp, 16);
-    if (*endp)
-    {
+    if (*endp) {
         printf("Invalid GUID syntax (high) (%s)\n", str);
         return false;
     }
@@ -2893,17 +3896,15 @@ bool getGUID(const char *s, guid_t *guid)
 
 ////////////////////////////////////////////////////////////////////////
 bool extractGUIDptr(u_int32_t sign, u_int32_t *buf, int buf_len,
-                     char *pref, u_int32_t *ind, int *nguids)
+                    char *pref, u_int32_t *ind, int *nguids)
 {
     u_int32_t offs = 0;
 
     // Check signature
-    if (sign)
-    {
+    if (sign) {
         u_int32_t signature = buf[(sign + 8)/4];
         TOCPU1(signature);
-        if (signature != SIGNATURE)
-        {
+        if (signature != SIGNATURE) {
             printf("%s pointer section not valid\n", pref);
             return false;
         }
@@ -2915,8 +3916,7 @@ bool extractGUIDptr(u_int32_t sign, u_int32_t *buf, int buf_len,
     *ind = buf[(offs+0x24)/4];
     TOCPU1(*ind);
     *ind += offs;
-    if (*ind >= (u_int32_t)buf_len)
-    {
+    if (*ind >= (u_int32_t)buf_len) {
         printf("%s image - insane GUID pointer (%08x)\n", pref, *ind);
         return false;
     }
@@ -2925,8 +3925,7 @@ bool extractGUIDptr(u_int32_t sign, u_int32_t *buf, int buf_len,
     *nguids /= 2;
 
     // More sanity check
-    if (*nguids > GUIDS)
-    {
+    if (*nguids > GUIDS) {
         printf("%s image - insane number of GUIDs (%d)\n", pref, *nguids);
         return false;
     }
@@ -2935,40 +3934,38 @@ bool extractGUIDptr(u_int32_t sign, u_int32_t *buf, int buf_len,
 } // extractGUIDptr
 
 ////////////////////////////////////////////////////////////////////////
-void pathGUIDsSection(u_int32_t *buf, u_int32_t ind,
-                      guid_t guids[GUIDS], int nguids)
+void patchGUIDsSection(u_int32_t *buf, u_int32_t ind,
+                       guid_t guids[GUIDS], int nguids)
 {
     u_int32_t       i, word;
     u_int32_t       new_buf[GUIDS*2];
     Crc16              crc;
 
     // Form new GUID section
-    for (i=0; i<(u_int32_t)nguids; i++)
-    {
+    for (i=0; i<(u_int32_t)nguids; i++) {
         new_buf[i*2] = guids[i].h;
         new_buf[i*2+1] = guids[i].l;
     }
 
     // Calculate new CRC16
-    for (i=ind/4 - 4; i<ind/4; i++)
-    {
-        word = buf[i];
-        TOCPU1(word);
+    for (i=ind/4 - 4; i<ind/4; i++) {
+        word = __be32_to_cpu(buf[i]);
         crc << word;
     }
     for (i=0; i<(u_int32_t)nguids*2; i++)
         crc << new_buf[i];
 
     // Patch GUIDs
-    TOCPU(new_buf);
+    for (i=0; i<sizeof(new_buf)/sizeof(u_int32_t); ++i) {
+        new_buf[i] = __cpu_to_be32(new_buf[i]);
+    }
     memcpy(&buf[ind/4], &new_buf[0], nguids * 2 * sizeof(u_int32_t));
 
     // Insert new CRC
     crc.finish();
     word = crc.get();
-    TOCPU1(word);
-    buf[ind/4 + nguids*2] = word;
-} // pathGUIDsSection
+    buf[ind/4 + nguids*2] = __cpu_to_be32(word);
+} // patchGUIDsSection
 
 
 ////////////////////////////////////////////////////////////////////////
@@ -2981,36 +3978,76 @@ void _patchVSD(FImage& f, int ind, char *vsd)
     memcpy(&ps->vsd[0], vsd, VSD_LEN);
 
     u_int32_t *qp = (u_int32_t *)ps;
-    for (unsigned int i=0; i<sizeof(PS)/sizeof(u_int32_t) - 1; i++)
-    {
+    for (unsigned int i=0; i<sizeof(PS)/sizeof(u_int32_t) - 1; i++) {
         u_int32_t qq = *qp++;
         TOCPU1(qq);
         crc << qq;
     }
     crc.finish();
     u_int32_t crc016 = crc.get();
-    TOCPU1(crc016);
-    ps->crc016 = crc016;
+    ps->crc016 = __cpu_to_be32(crc016);
 } // _patchVSD
 
 
 ////////////////////////////////////////////////////////////////////////
-bool patchVSD(FImage& f, char *vsd1, char *psid)
+//Note that vsd1 is a string of bytes.
+bool patchVSD(FImage& f, char *vsd1, char *curr_psid, const char* new_psid)
 {
     char       vsd[VSD_LEN];
 
+    PS *ps = (PS*)(f.getBuf() + f.get_sector_size()/4);
+
+    char flash_psid[sizeof(ps->psid) + 1];
+    char image_psid[sizeof(ps->psid) + 1];
+
     // Form new VSD
     memset(vsd, 0, VSD_LEN);
+    memset(flash_psid, 0 , sizeof(flash_psid));
+    memset(image_psid, 0 , sizeof(image_psid));
+
+
     if (vsd1)
         strncpy(&vsd[0], vsd1, VSD_OFFS);
-    if (psid)
-        strncpy(&vsd[VSD_OFFS], psid, VSD_LAST);
 
-    //VSD is kept in flash byte-swapped
+
+    if (new_psid == NULL) {
+        // New psid is not explicitly given - take it from image
+        memcpy(image_psid, (char*)ps->psid, sizeof(ps->psid));
+
+
+        // psid is kept in flash byte-swapped.
+        // decode it to string
+        u_int32_t *qp = (u_int32_t *)&image_psid[0];
+        for (u_int32_t i=0; i < sizeof(ps->psid)/4; i++) {
+            *qp = bswap_32(*qp);
+            qp++;
+        }
+
+    } else {
+        strncpy(image_psid, new_psid, sizeof(ps->psid));
+    }
+
+
+    if (strncmp( image_psid, (char*) curr_psid, sizeof(ps->psid))) {
+
+        // Copy the strings to a local buffer to assure '\0' termination (for printf) 
+        strncpy(flash_psid, curr_psid,sizeof(ps->psid));
+
+        printf("\n    You are about to replace current PSID in flash - \"%s\" with a different PSID - \"%s\".\n", flash_psid, image_psid);
+
+        if (! ask_user("\n    Is it OK ? (y/n) [n] : "))
+            return false;
+    }
+
+    // Copy correct PSID to image.
+    strncpy(&vsd[VSD_OFFS], image_psid, VSD_LAST);
+
+    //vsd is kept in flash byte-swapped.
+    //recode it back before patching
     u_int32_t *qp = (u_int32_t *)&vsd[0];
-    for (int i=0; i<VSD_LEN/4; i++)
-    {
-        qp[i] = bswap_32(qp[i]);
+    for (int i=0; i<VSD_LEN/4; i++) {
+        *qp = bswap_32(*qp);
+        qp++;
     }
 
     _patchVSD(f, f.get_sector_size(), vsd);      // Primary PS
@@ -3020,8 +4057,8 @@ bool patchVSD(FImage& f, char *vsd1, char *psid)
 
 
 ////////////////////////////////////////////////////////////////////////
-bool pathGUIDs(FImage& f, guid_t guids[GUIDS],
-               bool interactive)
+bool patchGUIDs(FImage& f, guid_t guids[GUIDS],
+                bool interactive)
 {
     guid_t       old_guids[GUIDS];
     u_int32_t       *buf = f.getBuf();
@@ -3031,8 +4068,7 @@ bool pathGUIDs(FImage& f, guid_t guids[GUIDS],
     int             nguid1, nguid2;
 
     TOCPU1(signature);
-    if (signature == SIGNATURE)
-    {
+    if (signature == SIGNATURE) {
         // Full image
         if (interactive)
             printf("\nFull image:\n\n");
@@ -3041,9 +4077,7 @@ bool pathGUIDs(FImage& f, guid_t guids[GUIDS],
         if (!extractGUIDptr(f.get_sector_size() *2, buf, buf_len, "Secondary", &ind2, &nguid2))
             return false;
 
-    }
-    else
-    {
+    } else {
         // Short image
         if (interactive)
             printf("\nShort image:\n\n");
@@ -3052,11 +4086,9 @@ bool pathGUIDs(FImage& f, guid_t guids[GUIDS],
     }
 
     // Print old GUIDs and get confirmation
-    if (interactive)
-    {
+    if (interactive) {
         bool old_guids_fmt = nguid1 < GUIDS;
-        for (int i=0; i<GUIDS; i++)
-        {
+        for (int i=0; i<GUIDS; i++) {
             u_int32_t h = buf[ind1/4 + i*2];
             TOCPU1(h);
             u_int32_t l = buf[ind1/4 + i*2 + 1];
@@ -3073,36 +4105,25 @@ bool pathGUIDs(FImage& f, guid_t guids[GUIDS],
         printf("        Port2:     " GUID_FORMAT "\n", old_guids[2].h,old_guids[2].l);
         if (!old_guids_fmt)
             printf("        Sys.Image: " GUID_FORMAT "\n", old_guids[3].h,old_guids[3].l);
-        printf("\n    You are about to change them to follow GUIDs:\n");
+        printf("\n    You are about to change them to following GUIDs:\n");
         printf("        Node:      " GUID_FORMAT "\n", guids[0].h,guids[0].l);
         printf("        Port1:     " GUID_FORMAT "\n", guids[1].h,guids[1].l);
         printf("        Port2:     " GUID_FORMAT "\n", guids[2].h,guids[2].l);
         if (!old_guids_fmt)
             printf("        Sys.Image: " GUID_FORMAT "\n", guids[3].h,guids[3].l);
 
-        printf("\n    Is it OK ? (y/n) [n] : ");
-        if (_assume_yes)
-            printf("y\n");
-        else
-        {
-            fflush(stdout);
-            char c = getchar();
-            if (c != '\n')
-                while (getchar() != '\n');
-            if (c != 'y')
-                return false;
-        }
+        if (!ask_user("\n    Is it OK ? (y/n) [n] : "))
+            return false;
     }
 
     // Path GUIDs section
-    pathGUIDsSection(buf, ind1, guids, nguid1);
+    patchGUIDsSection(buf, ind1, guids, nguid1);
     if (ind2)
-        pathGUIDsSection(buf, ind2, guids, nguid2);
+        patchGUIDsSection(buf, ind2, guids, nguid2);
 
-    if (!interactive)
-    {
+    if (!interactive) {
         bool old_guids_fmt = nguid1 < GUIDS;
-        printf("\n    Burn image with follow GUIDs:\n");
+        printf("\n    Burn image with the following GUIDs:\n");
         printf("        Node:      " GUID_FORMAT "\n", guids[0].h,guids[0].l);
         printf("        Port1:     " GUID_FORMAT "\n", guids[1].h,guids[1].l);
         printf("        Port2:     " GUID_FORMAT "\n", guids[2].h,guids[2].l);
@@ -3110,7 +4131,7 @@ bool pathGUIDs(FImage& f, guid_t guids[GUIDS],
             printf("        Sys.Image: " GUID_FORMAT "\n", guids[3].h,guids[3].l);
     }
     return true;
-} // pathGUIDs
+} // patchGUIDs
 
 
 ////////////////////////////////////////////////////////////////////////
@@ -3121,7 +4142,8 @@ bool pathGUIDs(FImage& f, guid_t guids[GUIDS],
 //                                                                    //
 ////////////////////////////////////////////////////////////////////////
 bool RevisionInfo(FBase& f, guid_t guids_out[GUIDS], char *vsd_out,
-                  bool *fs_image, bool internal_call = false)
+                  bool *fs_image, bool internal_call = false,
+                  bool read_guids = true, bool read_ps = true)
 {
     char      *im_type;
     u_int32_t prim_ptr, scnd_ptr, ps_start=0;
@@ -3131,31 +4153,23 @@ bool RevisionInfo(FBase& f, guid_t guids_out[GUIDS], char *vsd_out,
     READ4(f, 0x24, &signature, "Signature");
     TOCPU1(signature);
     _silent = true;
-    if (signature == SIGNATURE)
-    {
+    if (signature == SIGNATURE) {
         // Full image
         report("\nFailsafe image:\n\n");
-        if (checkPS(f, f.get_sector_size(), prim_ptr, "Primary  "))
-        {
+        if (checkPS(f, f.get_sector_size(), prim_ptr, "Primary  ")) {
             im_start = prim_ptr;
             ps_start = f.get_sector_size();
-        }
-        else if (checkPS(f, f.get_sector_size() * 2, scnd_ptr, "Secondary"))
-        {
+        } else if (checkPS(f, f.get_sector_size() * 2, scnd_ptr, "Secondary")) {
             im_start = scnd_ptr;
             ps_start = f.get_sector_size() * 2;
-        }
-        else
-        {
+        } else {
             _silent = internal_call;
             report("No valid image found.\n");
             return false;
         }
         im_type = "FailSafe";
         *fs_image = true;
-    }
-    else
-    {
+    } else {
         // Short image
         report("\nShort image:\n");
         im_type = "Short";
@@ -3171,59 +4185,61 @@ bool RevisionInfo(FBase& f, guid_t guids_out[GUIDS], char *vsd_out,
     fw_id >>= 24;
 
     // Read GUIDs
-    FImage    *fim = dynamic_cast<FImage*>(&f);
+    FImage   *fim;
+
+       fim = dynamic_cast<FImage*>(&f);
+
     u_int32_t guid_ptr, nguids;
     guid_t guids[GUIDS];
 
-    READ4(f, im_start + 0x24, &guid_ptr, "GUID PTR");
-    TOCPU1(guid_ptr);
-    guid_ptr += im_start;
-    if (guid_ptr >= (fim ? fim->getBufLength() : (u_int32_t)f.MAX_FLASH))
-    {
-        report("Insane GUID pointer (%08x)\n", guid_ptr);
-        return false;
-    }
-    READ4(f, guid_ptr - 3*sizeof(u_int32_t), &nguids, "Number of GUIDs");
-    TOCPU1(nguids);
-    if (nguids > GUIDS*2)
-    {
-        report("Insane Number of GUIDs (%d)\n", nguids);
-        return false;
+    if (read_guids) {
+        READ4(f, im_start + 0x24, &guid_ptr, "GUID PTR");
+        TOCPU1(guid_ptr);
+        guid_ptr += im_start;
+        if (guid_ptr >= (fim ? fim->getBufLength() : (u_int32_t)f.MAX_FLASH)) {
+            report("Insane GUID pointer (%08x)\n", guid_ptr);
+            return false;
+        }
+        READ4(f, guid_ptr - 3*sizeof(u_int32_t), &nguids, "Number of GUIDs");
+        TOCPU1(nguids);
+        if (nguids > GUIDS*2) {
+            report("Insane Number of GUIDs (%d)\n", nguids);
+            return false;
+        }
+        READBUF(f, guid_ptr, guids, nguids / 2 * sizeof(u_int64_t), "GUIDS");
+        TOCPUBY64(guids);
+        memcpy(&guids_out[0], &guids[0], sizeof(guids));
+
     }
-    READBUF(f, guid_ptr, guids, nguids / 2 * sizeof(guid_t), "GUIDS");
-    TOCPUBY64(guids);
-    memcpy(&guids_out[0], &guids[0], sizeof(guids));
 
     report("Image type: %s\n"
            "Chip rev.:  %X\n",
            im_type, fw_id);
-    report("GUIDs:      ");
-    u_int32_t i;
-    for (i=0; i<nguids/2; i++)
+
+    if (read_guids) {
+        report("GUIDs:      ");
+        for (u_int32_t i=0; i<nguids/2; i++)
             report(GUID_FORMAT " ", guids[i].h,guids[i].l);
-    if (*fs_image)
-    {
+    }
+
+    if (*fs_image && read_ps) {
         char       vsd[VSD_LEN+1];   // +1  => Leave a space for \0 when psid size == 16 .
 
         memset(vsd, 0, VSD_LEN+1);
         READBUF(f, ps_start + 0x20, vsd, VSD_LEN, "Vendor Specific Data (Board ID)");
-       //vsd is kept byte-swapped
-       u_int32_t *p = (u_int32_t *)(vsd);
-       for (i=0; i<sizeof(vsd)/sizeof(u_int32_t); i++) {
-               p[i] = bswap_32(p[i]);
-       }
-
-       #if (0)
-       // Show '\0' in VSD and PSID strings:
-       bool str_found = false;
-       for (int i = VSD_OFFS - 2; i >= 0 ; i--) {
-           if (!str_found && vsd[i] != '\0') 
-               str_found = true;
-           
-           if (str_found && vsd[i] == '\0') 
-               vsd[i] = '.'; 
-       }
-       #endif
+        TOCPUBY(vsd);
+
+#if (0)
+        // Show '\0' in VSD and PSID strings:
+        bool str_found = false;
+        for (int i = VSD_OFFS - 2; i >= 0 ; i--) {
+            if (!str_found && vsd[i] != '\0')
+                str_found = true;
+
+            if (str_found && vsd[i] == '\0')
+                vsd[i] = '.';
+        }
+#endif
 
         report("\nBoard ID:   %s", vsd);
         if (vsd[VSD_OFFS])
@@ -3232,13 +4248,101 @@ bool RevisionInfo(FBase& f, guid_t guids_out[GUIDS], char *vsd_out,
             report("\n");
         if (vsd_out)
             memcpy(vsd_out, &vsd[0], VSD_LEN);
-    }
-    else
+    } else
         report("\n");
 
     return true;
 } // RevisionInfo
 
+////////////////////////////////////////////////////////////////////////
+//                                                                    //
+// ****************************************************************** //
+//       Detect Device type and return matching Flash interface       //
+// ****************************************************************** //
+//                                                                    //
+////////////////////////////////////////////////////////////////////////
+
+Flash* get_serial_flash(mfile* mf) {
+
+    enum {
+        CR_FLASH_TYPE   = 0xf0810,
+        BO_FLASH_TYPE_S = 10,
+        BO_FLASH_TYPE_E = 11,
+    };
+
+    enum FlashType {
+        FT_LPC    = 0,
+        FT_SPI    = 1,
+        FT_XBUS   = 2,
+        FT_EEPROM = 3
+    };
+
+    char* flash_type_str[] = {"LPC", "SPI", "XBUS", "EEPROM"};
+
+    u_int32_ba strap_option;
+    u_int32_t  flash_type;
+
+    if (mread4(mf, CR_FLASH_TYPE, &strap_option) != 4) return false;
+
+    flash_type = strap_option.range(BO_FLASH_TYPE_E, BO_FLASH_TYPE_S);
+
+
+    switch (flash_type) {
+    case FT_SPI:
+        return new SpiFlash;
+    case FT_LPC:
+    case FT_XBUS:
+    case FT_EEPROM:
+        printf("*** ERROR *** flash of type %s not supported.\n",
+               flash_type_str[flash_type]);
+    }
+
+    return NULL;
+
+}
+
+
+Flash* get_flash(const char* device) {
+    Flash* f = NULL;
+
+    //
+    // Check device ID. Allocate flash accordingly
+    //
+
+    u_int32_t dev_id;
+
+    mfile* mf = mopen(device);
+    if (!mf) {
+        printf("*** ERROR *** Can't open %s: %s\n", device,  strerror(errno));
+        return NULL;
+    }
+
+    if (mread4(mf, 0xf0014, &dev_id) != 4) return false;
+
+    dev_id &= 0xffff;
+
+    //printf("-D- read dev id: %d\n", dev_id);
+
+    switch (dev_id) {
+    case 23108:
+    case 25208:
+        f = new ParallelFlash;
+        break;
+
+    case 24204:
+    case 25204:
+        f = get_serial_flash(mf);
+        break;
+
+    default:
+        printf("*** ERROR *** Device type %d not supported.\n", dev_id);
+    }
+
+    mclose(mf);
+
+    return f;
+}
+
 
 ////////////////////////////////////////////////////////////////////////
 //                                                                    //
@@ -3249,175 +4353,257 @@ bool RevisionInfo(FBase& f, guid_t guids_out[GUIDS], char *vsd_out,
 ////////////////////////////////////////////////////////////////////////
 // sed -e 's/"/\\"/g' < flint.txt | perl -pe 's/^(.*)$/"$1\\n"/'
 
-void usage(const char *sname)
+void usage(const char *sname, bool full = false)
 {
     const char *descr =
-"\n"
-"               FLINT - FLash INTerface\n"
-"\n"
-"InfiniHost flash memory operations.\n"
-"\n"
-"Usage:\n"
-"------\n"
-"\n"
-"    " FLINT_NAME " [switches...] <command> [parameters...]\n"
-"\n"
-"\n"
-"Switches summary:\n"
-"-----------------\n"
-"    -bsn <BSN>         - Mellanox Board Serial Number (BSN).\n"
-"                         Valid BSN format is:\n"
-"                                 MTxxxxx[-]R[xx]ddmmyy-nnn[-cc]\n"
-"                         Commands affected: burn\n"
-"\n"
-"    -crc               - Print CRC after each section when verify.\n"
-"\n"
-"    -d[evice] <device> - Device flash is connected to.\n"
-"                         Commands affected: all\n"
-"\n"
-"    -guid <GUID>       - Base value for up to 4 GUIDs, which\n"
-"                         are automatically assigned the\n"
-"                         following values:\n"
-"\n"
-"                         guid   -> node GUID\n"
-"                         guid+1 -> port1\n"
-"                         guid+2 -> port2\n"
-"                         guid+3 -> system image GUID.\n"
-"\n"
-"                         Commands affected: burn\n"
-"\n"
-"    -guids <GUIDs...>  - 4 GUIDs must be specified here.\n"
-"                         The specified GUIDs are assigned\n"
-"                         the following values, repectively:\n"
-"                         node, port1, port2 and system image GUID.\n"
-"\n"
-"                         Commands affected: burn\n"
-"\n"
-"    -h[elp]            - Prints this message and exits\n"
-"\n"
-"    -i[mage] <image>   - Binary image file.\n"
-"                         Commands affected: burn, verify\n"
-"\n"
-"    -nofs              - Burn image not in failsafe manner.\n"
-"\n"
-"    -unlock            - Use unlock bypass feature of the flash for quicker burn.\n"
-"                         Commands affected: burn\n"
-"\n"
-"    -s[ilent]          - Do not print burn progress flyer.\n"
-"                         Commands affected: burn\n"
-"\n"
-"    -y[es]             - Non interactive mode - assume answer\n"
-"                         \"yes\" to all questions.\n"
-"                         Commands affected: all\n"
-"\n"
-"    -vsd  <string>     - Write this string, of up to 208 characters, to VSD when burn.\n"
-"\n"
-"    -psid <PSID>       - Write the Parameter Set ID (PSID) string to PS-ID field (last 16 bytes of VSD) when burn.\n"
-"\n"
-"    -use_image_ps      - Burn vsd/psid as appears in the given image - don't keep existing vsd/psid on flash.\n"
-"                         Commands affected: burn\n"
-"\n"
-"    -v                 - Version info.\n"
-"\n"
-"Commands summary:\n"
-"-----------------\n"
-"    b[urn]   - Burn flash\n"
-"    e[rase]  - Erase sector\n"
-"    q[uery]  - Query misc. flash/FW characteristics\n"
-"    rw       - Read one dword from flash\n"
-"    v[erify] - Verify entire flash\n"
-"    ww       - Write one dword to flash\n"
-"    wwne     - Write one dword to flash without sector erase\n"
-"\n"
-"\n"
-"Command descriptions:\n"
-"----------------------------\n"
-"\n"
-"* Burn flash\n"
-"  Burns entire flash from raw binary image.\n"
-"\n"
-"    Command:\n"
-"        b[urn]\n"
-"    Parameters:\n"
-"        None\n"
-"    Examples:\n"
-"        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " -i image1.bin burn\n"
-"        " FLINT_NAME " -d " DEV_MST_EXAMPLE2 " -guid 0x2c9000100d050 -i image1.bin b\n"
-"\n"
-"\n"
-"* Erase sector.\n"
-"  Erases a sector that contains specified address.\n"
-"\n"
-"    Command:\n"
-"        e[rase]\n"
-"    Parameters:\n"
-"        addr - address of word in sector that you want\n"
-"                   to erase.\n"
-"    Example:\n"
-"        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " erase 0x10000\n"
-"\n"
-"\n"
-"* Query miscellaneous FW and flash parameters\n"
-"\n"
-"    Command:\n"
-"        q[uery]\n"
-"    Parameters:\n"
-"        None\n"
-"    Example:\n"
-"        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " query\n"
-"\n"
-"\n"
-"* Read one dword from flash.\n"
-"\n"
-"    Command:\n"
-"        rw\n"
-"    Parameters:\n"
-"        addr - address of word to read\n"
-"    Example:\n"
-"        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " rw 0x20\n"
-"\n"
-"\n"
-"* Verify entire flash.\n"
-"\n"
-"    Command:\n"
-"        v[erify]\n"
-"    Parameters:\n"
-"        None\n"
-"    Example:\n"
-"        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " v\n"
-"\n"
-"\n"
-"* Write one dword to flash.\n"
-"  Note that the utility will read an entire flash sector,\n"
-"  modify one word and write the sector back. This may take\n"
-"  a few seconds.\n"
-"\n"
-"    Command:\n"
-"        ww\n"
-"    Parameters:\n"
-"        addr - address of word\n"
-"        data - value of word\n"
-"    Example:\n"
-"        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " ww 0x10008 0x5a445a44\n"
-"\n"
-"\n"
-"* Write one dword to flash without sector erase.\n"
-"  Note that the result of operation is undefined and depends\n"
-"  on flash type. Usually \"bitwise AND\" (&) between specified\n"
-"  word and previous flash contents will be written to\n"
-"  specified address.\n"
-"\n"
-"    Command:\n"
-"        wwne\n"
-"    Parameters:\n"
-"        addr - address of word\n"
-"        data - value of word\n"
-"    Example:\n"
-"        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " wwne 0x10008 0x5a445a44\n"
-        "\n";
+    "\n"
+    "               FLINT - FLash INTerface\n"
+    "\n"
+    "InfiniHost flash memory operations.\n"
+    "\n"
+    "Usage:\n"
+    "------\n"
+    "\n"
+    "    " FLINT_NAME " [switches...] <command> [parameters...]\n"
+    "\n"
+    "\n"
+    "Switches summary:\n"
+    "-----------------\n"
+    "    -bsn <BSN>         - Mellanox Board Serial Number (BSN).\n"
+    "                         Valid BSN format is:\n"
+    "                                 MTxxxxx[-]R[xx]ddmmyy-nnn[-cc]\n"
+    "                         Commands affected: burn\n"
+    "\n"
+    "    -crc               - Print CRC after each section when verify.\n"
+    "\n"
+    "    -d[evice] <device> - Device flash is connected to.\n"
+    "                         Commands affected: all\n"
+    "\n"
+    "    -guid <GUID>       - Base value for up to 4 GUIDs, which\n"
+    "                         are automatically assigned the\n"
+    "                         following values:\n"
+    "\n"
+    "                         guid   -> node GUID\n"
+    "                         guid+1 -> port1\n"
+    "                         guid+2 -> port2\n"
+    "                         guid+3 -> system image GUID.\n"
+    "\n"
+    "                         Commands affected: burn\n"
+    "\n"
+    "    -guids <GUIDs...>  - 4 GUIDs must be specified here.\n"
+    "                         The specified GUIDs are assigned\n"
+    "                         the following values, repectively:\n"
+    "                         node, port1, port2 and system image GUID.\n"
+    "\n"
+    "                         Commands affected: burn\n"
+    "\n"
+    "    -h[elp]            - Prints this message and exits\n"
+    "    -hh                - Prints extended command help\n"
+    "\n"
+    "    -i[mage] <image>   - Binary image file.\n"
+    "                         Commands affected: burn, verify\n"
+    "\n"
+    "    -nofs              - Burn image not in failsafe manner.\n"
+    "\n"
+    "    -unlock            - Use unlock bypass feature of the flash for quicker burn.\n"
+    "                         Commands affected: burn\n"
+    "\n"
+    "    -s[ilent]          - Do not print burn progress flyer.\n"
+    "                         Commands affected: burn\n"
+    "\n"
+    "    -y[es]             - Non interactive mode - assume answer\n"
+    "                         \"yes\" to all questions.\n"
+    "                         Commands affected: all\n"
+    "\n"
+    "    -vsd  <string>     - Write this string, of up to 208 characters, to VSD when burn.\n"
+    "\n"
+    "    -psid <PSID>       - Write the Parameter Set ID (PSID) string to PS-ID field (last 16 bytes of VSD) when burn.\n"
+    "\n"
+    "    -use_image_ps      - Burn vsd/psid as appears in the given image - don't keep existing vsd/psid on flash.\n"
+    "                         Commands affected: burn\n"
+    "\n"
+    "    -dual_image        - Make the burn process burn two images on flash (previously default algorithm). Current\n" 
+    "                         default failsafe burn process burns a single image (in alternating locations).\n"
+    "                         Commands affected: burn\n"
+    "\n"
+    "    -v                 - Version info.\n"
+    "\n"
+    "Commands summary (use -hh flag for full commands description):\n"
+    "-----------------\n"
+    "    b[urn]   - Burn flash\n"
+    "    e[rase]  - Erase sector\n"
+    "    q[uery]  - Query misc. flash/FW characteristics\n"
+    "    rw       - Read one dword from flash\n"
+    "    v[erify] - Verify entire flash\n"
+    "    ww       - Write one dword to flash\n"
+    "    wwne     - Write one dword to flash without sector erase\n"
+    "    wbne     - Write a data block to flash without sector erase\n"
+    "    rb       - Read  a data block from flash\n"
+    "\n";
+
+    const char* full_descr =
+    "\n"
+    "Command descriptions:\n"
+    "----------------------------\n"
+    "\n"
+    "* Burn flash\n"
+    "  Burns entire flash from raw binary image.\n"
+    "\n"
+    "    Command:\n"
+    "        b[urn]\n"
+    "    Parameters:\n"
+    "        None\n"
+    "    Examples:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " -i image1.bin burn\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE2 " -guid 0x2c9000100d050 -i image1.bin b\n"
+    "\n"
+    "\n"
+    "* Erase sector.\n"
+    "  Erases a sector that contains specified address.\n"
+    "\n"
+    "    Command:\n"
+    "        e[rase]\n"
+    "    Parameters:\n"
+    "        addr - address of word in sector that you want\n"
+    "                   to erase.\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " erase 0x10000\n"
+    "\n"
+    "\n"
+    "* Query miscellaneous FW and flash parameters\n"
+    "\n"
+    "    Command:\n"
+    "        q[uery]\n"
+    "    Parameters:\n"
+    "        None\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " query\n"
+    "\n"
+    "\n"
+    "* Query flash device parameters (Common Flash Interface)\n"
+    "\n"
+    "    Command:\n"
+    "        cfi\n"
+    "    Parameters:\n"
+    "        None\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " cfi\n"
+    "\n"
+    "\n"
+    "* Read one dword from flash.\n"
+    "\n"
+    "    Command:\n"
+    "        rw\n"
+    "    Parameters:\n"
+    "        addr - address of word to read\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " rw 0x20\n"
+    "\n"
+    "\n"
+    "* Verify entire flash.\n"
+    "\n"
+    "    Command:\n"
+    "        v[erify]\n"
+    "    Parameters:\n"
+    "        None\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " v\n"
+    "\n"
+    "\n"
+    "* Write one dword to flash.\n"
+    "  Note that the utility will read an entire flash sector,\n"
+    "  modify one word and write the sector back. This may take\n"
+    "  a few seconds.\n"
+    "\n"
+    "    Command:\n"
+    "        ww\n"
+    "    Parameters:\n"
+    "        addr - address of word\n"
+    "        data - value of word\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " ww 0x10008 0x5a445a44\n"
+    "\n"
+    "\n"
+    "* Write one dword to flash without sector erase.\n"
+    "  Note that the result of operation is undefined and depends\n"
+    "  on flash type. Usually \"bitwise AND\" (&) between specified\n"
+    "  word and previous flash contents will be written to\n"
+    "  specified address.\n"
+    "\n"
+    "    Command:\n"
+    "        wwne\n"
+    "    Parameters:\n"
+    "        addr - address of word\n"
+    "        data - value of word\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " wwne 0x10008 0x5a445a44\n"
+    "\n"
+    "    Command:\n"
+    "        rb\n"
+    "    Parameters:\n"
+    "        addr - address of block\n"
+    "        size - size of data to read in bytes\n"
+    "        file - filename to write the block (raw binary). If no given the data\n"
+    "               is printed to screen\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " rb 0x10000 100 file.bin\n"
+    "\n"
+    "    Command:\n"
+    "        wbne\n"
+    "    Parameters:\n"
+    "        addr - address of block\n"
+    "        size - size of data to write in bytes\n"
+    "        data - data to write - space seperated dwords\n"
+    "    Example:\n"
+    "        " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " wbne 0x10000 12 0x30000 0x76800 0x5a445a44\n"
+    "\n";
+
     printf(descr, sname);
+
+    if (full) {
+        printf(full_descr);
+    }
+}
+
+
+//
+// Signal handlers 
+//
+
+Flash* g_flash = NULL;
+
+int g_signals_for_termination[] = {
+    SIGINT,
+#ifndef _WIN32
+    SIGHUP,
+#endif
+    SIGTERM
+};
+
+
+
+void TerminationHandler (int signum)
+{
+    static volatile sig_atomic_t fatal_error_in_progress = 0;
+    if (fatal_error_in_progress)
+        raise (signum);
+    fatal_error_in_progress = 1;
+
+    signal (signum, SIG_DFL);
+
+    if (g_flash != NULL) {
+        report("\n Received signal %d. Cleaning up ...", signum);
+        fflush(stdout);
+        sleep(1); // let erase sector end
+        g_flash->wait_ready("Process termination");
+
+        g_flash->close();
+        report(" Done.\n");
+    }
+    raise(signum);
 }
 
+
 ////////////////////////////////////////////////////////////////////////
 #define NEXTS(s) do {                                        \
     if (++i >= ac)                                           \
@@ -3440,136 +4626,138 @@ int main(int ac, char *av[])
     bool         guids_specified  = false; 
     bool         burn_failsafe    = true;
     bool         use_image_ps     = false;
+    bool         single_image_burn = true;
+
     char         *vsd1=0;
     char         *psid=0;
-    guid_t    guids[GUIDS];
+    guid_t       guids[GUIDS];
     char         vsds[VSD_LEN];
-    Flash        f;
+    int                 rc = 0;
+
+    auto_ptr<Flash>       f;
+
+    //
+    // Map termination signal handlers
+    //
+    int i;
+    for (i = 0 ; i < (int)(sizeof(g_signals_for_termination)/sizeof(g_signals_for_termination[0])) ; i++ ) {
+        signal (g_signals_for_termination[i], TerminationHandler);    
+    }
+
 
-    if (ac < 2)
-    {
+    if (ac < 2) {
         usage(av[0]);
-        return 1;
+        rc =  1; goto done; 
     }
 
     // Go thru command line options
-    for (int i=1; i < ac; i++)
-    {
+    for (i=1; i < ac; i++) {
         //
         // Switches
         // --------
         //
-        if (*av[i] == '-')
-        {
-            if (!strncmp(av[i], "-d", 2))
-            {
+        if (*av[i] == '-') {
+            if (!strncmp(av[i], "-dual_image", 10))
+                single_image_burn = false;
+
+            else if (!strncmp(av[i], "-d", 2)) {
                 NEXTS("-device");
                 device = av[i];
-                if (!f.open(device))
-                {
-                    printf("*** ERROR *** %s\n", f._err);
-                    return 1;
+
+                //f.reset( get_flash(device) );
+                auto_ptr<Flash>       tmp( get_flash(device));
+                               f = tmp;
+                               
+                if (f.get() == NULL) {
+                    printf("*** ERROR *** Can't get flash type using device %s\n", device);
+                    rc =  1;            goto done; 
                 }
-            }
-           else if (!strcmp(av[i], "-v") || !strcmp(av[i], "-vv")) {
-               printf("%s: Version %s.",
-                      av[0],
-                      _versionID);
-
-               if (!strcmp(av[i], "-vv")) {
-                   printf(" CVS %s", _cvsID + 1); 
-               }
-
-               printf("\n");
-               return 0;
-
-           }
-           else if (!strcmp(av[i], "-unlock")) {
-               _unlock_bypass = true;
-               f.unlock_bypass(true);
-           }
-            else if (!strcmp(av[i], "-noerase"))
+
+                g_flash = f.get();
+                if (!f->open(device)) {
+                    printf("*** ERROR *** Can't open %s: %s\n", device, f->_err);
+                    rc =  1; goto done; 
+                }
+            } else if (!strcmp(av[i], "-v") || !strcmp(av[i], "-vv")) {
+                printf("%s: Version %s .",
+                       av[0],
+                       _versionID);
+
+                if (!strcmp(av[i], "-vv")) {
+                    printf(" CVS %s", _cvsID + 1); 
+                }
+
+                printf("\n");
+                rc =  0; goto done; 
+
+            } else if (!strcmp(av[i], "-unlock")) {
+                _unlock_bypass = true;
+//             f->unlock_bypass(true);
+            } else if (!strcmp(av[i], "-noerase"))
                 _no_erase = true;
             else if (!strcmp(av[i], "-noburn"))
                 _no_burn = true;
             else if (!strcmp(av[i], "-crc"))
                 _print_crc = true;
             else if (!strcmp(av[i], "-bytewrite")) {
-               if (device) {
-                   printf("\"-bytewrite\" should be specifies before \"-device\" switch in the command line.\n");
-                   return 1;
-               }
+                if (device) {
+                    printf("\"-bytewrite\" should be specifies before \"-device\" switch in the command line.\n");
+                    rc =  1; goto done; 
+                }
                 _byte_write = true;
-           }
-            else if (!strcmp(av[i], "-vsd"))
-            {
+            } else if (!strcmp(av[i], "-vsd")) {
                 NEXTS("-vsd");
                 vsd1 = av[i];
             }
-           // -vsd1 is an alias to -vsd, for backward compatibility. Can be removed in the future.
-            else if (!strcmp(av[i], "-vsd1"))
-            {
+            // -vsd1 is an alias to -vsd, for backward compatibility. Can be removed in the future.
+            else if (!strcmp(av[i], "-vsd1")) {
                 NEXTS("-vsd1");
                 vsd1 = av[i];
-            }
-            else if (!strcmp(av[i], "-psid"))
-            {
+            } else if (!strcmp(av[i], "-psid")) {
                 NEXTS("-psid");
                 psid = av[i];
             }
-           // -vsd2 is an alias to psid, for backward compatibility. Can be removed in the future.
-            else if (!strcmp(av[i], "-vsd2"))
-            {
+            // -vsd2 is an alias to psid, for backward compatibility. Can be removed in the future.
+            else if (!strcmp(av[i], "-vsd2")) {
                 NEXTS("-vsd2");
                 psid = av[i];
-            }
-            else if (!strcmp(av[i], "-bsn"))
-            {
+            } else if (!strcmp(av[i], "-bsn")) {
                 NEXTS("-bsn");
                 GETBSN(av[i], &guids[0]);
                 for (int i=1; i<GUIDS; i++) {
                     u_int64_t g=guids[0].h;
                     g=(g<<32) | guids[0].l;
-                    ++g;
+                    g += i;
                     guids[i].h = (u_int32_t)(g>>32);
                     guids[i].l = (u_int32_t)g;
-               }
+                }
                 guids_specified = true;
-            }
-            else if (!strncmp(av[i], "-i", 2))
-            {
+            } else if (!strncmp(av[i], "-i", 2)) {
                 NEXTS("-image");
                 image_fname = av[i];
-            }
-           else if (!strcmp(av[i], "-guid"))
-            {
+            } else if (!strcmp(av[i], "-guid")) {
                 NEXTS("-guid");
                 GETGUID(av[i], &guids[0]);
                 for (int i=1; i<GUIDS; i++) {
                     u_int64_t g=guids[0].h;
                     g=(g<<32) | guids[0].l;
-                    ++g;
+                    g += i;
                     guids[i].h = (u_int32_t)(g>>32);
                     guids[i].l = (u_int32_t)g;
-               }
+                }
                 guids_specified = true;
-            }
-            else if (!strcmp(av[i], "-guids"))
-            {
+            } else if (!strcmp(av[i], "-guids")) {
                 NEXTS("-guids");
-                for (int j=0; j<GUIDS; j++)
-                {
+                for (int j=0; j<GUIDS; j++) {
                     GETGUID(av[i], &guids[j]);
-                    if (++i >= ac)
-                    {
+                    if (++i >= ac) {
                         printf("Exactly four GUIDs must be specified.\n");
-                        return 1;
+                        rc =  1; goto done; 
                     }
                 }
                 i--;
                 guids_specified = true;
-            }
-            else if (!strncmp(av[i], "-s", 2))
+            } else if (!strncmp(av[i], "-s", 2))
                 silent = true;
             else if (!strncmp(av[i], "-use_image_ps", 2))
                 use_image_ps = true;
@@ -3577,120 +4765,117 @@ int main(int ac, char *av[])
                 burn_failsafe = false;
             else if (!strncmp(av[i], "-y", 2))
                 _assume_yes = true;
-            else if (!strncmp(av[i], "-h", 2) ||  !strncmp(av[i], "--h", 3))
-            {
+
+            else if (!strncmp(av[i], "-hh", 3) ||  !strncmp(av[i], "--hh", 4)) {
+                usage(av[0], true);
+                rc =  1; goto done; 
+            } else if (!strncmp(av[i], "-h", 2) ||  !strncmp(av[i], "--h", 3)) {
                 usage(av[0]);
-                return 1;
-            }
-            else
-            {
+                rc =  1; goto done; 
+            } else {
                 printf("Invalid switch \"%s\" is specified.\n", av[i]);
-                return 1;
+                rc =  1; goto done; 
             }
-        }
-        else
-        {
+        } else {
             //
             // Commands
             // --------
             //
-            if (*av[i] == 'b')
-            {
+            if (*av[i] == 'b') {
                 //
                 // BURN
                 //
 
                 // Device
-                if (!device)
-                {
+                if (!device) {
                     printf("For burn command \"-device\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Image - check, open and verify
-                if (!image_fname)
-                {
+                if (!image_fname) {
                     printf("For burn command \"-image\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
                 FImage         fim;
-                if (!fim.open(image_fname))
-                {
+                if (!fim.open(image_fname)) {
                     printf("*** ERROR *** %s\n", fim._err);
-                    return 1;
+                    rc =  1; goto done; 
                 }
                 bool old_silent = _silent;
                 _silent = true;
-                if (!Verify(fim))
-                {
+                if (!Verify(fim)) {
                     printf("Not a valid image\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
-               // Check that the flash sector size is well defined in the image
-               if (fim.get_sector_size() && (fim.get_sector_size() != f.get_sector_size())) {
+                // Check that the flash sector size is well defined in the image
+                if (fim.get_sector_size() && (fim.get_sector_size() != f->get_sector_size())) {
                     printf("Flash sector size(0x%x) differs from sector size defined in image (0x%x)\n",
-                          f.get_sector_size(),
-                          fim.get_sector_size());
-                    return 1;
-               }
+                           f->get_sector_size(),
+                           fim.get_sector_size());
+                    rc =  1; goto done; 
+                }
 
                 // Get GUID and VSD info from flash
                 memset(vsds, 0, VSD_LEN);
 
-                if (!guids_specified  ||
-                    ((!vsd1  ||  !psid)  && !use_image_ps))
-                {
-                    if (!RevisionInfo(f, guids, &vsds[0], &fs_image))
-                        return 1;
-                }
+                bool read_guids = true;
+                bool read_ps    = true;
 
-                // Patch GUIDS
                 if (guids_specified)
-                {
-                    if (!pathGUIDs(fim, guids, isatty(0) != 0))
-                        return 1;
+                    read_guids = false;
+
+                if ((vsd1 && psid) || use_image_ps)
+                    read_ps = false;
+
+                if (read_guids || read_ps) {
+                    if (!RevisionInfo(*f, guids, vsds, &fs_image, false, read_guids, read_ps ))
+                        rc =  1; goto done; 
                 }
-                else
-                {
-                    if (!pathGUIDs(fim, guids, false))
-                        return 1;
+
+
+                // Patch GUIDS
+                if (guids_specified) {
+                    if (!patchGUIDs(fim, guids, isatty(0) != 0))
+                        rc =  1; goto done; 
+                } else {
+                    if (!patchGUIDs(fim, guids, false))
+                        rc =  1; goto done; 
                 }
 
                 // Patch VSD
                 if (vsd1)
                     strncpy(&vsds[0], vsd1, VSD_OFFS);
-                if (psid)
-                    strncpy(&vsds[VSD_OFFS], psid, VSD_LAST);
+                //if (psid)
+                //    strncpy(&vsds[VSD_OFFS], psid, VSD_LAST);
                 if (_image_is_full && !use_image_ps)
-                    if (!patchVSD(fim, &vsds[0], &vsds[VSD_OFFS]))
-                        return 1;
+                    if (!patchVSD(fim, &vsds[0], &vsds[VSD_OFFS], psid))
+                        rc =  1; goto done; 
 
-                // Burn it
+                    // Burn it
                 _silent = old_silent;
-                if (burn_failsafe)
-                {
+                if (burn_failsafe) {
                     // Failsafe burn
-                    if (!_image_is_full)
-                    {
+                    if (!_image_is_full) {
                         printf("\nIt is impossible to burn a short image in a failsafe mode.\n");
                         printf("If you want to burn in non failsafe mode, use the \"-nofs\" switch.\n");
                         printf("Otherwise, to burn in the failsafe mode, you need to specify the full image\n");
-                        return 1;
+                        rc =  1; goto done; 
                     }
 
                     // FS burn
-                    if (!f.FailSafe_burn(fim.getBuf(), fim.getBufLength(),
-                                              !silent))
-                    {
-                        printf("*** ERROR *** %s\n", f._err);
+                    if (!FailSafe_burn(*f, 
+                                       fim.getBuf(), 
+                                       fim.getBufLength(),
+                                       single_image_burn,
+                                       !silent)) {
+                        printf("*** ERROR *** %s\n", f->_err);
                         printf("It is impossible to burn this image in a failsafe mode.\n");
                         printf("If you want to burn in non failsafe mode, use the \"-nofs\" switch.\n");
-                        return 1;
+                        rc =  1; goto done; 
                     }
-                }
-                else
-                {
+                } else {
                     //
                     // Not failsafe (sequential) burn
                     //
@@ -3699,32 +4884,20 @@ int main(int ac, char *av[])
                     printf("\nBurn process will not be failsafe. No checks are performed\n");
                     printf("and ALL flash, including Invariant Sector will be overwritten.\n");
                     printf("If this process fails computer may remain in unoperatable state.\n");
-                    printf("\nAre you sure ? (y/n) [n] : ");
-                    if (_assume_yes)
-                        printf("y\n");
-                    else
-                    {
-                        fflush(stdout);
-                        char c = getchar();
-                        if (c != '\n')
-                            while (getchar() != '\n');
-                        if (c != 'y')
-                            return 1;
-                    }
+
+                    if (!ask_user("\nAre you sure ? (y/n) [n] : "))
+                        rc =  1; goto done; 
 
                     // Non FS burn
-                    if (!f.write_image(0, fim.getBuf(), fim.getBufLength(),
-                                       !silent))
-                    {
+                    if (!write_image(*f, 0, fim.getBuf(), fim.getBufLength(),
+                                     !silent)) {
                         report("\n");
-                        printf("*** ERROR *** %s\n", f._err);
-                        return 1;
+                        printf("*** ERROR *** %s\n", f->_err);
+                        rc =  1; goto done; 
                     }
                     report("\n");
                 }
-            }
-            else if (*av[i] == 'e')
-            {
+            } else if (*av[i] == 'e') {
                 //
                 // ERASE SECTOR <ADDR>
                 //     Parameters: <ADDR>
@@ -3733,196 +4906,156 @@ int main(int ac, char *av[])
                 char         *endp;
 
                 // Device
-                if (!device)
-                {
+                if (!device) {
                     printf("For erase command \"-device\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Address of sector to erase
                 NEXTC("<ADDR>", "erase");
                 addr = strtoul(av[i], &endp, 0);
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid address \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Erase
-                if (!f.erase_sector(addr))
-                {
-                    printf("*** ERROR *** %s\n", f._err);
-                    return 1;
+                if (!f->erase_sector(addr)) {
+                    printf("*** ERROR *** %s\n", f->_err);
+                    rc =  1; goto done; 
                 }
-            }
-            else if (*av[i] == 'q')
-            {
+            } else if (*av[i] == 'q') {
                 // QUERY
                 if (device)
-                    RevisionInfo(f, guids, 0, &fs_image);
-                else if (image_fname)
-                {
+                    RevisionInfo(*f, guids, 0, &fs_image);
+                else if (image_fname) {
                     FImage         fim;
-                    if (!fim.open(image_fname))
-                    {
+                    if (!fim.open(image_fname)) {
                         printf("*** ERROR *** %s\n", fim._err);
-                        return 1;
+                        rc =  1; goto done; 
                     }
                     RevisionInfo(fim, guids, 0, &fs_image);
-                }
-                else
-                {
+                } else {
                     printf("For query command \"-device\" or \"-image\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
-            }
-            else if (!strcmp(av[i], "rb"))
-            {
+            } else if (!strcmp(av[i], "rb")) {
                 // READ BLOCK
                 //     Parameters:  <ADDR> <LENGTH> [OUT_FILENAME]
-               //     if OUT_FILENAME is given, binari read block is stored
-               //     in the given file. Otherwise, data is printed to screen.
+                //     if OUT_FILENAME is given, binari read block is stored
+                //     in the given file. Otherwise, data is printed to screen.
                 u_int32_t    addr, length;
                 u_int8_t     *data;
                 char         *endp;
 
-               bool         to_file = false;
+                bool         to_file = false;
 
                 // Device
-                if (!device)
-                {
+                if (!device) {
                     printf("For rb command \"-device\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Address and length
                 NEXTC("<ADDR>", "rb");
                 addr = strtoul(av[i], &endp, 0);
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid address \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
                 NEXTC("<LENGTH>", "rb");
                 length = strtoul(av[i], &endp, 0);
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid length \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
                 data = new u_int8_t[length];
 
                 // Output file
                 int fd = -1;
-               
-               if (i + 2 == ac)  
-                   to_file = true;
-
-               if (to_file) {
-                   NEXTC("<OUT_FILENAME>", "rb");
-                   if ((fd = open(av[i], O_WRONLY | O_CREAT | O_BINARY, 0666)) < 0)
-                   {
+
+                if (i + 2 == ac)
+                    to_file = true;
+
+                if (to_file) {
+                    NEXTC("<OUT_FILENAME>", "rb");
+                    if ((fd = open(av[i], O_WRONLY | O_CREAT | O_BINARY, 0666)) < 0) {
                         fprintf(stderr, "Can't open ");
-                       perror(av[i]);
-                       return 1;
-                   }
-#ifndef __WIN__
-                   if (ftruncate(fd, 0) < 0)
-                   {
-                       fprintf(stderr, "Can't truncate ");
-                       perror(av[i]);
-                       return 1;
-                   }
-#endif
-               }
+                        perror(av[i]);
+                        rc =  1; goto done; 
+                    }
+                    if (ftruncate(fd, 0) < 0) {
+                        fprintf(stderr, "Can't truncate ");
+                        perror(av[i]);
+                        rc =  1; goto done; 
+                    }
+                }
 
                 // Read flash
-                if (!f.read(addr, data, length))
-                {
-                    printf("*** ERROR *** %s\n", f._err);
-                    return 1;
+                if (!f->read(addr, data, length)) {
+                    printf("*** ERROR *** %s\n", f->_err);
+                    rc =  1; goto done; 
                 }
 
                 if (to_file) {
-                   // Write output
-                   if (write(fd, data, length) != (int)length)
-                   {
-                       perror("Write error");
-                       return 1;
-                   }
-                   close(fd);
-               } 
-               else  
-               {
-                   const u_int32_t IN_LINE = 4;
-                   for (u_int32_t i = 0; i < length ; i++) {
-                       if ((i % IN_LINE) == 0) {
-                           printf("0x%06x:", addr + i);
-                       }
-                   
-                       printf(" %02x", data[i]);
-                   
-                       if (i > 0 && ((i + 1) % IN_LINE) == 0 ) {
-                           printf("\n");
-                       }
-                   }
-               }
+                    // Write output
+                    if (write(fd, data, length) != (int)length) {
+                        perror("Write error");
+                        rc =  1; goto done; 
+                    }
+                    close(fd);
+                } else {
+                    for (u_int32_t i = 0; i < length ; i+=4) {
+                        u_int32_t word = *((u_int32_t*)(data + i));
+
+                        word  = __be32_to_cpu(word);
+                        printf("0x%08x ", word);  
+                    }
+                    printf("\n");
+                }
                 delete [] data;
-            }
-            else if (!strcmp(av[i], "rw"))
-            {
+            } else if (!strcmp(av[i], "rw")) {
                 // READ DWORD <ADDR>
                 //     Parameters: <ADDR>
                 u_int32_t    data, addr;
                 char         *endp;
 
                 // Device
-                if (!device)
-                {
+                if (!device) {
                     printf("For rw command \"-device\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Address
                 NEXTC("<ADDR>", "rw");
                 addr = strtoul(av[i], &endp, 0);
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid address \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Read
-                if (!f.read(addr, &data))
-                {
-                    printf("*** ERROR *** %s\n", f._err);
-                    return 1;
+                if (!f->read(addr, &data)) {
+                    printf("*** ERROR *** %s\n", f->_err);
+                    rc =  1; goto done; 
                 }
                 printf("0x%08x\n", (unsigned int)__cpu_to_be32(data));
-            }
-            else if (*av[i] == 'v')
-            {
+            } else if (*av[i] == 'v') {
                 // VERIFY
                 if (device)
-                    Verify(f);
-                else if (image_fname)
-                {
+                    Verify(*f);
+                else if (image_fname) {
                     FImage         fim;
-                    if (!fim.open(image_fname))
-                    {
+                    if (!fim.open(image_fname)) {
                         printf("*** ERROR *** %s\n", fim._err);
-                        return 1;
+                        rc =  1; goto done; 
                     }
                     Verify(fim);
-                }
-                else
-                {
+                } else {
                     printf("For verify command \"-device\" or \"-image\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
-            }
-            else if (!strcmp(av[i], "wb"))
-            {
+            } else if (!strcmp(av[i], "wb")) {
                 // WRITE BLOCK
                 //     Parameters:  <IN_FILENAME> <ADDR>
                 u_int32_t    addr, length;
@@ -3930,27 +5063,24 @@ int main(int ac, char *av[])
                 char         *endp;
 
                 // Device
-                if (!device)
-                {
+                if (!device) {
                     printf("For wb command \"-device\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Input file
                 int         fd;
                 struct stat statbuf;
                 NEXTC("<IN_FILENAME>", "wb");
-                if ((fd = open(av[i], O_RDONLY | O_BINARY)) < 0)
-                {
+                if ((fd = ::open(av[i], O_RDONLY | O_BINARY), 0) < 0) {
                     fprintf(stderr, "Can't open ");
                     perror(av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
-                if (fstat(fd, &statbuf) < 0)
-                {
+                if (fstat(fd, &statbuf) < 0) {
                     fprintf(stderr, "Can't stat ");
                     perror(av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
                 length = statbuf.st_size;
                 data = new u_int8_t[length];
@@ -3958,128 +5088,155 @@ int main(int ac, char *av[])
                 // Address
                 NEXTC("<ADDR>", "wb");
                 addr = strtoul(av[i], &endp, 0);
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid address \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Read file
-                if (read(fd, data, length) != (int)length)
-                {
+                if (read(fd, data, length) != (int)length) {
                     perror("Read error");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Write flash
-                if (!f.write_image(addr, data, length, !silent))
-                {
-                    printf("*** ERROR *** %s\n", f._err);
-                    return 1;
+                if (!write_image(*f, addr, data, length, !silent)) {
+                    printf("*** ERROR *** %s\n", f->_err);
+                    rc =  1; goto done; 
                 }
 
                 close(fd);
                 delete [] data;
-            }
-            else if (!strcmp(av[i], "ww"))
-            {
+            } else if (!strcmp(av[i], "ww")) {
                 // WRITE DWORD
                 //     Parameters: <ADDR> <DATA>
                 u_int32_t    data, addr;
                 char         *endp;
 
                 // Device
-                if (!device)
-                {
+                if (!device) {
                     printf("For ww command \"-device\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Address and data
                 NEXTC("<ADDR>", "ww");
                 addr = strtoul(av[i], &endp, 0);
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid address \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
                 NEXTC("<DATA>", "ww");
                 data = __cpu_to_be32(strtoul(av[i], &endp, 0));
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid data \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
-                f.curr_sector = 0xffffffff;  // First time erase sector
-                if (!f.write(addr, data))
-                {
-                    printf("*** ERROR *** %s\n", f._err);
-                    return 1;
+                //f->curr_sector = 0xffffffff;  // First time erase sector
+                if (!f->write(addr, data)) {
+                    printf("*** ERROR *** %s\n", f->_err);
+                    rc =  1; goto done; 
                 }
-            }
-            else if (!strcmp(av[i], "wwne"))
-            {
+            } else if (!strcmp(av[i], "wbne")) {
+                // WRITE DWORD WITHOUT ERASE
+                //     Parameters: <ADDR> <SIZE> <DATA>
+                u_int32_t    size, addr;
+                char         *endp;
+
+                // Device
+                if (!device) {
+                    printf("For wbne command \"-device\" switch must be specified.\n");
+                    rc =  1; goto done; 
+                }
+
+                // Address and data
+                NEXTC("<ADDR>", "wbne");
+                addr = strtoul(av[i], &endp, 0);
+                if (*endp) {
+                    printf("Invalid address \"%s\"\n", av[i]);
+                    rc =  1; goto done; 
+                }
+                NEXTC("<SIZE>", "wbne");
+                size = strtoul(av[i], &endp, 0);
+                if (*endp || size % 4) {
+                    printf("Invalid size \"%s\"\n", av[i]);
+                    rc =  1; goto done; 
+                }
+                vector<u_int32_t> data_vec(size/4);
+                for (u_int32_t w = 0; w < size/4 ; w++) {
+                    NEXTC("<DATA>", "wwne");
+                    data_vec[w] = __cpu_to_be32(strtoul(av[i], &endp, 0));
+                    if (*endp) {
+                        printf("Invalid data \"%s\"\n", av[i]);
+                        rc =  1; goto done; 
+                    }
+
+                    //printf("-D- writing: %08x : %08x\n", addr + w*4 , data_vec[w]);
+                }
+
+                if (!f->write(addr, &data_vec[0], size, true, false)) {
+                    printf("*** ERROR *** %s\n", f->_err);
+                    rc =  1; goto done; 
+                }
+            } else if (!strcmp(av[i], "wwne")) {
                 // WRITE DWORD WITHOUT ERASE
                 //     Parameters: <ADDR> <DATA>
                 u_int32_t    data, addr;
                 char         *endp;
 
                 // Device
-                if (!device)
-                {
+                if (!device) {
                     printf("For wwne command \"-device\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
                 // Address and data
                 NEXTC("<ADDR>", "wwne");
                 addr = strtoul(av[i], &endp, 0);
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid address \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
                 NEXTC("<DATA>", "wwne");
                 data = __cpu_to_be32(strtoul(av[i], &endp, 0));
-                if (*endp)
-                {
+                if (*endp) {
                     printf("Invalid data \"%s\"\n", av[i]);
-                    return 1;
+                    rc =  1; goto done; 
                 }
 
-                if (!f.write(addr, &data, 4, true, true))
-                {
-                    printf("*** ERROR *** %s\n", f._err);
-                    return 1;
+                if (!f->write(addr, &data, 4, true, false)) {
+                    printf("*** ERROR *** %s\n", f->_err);
+                    rc =  1; goto done; 
                 }
-            }
-            else if (!strcmp(av[i], "cfi"))
-            {
+            } else if (!strcmp(av[i], "cfi")) {
                 // CFI (COMMON FLASH INTERFACE) QUERY
 
 
                 // Device
-                if (!device)
-                {
+                if (!device) {
                     printf("For cfi command \"-device\" switch must be specified.\n");
-                    return 1;
+                    rc =  1; goto done; 
                 }
-  
-                if (!f.query_cfi())
-                {
-                    printf("*** ERROR *** %s\n", f._err);
-                    return 1;
+
+                if (!f->print_cfi_info()) {
+                    printf("*** ERROR *** %s\n", f->_err);
+                    rc =  1; goto done; 
                 }
-            }
-           else
-            {
+            } else {
                 printf("Invalid command \"%s\".\n", av[i]);
-                return 1;
+                rc =  1; goto done; 
             }
 
         }
     }
 
-    return 0;
+done:
+    //mask signals   
+    for (i = 0 ; i < (int)(sizeof(g_signals_for_termination)/sizeof(g_signals_for_termination[0])) ; i++ ) {
+        signal (g_signals_for_termination[i], SIG_IGN);    
+    }
+
+    return rc;
 }