The wait in mci_WaitForEvent will delay all card transactions.
Fork of EALib by
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 }
Generated on Tue Jul 12 2022 15:13:41 by 1.7.2