The wait in mci_WaitForEvent will delay all card transactions.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers QSPIFileSystem.cpp Source File

QSPIFileSystem.cpp

00001 #include "QSPIFileSystem.h"
00002 #include "mbed_debug.h"
00003 
00004 #include "SPIFI.h"
00005 
00006 /******************************************************************************
00007  * Defines and typedefs
00008  *****************************************************************************/
00009 
00010 #define QSPI_DBG             0
00011 
00012 #define IS_ADDR_IN_SPIFI(__addr)  ( (((uint32_t)(__addr)) & 0xff000000) == SPIFI_MEM_BASE )
00013 
00014 #define MEM_SIZE    (memInfo.memSize)
00015 #define ERASE_SIZE  (memInfo.eraseBlockSize)
00016 #define NUM_BLOCKS  (memInfo.numEraseBlocks)
00017 
00018 typedef uint32_t toc_entry_t;
00019 
00020 #define TOC_BLOCK_ADDR   (memInfo.tocBlockAddr)   //(SPIFI_MEM_BASE + (NUM_BLOCKS - 1)*ERASE_SIZE)
00021 #define TOC_SIZE         (memInfo.tocSizeInBytes) //(sizeof(toc_entry_t) * NUM_BLOCKS)
00022 #define NUM_TOCS         (memInfo.numTocs)        //((int)(ERASE_SIZE/TOC_SIZE))
00023 #define NUM_TOC_BLOCKS   ((NUM_TOCS * TOC_SIZE) / ERASE_SIZE)
00024 #define NUM_TOC_ENTRIES  ((int)(TOC_SIZE/sizeof(toc_entry_t)))
00025 
00026 #define TOC_UNUSED          (0xffffffff)
00027 #define TOC_MAX             (NUM_BLOCKS - 1)
00028 #define TOC_VALID_MASK      (1UL<<31)
00029 #define TOC_RESERVED_MASK   (1UL<<30)
00030 #define TOC_USED_MASK       (1UL<<29)
00031 #define TOC_FILE_MASK       (1UL<<28)
00032 #define TOC_FSIZE_MASK      (0x3ffff)
00033 #define TOC_MANDAT_SET_MASK (0x0ffc0000)
00034 
00035 #define MANDATORY_BITS_SET(__v)  (((__v)&TOC_MANDAT_SET_MASK) == TOC_MANDAT_SET_MASK)
00036 
00037 #define VALID_TOC_ENTRY(__v)  (((__v)&TOC_VALID_MASK) == 0)
00038 #define USED_TOC_ENTRY(__v)   (VALID_TOC_ENTRY(__v) && (((__v)&TOC_USED_MASK) == 0))
00039 #define TOC_IS_FILE(__v)      (USED_TOC_ENTRY(__v) && (((__v)&TOC_FILE_MASK) == 0))
00040 #define TOC_IS_RESERVED(__v)  (VALID_TOC_ENTRY(__v) && (((__v)&TOC_RESERVED_MASK) == 0))
00041 #define FILESIZE(__v)         ((__v) & 0x3ffff)
00042 
00043 #define FS_MIN(__a, __b)  (((__a) < (__b)) ? (__a) : (__b))
00044 
00045 // Mask to compare the different access modes. In LPCXpresso this was defined
00046 // but not in uVision
00047 #ifndef O_ACCMODE
00048 #define O_ACCMODE  (O_RDONLY | O_WRONLY | O_RDWR)
00049 #endif
00050 
00051 
00052 /*
00053  * The file header currently only consists of the filename (including path)
00054  * and the string terminating character, but by separating the file name
00055  * length from the size of the header in the code it allows future additions
00056  * to the header without too much code modification.
00057  */
00058 #define HEADER_DNAME_MAXLEN  (250)
00059 #define HEADER_FNAME_STRLEN  (HEADER_DNAME_MAXLEN + 5)
00060 #define HEADER_FNAME_LEN     (HEADER_FNAME_STRLEN + 1)
00061 #define HEADER_LEN           (HEADER_FNAME_LEN) // only filename in header for now
00062 
00063 typedef enum
00064 {
00065   FS_OK,
00066   FS_ERR_NOT_FORMATTED,
00067   FS_ERR_NO_FILE,
00068   FS_ERR_FILE_EXIST,
00069   FS_ERR_INVALID_PARAM,
00070   FS_ERR_DISK_FULL,
00071   FS_ERR_SPIFI,
00072   FS_ERR_MALLOC, 
00073 
00074   // FS_ERR_SPIFI_* return codes are listed in the User's Manual
00075   // as possible return values from spifi_init(), spifi_program()
00076   // and spifi_erase() calls.
00077   FS_ERR_SPIFI_INTERNAL_ERROR  = 0x20002,  // 0x20002, Internal error in API code
00078   FS_ERR_SPIFI_TIMEOUT         = 0x20003,  // 0x20003, Time-out waiting for program or erase to begin: protection could not be removed.
00079   FS_ERR_SPIFI_OPERAND         = 0x20004,  // 0x20004, Operand error (i.e. invalid params)
00080   FS_ERR_SPIFI_STATUS          = 0x20005,  // 0x20005, Device status error
00081   FS_ERR_SPIFI_EXT_DEVICE_ID   = 0x20006,  // 0x20006, Unknown extended device ID value
00082   FS_ERR_SPIFI_DEVICE_ID       = 0x20007,  // 0x20007, Unknown device ID code
00083   FS_ERR_SPIFI_DEVICE_TYPE     = 0x20008,  // 0x20008, Unknown device type code
00084   FS_ERR_SPIFI_MANUFACTURER    = 0x20009,  // 0x20009, Unknown manufacturer code
00085   FS_ERR_SPIFI_INVALID_JDEC_ID = 0x2000A,  // 0x2000A, No operative serial flash (JEDEC ID all zeroes or all ones)
00086   FS_ERR_SPIFI_ERASE_CONFLICT  = 0x2000B,  // 0x2000B, S_CALLER_ERASE is included in options, and erasure is required.
00087   FS_ERR_SPIFI_VERIFICATION,               // other,   Other non-zero values can occur if options selects verification.
00088                                            //          They will be the address in the SPIFI memory area at which the first discrepancy was found.
00089 } fresult;
00090 
00091 // The number of times to re-attempt a spifi_program() or spifi_erase()
00092 // if the last one reported a verification error.
00093 #define NUM_VERIFICATION_ATTEMPTS  (1)
00094 
00095 typedef struct
00096 {
00097   uint32_t memSize;
00098   uint32_t eraseBlockSize;
00099   uint32_t numEraseBlocks;
00100   uint32_t tocBlockAddr;
00101   uint32_t numTocs;
00102   uint32_t tocSizeInBytes;
00103   char memName[30];
00104 } meminfo_t;
00105 
00106 typedef struct
00107 {
00108   int      tocIdx;
00109   uint32_t size;
00110   uint16_t lastBlock;
00111 } fileHandle_t;
00112 
00113 /******************************************************************************
00114  * Local variables
00115  *****************************************************************************/
00116 
00117 static toc_entry_t* TOC = NULL;
00118 static int activeTOC = -1;
00119 
00120 static const SPIFI_RTNS *spifi = NULL;
00121 static SPIFIobj* obj;
00122 static SPIFIopers opers;
00123 
00124 static char addr_conflict_buff[PROG_SIZE];
00125 
00126 static meminfo_t memInfo = {0,0,0,0,0,0,{0}};
00127 
00128 /******************************************************************************
00129  * Forward Declarations of Local Functions
00130  *****************************************************************************/
00131 static fresult qspifs_init();
00132 static fresult qspifs_translateSpifiError(int rc);
00133 static fresult qspifs_readTOC(void);
00134 static fresult qspifs_saveTOC(void);
00135 static fresult qspifs_findFile(const char* filename, fileHandle_t* fh);
00136 static fresult qspifs_fileSize(int tocIdx, uint32_t* pSize);
00137 static fresult qspifs_eraseBlock(int block);
00138 static fresult qspifs_allocateFile(const char* filename, int neededBlocks, int* pTocIdx);
00139 static void qspifs_deleteFile(fileHandle_t* fh);
00140 static fresult qspifs_allocateSpace(fileHandle_t* fh, uint32_t size);
00141 static fresult qspifs_format(unsigned int minReservedBytes);
00142 static fresult qspifs_write(fileHandle_t* fh, const uint8_t * const pData, uint32_t size);
00143 static bool qspifs_startsWith(const char* prefix, const char* str);
00144 
00145 /******************************************************************************
00146  * Local Functions
00147  *****************************************************************************/
00148 
00149 /******************************************************************************
00150  *
00151  * Description:
00152  *    Initializes spifi, identifies the chip and reads the file system's
00153  *    table of content.
00154  *
00155  * Params:
00156  *    None
00157  *
00158  * Returns:
00159  *    FS_OK or one of the FS_ERR_* error codes
00160  *
00161  *****************************************************************************/
00162 static fresult qspifs_init()
00163 {
00164   if (spifi == NULL) {
00165     SPIFI::SpifiError err;
00166     err = SPIFI::instance().init();
00167     if (err != SPIFI::Ok) {
00168       spifi = NULL;
00169       return FS_ERR_SPIFI;
00170     }
00171     
00172     SPIFI::instance().internalData(&obj, &spifi);
00173 
00174     /* Make sure it is a tested flash module */
00175     switch (SPIFI::instance().device()) {
00176       case SPIFI::Spansion_S25FL032:
00177         /* For the Spansion memory the TOC occupies 256bytes and the TOC block will
00178            hold 256 TOCs. */
00179         strcpy(memInfo.memName, "Spansion S25FL032");
00180         memInfo.memSize        = obj->memSize;
00181         memInfo.eraseBlockSize = 64*1024;
00182         memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
00183         memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
00184         memInfo.numTocs        = memInfo.eraseBlockSize / memInfo.tocSizeInBytes;
00185         memInfo.tocBlockAddr   = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
00186         break;
00187       
00188       case SPIFI::Winbond_W25Q64FV:
00189         /* For the Winbond memory the TOC occupies 8192 bytes and that is bigger than 
00190            one erase block (which is 4096 bytes). It is possible to either keep only
00191            one TOC or to create a couple to reduce wear on the memory. In this case 
00192            the multiple TOCs option is used. */
00193         strcpy(memInfo.memName, "Winbond W25Q64FV");
00194         memInfo.memSize        = obj->memSize;
00195         memInfo.eraseBlockSize = 4*1024;
00196         memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
00197         memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
00198         memInfo.numTocs        = 8;
00199         memInfo.tocBlockAddr   = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);      
00200         break;
00201       
00202       case SPIFI::UnknownDevice:
00203       default:
00204         debug("INIT: Memory is unknown and may not work as expected\n");
00205         
00206         // Asuming it has 64Kb erase blocks (i.e. same setup as the Spansion S25FL032
00207         strcpy(memInfo.memName, "Unknown - check ID");
00208         memInfo.memSize        = obj->memSize;
00209         memInfo.eraseBlockSize = 64*1024;
00210         memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;      
00211         memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
00212         memInfo.numTocs        = memInfo.eraseBlockSize / memInfo.tocSizeInBytes;
00213         memInfo.tocBlockAddr   = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);      
00214 
00215         /*
00216          * If this happens, check the manufacturer and device information
00217          * and compare with the data sheet for your chip. Also make sure
00218          * that the sector sizes are the same (i.e. 64KB) for your chip.
00219          * If everything is the same then add an exception for your chip.
00220          */
00221         break;
00222     }
00223       
00224     debug_if(QSPI_DBG, "INIT: Found %dMB %s\n", memInfo.memSize/0x100000, memInfo.memName);
00225     
00226     if (TOC != NULL) {
00227       delete TOC;
00228     }
00229     TOC = (toc_entry_t*)malloc(TOC_SIZE);
00230     if (TOC == NULL) {
00231       debug_if(QSPI_DBG, "INIT: Failed to allocate memory for TOC\n");
00232       spifi = NULL;
00233       return FS_ERR_MALLOC;
00234     }
00235   }
00236   if (activeTOC == -1)
00237   {
00238     return qspifs_readTOC();
00239   }
00240   return FS_OK;
00241 }
00242 
00243 /******************************************************************************
00244  *
00245  * Description:
00246  *    Converts the return value from one of the spifi_init(), spifi_program()
00247  *    or spifi_erase() calls into a FS_* error code to simplify it for the
00248  *    fs_qspi API user.
00249  *    This function also attempts to detect the verification failure error.
00250  *    When a verification error occurs the spifi_* functions returns the
00251  *    conflicting address and not an error code. As this can be any address
00252  *    it is difficult to test but this function converts it into the
00253  *    FS_ERR_SPIFI_VERIFICATION error code which can be tested against.
00254  *
00255  * Params:
00256  *    [in] rc - The return code from any of the spifi_* functions
00257  *
00258  * Returns:
00259  *    FS_OK or one of the FS_ERR_* error codes
00260  *
00261  *****************************************************************************/
00262 static fresult qspifs_translateSpifiError(int rc)
00263 {
00264   fresult res;
00265   if (rc == 0)
00266   {
00267     res = FS_OK;
00268   }
00269   else if ((rc >= FS_ERR_SPIFI_INTERNAL_ERROR) && (rc <= FS_ERR_SPIFI_ERASE_CONFLICT))
00270   {
00271     // This is a known error code
00272     res = (fresult)rc;
00273   }
00274   else if (opers.options & (S_VERIFY_PROG | S_VERIFY_ERASE))
00275   {
00276     // As verification was selected and rc is not in the list of known
00277     // codes this falls into this category in the User's Manual:
00278     //
00279     // "Other non-zero values can occur if options selects verification.
00280     //  They will be the address in the SPIFI memory area at which the
00281     //  first discrepancy was found."
00282     res = FS_ERR_SPIFI_VERIFICATION;
00283   }
00284   else
00285   {
00286     // Should never happen :-) as all listed error codes are covered but
00287     // to be on the safe side and not interpret this as a success, a generic
00288     // error is set.
00289     res = FS_ERR_SPIFI;
00290   }
00291   return res;
00292 }
00293 
00294 /******************************************************************************
00295  *
00296  * Description:
00297  *    Reads the table of contents (TOC). The TOC is stored in the last erase
00298  *    block on the QSPI flash. As the QSPI flash is not exactly RW (might
00299  *    require erasing before writing) the TOC is relocated inside the erase
00300  *    block everytime it is saved (see saveTOC()). The currently valid TOC 
00301  *    is allways the last one stored.
00302  *
00303  * Params:
00304  *    None
00305  *
00306  * Returns:
00307  *    FS_OK or one of the FS_ERR_* error codes
00308  *
00309  *****************************************************************************/
00310 static fresult qspifs_readTOC(void)
00311 {
00312   int i, j;
00313   toc_entry_t* p;
00314   uint8_t invalid = 0;
00315   int lastValid = -1;
00316 
00317   // Search for the first unused TOC, keeping track of the valid
00318   // ones as we go.
00319   for (i = 0; (i < NUM_TOCS) && !invalid; i++)
00320   {
00321     p = (toc_entry_t*)(TOC_BLOCK_ADDR + i*TOC_SIZE);
00322     for (j = 0; j < NUM_BLOCKS; j++)
00323     {
00324       if (!VALID_TOC_ENTRY(*p) || !MANDATORY_BITS_SET(*p))
00325       {
00326         // invalid TOC entry, stop looking
00327         invalid = 1;
00328         break;
00329       }
00330       p++;
00331     }
00332 
00333     if (!invalid)
00334     {
00335       // this TOC was ok, but perhaps there is a newer one?
00336       lastValid = i;
00337     }
00338   }
00339 
00340   if (lastValid == -1)
00341   {
00342     // no valid TOCs on the flash
00343     return FS_ERR_NOT_FORMATTED;
00344   }
00345   else
00346   {
00347     // previous entry was ok so use that
00348     activeTOC = lastValid;
00349     p = (toc_entry_t*)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE);
00350     memcpy(TOC, p, TOC_SIZE);
00351     return FS_OK;
00352   }
00353 }
00354 
00355 /******************************************************************************
00356  *
00357  * Description:
00358  *    Saves the table of contents (TOC). The TOC is stored in the last erase
00359  *    block on the QSPI flash. As the QSPI flash is not exactly RW (might
00360  *    require erasing before writing) the TOC is first compared with what is
00361  *    stored in the QSPI flash and if there are no changes or all changes
00362  *    only require bit changes 1->0 then the current TOC can be overwritten.
00363  *    If bit value changes 0->1 are required then the current stored TOC
00364  *    cannot be overwritten and the new TOC is instead stored in the next
00365  *    available space. If the entire last block is filled then it is erased
00366  *    and the new TOC is placed at the start of it.
00367  *
00368  * Params:
00369  *    None
00370  *
00371  * Returns:
00372  *    FS_OK or one of the FS_ERR_* error codes
00373  *
00374  *****************************************************************************/
00375 static fresult qspifs_saveTOC(void)
00376 {
00377   int i, rc = 0;
00378   uint32_t* pSrc;
00379   uint32_t* pDest;
00380   uint32_t tmp;
00381   uint8_t identical = 1;
00382 
00383   // active TOC same as the one we want to save?
00384   pSrc = (uint32_t*)TOC;
00385   pDest = (uint32_t*)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE);
00386   for (i = 0; i < NUM_TOC_ENTRIES; i++)
00387   {
00388     if (*pSrc != *pDest)
00389     {
00390       identical = 0;
00391       tmp = ((*pDest) ^ (*pSrc)) & (*pSrc);
00392       if (tmp > 0)
00393       {
00394         // found a change that contains 0->1 bit modification which
00395         // requires erasing or a new location
00396         activeTOC = (activeTOC + 1)%NUM_TOCS;
00397         if (activeTOC == 0)
00398         {
00399           // no more free TOCs so an erase is needed          
00400 #if 0          
00401           opers.options &= ~S_CALLER_ERASE;
00402           opers.options |= S_FORCE_ERASE;
00403 #else
00404           opers.dest = (char *) TOC_BLOCK_ADDR;
00405           opers.length = TOC_SIZE * NUM_TOCS;
00406           opers.scratch = NULL;
00407           opers.protect = 0;
00408           opers.options = S_NO_VERIFY;
00409           rc = spifi->spifi_erase(obj, &opers);
00410           if (rc) {
00411             return qspifs_translateSpifiError(rc);
00412           }
00413 #endif          
00414         }
00415         break;
00416       }
00417     }
00418     pSrc++;
00419     pDest++;
00420   }
00421 
00422   if (!identical)
00423   {
00424     opers.length = FS_MIN(TOC_SIZE, PROG_SIZE);
00425     opers.scratch = NULL;
00426     opers.protect = 0;
00427     opers.options = S_VERIFY_PROG | S_CALLER_ERASE;
00428     for (int i = 0; i < (TOC_SIZE / PROG_SIZE); i++) 
00429     {
00430       opers.dest = (char *)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE + i*PROG_SIZE);
00431       rc = spifi->spifi_program(obj, ((char*)TOC)+i*PROG_SIZE, &opers);
00432       if (rc) 
00433       {
00434         break;
00435       }
00436     }
00437     return qspifs_translateSpifiError(rc);
00438   }
00439   return FS_OK;
00440 }
00441 
00442 /******************************************************************************
00443  *
00444  * Description:
00445  *    Searches the file system for a file with the specified name and
00446  *    (if found) returns the file's position in the TOC.
00447  *
00448  *    Note that the content of fh is only valid if FS_OK is returned.
00449  *
00450  * Params:
00451  *    [in] filename - The name of the file to find
00452  *    [out] fh      - The handle with the file information
00453  *
00454  * Returns:
00455  *    FS_OK or one of the FS_ERR_* error codes
00456  *
00457  *****************************************************************************/
00458 static fresult qspifs_findFile(const char* filename, fileHandle_t* fh)
00459 {
00460   int i;
00461 
00462   if (activeTOC == -1)
00463   {
00464     return FS_ERR_NOT_FORMATTED;
00465   }
00466 
00467   // Look at all blocks except for the reserved ones
00468   for (i = 0; i < NUM_BLOCKS; i++)
00469   {
00470     if (TOC_IS_FILE(TOC[i]) && !TOC_IS_RESERVED(TOC[i]))
00471     {
00472       // found a file, see if name matches
00473       char* p = (char*)(SPIFI_MEM_BASE + i*ERASE_SIZE);
00474       if (strncmp(filename, p, HEADER_FNAME_LEN) == 0)
00475       {
00476         // found a matching name
00477         fh->tocIdx = i;
00478         fresult res = qspifs_fileSize(fh->tocIdx, &fh->size);
00479         if (res == FS_OK) {
00480             fh->lastBlock = fh->tocIdx + ((fh->size + HEADER_LEN)/ ERASE_SIZE);
00481         }
00482         return FS_OK;
00483       }
00484     }
00485   }
00486   return FS_ERR_NO_FILE;
00487 }
00488 
00489 /******************************************************************************
00490  *
00491  * Description:
00492  *    Calculates and returns the file's size.
00493  *
00494  *    Note that the content of pSize is only valid if FS_OK is returned.
00495  *
00496  * Params:
00497  *    [in] tocIdx - The file's position in the TOC
00498  *    [out] pSize - The file's size
00499  *
00500  * Returns:
00501  *    FS_OK or one of the FS_ERR_* error codes
00502  *
00503  *****************************************************************************/
00504 static fresult qspifs_fileSize(int tocIdx, uint32_t* pSize)
00505 {
00506   int i;
00507 
00508   if (tocIdx < 0 || tocIdx > NUM_BLOCKS || !TOC_IS_FILE(TOC[tocIdx]))
00509   {
00510     return FS_ERR_NO_FILE;
00511   }
00512 
00513   *pSize = 0;
00514 
00515   // A file is always stored in sequential blocks so start with the files
00516   // first block and as long as it is full continue sum up the occupied
00517   // block sizes. As soon as a non-full block is found that must be the
00518   // file's last block.
00519   for (i = tocIdx; i < NUM_BLOCKS; i++)
00520   {
00521     *pSize += FILESIZE(TOC[i]);
00522     if (FILESIZE(TOC[i]) < ERASE_SIZE)
00523     {
00524       // last block in chain
00525       break;
00526     }
00527   }
00528 
00529   // Remove the filename header from the file's size
00530   *pSize -= HEADER_LEN;
00531 
00532   return FS_OK;
00533 }
00534 
00535 /******************************************************************************
00536  *
00537  * Description:
00538  *    Erases everything in one block on the QSPI flash.
00539  *
00540  * Params:
00541  *    [in] block - The block's number
00542  *
00543  * Returns:
00544  *    FS_OK or one of the FS_ERR_* error codes
00545  *
00546  *****************************************************************************/
00547 static fresult qspifs_eraseBlock(int block)
00548 {
00549   opers.dest = (char *)(block * ERASE_SIZE);
00550   opers.length = ERASE_SIZE;
00551   opers.scratch = NULL;
00552   opers.protect = 0;
00553   opers.options = S_NO_VERIFY;
00554   return qspifs_translateSpifiError(spifi->spifi_erase (obj, &opers));
00555 }
00556 
00557 /******************************************************************************
00558  *
00559  * Description:
00560  *    Creates a new file if there is enough space for it on the file system.
00561  *    The TOC is searched for a unused sequence of blocks of at least the
00562  *    needed size. That block is marked as used and the file's name is stored
00563  *    in the first bytes of the file's first block.
00564  *
00565  *    Note: The filename will not be tested for uniqueness.
00566  *    Note: The value of pTocIdx will only be valid if FS_OK is returned.
00567  *
00568  * Params:
00569  *    [in] filename - The name of the new file
00570  *    [in] neededBlocks - The number of blocks (in sequence) to allocate
00571  *    [out] pTocIdx - The new file's position in the TOC
00572  *
00573  * Returns:
00574  *    FS_OK or one of the FS_ERR_* error codes
00575  *
00576  *****************************************************************************/
00577 static fresult qspifs_allocateFile(const char* filename, int neededBlocks, int* pTocIdx)
00578 {
00579   int i, rc;
00580 
00581   if (activeTOC == -1)
00582   {
00583     return FS_ERR_NOT_FORMATTED;
00584   }
00585 
00586   // Look at all blocks except for the reserved ones
00587   for (i = 0; i < NUM_BLOCKS; i++)
00588   {
00589     //TODO: Improve search to use gaps to avoid having to move files
00590     //      that are written to
00591     if (!USED_TOC_ENTRY(TOC[i]) && !TOC_IS_RESERVED(TOC[i]))
00592     {
00593       int j;
00594       for (j = 1; j < neededBlocks; j++)
00595       {
00596         if (USED_TOC_ENTRY(TOC[i+j]) || TOC_IS_RESERVED(TOC[i+j]))
00597         {
00598           // not enough free blocks in sequence, skip past these
00599           // tested entries and continue searching
00600           i += j;
00601           break;
00602         }
00603       }
00604 
00605       if (j == neededBlocks)
00606       {
00607         const char* pSrc = filename;
00608         if (IS_ADDR_IN_SPIFI(filename))
00609         {
00610           // The SPIFI ROM driver cannot write data from SPIFI into
00611           // SPIFI (i.e. cannot read and write at the same time).
00612           // The workaround is to copy the source data into a buffer
00613           // in local memory and use that as source for the write
00614           // instead.
00615           memcpy(addr_conflict_buff, filename, strlen(filename)+1);
00616           pSrc = addr_conflict_buff;
00617         }
00618 
00619         // Erase the new file's first block and store the filename at the
00620         // start of it
00621         opers.length = strlen(pSrc)+1;
00622         opers.scratch = NULL;
00623         opers.protect = 0;
00624         opers.options = S_VERIFY_PROG | S_FORCE_ERASE;// S_CALLER_ERASE;
00625         opers.dest = (char *)(i*ERASE_SIZE);
00626         rc = spifi->spifi_program(obj, (char*)pSrc, &opers);
00627         if (rc) {
00628           return qspifs_translateSpifiError(rc);
00629         }
00630 
00631         TOC[i] &= ~(TOC_VALID_MASK | TOC_USED_MASK | TOC_FILE_MASK | TOC_FSIZE_MASK);
00632         TOC[i] |= HEADER_LEN;
00633 
00634         *pTocIdx = i;
00635         return FS_OK;
00636       }
00637     }
00638   }
00639   return FS_ERR_DISK_FULL;
00640 }
00641 
00642 /******************************************************************************
00643  *
00644  * Description:
00645  *    Deletes the specified file by marking all its blocks as unused in
00646  *    the TOC.
00647  *
00648  *    Note: The deleted blocks are not erased here - that is done when they
00649  *          are allocated the next time.
00650  *
00651  * Params:
00652  *    [in] fh - The file handle with information about what to delete
00653  *
00654  * Returns:
00655  *    None
00656  *
00657  *****************************************************************************/
00658 static void qspifs_deleteFile(fileHandle_t* fh)
00659 {
00660   int i;
00661 
00662   for (i = fh->lastBlock; i >= fh->tocIdx; i--)
00663   {
00664     TOC[i] = ~TOC_VALID_MASK;
00665   }
00666 }
00667 
00668 /******************************************************************************
00669  *
00670  * Description:
00671  *    Ensures that the specified file can grow to the wanted size.
00672  *    If the file size will increase enough to need one or more new blocks
00673  *    and there isn't enough space then an attempt is made to move the
00674  *    current file to a large enough space somewhere else.
00675  *
00676  *    If there are more free block(s) at the end of the file then it is not
00677  *    moved and instead those blocks are marked as used.
00678  *
00679  *    Note: The filename will not be tested for uniqueness.
00680  *    Note: The value of pTocIdx will only be valid if FS_OK is returned.
00681  *
00682  * Params:
00683  *    [in/out] fh - The current file handle, might be updated after a move
00684  *    [in] size   - The wanted new size
00685  *
00686  * Returns:
00687  *    FS_OK or one of the FS_ERR_* error codes
00688  *
00689  *****************************************************************************/
00690 static fresult qspifs_allocateSpace(fileHandle_t* fh, uint32_t size)
00691 {
00692   uint16_t oldNumBlocks = (fh->size + HEADER_LEN) / ERASE_SIZE;
00693   uint16_t newNumBlocks = (fh->size + HEADER_LEN + size) / ERASE_SIZE;
00694   uint16_t numNeeded = newNumBlocks - oldNumBlocks;
00695   fresult res = FS_OK;
00696 
00697   if (numNeeded > 0)
00698   {
00699     uint16_t i;
00700     for (i = 0; i < numNeeded; i++)
00701     {
00702       if (USED_TOC_ENTRY(TOC[fh->tocIdx + oldNumBlocks + 1 + i]) || 
00703           TOC_IS_RESERVED(TOC[fh->tocIdx + oldNumBlocks + 1 + i]))
00704       {
00705         fileHandle_t fhNew;
00706 
00707         // have to move the chain
00708         char* filename = (char*)(SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE);
00709         res = qspifs_allocateFile(filename, newNumBlocks, &(fhNew.tocIdx));
00710         if (res == FS_OK)
00711         {
00712           // copy data
00713           fhNew.lastBlock = fhNew.tocIdx;
00714           fhNew.size = 0;
00715           res = qspifs_write(&fhNew, (uint8_t*)(SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE + HEADER_LEN), fh->size);
00716         }
00717         if (res == FS_OK)
00718         {
00719           // remove old entries
00720             qspifs_deleteFile(fh);
00721 
00722           // modify old handle to point to new information
00723           fh->lastBlock = fhNew.lastBlock;
00724           fh->size = fhNew.size;
00725           fh->tocIdx = fhNew.tocIdx;
00726         }
00727         if (res != FS_OK)
00728         {
00729           // not possible to relocate the file => abort
00730           return res;
00731         }
00732         break;
00733       }
00734     }
00735 
00736     // have space that is unused, so mark as used
00737     for (i = 0; i < numNeeded; i++)
00738     {
00739       int tocIdx = fh->tocIdx + oldNumBlocks + 1 + i;
00740       TOC[tocIdx] &= ~TOC_USED_MASK;
00741       qspifs_eraseBlock(tocIdx);
00742     }
00743   }
00744 
00745   return res;
00746 }
00747 
00748 /******************************************************************************
00749  *
00750  * Description:
00751  *    Adds a file system to the QSPI flash. The entire flash will be erase 
00752  *    except for the minReservedBytes first bytes. That reserved area (rounded
00753  *    up to the closest even multiple of the erase block size) can be used 
00754  *    for anything and will never be touched by the file system. That area is
00755  *    typically used for executing programs from when the internal flash is
00756  *    full.
00757  *
00758  *    The file system will have a table of content (TOC) placed at the start
00759  *    of the last erase block on the flash.
00760  *
00761  * Params:
00762  *    [in] minReservedBytes  - The number of bytes to ignore at the start of
00763  *                             the flash.
00764  *
00765  * Returns:
00766  *    FS_OK on success or one of the FS_ERR_* on failure
00767  *
00768  *****************************************************************************/
00769 static fresult qspifs_format(unsigned int minReservedBytes)
00770 {
00771   int i, rc;
00772   int numReserved = 0;
00773   
00774   if (minReservedBytes > 0) {
00775     numReserved = (minReservedBytes + ERASE_SIZE - 1) / ERASE_SIZE;
00776     if (numReserved >= (NUM_BLOCKS - 2)) {
00777       // Too many of the erase blocks are reserved - not even room for one file
00778       return FS_ERR_INVALID_PARAM;
00779     }
00780   }
00781 
00782 #if 0   // works but is really slow  
00783   // Erase all non-reserved blocks
00784   for (i = numReserved; i < NUM_BLOCKS; i++) {
00785     opers.dest = (char *) (i * ERASE_SIZE);
00786     opers.length = ERASE_SIZE;
00787     opers.scratch = NULL;
00788     opers.protect = 0;
00789     opers.options = S_NO_VERIFY;
00790     rc = spifi->spifi_erase(&obj, &opers);
00791     if (rc) {
00792       return qspifs_translateSpifiError(rc);
00793     }
00794   }
00795 #else
00796   // Erase all non-reserved blocks
00797   opers.dest = (char *) (numReserved * ERASE_SIZE);
00798   opers.length = MEM_SIZE - (numReserved * ERASE_SIZE);
00799   opers.scratch = NULL;
00800   opers.protect = 0;
00801   opers.options = S_NO_VERIFY;
00802   rc = spifi->spifi_erase(obj, &opers);
00803   if (rc) {
00804     return qspifs_translateSpifiError(rc);
00805   }
00806 #endif  
00807 
00808   // Create the TOC, mark requested blocks as reserved and mark the TOC's
00809   // block(s) as reserved as well.
00810   for (i = 0; i < numReserved; i++) {
00811     TOC[i] = ~(TOC_VALID_MASK | TOC_RESERVED_MASK);
00812   }
00813   for (; i < (NUM_BLOCKS - NUM_TOC_BLOCKS); i++) {
00814     TOC[i] = ~TOC_VALID_MASK;
00815   }
00816   for (; i < NUM_BLOCKS; i++) {
00817     TOC[i] = ~(TOC_VALID_MASK | TOC_RESERVED_MASK);
00818   }
00819   
00820   // Save the TOC in the last block
00821   activeTOC = 0;
00822   fresult res = qspifs_saveTOC();
00823   if (res != FS_OK) {
00824     activeTOC = -1;
00825     return res;
00826   }
00827 //   opers.dest = (char *) TOC_BLOCK_ADDR;
00828 //   opers.length = TOC_SIZE;
00829 //   opers.scratch = NULL;
00830 //   opers.protect = 0;
00831 //   opers.options = S_VERIFY_PROG | S_CALLER_ERASE;
00832 //   rc = spifi->spifi_program(&obj, (char*) TOC, &opers);
00833 //   if (rc) {
00834 //     return qspifs_translateSpifiError(rc);
00835 //   }
00836 
00837   // Read back TOC to be sure it worked
00838   return qspifs_readTOC();
00839 }
00840 
00841 /******************************************************************************
00842  *
00843  * Description:
00844  *    Deletes all files on the file system. This is a "quick format" that
00845  *    leaves all blocks untouched and only modifies the TOC. Any reserved
00846  *    blocks are kept reserved.
00847  *
00848  *    The purpose of this function is to make it easy to clear the file system
00849  *    without going through a time consuming complete erase every time.
00850  *
00851  * Params:
00852  *    None
00853  *
00854  * Returns:
00855  *    FS_OK on success or one of the FS_ERR_* on failure
00856  *
00857  *****************************************************************************/
00858 // static fresult qspifs_deleteAllFiles(void)
00859 // {
00860 //   for (int i = 0; i < NUM_BLOCKS; i++)
00861 //   {
00862 //     if (!TOC_IS_RESERVED(TOC[i])) {
00863 //       TOC[i] = ~TOC_VALID_MASK;
00864 //     }
00865 //   }
00866 //   
00867 //   return qspifs_saveTOC();
00868 // }
00869 
00870 /******************************************************************************
00871  *
00872  * Description:
00873  *    Appends the data to the end of the file.
00874  *
00875  * Params:
00876  *    [in] fh     - The handle to the file as returned from fs_open_append()
00877  *    [in] pData  - The data to save
00878  *    [in] size   - Number of bytes to save
00879  *
00880  * Returns:
00881  *    FS_OK on success or one of the FS_ERR_* on failure
00882  *
00883  *****************************************************************************/
00884 static fresult qspifs_write(fileHandle_t* fh, const uint8_t * const pData, uint32_t size)
00885 {
00886     uint32_t left = size;
00887     const uint8_t* pSrc = pData;
00888     int rc, i;
00889     fresult res;
00890     int failed_attempts = 0;
00891 
00892     do {
00893         res = qspifs_allocateSpace(fh, size);
00894         if (res != FS_OK) {
00895             break;
00896         }
00897 
00898         opers.dest = (char *) (SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE
00899                 + HEADER_LEN + fh->size);
00900         opers.scratch = NULL;
00901         opers.protect = 0;
00902         opers.options = S_VERIFY_PROG; // | S_FORCE_ERASE;
00903 
00904         while ((res == FS_OK) && (left > 0)) {
00905             if (left >= PROG_SIZE) {
00906                 opers.length = PROG_SIZE;
00907             } else {
00908                 opers.length = left;
00909             }
00910             if (IS_ADDR_IN_SPIFI(pData)) {
00911                 memcpy(addr_conflict_buff, pSrc, opers.length);
00912                 rc = spifi->spifi_program(obj, addr_conflict_buff, &opers);
00913             } else {
00914                 rc = spifi->spifi_program(obj, (char*) pSrc, &opers);
00915             }
00916             res = qspifs_translateSpifiError(rc);
00917             if ((res == FS_ERR_SPIFI_VERIFICATION)
00918                     && (++failed_attempts <= NUM_VERIFICATION_ATTEMPTS)) {
00919                 // The verification process failed.
00920                 // In all the observed occasions re-running the exact same
00921                 // spifi_program command again yielded a 0 as a return value
00922                 // the second time.
00923                 // The quick'N'dirty fix is to re-run that program instruction
00924                 // NUM_VERIFICATION_ATTEMPTS more time(s) when this happens.
00925                 res = FS_OK;
00926                 continue;
00927             }
00928             if (res != FS_OK) {
00929                 // Got an error but cannot exit this function here as parts of the data
00930                 // (previous loops?) may have been written so the TOC must be updated.
00931                 break;
00932             }
00933             pSrc += opers.length;
00934             opers.dest += opers.length;
00935             left -= opers.length;
00936             failed_attempts = 0;
00937         }
00938 
00939         // update file information
00940         fh->size = fh->size + size - left;
00941         fh->lastBlock = fh->tocIdx + ((fh->size + HEADER_LEN)/ ERASE_SIZE);
00942         left = fh->size + HEADER_LEN;
00943         for (i = 0; i <= (fh->lastBlock - fh->tocIdx); i++) {
00944             TOC[fh->tocIdx + i] &= ~TOC_FSIZE_MASK;
00945             TOC[fh->tocIdx + i] |= FS_MIN(ERASE_SIZE, left);
00946             left -= FILESIZE(TOC[fh->tocIdx + i]);
00947         }
00948 
00949         if (res == FS_OK) {
00950             res = qspifs_saveTOC();
00951         } else {
00952             // Want to save the TOC but not overwrite the previous error with
00953             // a possibly successful TOC saving thus making it seem like there
00954             // was no error
00955             qspifs_saveTOC();
00956         }
00957     } while (0);
00958 
00959     return res;
00960 }
00961 
00962 /******************************************************************************
00963  *
00964  * Description:
00965  *    Tests if str starts with prefix. A prefix of NULL or an empty string
00966  *    results in a positive result regardless of the content of str.
00967  *
00968  * Params:
00969  *    [in] prefix - The prefix to look for
00970  *    [in] str    - The string to search for prefix
00971  *
00972  * Returns:
00973  *    True if the specified string starts with prefix
00974  *
00975  *****************************************************************************/
00976 static bool qspifs_startsWith(const char* prefix, const char* str)
00977 {
00978     const char* pA = prefix;
00979     const char* pB = str;
00980 
00981     if (pA == NULL)
00982     {
00983       return true;
00984     }
00985     for (; *pA != '\0'; pA++, pB++)
00986     {
00987       if (*pB != *pA)
00988       {
00989         return false;
00990       }
00991     }
00992 
00993     return true;
00994 }
00995 
00996 /******************************************************************************
00997  * Class Declarations
00998  *****************************************************************************/
00999 
01000 class QSPIFileHandle : public FileHandle {
01001 
01002 public:
01003     QSPIFileHandle(fileHandle_t* handle, int flags);
01004 
01005     virtual int close();
01006 
01007     virtual ssize_t write(const void *buffer, size_t length);
01008 
01009     virtual ssize_t read(void *buffer, size_t length);
01010 
01011     virtual int isatty();
01012 
01013     virtual off_t lseek(off_t position, int whence);
01014 
01015     virtual int fsync();
01016 
01017     virtual off_t flen();
01018 
01019 protected:
01020 
01021     fileHandle_t fh;
01022     bool allowReading;
01023     bool allowWriting;
01024     uint32_t pos;
01025 };
01026 
01027 class QSPIDirHandle : public DirHandle {
01028 
01029 public:
01030     static QSPIDirHandle* openDir(const char* dirname);
01031 
01032     virtual ~QSPIDirHandle();
01033 
01034     virtual int closedir();
01035     virtual struct dirent *readdir();
01036     virtual void rewinddir();
01037 
01038 private:
01039     QSPIDirHandle(const char* dirname);    
01040 
01041     int findFileWithPrefix(const char* prefix, int startTOCIdx, int maxTOCIdx) const;
01042 
01043 protected:
01044   
01045     char* dirname;
01046     int nextTocIdx;
01047 
01048     bool isRoot;
01049 
01050     struct dirent cur_entry;
01051 };
01052 
01053 /******************************************************************************
01054  * Class Implementations
01055  *****************************************************************************/
01056 
01057 QSPIFileHandle::QSPIFileHandle(fileHandle_t* handle, int flags)
01058 {
01059     fh = *handle;
01060     int accmode = (flags & O_ACCMODE);
01061     allowReading = (accmode == O_RDONLY) || (accmode == O_RDWR);
01062     allowWriting = (accmode == O_WRONLY) || (accmode == O_RDWR) || (flags & O_APPEND);
01063     pos = 0;
01064 }
01065 
01066 int QSPIFileHandle::close()
01067 {
01068     delete this;
01069     return 0;
01070 }
01071 
01072 ssize_t QSPIFileHandle::write(const void *buffer, size_t length)
01073 {
01074     if (!allowWriting) {
01075         return -1;
01076     }
01077     fresult res = qspifs_write(&fh, (const uint8_t*)buffer, length);
01078     if (res == FS_OK) {
01079         // A write is always 'append' in this file system so the file
01080         // position is always end of file after a write
01081         pos = fh.size;
01082         return length;
01083     }
01084     return -1;
01085 }
01086 
01087 ssize_t QSPIFileHandle::read(void *buffer, size_t length)
01088 {
01089     if (!allowReading) {
01090         return -1;
01091     }
01092     if (pos >= fh.size) {
01093         return 0;
01094     }
01095     uint32_t len = FS_MIN(length, fh.size - pos);
01096     const char* pData = (const char*)(SPIFI_MEM_BASE + fh.tocIdx*ERASE_SIZE + HEADER_LEN + pos);
01097     memcpy(buffer, pData, len);
01098     pos += len;
01099     return len;
01100 }
01101 
01102 int QSPIFileHandle::isatty()
01103 {
01104     return 0;
01105 }
01106 
01107 off_t QSPIFileHandle::lseek(off_t position, int whence)
01108 {
01109     switch (whence) {
01110     case SEEK_SET:
01111         pos = position;
01112         break;
01113 
01114     case SEEK_CUR:
01115         pos += position;
01116         break;
01117 
01118     case SEEK_END:
01119         pos = fh.size + position;
01120         break;
01121 
01122     default:
01123         return -1;
01124     }
01125     return pos;
01126 }
01127 
01128 int QSPIFileHandle::fsync()
01129 {
01130     return 0; // always synced
01131 }
01132 
01133 off_t QSPIFileHandle::flen()
01134 {
01135     return fh.size;
01136 }
01137 
01138 QSPIDirHandle::QSPIDirHandle(const char* dirname) {
01139     size_t len = strlen(dirname);
01140     this->dirname = (char*)malloc(len + 2); // null termination and possible ending '/'
01141     if (this->dirname != NULL) {
01142         if (len == 0 || ((len == 1) && (dirname[0] == '/'))) {
01143             isRoot = true;
01144             this->dirname[0] = '\0';
01145         } else {
01146             isRoot = false;
01147             memcpy(this->dirname, dirname, len+1);
01148             if (dirname[len - 1] != '/') {
01149                 this->dirname[len] = '/';
01150                 this->dirname[len+1] = '\0';
01151             }
01152         }
01153         cur_entry.d_name[HEADER_FNAME_STRLEN] = '\0';
01154         rewinddir();
01155       }
01156 }
01157 
01158 QSPIDirHandle::~QSPIDirHandle()
01159 {
01160   if (dirname != NULL) {
01161     delete dirname;
01162     dirname = NULL;
01163   }
01164 }
01165 
01166 QSPIDirHandle* QSPIDirHandle::openDir(const char* dirname)
01167 {
01168   QSPIDirHandle* d = new QSPIDirHandle(dirname);
01169   if (d->dirname == NULL) {
01170     // failed to allocate memory for the folder name
01171     delete d;
01172     d = NULL;
01173   } else if (!d->isRoot) {
01174     if (d->findFileWithPrefix(d->dirname, 0, NUM_BLOCKS) == NUM_BLOCKS) {
01175       // There are no files in this directory, i.e. it does not exist
01176       delete d;
01177       d = NULL;
01178     }
01179   }
01180   return d;
01181 }
01182 
01183 int QSPIDirHandle::closedir() {
01184     delete this;
01185     return 0;
01186 }
01187 
01188 int QSPIDirHandle::findFileWithPrefix(const char* prefix, int startTOCIdx, int maxTOCIdx) const
01189 {
01190   for (int i = startTOCIdx; i < maxTOCIdx; i++) {
01191     if (TOC_IS_FILE(TOC[i])) {
01192       const char* filename = (const char*) (SPIFI_MEM_BASE + i * ERASE_SIZE);
01193       if (qspifs_startsWith(prefix, filename)) {
01194         return i;
01195       }
01196     }
01197   }
01198   return NUM_BLOCKS; // no match
01199 }
01200 
01201 
01202 struct dirent *QSPIDirHandle::readdir() {
01203   if (nextTocIdx < NUM_BLOCKS) {
01204     for (int i = nextTocIdx; i < NUM_BLOCKS; i++) {
01205       int possible = findFileWithPrefix(dirname, i, NUM_BLOCKS);
01206       if (possible < NUM_BLOCKS) {
01207         const char* fullfilename = (const char*) (SPIFI_MEM_BASE + possible * ERASE_SIZE);
01208         const char* filename = fullfilename + strlen(dirname);
01209         
01210         if (strchr(filename, '/') == NULL) {
01211           // file is not in any sub folder so it is truly in the wanted dir
01212           nextTocIdx = possible + 1;
01213           strcpy(cur_entry.d_name, filename);
01214           return &cur_entry;
01215         }
01216         
01217         // this is a file in a subfolder and should not be reported,
01218         // but the folder name itself should
01219         strcpy(cur_entry.d_name, fullfilename);
01220         char* pSlash = strchr(cur_entry.d_name + strlen(dirname), '/');
01221         pSlash++;
01222         *pSlash = '\0';
01223         
01224         // now that cur_entry.d_name contains the folder's complete 
01225         // path with a trailing '/', see if it has occurred earlier
01226         int older = findFileWithPrefix(cur_entry.d_name, 0, i);
01227         if (older < possible) {
01228           // already reported, move past this entry
01229           i = possible;
01230         } else {
01231           // found a new subfolder 
01232           nextTocIdx = possible + 1;
01233           strcpy(cur_entry.d_name, filename);
01234           char* pSlash = strchr(cur_entry.d_name, '/');
01235 //          pSlash++; //with ++ the returned dir name is "mydir/" without ++ "mydir" is returned
01236           *pSlash = '\0';
01237           return &cur_entry;
01238         }
01239       }
01240     }
01241   }
01242   return NULL;
01243 }
01244 
01245 void QSPIDirHandle::rewinddir() {
01246   nextTocIdx = 0;
01247 }
01248 
01249 
01250 QSPIFileSystem::QSPIFileSystem(const char* name) :
01251     FileSystemLike(name) {
01252 
01253     activeTOC = -1;
01254     spifi = NULL;
01255 }
01256 
01257 // All modes are supported but:
01258 //
01259 //    1) All writes are treated as appends
01260 //    2) Truncation is only to size 0, i.e. effectively a delete
01261 //    3) File position operations work like this:
01262 //       ReadOnly - dictates where to read from
01263 //       WriteOnly - ignored, writes are always at the end
01264 //       ReadWrite - dictates where to read from, writes ignore it but
01265 //                   sets the position to the end afterwards
01266 //
01267 FileHandle *QSPIFileSystem::open(const char *filename, int flags)
01268 {
01269     fresult res = qspifs_init();
01270 //     if (res == FS_OK) {
01271 //         if ((flags & O_ACCMODE) == O_RDONLY) {
01272 //             // ok
01273 //         } else if (flags & O_APPEND) {
01274 //             // ok
01275 //         } else {
01276 //             // not supported yet, this includes all combination of flags
01277 //             // allowing writing at specific positions in the file. This file system
01278 //             // only allows appending
01279 //             res = FS_ERR_INVALID_PARAM;
01280 //         }
01281 //     }
01282     if (res == FS_OK) {
01283         if (strlen(filename) > HEADER_FNAME_STRLEN) {
01284             // Filename is too long
01285             res = FS_ERR_INVALID_PARAM;
01286         }
01287     }
01288     if (res == FS_OK) {
01289       // Handle truncation by silently deleting the file before
01290       // attempting to open it
01291       if (flags & O_TRUNC) {
01292         remove(filename);
01293       }
01294     }
01295     if (res == FS_OK) {
01296         fileHandle_t fh = {0,0,0};
01297         res = qspifs_findFile(filename, &fh);
01298         if ((res == FS_ERR_NO_FILE) && (flags & O_CREAT)) {
01299             res = qspifs_allocateFile(filename, 1, &fh.tocIdx);
01300         }
01301         if (res == FS_OK) {
01302             res = qspifs_saveTOC();
01303         }
01304         if (res == FS_OK) {
01305             return new QSPIFileHandle(&fh, flags);
01306         }
01307     }
01308     debug_if(QSPI_DBG, "QSPIFS: Failed to open: %d\n", res);
01309     return NULL;
01310 }
01311 
01312 int QSPIFileSystem::remove(const char *filename)
01313 {
01314     fileHandle_t fh = {0,0,0};
01315     fresult res = qspifs_init();
01316     if (res == FS_OK) {
01317         res = qspifs_findFile(filename, &fh);
01318     }
01319     if (res == FS_OK) {
01320         qspifs_deleteFile(&fh);
01321         res = qspifs_saveTOC();
01322     }
01323     else if (res == FS_ERR_NO_FILE) {
01324         // file does not exist so treat it as a successful deletion
01325         res = FS_OK;
01326     }
01327     if (res != FS_OK) {
01328         debug_if(QSPI_DBG, "QSPIFS: Failed to delete %s: %d\n", filename, res);
01329         return -1;
01330     }
01331     return 0;
01332 }
01333 
01334 int QSPIFileSystem::rename(const char *oldname, const char *newname)
01335 {
01336     fileHandle_t fhOld = {0,0,0};
01337     fileHandle_t fhNew = {0,0,0};
01338 
01339     fresult res = qspifs_init();
01340     if (res == FS_OK) {
01341         res = qspifs_findFile(oldname, &fhOld);
01342     }
01343     if (res == FS_OK) {
01344         // Make sure the destination file doesn't exist
01345         res = qspifs_findFile(newname, &fhNew);
01346         if (res == FS_OK) {
01347             res = FS_ERR_FILE_EXIST;
01348         } else if (res == FS_ERR_NO_FILE) {
01349             res = FS_OK;
01350         }
01351     }
01352     if (res == FS_OK) {
01353         int numNeededBlocks = 1 + ((fhOld.size + HEADER_LEN) / ERASE_SIZE);
01354         res = qspifs_allocateFile(newname, numNeededBlocks, &fhNew.tocIdx);
01355         if (res == FS_OK) {
01356             const uint8_t* pData = (const uint8_t*)(SPIFI_MEM_BASE + fhOld.tocIdx*ERASE_SIZE + HEADER_LEN);
01357             res = qspifs_write(&fhNew, pData, fhOld.size);
01358             if (res == FS_OK) {
01359                 qspifs_deleteFile(&fhOld);
01360             } else {
01361                 qspifs_deleteFile(&fhNew);
01362             }
01363         }
01364         qspifs_saveTOC();
01365     }
01366     if (res != FS_OK) {
01367         debug_if(QSPI_DBG, "QSPIFS: Failed to rename '%s' to '%s': %d\n", oldname, newname, res);
01368         return -1;
01369     }
01370     return 0;
01371 }
01372 
01373 DirHandle *QSPIFileSystem::opendir(const char *name)
01374 {
01375   FileHandle* fh = open(name, O_RDONLY);
01376   if (fh != NULL) {
01377     // Attempting to open a file as a dir
01378     delete fh;
01379     return NULL;
01380   }
01381   
01382 //     printf("opendir: name '%s'\n", name);
01383   if (strlen(name) <= HEADER_DNAME_MAXLEN) {
01384     return QSPIDirHandle::openDir(name);
01385   }
01386   return NULL;
01387 }
01388 
01389 int QSPIFileSystem::mkdir(const char *name, mode_t mode)
01390 {
01391     // Creating folders is always successful as there are no folders in this filesystem
01392     return 0;
01393 }
01394 
01395 int QSPIFileSystem::format(unsigned int fsSizeInMB)
01396 {
01397     fresult res = qspifs_init();
01398     if (res == FS_OK || res == FS_ERR_NOT_FORMATTED) {
01399         if (((fsSizeInMB<<20) > memInfo.memSize) || (fsSizeInMB < 1)) {
01400             debug_if(QSPI_DBG, "QSPIFS: Failed to format to size %d MByte: error %d\n", fsSizeInMB, res);
01401             return -1;
01402         }
01403         activeTOC = -1;
01404         res = qspifs_format(memInfo.memSize - (fsSizeInMB<<20));
01405     }
01406 
01407     if (res != FS_OK) {
01408         debug_if(QSPI_DBG, "QSPIFS: Failed to format: %d\n", res);
01409         return -1;
01410     }
01411     return 0;
01412 }
01413 
01414 bool QSPIFileSystem::isformatted()
01415 {
01416     fresult res = qspifs_init();
01417     if (res == FS_OK) {
01418         return true;
01419     } else if (res == FS_ERR_NOT_FORMATTED) {
01420         return false;
01421     }
01422     debug_if(QSPI_DBG, "QSPIFS: Failed to detect status: %d\n", res);
01423     return false;
01424 }
01425 
01426 bool QSPIFileSystem::getMemoryBoundaries(uint32_t* pStartAddr, uint32_t* pEndAddr)
01427 {
01428   if (isformatted())
01429   {
01430     *pEndAddr = 0x28000000 + memInfo.memSize;
01431     
01432     // Look at all blocks except for the reserved ones
01433     for (int i = 0; i < NUM_BLOCKS; i++)
01434     {
01435       if (!TOC_IS_RESERVED(TOC[i]))
01436       {
01437         // Found first non-reserved erase block, indicating the start of
01438         // the file system.
01439         *pStartAddr = SPIFI_MEM_BASE + i*ERASE_SIZE;
01440         return true;
01441       }
01442     }
01443     
01444     // The entire file system seems to be reserved which should never happen
01445     // but just in case, report it as beeing 1MB in size.
01446     *pStartAddr = *pEndAddr - 1024*1024;
01447     return true;
01448   }
01449   return false;
01450 }