Subdirectory provided by Embedded Artists

Dependencies:   DM_FATFileSystem DM_HttpServer DM_USBHost EthernetInterface USBDevice mbed-rpc mbed-rtos mbed-src

Dependents:   lpc4088_displaymodule_hello_world_Sept_2018

Fork of DMSupport by Embedded Artists

Committer:
embeddedartists
Date:
Fri Jan 09 11:42:06 2015 +0100
Revision:
19:2efb6f5f69a4
Parent:
14:c21497031b1f
Child:
22:1a58a518435c
Added support for the new Macronix_MX25L12835F QSPI flash

Who changed what in which revision?

UserRevisionLine numberNew contents of line
embeddedartists 0:6b68dac0d986 1 /*
embeddedartists 9:a33326afd686 2 * Copyright 2014 Embedded Artists AB
embeddedartists 0:6b68dac0d986 3 *
embeddedartists 0:6b68dac0d986 4 * Licensed under the Apache License, Version 2.0 (the "License");
embeddedartists 0:6b68dac0d986 5 * you may not use this file except in compliance with the License.
embeddedartists 0:6b68dac0d986 6 * You may obtain a copy of the License at
embeddedartists 0:6b68dac0d986 7 *
embeddedartists 0:6b68dac0d986 8 * http://www.apache.org/licenses/LICENSE-2.0
embeddedartists 0:6b68dac0d986 9 *
embeddedartists 0:6b68dac0d986 10 * Unless required by applicable law or agreed to in writing, software
embeddedartists 0:6b68dac0d986 11 * distributed under the License is distributed on an "AS IS" BASIS,
embeddedartists 0:6b68dac0d986 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
embeddedartists 0:6b68dac0d986 13 * See the License for the specific language governing permissions and
embeddedartists 0:6b68dac0d986 14 * limitations under the License.
embeddedartists 0:6b68dac0d986 15 */
embeddedartists 0:6b68dac0d986 16
embeddedartists 0:6b68dac0d986 17 #include "QSPIFileSystem.h"
embeddedartists 0:6b68dac0d986 18 #include "mbed_debug.h"
embeddedartists 0:6b68dac0d986 19
embeddedartists 0:6b68dac0d986 20 #include "SPIFI.h"
embeddedartists 0:6b68dac0d986 21
embeddedartists 0:6b68dac0d986 22 /******************************************************************************
embeddedartists 0:6b68dac0d986 23 * Defines and typedefs
embeddedartists 0:6b68dac0d986 24 *****************************************************************************/
embeddedartists 0:6b68dac0d986 25
embeddedartists 0:6b68dac0d986 26 #define QSPI_DBG 0
embeddedartists 0:6b68dac0d986 27
embeddedartists 0:6b68dac0d986 28 #define IS_ADDR_IN_SPIFI(__addr) ( (((uint32_t)(__addr)) & 0xff000000) == SPIFI_MEM_BASE )
embeddedartists 0:6b68dac0d986 29
embeddedartists 0:6b68dac0d986 30 #define MEM_SIZE (memInfo.memSize)
embeddedartists 0:6b68dac0d986 31 #define ERASE_SIZE (memInfo.eraseBlockSize)
embeddedartists 0:6b68dac0d986 32 #define NUM_BLOCKS (memInfo.numEraseBlocks)
embeddedartists 0:6b68dac0d986 33
embeddedartists 0:6b68dac0d986 34 typedef uint32_t toc_entry_t;
embeddedartists 0:6b68dac0d986 35
embeddedartists 0:6b68dac0d986 36 #define TOC_BLOCK_ADDR (memInfo.tocBlockAddr) //(SPIFI_MEM_BASE + (NUM_BLOCKS - 1)*ERASE_SIZE)
embeddedartists 0:6b68dac0d986 37 #define TOC_SIZE (memInfo.tocSizeInBytes) //(sizeof(toc_entry_t) * NUM_BLOCKS)
embeddedartists 0:6b68dac0d986 38 #define NUM_TOCS (memInfo.numTocs) //((int)(ERASE_SIZE/TOC_SIZE))
embeddedartists 0:6b68dac0d986 39 #define NUM_TOC_BLOCKS ((NUM_TOCS * TOC_SIZE) / ERASE_SIZE)
embeddedartists 0:6b68dac0d986 40 #define NUM_TOC_ENTRIES ((int)(TOC_SIZE/sizeof(toc_entry_t)))
embeddedartists 0:6b68dac0d986 41
embeddedartists 0:6b68dac0d986 42 #define TOC_UNUSED (0xffffffff)
embeddedartists 0:6b68dac0d986 43 #define TOC_MAX (NUM_BLOCKS - 1)
embeddedartists 0:6b68dac0d986 44 #define TOC_VALID_MASK (1UL<<31)
embeddedartists 0:6b68dac0d986 45 #define TOC_RESERVED_MASK (1UL<<30)
embeddedartists 0:6b68dac0d986 46 #define TOC_USED_MASK (1UL<<29)
embeddedartists 0:6b68dac0d986 47 #define TOC_FILE_MASK (1UL<<28)
embeddedartists 0:6b68dac0d986 48 #define TOC_FSIZE_MASK (0x3ffff)
embeddedartists 0:6b68dac0d986 49 #define TOC_MANDAT_SET_MASK (0x0ffc0000)
embeddedartists 0:6b68dac0d986 50
embeddedartists 0:6b68dac0d986 51 #define MANDATORY_BITS_SET(__v) (((__v)&TOC_MANDAT_SET_MASK) == TOC_MANDAT_SET_MASK)
embeddedartists 0:6b68dac0d986 52
embeddedartists 0:6b68dac0d986 53 #define VALID_TOC_ENTRY(__v) (((__v)&TOC_VALID_MASK) == 0)
embeddedartists 0:6b68dac0d986 54 #define USED_TOC_ENTRY(__v) (VALID_TOC_ENTRY(__v) && (((__v)&TOC_USED_MASK) == 0))
embeddedartists 0:6b68dac0d986 55 #define TOC_IS_FILE(__v) (USED_TOC_ENTRY(__v) && (((__v)&TOC_FILE_MASK) == 0))
embeddedartists 0:6b68dac0d986 56 #define TOC_IS_RESERVED(__v) (VALID_TOC_ENTRY(__v) && (((__v)&TOC_RESERVED_MASK) == 0))
embeddedartists 0:6b68dac0d986 57 #define FILESIZE(__v) ((__v) & 0x3ffff)
embeddedartists 0:6b68dac0d986 58
embeddedartists 0:6b68dac0d986 59 #define FS_MIN(__a, __b) (((__a) < (__b)) ? (__a) : (__b))
embeddedartists 0:6b68dac0d986 60
embeddedartists 0:6b68dac0d986 61 // Mask to compare the different access modes. In LPCXpresso this was defined
embeddedartists 0:6b68dac0d986 62 // but not in uVision
embeddedartists 0:6b68dac0d986 63 #ifndef O_ACCMODE
embeddedartists 0:6b68dac0d986 64 #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
embeddedartists 0:6b68dac0d986 65 #endif
embeddedartists 0:6b68dac0d986 66
embeddedartists 0:6b68dac0d986 67
embeddedartists 0:6b68dac0d986 68 /*
embeddedartists 0:6b68dac0d986 69 * The file header currently only consists of the filename (including path)
embeddedartists 0:6b68dac0d986 70 * and the string terminating character, but by separating the file name
embeddedartists 0:6b68dac0d986 71 * length from the size of the header in the code it allows future additions
embeddedartists 0:6b68dac0d986 72 * to the header without too much code modification.
embeddedartists 0:6b68dac0d986 73 */
embeddedartists 0:6b68dac0d986 74 #define HEADER_DNAME_MAXLEN (250)
embeddedartists 0:6b68dac0d986 75 #define HEADER_FNAME_STRLEN (HEADER_DNAME_MAXLEN + 5)
embeddedartists 0:6b68dac0d986 76 #define HEADER_FNAME_LEN (HEADER_FNAME_STRLEN + 1)
embeddedartists 0:6b68dac0d986 77 #define HEADER_LEN (HEADER_FNAME_LEN) // only filename in header for now
embeddedartists 0:6b68dac0d986 78
embeddedartists 0:6b68dac0d986 79 typedef enum
embeddedartists 0:6b68dac0d986 80 {
embeddedartists 0:6b68dac0d986 81 FS_OK,
embeddedartists 0:6b68dac0d986 82 FS_ERR_NOT_FORMATTED,
embeddedartists 0:6b68dac0d986 83 FS_ERR_NO_FILE,
embeddedartists 0:6b68dac0d986 84 FS_ERR_FILE_EXIST,
embeddedartists 0:6b68dac0d986 85 FS_ERR_INVALID_PARAM,
embeddedartists 0:6b68dac0d986 86 FS_ERR_DISK_FULL,
embeddedartists 0:6b68dac0d986 87 FS_ERR_SPIFI,
embeddedartists 0:6b68dac0d986 88 FS_ERR_MALLOC,
embeddedartists 0:6b68dac0d986 89
embeddedartists 0:6b68dac0d986 90 // FS_ERR_SPIFI_* return codes are listed in the User's Manual
embeddedartists 0:6b68dac0d986 91 // as possible return values from spifi_init(), spifi_program()
embeddedartists 0:6b68dac0d986 92 // and spifi_erase() calls.
embeddedartists 0:6b68dac0d986 93 FS_ERR_SPIFI_INTERNAL_ERROR = 0x20002, // 0x20002, Internal error in API code
embeddedartists 0:6b68dac0d986 94 FS_ERR_SPIFI_TIMEOUT = 0x20003, // 0x20003, Time-out waiting for program or erase to begin: protection could not be removed.
embeddedartists 0:6b68dac0d986 95 FS_ERR_SPIFI_OPERAND = 0x20004, // 0x20004, Operand error (i.e. invalid params)
embeddedartists 0:6b68dac0d986 96 FS_ERR_SPIFI_STATUS = 0x20005, // 0x20005, Device status error
embeddedartists 0:6b68dac0d986 97 FS_ERR_SPIFI_EXT_DEVICE_ID = 0x20006, // 0x20006, Unknown extended device ID value
embeddedartists 0:6b68dac0d986 98 FS_ERR_SPIFI_DEVICE_ID = 0x20007, // 0x20007, Unknown device ID code
embeddedartists 0:6b68dac0d986 99 FS_ERR_SPIFI_DEVICE_TYPE = 0x20008, // 0x20008, Unknown device type code
embeddedartists 0:6b68dac0d986 100 FS_ERR_SPIFI_MANUFACTURER = 0x20009, // 0x20009, Unknown manufacturer code
embeddedartists 0:6b68dac0d986 101 FS_ERR_SPIFI_INVALID_JDEC_ID = 0x2000A, // 0x2000A, No operative serial flash (JEDEC ID all zeroes or all ones)
embeddedartists 0:6b68dac0d986 102 FS_ERR_SPIFI_ERASE_CONFLICT = 0x2000B, // 0x2000B, S_CALLER_ERASE is included in options, and erasure is required.
embeddedartists 0:6b68dac0d986 103 FS_ERR_SPIFI_VERIFICATION, // other, Other non-zero values can occur if options selects verification.
embeddedartists 0:6b68dac0d986 104 // They will be the address in the SPIFI memory area at which the first discrepancy was found.
embeddedartists 0:6b68dac0d986 105 } fresult;
embeddedartists 0:6b68dac0d986 106
embeddedartists 0:6b68dac0d986 107 // The number of times to re-attempt a spifi_program() or spifi_erase()
embeddedartists 0:6b68dac0d986 108 // if the last one reported a verification error.
embeddedartists 0:6b68dac0d986 109 #define NUM_VERIFICATION_ATTEMPTS (1)
embeddedartists 0:6b68dac0d986 110
embeddedartists 0:6b68dac0d986 111 typedef struct
embeddedartists 0:6b68dac0d986 112 {
embeddedartists 0:6b68dac0d986 113 uint32_t memSize;
embeddedartists 0:6b68dac0d986 114 uint32_t eraseBlockSize;
embeddedartists 0:6b68dac0d986 115 uint32_t numEraseBlocks;
embeddedartists 0:6b68dac0d986 116 uint32_t tocBlockAddr;
embeddedartists 0:6b68dac0d986 117 uint32_t numTocs;
embeddedartists 0:6b68dac0d986 118 uint32_t tocSizeInBytes;
embeddedartists 0:6b68dac0d986 119 char memName[30];
embeddedartists 0:6b68dac0d986 120 } meminfo_t;
embeddedartists 0:6b68dac0d986 121
embeddedartists 0:6b68dac0d986 122 typedef struct
embeddedartists 0:6b68dac0d986 123 {
embeddedartists 0:6b68dac0d986 124 int tocIdx;
embeddedartists 0:6b68dac0d986 125 uint32_t size;
embeddedartists 0:6b68dac0d986 126 uint16_t lastBlock;
embeddedartists 0:6b68dac0d986 127 } fileHandle_t;
embeddedartists 0:6b68dac0d986 128
embeddedartists 0:6b68dac0d986 129 /******************************************************************************
embeddedartists 0:6b68dac0d986 130 * Local variables
embeddedartists 0:6b68dac0d986 131 *****************************************************************************/
embeddedartists 0:6b68dac0d986 132
embeddedartists 0:6b68dac0d986 133 static toc_entry_t* TOC = NULL;
embeddedartists 0:6b68dac0d986 134 static int activeTOC = -1;
embeddedartists 0:6b68dac0d986 135
embeddedartists 0:6b68dac0d986 136 static const SPIFI_RTNS *spifi = NULL;
embeddedartists 0:6b68dac0d986 137 static SPIFIobj* obj;
embeddedartists 0:6b68dac0d986 138 static SPIFIopers opers;
embeddedartists 0:6b68dac0d986 139
embeddedartists 0:6b68dac0d986 140 static char addr_conflict_buff[PROG_SIZE];
embeddedartists 0:6b68dac0d986 141
embeddedartists 0:6b68dac0d986 142 static meminfo_t memInfo = {0,0,0,0,0,0,{0}};
embeddedartists 0:6b68dac0d986 143
embeddedartists 0:6b68dac0d986 144 /******************************************************************************
embeddedartists 0:6b68dac0d986 145 * Forward Declarations of Local Functions
embeddedartists 0:6b68dac0d986 146 *****************************************************************************/
embeddedartists 0:6b68dac0d986 147 static fresult qspifs_init();
embeddedartists 0:6b68dac0d986 148 static fresult qspifs_translateSpifiError(int rc);
embeddedartists 0:6b68dac0d986 149 static fresult qspifs_readTOC(void);
embeddedartists 0:6b68dac0d986 150 static fresult qspifs_saveTOC(void);
embeddedartists 0:6b68dac0d986 151 static fresult qspifs_findFile(const char* filename, fileHandle_t* fh);
embeddedartists 0:6b68dac0d986 152 static fresult qspifs_fileSize(int tocIdx, uint32_t* pSize);
embeddedartists 0:6b68dac0d986 153 static fresult qspifs_eraseBlock(int block);
embeddedartists 0:6b68dac0d986 154 static fresult qspifs_allocateFile(const char* filename, int neededBlocks, int* pTocIdx);
embeddedartists 0:6b68dac0d986 155 static void qspifs_deleteFile(fileHandle_t* fh);
embeddedartists 0:6b68dac0d986 156 static fresult qspifs_allocateSpace(fileHandle_t* fh, uint32_t size);
embeddedartists 0:6b68dac0d986 157 static fresult qspifs_format(unsigned int minReservedBytes);
embeddedartists 0:6b68dac0d986 158 static fresult qspifs_write(fileHandle_t* fh, const uint8_t * const pData, uint32_t size);
embeddedartists 0:6b68dac0d986 159 static bool qspifs_startsWith(const char* prefix, const char* str);
embeddedartists 0:6b68dac0d986 160
embeddedartists 0:6b68dac0d986 161 /******************************************************************************
embeddedartists 0:6b68dac0d986 162 * Local Functions
embeddedartists 0:6b68dac0d986 163 *****************************************************************************/
embeddedartists 0:6b68dac0d986 164
embeddedartists 0:6b68dac0d986 165 /******************************************************************************
embeddedartists 0:6b68dac0d986 166 *
embeddedartists 0:6b68dac0d986 167 * Description:
embeddedartists 0:6b68dac0d986 168 * Initializes spifi, identifies the chip and reads the file system's
embeddedartists 0:6b68dac0d986 169 * table of content.
embeddedartists 0:6b68dac0d986 170 *
embeddedartists 0:6b68dac0d986 171 * Params:
embeddedartists 0:6b68dac0d986 172 * None
embeddedartists 0:6b68dac0d986 173 *
embeddedartists 0:6b68dac0d986 174 * Returns:
embeddedartists 0:6b68dac0d986 175 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 176 *
embeddedartists 0:6b68dac0d986 177 *****************************************************************************/
embeddedartists 0:6b68dac0d986 178 static fresult qspifs_init()
embeddedartists 0:6b68dac0d986 179 {
embeddedartists 0:6b68dac0d986 180 if (spifi == NULL) {
embeddedartists 0:6b68dac0d986 181 SPIFI::SpifiError err;
embeddedartists 0:6b68dac0d986 182 err = SPIFI::instance().init();
embeddedartists 0:6b68dac0d986 183 if (err != SPIFI::Ok) {
embeddedartists 0:6b68dac0d986 184 spifi = NULL;
embeddedartists 0:6b68dac0d986 185 return FS_ERR_SPIFI;
embeddedartists 0:6b68dac0d986 186 }
embeddedartists 0:6b68dac0d986 187
embeddedartists 0:6b68dac0d986 188 SPIFI::instance().internalData(&obj, &spifi);
embeddedartists 0:6b68dac0d986 189
embeddedartists 0:6b68dac0d986 190 /* Make sure it is a tested flash module */
embeddedartists 0:6b68dac0d986 191 switch (SPIFI::instance().device()) {
embeddedartists 0:6b68dac0d986 192 case SPIFI::Spansion_S25FL032:
embeddedartists 0:6b68dac0d986 193 /* For the Spansion memory the TOC occupies 256bytes and the TOC block will
embeddedartists 0:6b68dac0d986 194 hold 256 TOCs. */
embeddedartists 0:6b68dac0d986 195 strcpy(memInfo.memName, "Spansion S25FL032");
embeddedartists 0:6b68dac0d986 196 memInfo.memSize = obj->memSize;
embeddedartists 0:6b68dac0d986 197 memInfo.eraseBlockSize = 64*1024;
embeddedartists 0:6b68dac0d986 198 memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
embeddedartists 0:6b68dac0d986 199 memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
embeddedartists 0:6b68dac0d986 200 memInfo.numTocs = memInfo.eraseBlockSize / memInfo.tocSizeInBytes;
embeddedartists 0:6b68dac0d986 201 memInfo.tocBlockAddr = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
embeddedartists 0:6b68dac0d986 202 break;
embeddedartists 0:6b68dac0d986 203
embeddedartists 0:6b68dac0d986 204 case SPIFI::Winbond_W25Q64FV:
embeddedartists 0:6b68dac0d986 205 /* For the Winbond memory the TOC occupies 8192 bytes and that is bigger than
embeddedartists 0:6b68dac0d986 206 one erase block (which is 4096 bytes). It is possible to either keep only
embeddedartists 0:6b68dac0d986 207 one TOC or to create a couple to reduce wear on the memory. In this case
embeddedartists 0:6b68dac0d986 208 the multiple TOCs option is used. */
embeddedartists 0:6b68dac0d986 209 strcpy(memInfo.memName, "Winbond W25Q64FV");
embeddedartists 0:6b68dac0d986 210 memInfo.memSize = obj->memSize;
embeddedartists 0:6b68dac0d986 211 memInfo.eraseBlockSize = 4*1024;
embeddedartists 0:6b68dac0d986 212 memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
embeddedartists 0:6b68dac0d986 213 memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
embeddedartists 0:6b68dac0d986 214 memInfo.numTocs = 8;
embeddedartists 0:6b68dac0d986 215 memInfo.tocBlockAddr = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
embeddedartists 0:6b68dac0d986 216 break;
embeddedartists 0:6b68dac0d986 217
embeddedartists 19:2efb6f5f69a4 218 case SPIFI::Macronix_MX25L6435E:
embeddedartists 0:6b68dac0d986 219 /* For the Macronix memory the TOC occupies 8192 bytes and that is bigger than
embeddedartists 0:6b68dac0d986 220 one erase block (which is 4096 bytes). It is possible to either keep only
embeddedartists 0:6b68dac0d986 221 one TOC or to create a couple to reduce wear on the memory. In this case
embeddedartists 0:6b68dac0d986 222 the multiple TOCs option is used. */
embeddedartists 19:2efb6f5f69a4 223 strcpy(memInfo.memName, "Macronix_MX25L6435E");
embeddedartists 0:6b68dac0d986 224 memInfo.memSize = obj->memSize;
embeddedartists 0:6b68dac0d986 225 memInfo.eraseBlockSize = 4*1024;
embeddedartists 0:6b68dac0d986 226 memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
embeddedartists 0:6b68dac0d986 227 memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
embeddedartists 0:6b68dac0d986 228 memInfo.numTocs = 8;
embeddedartists 0:6b68dac0d986 229 memInfo.tocBlockAddr = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
embeddedartists 0:6b68dac0d986 230 break;
embeddedartists 0:6b68dac0d986 231
embeddedartists 19:2efb6f5f69a4 232 case SPIFI::Macronix_MX25L12835F:
embeddedartists 19:2efb6f5f69a4 233 /* For the Macronix memory the TOC occupies 16384 bytes and that is bigger than
embeddedartists 19:2efb6f5f69a4 234 one erase block (which is 4096 bytes). It is possible to either keep only
embeddedartists 19:2efb6f5f69a4 235 one TOC or to create a couple to reduce wear on the memory. In this case
embeddedartists 19:2efb6f5f69a4 236 the multiple TOCs option is used. */
embeddedartists 19:2efb6f5f69a4 237 strcpy(memInfo.memName, "Macronix_MX25L12835F");
embeddedartists 19:2efb6f5f69a4 238 memInfo.memSize = obj->memSize;
embeddedartists 19:2efb6f5f69a4 239 memInfo.eraseBlockSize = 4*1024;
embeddedartists 19:2efb6f5f69a4 240 memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
embeddedartists 19:2efb6f5f69a4 241 memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
embeddedartists 19:2efb6f5f69a4 242 memInfo.numTocs = 4;
embeddedartists 19:2efb6f5f69a4 243 memInfo.tocBlockAddr = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
embeddedartists 19:2efb6f5f69a4 244 break;
embeddedartists 19:2efb6f5f69a4 245
embeddedartists 0:6b68dac0d986 246 case SPIFI::UnknownDevice:
embeddedartists 0:6b68dac0d986 247 default:
embeddedartists 0:6b68dac0d986 248 debug("INIT: Memory is unknown and may not work as expected\n");
embeddedartists 0:6b68dac0d986 249
embeddedartists 0:6b68dac0d986 250 // Asuming it has 64Kb erase blocks (i.e. same setup as the Spansion S25FL032
embeddedartists 0:6b68dac0d986 251 strcpy(memInfo.memName, "Unknown - check ID");
embeddedartists 0:6b68dac0d986 252 memInfo.memSize = obj->memSize;
embeddedartists 0:6b68dac0d986 253 memInfo.eraseBlockSize = 64*1024;
embeddedartists 0:6b68dac0d986 254 memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
embeddedartists 0:6b68dac0d986 255 memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
embeddedartists 0:6b68dac0d986 256 memInfo.numTocs = memInfo.eraseBlockSize / memInfo.tocSizeInBytes;
embeddedartists 0:6b68dac0d986 257 memInfo.tocBlockAddr = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
embeddedartists 0:6b68dac0d986 258
embeddedartists 0:6b68dac0d986 259 /*
embeddedartists 0:6b68dac0d986 260 * If this happens, check the manufacturer and device information
embeddedartists 0:6b68dac0d986 261 * and compare with the data sheet for your chip. Also make sure
embeddedartists 0:6b68dac0d986 262 * that the sector sizes are the same (i.e. 64KB) for your chip.
embeddedartists 0:6b68dac0d986 263 * If everything is the same then add an exception for your chip.
embeddedartists 0:6b68dac0d986 264 */
embeddedartists 0:6b68dac0d986 265 break;
embeddedartists 0:6b68dac0d986 266 }
embeddedartists 0:6b68dac0d986 267
embeddedartists 0:6b68dac0d986 268 debug_if(QSPI_DBG, "INIT: Found %dMB %s\n", memInfo.memSize/0x100000, memInfo.memName);
embeddedartists 0:6b68dac0d986 269
embeddedartists 0:6b68dac0d986 270 if (TOC != NULL) {
embeddedartists 0:6b68dac0d986 271 delete TOC;
embeddedartists 0:6b68dac0d986 272 }
embeddedartists 0:6b68dac0d986 273 TOC = (toc_entry_t*)malloc(TOC_SIZE);
embeddedartists 0:6b68dac0d986 274 if (TOC == NULL) {
embeddedartists 0:6b68dac0d986 275 debug_if(QSPI_DBG, "INIT: Failed to allocate memory for TOC\n");
embeddedartists 0:6b68dac0d986 276 spifi = NULL;
embeddedartists 0:6b68dac0d986 277 return FS_ERR_MALLOC;
embeddedartists 0:6b68dac0d986 278 }
embeddedartists 0:6b68dac0d986 279 }
embeddedartists 0:6b68dac0d986 280 if (activeTOC == -1)
embeddedartists 0:6b68dac0d986 281 {
embeddedartists 0:6b68dac0d986 282 return qspifs_readTOC();
embeddedartists 0:6b68dac0d986 283 }
embeddedartists 0:6b68dac0d986 284 return FS_OK;
embeddedartists 0:6b68dac0d986 285 }
embeddedartists 0:6b68dac0d986 286
embeddedartists 0:6b68dac0d986 287 /******************************************************************************
embeddedartists 0:6b68dac0d986 288 *
embeddedartists 0:6b68dac0d986 289 * Description:
embeddedartists 0:6b68dac0d986 290 * Converts the return value from one of the spifi_init(), spifi_program()
embeddedartists 0:6b68dac0d986 291 * or spifi_erase() calls into a FS_* error code to simplify it for the
embeddedartists 0:6b68dac0d986 292 * fs_qspi API user.
embeddedartists 0:6b68dac0d986 293 * This function also attempts to detect the verification failure error.
embeddedartists 0:6b68dac0d986 294 * When a verification error occurs the spifi_* functions returns the
embeddedartists 0:6b68dac0d986 295 * conflicting address and not an error code. As this can be any address
embeddedartists 0:6b68dac0d986 296 * it is difficult to test but this function converts it into the
embeddedartists 0:6b68dac0d986 297 * FS_ERR_SPIFI_VERIFICATION error code which can be tested against.
embeddedartists 0:6b68dac0d986 298 *
embeddedartists 0:6b68dac0d986 299 * Params:
embeddedartists 0:6b68dac0d986 300 * [in] rc - The return code from any of the spifi_* functions
embeddedartists 0:6b68dac0d986 301 *
embeddedartists 0:6b68dac0d986 302 * Returns:
embeddedartists 0:6b68dac0d986 303 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 304 *
embeddedartists 0:6b68dac0d986 305 *****************************************************************************/
embeddedartists 0:6b68dac0d986 306 static fresult qspifs_translateSpifiError(int rc)
embeddedartists 0:6b68dac0d986 307 {
embeddedartists 0:6b68dac0d986 308 fresult res;
embeddedartists 0:6b68dac0d986 309 if (rc == 0)
embeddedartists 0:6b68dac0d986 310 {
embeddedartists 0:6b68dac0d986 311 res = FS_OK;
embeddedartists 0:6b68dac0d986 312 }
embeddedartists 0:6b68dac0d986 313 else if ((rc >= FS_ERR_SPIFI_INTERNAL_ERROR) && (rc <= FS_ERR_SPIFI_ERASE_CONFLICT))
embeddedartists 0:6b68dac0d986 314 {
embeddedartists 0:6b68dac0d986 315 // This is a known error code
embeddedartists 0:6b68dac0d986 316 res = (fresult)rc;
embeddedartists 0:6b68dac0d986 317 }
embeddedartists 0:6b68dac0d986 318 else if (opers.options & (S_VERIFY_PROG | S_VERIFY_ERASE))
embeddedartists 0:6b68dac0d986 319 {
embeddedartists 0:6b68dac0d986 320 // As verification was selected and rc is not in the list of known
embeddedartists 0:6b68dac0d986 321 // codes this falls into this category in the User's Manual:
embeddedartists 0:6b68dac0d986 322 //
embeddedartists 0:6b68dac0d986 323 // "Other non-zero values can occur if options selects verification.
embeddedartists 0:6b68dac0d986 324 // They will be the address in the SPIFI memory area at which the
embeddedartists 0:6b68dac0d986 325 // first discrepancy was found."
embeddedartists 0:6b68dac0d986 326 res = FS_ERR_SPIFI_VERIFICATION;
embeddedartists 0:6b68dac0d986 327 }
embeddedartists 0:6b68dac0d986 328 else
embeddedartists 0:6b68dac0d986 329 {
embeddedartists 0:6b68dac0d986 330 // Should never happen :-) as all listed error codes are covered but
embeddedartists 0:6b68dac0d986 331 // to be on the safe side and not interpret this as a success, a generic
embeddedartists 0:6b68dac0d986 332 // error is set.
embeddedartists 0:6b68dac0d986 333 res = FS_ERR_SPIFI;
embeddedartists 0:6b68dac0d986 334 }
embeddedartists 0:6b68dac0d986 335 return res;
embeddedartists 0:6b68dac0d986 336 }
embeddedartists 0:6b68dac0d986 337
embeddedartists 0:6b68dac0d986 338 /******************************************************************************
embeddedartists 0:6b68dac0d986 339 *
embeddedartists 0:6b68dac0d986 340 * Description:
embeddedartists 0:6b68dac0d986 341 * Reads the table of contents (TOC). The TOC is stored in the last erase
embeddedartists 0:6b68dac0d986 342 * block on the QSPI flash. As the QSPI flash is not exactly RW (might
embeddedartists 0:6b68dac0d986 343 * require erasing before writing) the TOC is relocated inside the erase
embeddedartists 0:6b68dac0d986 344 * block everytime it is saved (see saveTOC()). The currently valid TOC
embeddedartists 0:6b68dac0d986 345 * is allways the last one stored.
embeddedartists 0:6b68dac0d986 346 *
embeddedartists 0:6b68dac0d986 347 * Params:
embeddedartists 0:6b68dac0d986 348 * None
embeddedartists 0:6b68dac0d986 349 *
embeddedartists 0:6b68dac0d986 350 * Returns:
embeddedartists 0:6b68dac0d986 351 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 352 *
embeddedartists 0:6b68dac0d986 353 *****************************************************************************/
embeddedartists 0:6b68dac0d986 354 static fresult qspifs_readTOC(void)
embeddedartists 0:6b68dac0d986 355 {
embeddedartists 0:6b68dac0d986 356 int i, j;
embeddedartists 0:6b68dac0d986 357 toc_entry_t* p;
embeddedartists 0:6b68dac0d986 358 uint8_t invalid = 0;
embeddedartists 0:6b68dac0d986 359 int lastValid = -1;
embeddedartists 0:6b68dac0d986 360
embeddedartists 0:6b68dac0d986 361 // Search for the first unused TOC, keeping track of the valid
embeddedartists 0:6b68dac0d986 362 // ones as we go.
embeddedartists 0:6b68dac0d986 363 for (i = 0; (i < NUM_TOCS) && !invalid; i++)
embeddedartists 0:6b68dac0d986 364 {
embeddedartists 0:6b68dac0d986 365 p = (toc_entry_t*)(TOC_BLOCK_ADDR + i*TOC_SIZE);
embeddedartists 0:6b68dac0d986 366 for (j = 0; j < NUM_BLOCKS; j++)
embeddedartists 0:6b68dac0d986 367 {
embeddedartists 0:6b68dac0d986 368 if (!VALID_TOC_ENTRY(*p) || !MANDATORY_BITS_SET(*p))
embeddedartists 0:6b68dac0d986 369 {
embeddedartists 0:6b68dac0d986 370 // invalid TOC entry, stop looking
embeddedartists 0:6b68dac0d986 371 invalid = 1;
embeddedartists 0:6b68dac0d986 372 break;
embeddedartists 0:6b68dac0d986 373 }
embeddedartists 0:6b68dac0d986 374 p++;
embeddedartists 0:6b68dac0d986 375 }
embeddedartists 0:6b68dac0d986 376
embeddedartists 0:6b68dac0d986 377 if (!invalid)
embeddedartists 0:6b68dac0d986 378 {
embeddedartists 0:6b68dac0d986 379 // this TOC was ok, but perhaps there is a newer one?
embeddedartists 0:6b68dac0d986 380 lastValid = i;
embeddedartists 0:6b68dac0d986 381 }
embeddedartists 0:6b68dac0d986 382 }
embeddedartists 0:6b68dac0d986 383
embeddedartists 0:6b68dac0d986 384 if (lastValid == -1)
embeddedartists 0:6b68dac0d986 385 {
embeddedartists 0:6b68dac0d986 386 // no valid TOCs on the flash
embeddedartists 0:6b68dac0d986 387 return FS_ERR_NOT_FORMATTED;
embeddedartists 0:6b68dac0d986 388 }
embeddedartists 0:6b68dac0d986 389 else
embeddedartists 0:6b68dac0d986 390 {
embeddedartists 0:6b68dac0d986 391 // previous entry was ok so use that
embeddedartists 0:6b68dac0d986 392 activeTOC = lastValid;
embeddedartists 0:6b68dac0d986 393 p = (toc_entry_t*)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE);
embeddedartists 0:6b68dac0d986 394 memcpy(TOC, p, TOC_SIZE);
embeddedartists 0:6b68dac0d986 395 return FS_OK;
embeddedartists 0:6b68dac0d986 396 }
embeddedartists 0:6b68dac0d986 397 }
embeddedartists 0:6b68dac0d986 398
embeddedartists 0:6b68dac0d986 399 /******************************************************************************
embeddedartists 0:6b68dac0d986 400 *
embeddedartists 0:6b68dac0d986 401 * Description:
embeddedartists 0:6b68dac0d986 402 * Saves the table of contents (TOC). The TOC is stored in the last erase
embeddedartists 0:6b68dac0d986 403 * block on the QSPI flash. As the QSPI flash is not exactly RW (might
embeddedartists 0:6b68dac0d986 404 * require erasing before writing) the TOC is first compared with what is
embeddedartists 0:6b68dac0d986 405 * stored in the QSPI flash and if there are no changes or all changes
embeddedartists 0:6b68dac0d986 406 * only require bit changes 1->0 then the current TOC can be overwritten.
embeddedartists 0:6b68dac0d986 407 * If bit value changes 0->1 are required then the current stored TOC
embeddedartists 0:6b68dac0d986 408 * cannot be overwritten and the new TOC is instead stored in the next
embeddedartists 0:6b68dac0d986 409 * available space. If the entire last block is filled then it is erased
embeddedartists 0:6b68dac0d986 410 * and the new TOC is placed at the start of it.
embeddedartists 0:6b68dac0d986 411 *
embeddedartists 0:6b68dac0d986 412 * Params:
embeddedartists 0:6b68dac0d986 413 * None
embeddedartists 0:6b68dac0d986 414 *
embeddedartists 0:6b68dac0d986 415 * Returns:
embeddedartists 0:6b68dac0d986 416 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 417 *
embeddedartists 0:6b68dac0d986 418 *****************************************************************************/
embeddedartists 0:6b68dac0d986 419 static fresult qspifs_saveTOC(void)
embeddedartists 0:6b68dac0d986 420 {
embeddedartists 0:6b68dac0d986 421 int i, rc = 0;
embeddedartists 0:6b68dac0d986 422 uint32_t* pSrc;
embeddedartists 0:6b68dac0d986 423 uint32_t* pDest;
embeddedartists 0:6b68dac0d986 424 uint32_t tmp;
embeddedartists 0:6b68dac0d986 425 uint8_t identical = 1;
embeddedartists 0:6b68dac0d986 426
embeddedartists 0:6b68dac0d986 427 // active TOC same as the one we want to save?
embeddedartists 0:6b68dac0d986 428 pSrc = (uint32_t*)TOC;
embeddedartists 0:6b68dac0d986 429 pDest = (uint32_t*)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE);
embeddedartists 0:6b68dac0d986 430 for (i = 0; i < NUM_TOC_ENTRIES; i++)
embeddedartists 0:6b68dac0d986 431 {
embeddedartists 0:6b68dac0d986 432 if (*pSrc != *pDest)
embeddedartists 0:6b68dac0d986 433 {
embeddedartists 0:6b68dac0d986 434 identical = 0;
embeddedartists 0:6b68dac0d986 435 tmp = ((*pDest) ^ (*pSrc)) & (*pSrc);
embeddedartists 0:6b68dac0d986 436 if (tmp > 0)
embeddedartists 0:6b68dac0d986 437 {
embeddedartists 0:6b68dac0d986 438 // found a change that contains 0->1 bit modification which
embeddedartists 0:6b68dac0d986 439 // requires erasing or a new location
embeddedartists 0:6b68dac0d986 440 activeTOC = (activeTOC + 1)%NUM_TOCS;
embeddedartists 0:6b68dac0d986 441 if (activeTOC == 0)
embeddedartists 0:6b68dac0d986 442 {
embeddedartists 0:6b68dac0d986 443 // no more free TOCs so an erase is needed
embeddedartists 0:6b68dac0d986 444 #if 0
embeddedartists 0:6b68dac0d986 445 opers.options &= ~S_CALLER_ERASE;
embeddedartists 0:6b68dac0d986 446 opers.options |= S_FORCE_ERASE;
embeddedartists 0:6b68dac0d986 447 #else
embeddedartists 0:6b68dac0d986 448 opers.dest = (char *) TOC_BLOCK_ADDR;
embeddedartists 0:6b68dac0d986 449 opers.length = TOC_SIZE * NUM_TOCS;
embeddedartists 0:6b68dac0d986 450 opers.scratch = NULL;
embeddedartists 0:6b68dac0d986 451 opers.protect = 0;
embeddedartists 0:6b68dac0d986 452 opers.options = S_NO_VERIFY;
embeddedartists 0:6b68dac0d986 453 rc = spifi->spifi_erase(obj, &opers);
embeddedartists 0:6b68dac0d986 454 if (rc) {
embeddedartists 0:6b68dac0d986 455 return qspifs_translateSpifiError(rc);
embeddedartists 0:6b68dac0d986 456 }
embeddedartists 0:6b68dac0d986 457 #endif
embeddedartists 0:6b68dac0d986 458 }
embeddedartists 0:6b68dac0d986 459 break;
embeddedartists 0:6b68dac0d986 460 }
embeddedartists 0:6b68dac0d986 461 }
embeddedartists 0:6b68dac0d986 462 pSrc++;
embeddedartists 0:6b68dac0d986 463 pDest++;
embeddedartists 0:6b68dac0d986 464 }
embeddedartists 0:6b68dac0d986 465
embeddedartists 0:6b68dac0d986 466 if (!identical)
embeddedartists 0:6b68dac0d986 467 {
embeddedartists 0:6b68dac0d986 468 opers.length = FS_MIN(TOC_SIZE, PROG_SIZE);
embeddedartists 0:6b68dac0d986 469 opers.scratch = NULL;
embeddedartists 0:6b68dac0d986 470 opers.protect = 0;
embeddedartists 0:6b68dac0d986 471 opers.options = S_VERIFY_PROG | S_CALLER_ERASE;
embeddedartists 0:6b68dac0d986 472 for (int i = 0; i < (TOC_SIZE / PROG_SIZE); i++)
embeddedartists 0:6b68dac0d986 473 {
embeddedartists 0:6b68dac0d986 474 opers.dest = (char *)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE + i*PROG_SIZE);
embeddedartists 0:6b68dac0d986 475 rc = spifi->spifi_program(obj, ((char*)TOC)+i*PROG_SIZE, &opers);
embeddedartists 0:6b68dac0d986 476 if (rc)
embeddedartists 0:6b68dac0d986 477 {
embeddedartists 0:6b68dac0d986 478 break;
embeddedartists 0:6b68dac0d986 479 }
embeddedartists 0:6b68dac0d986 480 }
embeddedartists 0:6b68dac0d986 481 return qspifs_translateSpifiError(rc);
embeddedartists 0:6b68dac0d986 482 }
embeddedartists 0:6b68dac0d986 483 return FS_OK;
embeddedartists 0:6b68dac0d986 484 }
embeddedartists 0:6b68dac0d986 485
embeddedartists 0:6b68dac0d986 486 /******************************************************************************
embeddedartists 0:6b68dac0d986 487 *
embeddedartists 0:6b68dac0d986 488 * Description:
embeddedartists 0:6b68dac0d986 489 * Searches the file system for a file with the specified name and
embeddedartists 0:6b68dac0d986 490 * (if found) returns the file's position in the TOC.
embeddedartists 0:6b68dac0d986 491 *
embeddedartists 0:6b68dac0d986 492 * Note that the content of fh is only valid if FS_OK is returned.
embeddedartists 0:6b68dac0d986 493 *
embeddedartists 0:6b68dac0d986 494 * Params:
embeddedartists 0:6b68dac0d986 495 * [in] filename - The name of the file to find
embeddedartists 0:6b68dac0d986 496 * [out] fh - The handle with the file information
embeddedartists 0:6b68dac0d986 497 *
embeddedartists 0:6b68dac0d986 498 * Returns:
embeddedartists 0:6b68dac0d986 499 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 500 *
embeddedartists 0:6b68dac0d986 501 *****************************************************************************/
embeddedartists 0:6b68dac0d986 502 static fresult qspifs_findFile(const char* filename, fileHandle_t* fh)
embeddedartists 0:6b68dac0d986 503 {
embeddedartists 0:6b68dac0d986 504 int i;
embeddedartists 0:6b68dac0d986 505
embeddedartists 0:6b68dac0d986 506 if (activeTOC == -1)
embeddedartists 0:6b68dac0d986 507 {
embeddedartists 0:6b68dac0d986 508 return FS_ERR_NOT_FORMATTED;
embeddedartists 0:6b68dac0d986 509 }
embeddedartists 0:6b68dac0d986 510
embeddedartists 0:6b68dac0d986 511 // Look at all blocks except for the reserved ones
embeddedartists 0:6b68dac0d986 512 for (i = 0; i < NUM_BLOCKS; i++)
embeddedartists 0:6b68dac0d986 513 {
embeddedartists 0:6b68dac0d986 514 if (TOC_IS_FILE(TOC[i]) && !TOC_IS_RESERVED(TOC[i]))
embeddedartists 0:6b68dac0d986 515 {
embeddedartists 0:6b68dac0d986 516 // found a file, see if name matches
embeddedartists 0:6b68dac0d986 517 char* p = (char*)(SPIFI_MEM_BASE + i*ERASE_SIZE);
embeddedartists 0:6b68dac0d986 518 if (strncmp(filename, p, HEADER_FNAME_LEN) == 0)
embeddedartists 0:6b68dac0d986 519 {
embeddedartists 0:6b68dac0d986 520 // found a matching name
embeddedartists 0:6b68dac0d986 521 fh->tocIdx = i;
embeddedartists 0:6b68dac0d986 522 fresult res = qspifs_fileSize(fh->tocIdx, &fh->size);
embeddedartists 0:6b68dac0d986 523 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 524 fh->lastBlock = fh->tocIdx + ((fh->size + HEADER_LEN)/ ERASE_SIZE);
embeddedartists 0:6b68dac0d986 525 }
embeddedartists 0:6b68dac0d986 526 return FS_OK;
embeddedartists 0:6b68dac0d986 527 }
embeddedartists 0:6b68dac0d986 528 }
embeddedartists 0:6b68dac0d986 529 }
embeddedartists 0:6b68dac0d986 530 return FS_ERR_NO_FILE;
embeddedartists 0:6b68dac0d986 531 }
embeddedartists 0:6b68dac0d986 532
embeddedartists 0:6b68dac0d986 533 /******************************************************************************
embeddedartists 0:6b68dac0d986 534 *
embeddedartists 0:6b68dac0d986 535 * Description:
embeddedartists 0:6b68dac0d986 536 * Calculates and returns the file's size.
embeddedartists 0:6b68dac0d986 537 *
embeddedartists 0:6b68dac0d986 538 * Note that the content of pSize is only valid if FS_OK is returned.
embeddedartists 0:6b68dac0d986 539 *
embeddedartists 0:6b68dac0d986 540 * Params:
embeddedartists 0:6b68dac0d986 541 * [in] tocIdx - The file's position in the TOC
embeddedartists 0:6b68dac0d986 542 * [out] pSize - The file's size
embeddedartists 0:6b68dac0d986 543 *
embeddedartists 0:6b68dac0d986 544 * Returns:
embeddedartists 0:6b68dac0d986 545 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 546 *
embeddedartists 0:6b68dac0d986 547 *****************************************************************************/
embeddedartists 0:6b68dac0d986 548 static fresult qspifs_fileSize(int tocIdx, uint32_t* pSize)
embeddedartists 0:6b68dac0d986 549 {
embeddedartists 0:6b68dac0d986 550 int i;
embeddedartists 0:6b68dac0d986 551
embeddedartists 0:6b68dac0d986 552 if (tocIdx < 0 || tocIdx > NUM_BLOCKS || !TOC_IS_FILE(TOC[tocIdx]))
embeddedartists 0:6b68dac0d986 553 {
embeddedartists 0:6b68dac0d986 554 return FS_ERR_NO_FILE;
embeddedartists 0:6b68dac0d986 555 }
embeddedartists 0:6b68dac0d986 556
embeddedartists 0:6b68dac0d986 557 *pSize = 0;
embeddedartists 0:6b68dac0d986 558
embeddedartists 0:6b68dac0d986 559 // A file is always stored in sequential blocks so start with the files
embeddedartists 0:6b68dac0d986 560 // first block and as long as it is full continue sum up the occupied
embeddedartists 0:6b68dac0d986 561 // block sizes. As soon as a non-full block is found that must be the
embeddedartists 0:6b68dac0d986 562 // file's last block.
embeddedartists 0:6b68dac0d986 563 for (i = tocIdx; i < NUM_BLOCKS; i++)
embeddedartists 0:6b68dac0d986 564 {
embeddedartists 0:6b68dac0d986 565 *pSize += FILESIZE(TOC[i]);
embeddedartists 0:6b68dac0d986 566 if (FILESIZE(TOC[i]) < ERASE_SIZE)
embeddedartists 0:6b68dac0d986 567 {
embeddedartists 0:6b68dac0d986 568 // last block in chain
embeddedartists 0:6b68dac0d986 569 break;
embeddedartists 0:6b68dac0d986 570 }
embeddedartists 0:6b68dac0d986 571 }
embeddedartists 0:6b68dac0d986 572
embeddedartists 0:6b68dac0d986 573 // Remove the filename header from the file's size
embeddedartists 0:6b68dac0d986 574 *pSize -= HEADER_LEN;
embeddedartists 0:6b68dac0d986 575
embeddedartists 0:6b68dac0d986 576 return FS_OK;
embeddedartists 0:6b68dac0d986 577 }
embeddedartists 0:6b68dac0d986 578
embeddedartists 0:6b68dac0d986 579 /******************************************************************************
embeddedartists 0:6b68dac0d986 580 *
embeddedartists 0:6b68dac0d986 581 * Description:
embeddedartists 0:6b68dac0d986 582 * Erases everything in one block on the QSPI flash.
embeddedartists 0:6b68dac0d986 583 *
embeddedartists 0:6b68dac0d986 584 * Params:
embeddedartists 0:6b68dac0d986 585 * [in] block - The block's number
embeddedartists 0:6b68dac0d986 586 *
embeddedartists 0:6b68dac0d986 587 * Returns:
embeddedartists 0:6b68dac0d986 588 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 589 *
embeddedartists 0:6b68dac0d986 590 *****************************************************************************/
embeddedartists 0:6b68dac0d986 591 static fresult qspifs_eraseBlock(int block)
embeddedartists 0:6b68dac0d986 592 {
embeddedartists 0:6b68dac0d986 593 opers.dest = (char *)(block * ERASE_SIZE);
embeddedartists 0:6b68dac0d986 594 opers.length = ERASE_SIZE;
embeddedartists 0:6b68dac0d986 595 opers.scratch = NULL;
embeddedartists 0:6b68dac0d986 596 opers.protect = 0;
embeddedartists 0:6b68dac0d986 597 opers.options = S_NO_VERIFY;
embeddedartists 0:6b68dac0d986 598 return qspifs_translateSpifiError(spifi->spifi_erase (obj, &opers));
embeddedartists 0:6b68dac0d986 599 }
embeddedartists 0:6b68dac0d986 600
embeddedartists 0:6b68dac0d986 601 /******************************************************************************
embeddedartists 0:6b68dac0d986 602 *
embeddedartists 0:6b68dac0d986 603 * Description:
embeddedartists 0:6b68dac0d986 604 * Creates a new file if there is enough space for it on the file system.
embeddedartists 0:6b68dac0d986 605 * The TOC is searched for a unused sequence of blocks of at least the
embeddedartists 0:6b68dac0d986 606 * needed size. That block is marked as used and the file's name is stored
embeddedartists 0:6b68dac0d986 607 * in the first bytes of the file's first block.
embeddedartists 0:6b68dac0d986 608 *
embeddedartists 0:6b68dac0d986 609 * Note: The filename will not be tested for uniqueness.
embeddedartists 0:6b68dac0d986 610 * Note: The value of pTocIdx will only be valid if FS_OK is returned.
embeddedartists 0:6b68dac0d986 611 *
embeddedartists 0:6b68dac0d986 612 * Params:
embeddedartists 0:6b68dac0d986 613 * [in] filename - The name of the new file
embeddedartists 0:6b68dac0d986 614 * [in] neededBlocks - The number of blocks (in sequence) to allocate
embeddedartists 0:6b68dac0d986 615 * [out] pTocIdx - The new file's position in the TOC
embeddedartists 0:6b68dac0d986 616 *
embeddedartists 0:6b68dac0d986 617 * Returns:
embeddedartists 0:6b68dac0d986 618 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 619 *
embeddedartists 0:6b68dac0d986 620 *****************************************************************************/
embeddedartists 0:6b68dac0d986 621 static fresult qspifs_allocateFile(const char* filename, int neededBlocks, int* pTocIdx)
embeddedartists 0:6b68dac0d986 622 {
embeddedartists 0:6b68dac0d986 623 int i, rc;
embeddedartists 0:6b68dac0d986 624
embeddedartists 0:6b68dac0d986 625 if (activeTOC == -1)
embeddedartists 0:6b68dac0d986 626 {
embeddedartists 0:6b68dac0d986 627 return FS_ERR_NOT_FORMATTED;
embeddedartists 0:6b68dac0d986 628 }
embeddedartists 0:6b68dac0d986 629
embeddedartists 0:6b68dac0d986 630 // Look at all blocks except for the reserved ones
embeddedartists 0:6b68dac0d986 631 for (i = 0; i < NUM_BLOCKS; i++)
embeddedartists 0:6b68dac0d986 632 {
embeddedartists 0:6b68dac0d986 633 //TODO: Improve search to use gaps to avoid having to move files
embeddedartists 0:6b68dac0d986 634 // that are written to
embeddedartists 0:6b68dac0d986 635 if (!USED_TOC_ENTRY(TOC[i]) && !TOC_IS_RESERVED(TOC[i]))
embeddedartists 0:6b68dac0d986 636 {
embeddedartists 0:6b68dac0d986 637 int j;
embeddedartists 0:6b68dac0d986 638 for (j = 1; j < neededBlocks; j++)
embeddedartists 0:6b68dac0d986 639 {
embeddedartists 0:6b68dac0d986 640 if (USED_TOC_ENTRY(TOC[i+j]) || TOC_IS_RESERVED(TOC[i+j]))
embeddedartists 0:6b68dac0d986 641 {
embeddedartists 0:6b68dac0d986 642 // not enough free blocks in sequence, skip past these
embeddedartists 0:6b68dac0d986 643 // tested entries and continue searching
embeddedartists 0:6b68dac0d986 644 i += j;
embeddedartists 0:6b68dac0d986 645 break;
embeddedartists 0:6b68dac0d986 646 }
embeddedartists 0:6b68dac0d986 647 }
embeddedartists 0:6b68dac0d986 648
embeddedartists 0:6b68dac0d986 649 if (j == neededBlocks)
embeddedartists 0:6b68dac0d986 650 {
embeddedartists 0:6b68dac0d986 651 const char* pSrc = filename;
embeddedartists 0:6b68dac0d986 652 if (IS_ADDR_IN_SPIFI(filename))
embeddedartists 0:6b68dac0d986 653 {
embeddedartists 0:6b68dac0d986 654 // The SPIFI ROM driver cannot write data from SPIFI into
embeddedartists 0:6b68dac0d986 655 // SPIFI (i.e. cannot read and write at the same time).
embeddedartists 0:6b68dac0d986 656 // The workaround is to copy the source data into a buffer
embeddedartists 0:6b68dac0d986 657 // in local memory and use that as source for the write
embeddedartists 0:6b68dac0d986 658 // instead.
embeddedartists 0:6b68dac0d986 659 memcpy(addr_conflict_buff, filename, strlen(filename)+1);
embeddedartists 0:6b68dac0d986 660 pSrc = addr_conflict_buff;
embeddedartists 0:6b68dac0d986 661 }
embeddedartists 0:6b68dac0d986 662
embeddedartists 0:6b68dac0d986 663 // Erase the new file's first block and store the filename at the
embeddedartists 0:6b68dac0d986 664 // start of it
embeddedartists 0:6b68dac0d986 665 opers.length = strlen(pSrc)+1;
embeddedartists 0:6b68dac0d986 666 opers.scratch = NULL;
embeddedartists 0:6b68dac0d986 667 opers.protect = 0;
embeddedartists 0:6b68dac0d986 668 opers.options = S_VERIFY_PROG | S_FORCE_ERASE;// S_CALLER_ERASE;
embeddedartists 0:6b68dac0d986 669 opers.dest = (char *)(i*ERASE_SIZE);
embeddedartists 0:6b68dac0d986 670 rc = spifi->spifi_program(obj, (char*)pSrc, &opers);
embeddedartists 0:6b68dac0d986 671 if (rc) {
embeddedartists 0:6b68dac0d986 672 return qspifs_translateSpifiError(rc);
embeddedartists 0:6b68dac0d986 673 }
embeddedartists 0:6b68dac0d986 674
embeddedartists 0:6b68dac0d986 675 TOC[i] &= ~(TOC_VALID_MASK | TOC_USED_MASK | TOC_FILE_MASK | TOC_FSIZE_MASK);
embeddedartists 0:6b68dac0d986 676 TOC[i] |= HEADER_LEN;
embeddedartists 0:6b68dac0d986 677
embeddedartists 0:6b68dac0d986 678 *pTocIdx = i;
embeddedartists 0:6b68dac0d986 679 return FS_OK;
embeddedartists 0:6b68dac0d986 680 }
embeddedartists 0:6b68dac0d986 681 }
embeddedartists 0:6b68dac0d986 682 }
embeddedartists 0:6b68dac0d986 683 return FS_ERR_DISK_FULL;
embeddedartists 0:6b68dac0d986 684 }
embeddedartists 0:6b68dac0d986 685
embeddedartists 0:6b68dac0d986 686 /******************************************************************************
embeddedartists 0:6b68dac0d986 687 *
embeddedartists 0:6b68dac0d986 688 * Description:
embeddedartists 0:6b68dac0d986 689 * Deletes the specified file by marking all its blocks as unused in
embeddedartists 0:6b68dac0d986 690 * the TOC.
embeddedartists 0:6b68dac0d986 691 *
embeddedartists 0:6b68dac0d986 692 * Note: The deleted blocks are not erased here - that is done when they
embeddedartists 0:6b68dac0d986 693 * are allocated the next time.
embeddedartists 0:6b68dac0d986 694 *
embeddedartists 0:6b68dac0d986 695 * Params:
embeddedartists 0:6b68dac0d986 696 * [in] fh - The file handle with information about what to delete
embeddedartists 0:6b68dac0d986 697 *
embeddedartists 0:6b68dac0d986 698 * Returns:
embeddedartists 0:6b68dac0d986 699 * None
embeddedartists 0:6b68dac0d986 700 *
embeddedartists 0:6b68dac0d986 701 *****************************************************************************/
embeddedartists 0:6b68dac0d986 702 static void qspifs_deleteFile(fileHandle_t* fh)
embeddedartists 0:6b68dac0d986 703 {
embeddedartists 0:6b68dac0d986 704 int i;
embeddedartists 0:6b68dac0d986 705
embeddedartists 0:6b68dac0d986 706 for (i = fh->lastBlock; i >= fh->tocIdx; i--)
embeddedartists 0:6b68dac0d986 707 {
embeddedartists 0:6b68dac0d986 708 TOC[i] = ~TOC_VALID_MASK;
embeddedartists 0:6b68dac0d986 709 }
embeddedartists 0:6b68dac0d986 710 }
embeddedartists 0:6b68dac0d986 711
embeddedartists 0:6b68dac0d986 712 /******************************************************************************
embeddedartists 0:6b68dac0d986 713 *
embeddedartists 0:6b68dac0d986 714 * Description:
embeddedartists 0:6b68dac0d986 715 * Ensures that the specified file can grow to the wanted size.
embeddedartists 0:6b68dac0d986 716 * If the file size will increase enough to need one or more new blocks
embeddedartists 0:6b68dac0d986 717 * and there isn't enough space then an attempt is made to move the
embeddedartists 0:6b68dac0d986 718 * current file to a large enough space somewhere else.
embeddedartists 0:6b68dac0d986 719 *
embeddedartists 0:6b68dac0d986 720 * If there are more free block(s) at the end of the file then it is not
embeddedartists 0:6b68dac0d986 721 * moved and instead those blocks are marked as used.
embeddedartists 0:6b68dac0d986 722 *
embeddedartists 0:6b68dac0d986 723 * Note: The filename will not be tested for uniqueness.
embeddedartists 0:6b68dac0d986 724 * Note: The value of pTocIdx will only be valid if FS_OK is returned.
embeddedartists 0:6b68dac0d986 725 *
embeddedartists 0:6b68dac0d986 726 * Params:
embeddedartists 0:6b68dac0d986 727 * [in/out] fh - The current file handle, might be updated after a move
embeddedartists 0:6b68dac0d986 728 * [in] size - The wanted new size
embeddedartists 0:6b68dac0d986 729 *
embeddedartists 0:6b68dac0d986 730 * Returns:
embeddedartists 0:6b68dac0d986 731 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:6b68dac0d986 732 *
embeddedartists 0:6b68dac0d986 733 *****************************************************************************/
embeddedartists 0:6b68dac0d986 734 static fresult qspifs_allocateSpace(fileHandle_t* fh, uint32_t size)
embeddedartists 0:6b68dac0d986 735 {
embeddedartists 0:6b68dac0d986 736 uint16_t oldNumBlocks = (fh->size + HEADER_LEN) / ERASE_SIZE;
embeddedartists 0:6b68dac0d986 737 uint16_t newNumBlocks = (fh->size + HEADER_LEN + size) / ERASE_SIZE;
embeddedartists 0:6b68dac0d986 738 uint16_t numNeeded = newNumBlocks - oldNumBlocks;
embeddedartists 0:6b68dac0d986 739 fresult res = FS_OK;
embeddedartists 0:6b68dac0d986 740
embeddedartists 0:6b68dac0d986 741 if (numNeeded > 0)
embeddedartists 0:6b68dac0d986 742 {
embeddedartists 0:6b68dac0d986 743 uint16_t i;
embeddedartists 0:6b68dac0d986 744 for (i = 0; i < numNeeded; i++)
embeddedartists 0:6b68dac0d986 745 {
embeddedartists 0:6b68dac0d986 746 if (USED_TOC_ENTRY(TOC[fh->tocIdx + oldNumBlocks + 1 + i]) ||
embeddedartists 0:6b68dac0d986 747 TOC_IS_RESERVED(TOC[fh->tocIdx + oldNumBlocks + 1 + i]))
embeddedartists 0:6b68dac0d986 748 {
embeddedartists 0:6b68dac0d986 749 fileHandle_t fhNew;
embeddedartists 0:6b68dac0d986 750
embeddedartists 0:6b68dac0d986 751 // have to move the chain
embeddedartists 0:6b68dac0d986 752 char* filename = (char*)(SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE);
embeddedartists 0:6b68dac0d986 753 res = qspifs_allocateFile(filename, newNumBlocks, &(fhNew.tocIdx));
embeddedartists 0:6b68dac0d986 754 if (res == FS_OK)
embeddedartists 0:6b68dac0d986 755 {
embeddedartists 0:6b68dac0d986 756 // copy data
embeddedartists 0:6b68dac0d986 757 fhNew.lastBlock = fhNew.tocIdx;
embeddedartists 0:6b68dac0d986 758 fhNew.size = 0;
embeddedartists 0:6b68dac0d986 759 res = qspifs_write(&fhNew, (uint8_t*)(SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE + HEADER_LEN), fh->size);
embeddedartists 0:6b68dac0d986 760 }
embeddedartists 0:6b68dac0d986 761 if (res == FS_OK)
embeddedartists 0:6b68dac0d986 762 {
embeddedartists 0:6b68dac0d986 763 // remove old entries
embeddedartists 0:6b68dac0d986 764 qspifs_deleteFile(fh);
embeddedartists 0:6b68dac0d986 765
embeddedartists 0:6b68dac0d986 766 // modify old handle to point to new information
embeddedartists 0:6b68dac0d986 767 fh->lastBlock = fhNew.lastBlock;
embeddedartists 0:6b68dac0d986 768 fh->size = fhNew.size;
embeddedartists 0:6b68dac0d986 769 fh->tocIdx = fhNew.tocIdx;
embeddedartists 0:6b68dac0d986 770 }
embeddedartists 0:6b68dac0d986 771 if (res != FS_OK)
embeddedartists 0:6b68dac0d986 772 {
embeddedartists 0:6b68dac0d986 773 // not possible to relocate the file => abort
embeddedartists 0:6b68dac0d986 774 return res;
embeddedartists 0:6b68dac0d986 775 }
embeddedartists 0:6b68dac0d986 776 break;
embeddedartists 0:6b68dac0d986 777 }
embeddedartists 0:6b68dac0d986 778 }
embeddedartists 0:6b68dac0d986 779
embeddedartists 0:6b68dac0d986 780 // have space that is unused, so mark as used
embeddedartists 0:6b68dac0d986 781 for (i = 0; i < numNeeded; i++)
embeddedartists 0:6b68dac0d986 782 {
embeddedartists 0:6b68dac0d986 783 int tocIdx = fh->tocIdx + oldNumBlocks + 1 + i;
embeddedartists 0:6b68dac0d986 784 TOC[tocIdx] &= ~TOC_USED_MASK;
embeddedartists 0:6b68dac0d986 785 qspifs_eraseBlock(tocIdx);
embeddedartists 0:6b68dac0d986 786 }
embeddedartists 0:6b68dac0d986 787 }
embeddedartists 0:6b68dac0d986 788
embeddedartists 0:6b68dac0d986 789 return res;
embeddedartists 0:6b68dac0d986 790 }
embeddedartists 0:6b68dac0d986 791
embeddedartists 0:6b68dac0d986 792 /******************************************************************************
embeddedartists 0:6b68dac0d986 793 *
embeddedartists 0:6b68dac0d986 794 * Description:
embeddedartists 0:6b68dac0d986 795 * Adds a file system to the QSPI flash. The entire flash will be erase
embeddedartists 0:6b68dac0d986 796 * except for the minReservedBytes first bytes. That reserved area (rounded
embeddedartists 0:6b68dac0d986 797 * up to the closest even multiple of the erase block size) can be used
embeddedartists 0:6b68dac0d986 798 * for anything and will never be touched by the file system. That area is
embeddedartists 0:6b68dac0d986 799 * typically used for executing programs from when the internal flash is
embeddedartists 0:6b68dac0d986 800 * full.
embeddedartists 0:6b68dac0d986 801 *
embeddedartists 0:6b68dac0d986 802 * The file system will have a table of content (TOC) placed at the start
embeddedartists 0:6b68dac0d986 803 * of the last erase block on the flash.
embeddedartists 0:6b68dac0d986 804 *
embeddedartists 0:6b68dac0d986 805 * Params:
embeddedartists 0:6b68dac0d986 806 * [in] minReservedBytes - The number of bytes to ignore at the start of
embeddedartists 0:6b68dac0d986 807 * the flash.
embeddedartists 0:6b68dac0d986 808 *
embeddedartists 0:6b68dac0d986 809 * Returns:
embeddedartists 0:6b68dac0d986 810 * FS_OK on success or one of the FS_ERR_* on failure
embeddedartists 0:6b68dac0d986 811 *
embeddedartists 0:6b68dac0d986 812 *****************************************************************************/
embeddedartists 0:6b68dac0d986 813 static fresult qspifs_format(unsigned int minReservedBytes)
embeddedartists 0:6b68dac0d986 814 {
embeddedartists 0:6b68dac0d986 815 int i, rc;
embeddedartists 0:6b68dac0d986 816 int numReserved = 0;
embeddedartists 0:6b68dac0d986 817
embeddedartists 0:6b68dac0d986 818 if (minReservedBytes > 0) {
embeddedartists 0:6b68dac0d986 819 numReserved = (minReservedBytes + ERASE_SIZE - 1) / ERASE_SIZE;
embeddedartists 0:6b68dac0d986 820 if (numReserved >= (NUM_BLOCKS - 2)) {
embeddedartists 0:6b68dac0d986 821 // Too many of the erase blocks are reserved - not even room for one file
embeddedartists 0:6b68dac0d986 822 return FS_ERR_INVALID_PARAM;
embeddedartists 0:6b68dac0d986 823 }
embeddedartists 0:6b68dac0d986 824 }
embeddedartists 0:6b68dac0d986 825
embeddedartists 0:6b68dac0d986 826 #if 0 // works but is really slow
embeddedartists 0:6b68dac0d986 827 // Erase all non-reserved blocks
embeddedartists 0:6b68dac0d986 828 for (i = numReserved; i < NUM_BLOCKS; i++) {
embeddedartists 0:6b68dac0d986 829 opers.dest = (char *) (i * ERASE_SIZE);
embeddedartists 0:6b68dac0d986 830 opers.length = ERASE_SIZE;
embeddedartists 0:6b68dac0d986 831 opers.scratch = NULL;
embeddedartists 0:6b68dac0d986 832 opers.protect = 0;
embeddedartists 0:6b68dac0d986 833 opers.options = S_NO_VERIFY;
embeddedartists 0:6b68dac0d986 834 rc = spifi->spifi_erase(&obj, &opers);
embeddedartists 0:6b68dac0d986 835 if (rc) {
embeddedartists 0:6b68dac0d986 836 return qspifs_translateSpifiError(rc);
embeddedartists 0:6b68dac0d986 837 }
embeddedartists 0:6b68dac0d986 838 }
embeddedartists 0:6b68dac0d986 839 #else
embeddedartists 0:6b68dac0d986 840 // Erase all non-reserved blocks
embeddedartists 0:6b68dac0d986 841 opers.dest = (char *) (numReserved * ERASE_SIZE);
embeddedartists 0:6b68dac0d986 842 opers.length = MEM_SIZE - (numReserved * ERASE_SIZE);
embeddedartists 0:6b68dac0d986 843 opers.scratch = NULL;
embeddedartists 0:6b68dac0d986 844 opers.protect = 0;
embeddedartists 0:6b68dac0d986 845 opers.options = S_NO_VERIFY;
embeddedartists 0:6b68dac0d986 846 rc = spifi->spifi_erase(obj, &opers);
embeddedartists 0:6b68dac0d986 847 if (rc) {
embeddedartists 0:6b68dac0d986 848 return qspifs_translateSpifiError(rc);
embeddedartists 0:6b68dac0d986 849 }
embeddedartists 0:6b68dac0d986 850 #endif
embeddedartists 0:6b68dac0d986 851
embeddedartists 0:6b68dac0d986 852 // Create the TOC, mark requested blocks as reserved and mark the TOC's
embeddedartists 0:6b68dac0d986 853 // block(s) as reserved as well.
embeddedartists 0:6b68dac0d986 854 for (i = 0; i < numReserved; i++) {
embeddedartists 0:6b68dac0d986 855 TOC[i] = ~(TOC_VALID_MASK | TOC_RESERVED_MASK);
embeddedartists 0:6b68dac0d986 856 }
embeddedartists 0:6b68dac0d986 857 for (; i < (NUM_BLOCKS - NUM_TOC_BLOCKS); i++) {
embeddedartists 0:6b68dac0d986 858 TOC[i] = ~TOC_VALID_MASK;
embeddedartists 0:6b68dac0d986 859 }
embeddedartists 0:6b68dac0d986 860 for (; i < NUM_BLOCKS; i++) {
embeddedartists 0:6b68dac0d986 861 TOC[i] = ~(TOC_VALID_MASK | TOC_RESERVED_MASK);
embeddedartists 0:6b68dac0d986 862 }
embeddedartists 0:6b68dac0d986 863
embeddedartists 0:6b68dac0d986 864 // Save the TOC in the last block
embeddedartists 0:6b68dac0d986 865 activeTOC = 0;
embeddedartists 0:6b68dac0d986 866 fresult res = qspifs_saveTOC();
embeddedartists 0:6b68dac0d986 867 if (res != FS_OK) {
embeddedartists 0:6b68dac0d986 868 activeTOC = -1;
embeddedartists 0:6b68dac0d986 869 return res;
embeddedartists 0:6b68dac0d986 870 }
embeddedartists 0:6b68dac0d986 871 // opers.dest = (char *) TOC_BLOCK_ADDR;
embeddedartists 0:6b68dac0d986 872 // opers.length = TOC_SIZE;
embeddedartists 0:6b68dac0d986 873 // opers.scratch = NULL;
embeddedartists 0:6b68dac0d986 874 // opers.protect = 0;
embeddedartists 0:6b68dac0d986 875 // opers.options = S_VERIFY_PROG | S_CALLER_ERASE;
embeddedartists 0:6b68dac0d986 876 // rc = spifi->spifi_program(&obj, (char*) TOC, &opers);
embeddedartists 0:6b68dac0d986 877 // if (rc) {
embeddedartists 0:6b68dac0d986 878 // return qspifs_translateSpifiError(rc);
embeddedartists 0:6b68dac0d986 879 // }
embeddedartists 0:6b68dac0d986 880
embeddedartists 0:6b68dac0d986 881 // Read back TOC to be sure it worked
embeddedartists 0:6b68dac0d986 882 return qspifs_readTOC();
embeddedartists 0:6b68dac0d986 883 }
embeddedartists 0:6b68dac0d986 884
embeddedartists 0:6b68dac0d986 885 /******************************************************************************
embeddedartists 0:6b68dac0d986 886 *
embeddedartists 0:6b68dac0d986 887 * Description:
embeddedartists 0:6b68dac0d986 888 * Deletes all files on the file system. This is a "quick format" that
embeddedartists 0:6b68dac0d986 889 * leaves all blocks untouched and only modifies the TOC. Any reserved
embeddedartists 0:6b68dac0d986 890 * blocks are kept reserved.
embeddedartists 0:6b68dac0d986 891 *
embeddedartists 0:6b68dac0d986 892 * The purpose of this function is to make it easy to clear the file system
embeddedartists 0:6b68dac0d986 893 * without going through a time consuming complete erase every time.
embeddedartists 0:6b68dac0d986 894 *
embeddedartists 0:6b68dac0d986 895 * Params:
embeddedartists 0:6b68dac0d986 896 * None
embeddedartists 0:6b68dac0d986 897 *
embeddedartists 0:6b68dac0d986 898 * Returns:
embeddedartists 0:6b68dac0d986 899 * FS_OK on success or one of the FS_ERR_* on failure
embeddedartists 0:6b68dac0d986 900 *
embeddedartists 0:6b68dac0d986 901 *****************************************************************************/
embeddedartists 0:6b68dac0d986 902 // static fresult qspifs_deleteAllFiles(void)
embeddedartists 0:6b68dac0d986 903 // {
embeddedartists 0:6b68dac0d986 904 // for (int i = 0; i < NUM_BLOCKS; i++)
embeddedartists 0:6b68dac0d986 905 // {
embeddedartists 0:6b68dac0d986 906 // if (!TOC_IS_RESERVED(TOC[i])) {
embeddedartists 0:6b68dac0d986 907 // TOC[i] = ~TOC_VALID_MASK;
embeddedartists 0:6b68dac0d986 908 // }
embeddedartists 0:6b68dac0d986 909 // }
embeddedartists 0:6b68dac0d986 910 //
embeddedartists 0:6b68dac0d986 911 // return qspifs_saveTOC();
embeddedartists 0:6b68dac0d986 912 // }
embeddedartists 0:6b68dac0d986 913
embeddedartists 0:6b68dac0d986 914 /******************************************************************************
embeddedartists 0:6b68dac0d986 915 *
embeddedartists 0:6b68dac0d986 916 * Description:
embeddedartists 0:6b68dac0d986 917 * Appends the data to the end of the file.
embeddedartists 0:6b68dac0d986 918 *
embeddedartists 0:6b68dac0d986 919 * Params:
embeddedartists 0:6b68dac0d986 920 * [in] fh - The handle to the file as returned from fs_open_append()
embeddedartists 0:6b68dac0d986 921 * [in] pData - The data to save
embeddedartists 0:6b68dac0d986 922 * [in] size - Number of bytes to save
embeddedartists 0:6b68dac0d986 923 *
embeddedartists 0:6b68dac0d986 924 * Returns:
embeddedartists 0:6b68dac0d986 925 * FS_OK on success or one of the FS_ERR_* on failure
embeddedartists 0:6b68dac0d986 926 *
embeddedartists 0:6b68dac0d986 927 *****************************************************************************/
embeddedartists 0:6b68dac0d986 928 static fresult qspifs_write(fileHandle_t* fh, const uint8_t * const pData, uint32_t size)
embeddedartists 0:6b68dac0d986 929 {
embeddedartists 0:6b68dac0d986 930 uint32_t left = size;
embeddedartists 0:6b68dac0d986 931 const uint8_t* pSrc = pData;
embeddedartists 0:6b68dac0d986 932 int rc, i;
embeddedartists 0:6b68dac0d986 933 fresult res;
embeddedartists 0:6b68dac0d986 934 int failed_attempts = 0;
embeddedartists 0:6b68dac0d986 935
embeddedartists 0:6b68dac0d986 936 do {
embeddedartists 0:6b68dac0d986 937 res = qspifs_allocateSpace(fh, size);
embeddedartists 0:6b68dac0d986 938 if (res != FS_OK) {
embeddedartists 0:6b68dac0d986 939 break;
embeddedartists 0:6b68dac0d986 940 }
embeddedartists 0:6b68dac0d986 941
embeddedartists 0:6b68dac0d986 942 opers.dest = (char *) (SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE
embeddedartists 0:6b68dac0d986 943 + HEADER_LEN + fh->size);
embeddedartists 0:6b68dac0d986 944 opers.scratch = NULL;
embeddedartists 0:6b68dac0d986 945 opers.protect = 0;
embeddedartists 0:6b68dac0d986 946 opers.options = S_VERIFY_PROG; // | S_FORCE_ERASE;
embeddedartists 0:6b68dac0d986 947
embeddedartists 0:6b68dac0d986 948 while ((res == FS_OK) && (left > 0)) {
embeddedartists 0:6b68dac0d986 949 if (left >= PROG_SIZE) {
embeddedartists 0:6b68dac0d986 950 opers.length = PROG_SIZE;
embeddedartists 0:6b68dac0d986 951 } else {
embeddedartists 0:6b68dac0d986 952 opers.length = left;
embeddedartists 0:6b68dac0d986 953 }
embeddedartists 0:6b68dac0d986 954 if (IS_ADDR_IN_SPIFI(pData)) {
embeddedartists 0:6b68dac0d986 955 memcpy(addr_conflict_buff, pSrc, opers.length);
embeddedartists 0:6b68dac0d986 956 rc = spifi->spifi_program(obj, addr_conflict_buff, &opers);
embeddedartists 0:6b68dac0d986 957 } else {
embeddedartists 0:6b68dac0d986 958 rc = spifi->spifi_program(obj, (char*) pSrc, &opers);
embeddedartists 0:6b68dac0d986 959 }
embeddedartists 0:6b68dac0d986 960 res = qspifs_translateSpifiError(rc);
embeddedartists 0:6b68dac0d986 961 if ((res == FS_ERR_SPIFI_VERIFICATION)
embeddedartists 0:6b68dac0d986 962 && (++failed_attempts <= NUM_VERIFICATION_ATTEMPTS)) {
embeddedartists 0:6b68dac0d986 963 // The verification process failed.
embeddedartists 0:6b68dac0d986 964 // In all the observed occasions re-running the exact same
embeddedartists 0:6b68dac0d986 965 // spifi_program command again yielded a 0 as a return value
embeddedartists 0:6b68dac0d986 966 // the second time.
embeddedartists 0:6b68dac0d986 967 // The quick'N'dirty fix is to re-run that program instruction
embeddedartists 0:6b68dac0d986 968 // NUM_VERIFICATION_ATTEMPTS more time(s) when this happens.
embeddedartists 0:6b68dac0d986 969 res = FS_OK;
embeddedartists 0:6b68dac0d986 970 continue;
embeddedartists 0:6b68dac0d986 971 }
embeddedartists 0:6b68dac0d986 972 if (res != FS_OK) {
embeddedartists 0:6b68dac0d986 973 // Got an error but cannot exit this function here as parts of the data
embeddedartists 0:6b68dac0d986 974 // (previous loops?) may have been written so the TOC must be updated.
embeddedartists 0:6b68dac0d986 975 break;
embeddedartists 0:6b68dac0d986 976 }
embeddedartists 0:6b68dac0d986 977 pSrc += opers.length;
embeddedartists 0:6b68dac0d986 978 opers.dest += opers.length;
embeddedartists 0:6b68dac0d986 979 left -= opers.length;
embeddedartists 0:6b68dac0d986 980 failed_attempts = 0;
embeddedartists 0:6b68dac0d986 981 }
embeddedartists 0:6b68dac0d986 982
embeddedartists 0:6b68dac0d986 983 // update file information
embeddedartists 0:6b68dac0d986 984 fh->size = fh->size + size - left;
embeddedartists 0:6b68dac0d986 985 fh->lastBlock = fh->tocIdx + ((fh->size + HEADER_LEN)/ ERASE_SIZE);
embeddedartists 0:6b68dac0d986 986 left = fh->size + HEADER_LEN;
embeddedartists 0:6b68dac0d986 987 for (i = 0; i <= (fh->lastBlock - fh->tocIdx); i++) {
embeddedartists 0:6b68dac0d986 988 TOC[fh->tocIdx + i] &= ~TOC_FSIZE_MASK;
embeddedartists 0:6b68dac0d986 989 TOC[fh->tocIdx + i] |= FS_MIN(ERASE_SIZE, left);
embeddedartists 0:6b68dac0d986 990 left -= FILESIZE(TOC[fh->tocIdx + i]);
embeddedartists 0:6b68dac0d986 991 }
embeddedartists 0:6b68dac0d986 992
embeddedartists 0:6b68dac0d986 993 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 994 res = qspifs_saveTOC();
embeddedartists 0:6b68dac0d986 995 } else {
embeddedartists 0:6b68dac0d986 996 // Want to save the TOC but not overwrite the previous error with
embeddedartists 0:6b68dac0d986 997 // a possibly successful TOC saving thus making it seem like there
embeddedartists 0:6b68dac0d986 998 // was no error
embeddedartists 0:6b68dac0d986 999 qspifs_saveTOC();
embeddedartists 0:6b68dac0d986 1000 }
embeddedartists 0:6b68dac0d986 1001 } while (0);
embeddedartists 0:6b68dac0d986 1002
embeddedartists 0:6b68dac0d986 1003 return res;
embeddedartists 0:6b68dac0d986 1004 }
embeddedartists 0:6b68dac0d986 1005
embeddedartists 0:6b68dac0d986 1006 /******************************************************************************
embeddedartists 0:6b68dac0d986 1007 *
embeddedartists 0:6b68dac0d986 1008 * Description:
embeddedartists 0:6b68dac0d986 1009 * Tests if str starts with prefix. A prefix of NULL or an empty string
embeddedartists 0:6b68dac0d986 1010 * results in a positive result regardless of the content of str.
embeddedartists 0:6b68dac0d986 1011 *
embeddedartists 0:6b68dac0d986 1012 * Params:
embeddedartists 0:6b68dac0d986 1013 * [in] prefix - The prefix to look for
embeddedartists 0:6b68dac0d986 1014 * [in] str - The string to search for prefix
embeddedartists 0:6b68dac0d986 1015 *
embeddedartists 0:6b68dac0d986 1016 * Returns:
embeddedartists 0:6b68dac0d986 1017 * True if the specified string starts with prefix
embeddedartists 0:6b68dac0d986 1018 *
embeddedartists 0:6b68dac0d986 1019 *****************************************************************************/
embeddedartists 0:6b68dac0d986 1020 static bool qspifs_startsWith(const char* prefix, const char* str)
embeddedartists 0:6b68dac0d986 1021 {
embeddedartists 0:6b68dac0d986 1022 const char* pA = prefix;
embeddedartists 0:6b68dac0d986 1023 const char* pB = str;
embeddedartists 0:6b68dac0d986 1024
embeddedartists 0:6b68dac0d986 1025 if (pA == NULL)
embeddedartists 0:6b68dac0d986 1026 {
embeddedartists 0:6b68dac0d986 1027 return true;
embeddedartists 0:6b68dac0d986 1028 }
embeddedartists 0:6b68dac0d986 1029 for (; *pA != '\0'; pA++, pB++)
embeddedartists 0:6b68dac0d986 1030 {
embeddedartists 0:6b68dac0d986 1031 if (*pB != *pA)
embeddedartists 0:6b68dac0d986 1032 {
embeddedartists 0:6b68dac0d986 1033 return false;
embeddedartists 0:6b68dac0d986 1034 }
embeddedartists 0:6b68dac0d986 1035 }
embeddedartists 0:6b68dac0d986 1036
embeddedartists 0:6b68dac0d986 1037 return true;
embeddedartists 0:6b68dac0d986 1038 }
embeddedartists 0:6b68dac0d986 1039
embeddedartists 0:6b68dac0d986 1040 /******************************************************************************
embeddedartists 0:6b68dac0d986 1041 * Class Declarations
embeddedartists 0:6b68dac0d986 1042 *****************************************************************************/
embeddedartists 0:6b68dac0d986 1043
embeddedartists 0:6b68dac0d986 1044 class QSPIFileHandle : public FileHandle {
embeddedartists 0:6b68dac0d986 1045
embeddedartists 0:6b68dac0d986 1046 public:
embeddedartists 0:6b68dac0d986 1047 QSPIFileHandle(fileHandle_t* handle, int flags);
embeddedartists 0:6b68dac0d986 1048
embeddedartists 0:6b68dac0d986 1049 virtual int close();
embeddedartists 0:6b68dac0d986 1050
embeddedartists 0:6b68dac0d986 1051 virtual ssize_t write(const void *buffer, size_t length);
embeddedartists 0:6b68dac0d986 1052
embeddedartists 0:6b68dac0d986 1053 virtual ssize_t read(void *buffer, size_t length);
embeddedartists 0:6b68dac0d986 1054
embeddedartists 0:6b68dac0d986 1055 virtual int isatty();
embeddedartists 0:6b68dac0d986 1056
embeddedartists 0:6b68dac0d986 1057 virtual off_t lseek(off_t position, int whence);
embeddedartists 0:6b68dac0d986 1058
embeddedartists 0:6b68dac0d986 1059 virtual int fsync();
embeddedartists 0:6b68dac0d986 1060
embeddedartists 0:6b68dac0d986 1061 virtual off_t flen();
embeddedartists 0:6b68dac0d986 1062
embeddedartists 0:6b68dac0d986 1063 protected:
embeddedartists 0:6b68dac0d986 1064
embeddedartists 0:6b68dac0d986 1065 fileHandle_t fh;
embeddedartists 0:6b68dac0d986 1066 bool allowReading;
embeddedartists 0:6b68dac0d986 1067 bool allowWriting;
embeddedartists 0:6b68dac0d986 1068 uint32_t pos;
embeddedartists 0:6b68dac0d986 1069 };
embeddedartists 0:6b68dac0d986 1070
embeddedartists 0:6b68dac0d986 1071 class QSPIDirHandle : public DirHandle {
embeddedartists 0:6b68dac0d986 1072
embeddedartists 0:6b68dac0d986 1073 public:
embeddedartists 0:6b68dac0d986 1074 static QSPIDirHandle* openDir(const char* dirname);
embeddedartists 0:6b68dac0d986 1075
embeddedartists 0:6b68dac0d986 1076 virtual ~QSPIDirHandle();
embeddedartists 0:6b68dac0d986 1077
embeddedartists 0:6b68dac0d986 1078 virtual int closedir();
embeddedartists 0:6b68dac0d986 1079 virtual struct dirent *readdir();
embeddedartists 0:6b68dac0d986 1080 virtual void rewinddir();
embeddedartists 0:6b68dac0d986 1081
embeddedartists 0:6b68dac0d986 1082 private:
embeddedartists 0:6b68dac0d986 1083 QSPIDirHandle(const char* dirname);
embeddedartists 0:6b68dac0d986 1084
embeddedartists 0:6b68dac0d986 1085 int findFileWithPrefix(const char* prefix, int startTOCIdx, int maxTOCIdx) const;
embeddedartists 0:6b68dac0d986 1086
embeddedartists 0:6b68dac0d986 1087 protected:
embeddedartists 0:6b68dac0d986 1088
embeddedartists 0:6b68dac0d986 1089 char* dirname;
embeddedartists 0:6b68dac0d986 1090 int nextTocIdx;
embeddedartists 0:6b68dac0d986 1091
embeddedartists 0:6b68dac0d986 1092 bool isRoot;
embeddedartists 0:6b68dac0d986 1093
embeddedartists 0:6b68dac0d986 1094 struct dirent cur_entry;
embeddedartists 0:6b68dac0d986 1095 };
embeddedartists 0:6b68dac0d986 1096
embeddedartists 0:6b68dac0d986 1097 /******************************************************************************
embeddedartists 0:6b68dac0d986 1098 * Class Implementations
embeddedartists 0:6b68dac0d986 1099 *****************************************************************************/
embeddedartists 0:6b68dac0d986 1100
embeddedartists 0:6b68dac0d986 1101 QSPIFileHandle::QSPIFileHandle(fileHandle_t* handle, int flags)
embeddedartists 0:6b68dac0d986 1102 {
embeddedartists 0:6b68dac0d986 1103 fh = *handle;
embeddedartists 0:6b68dac0d986 1104 int accmode = (flags & O_ACCMODE);
embeddedartists 0:6b68dac0d986 1105 allowReading = (accmode == O_RDONLY) || (accmode == O_RDWR);
embeddedartists 0:6b68dac0d986 1106 allowWriting = (accmode == O_WRONLY) || (accmode == O_RDWR) || (flags & O_APPEND);
embeddedartists 0:6b68dac0d986 1107 pos = 0;
embeddedartists 0:6b68dac0d986 1108 }
embeddedartists 0:6b68dac0d986 1109
embeddedartists 0:6b68dac0d986 1110 int QSPIFileHandle::close()
embeddedartists 0:6b68dac0d986 1111 {
embeddedartists 0:6b68dac0d986 1112 delete this;
embeddedartists 0:6b68dac0d986 1113 return 0;
embeddedartists 0:6b68dac0d986 1114 }
embeddedartists 0:6b68dac0d986 1115
embeddedartists 0:6b68dac0d986 1116 ssize_t QSPIFileHandle::write(const void *buffer, size_t length)
embeddedartists 0:6b68dac0d986 1117 {
embeddedartists 0:6b68dac0d986 1118 if (!allowWriting) {
embeddedartists 0:6b68dac0d986 1119 return -1;
embeddedartists 0:6b68dac0d986 1120 }
embeddedartists 0:6b68dac0d986 1121 fresult res = qspifs_write(&fh, (const uint8_t*)buffer, length);
embeddedartists 0:6b68dac0d986 1122 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1123 // A write is always 'append' in this file system so the file
embeddedartists 0:6b68dac0d986 1124 // position is always end of file after a write
embeddedartists 0:6b68dac0d986 1125 pos = fh.size;
embeddedartists 0:6b68dac0d986 1126 return length;
embeddedartists 0:6b68dac0d986 1127 }
embeddedartists 0:6b68dac0d986 1128 return -1;
embeddedartists 0:6b68dac0d986 1129 }
embeddedartists 0:6b68dac0d986 1130
embeddedartists 0:6b68dac0d986 1131 ssize_t QSPIFileHandle::read(void *buffer, size_t length)
embeddedartists 0:6b68dac0d986 1132 {
embeddedartists 0:6b68dac0d986 1133 if (!allowReading) {
embeddedartists 0:6b68dac0d986 1134 return -1;
embeddedartists 0:6b68dac0d986 1135 }
embeddedartists 0:6b68dac0d986 1136 if (pos >= fh.size) {
embeddedartists 0:6b68dac0d986 1137 return 0;
embeddedartists 0:6b68dac0d986 1138 }
embeddedartists 0:6b68dac0d986 1139 uint32_t len = FS_MIN(length, fh.size - pos);
embeddedartists 0:6b68dac0d986 1140 const char* pData = (const char*)(SPIFI_MEM_BASE + fh.tocIdx*ERASE_SIZE + HEADER_LEN + pos);
embeddedartists 0:6b68dac0d986 1141 memcpy(buffer, pData, len);
embeddedartists 0:6b68dac0d986 1142 pos += len;
embeddedartists 0:6b68dac0d986 1143 return len;
embeddedartists 0:6b68dac0d986 1144 }
embeddedartists 0:6b68dac0d986 1145
embeddedartists 0:6b68dac0d986 1146 int QSPIFileHandle::isatty()
embeddedartists 0:6b68dac0d986 1147 {
embeddedartists 0:6b68dac0d986 1148 return 0;
embeddedartists 0:6b68dac0d986 1149 }
embeddedartists 0:6b68dac0d986 1150
embeddedartists 0:6b68dac0d986 1151 off_t QSPIFileHandle::lseek(off_t position, int whence)
embeddedartists 0:6b68dac0d986 1152 {
embeddedartists 0:6b68dac0d986 1153 switch (whence) {
embeddedartists 0:6b68dac0d986 1154 case SEEK_SET:
embeddedartists 0:6b68dac0d986 1155 pos = position;
embeddedartists 0:6b68dac0d986 1156 break;
embeddedartists 0:6b68dac0d986 1157
embeddedartists 0:6b68dac0d986 1158 case SEEK_CUR:
embeddedartists 0:6b68dac0d986 1159 pos += position;
embeddedartists 0:6b68dac0d986 1160 break;
embeddedartists 0:6b68dac0d986 1161
embeddedartists 0:6b68dac0d986 1162 case SEEK_END:
embeddedartists 0:6b68dac0d986 1163 pos = fh.size + position;
embeddedartists 0:6b68dac0d986 1164 break;
embeddedartists 0:6b68dac0d986 1165
embeddedartists 0:6b68dac0d986 1166 default:
embeddedartists 0:6b68dac0d986 1167 return -1;
embeddedartists 0:6b68dac0d986 1168 }
embeddedartists 0:6b68dac0d986 1169 return pos;
embeddedartists 0:6b68dac0d986 1170 }
embeddedartists 0:6b68dac0d986 1171
embeddedartists 0:6b68dac0d986 1172 int QSPIFileHandle::fsync()
embeddedartists 0:6b68dac0d986 1173 {
embeddedartists 0:6b68dac0d986 1174 return 0; // always synced
embeddedartists 0:6b68dac0d986 1175 }
embeddedartists 0:6b68dac0d986 1176
embeddedartists 0:6b68dac0d986 1177 off_t QSPIFileHandle::flen()
embeddedartists 0:6b68dac0d986 1178 {
embeddedartists 0:6b68dac0d986 1179 return fh.size;
embeddedartists 0:6b68dac0d986 1180 }
embeddedartists 0:6b68dac0d986 1181
embeddedartists 0:6b68dac0d986 1182 QSPIDirHandle::QSPIDirHandle(const char* dirname) {
embeddedartists 0:6b68dac0d986 1183 size_t len = strlen(dirname);
embeddedartists 0:6b68dac0d986 1184 this->dirname = (char*)malloc(len + 2); // null termination and possible ending '/'
embeddedartists 0:6b68dac0d986 1185 if (this->dirname != NULL) {
embeddedartists 0:6b68dac0d986 1186 if (len == 0 || ((len == 1) && (dirname[0] == '/'))) {
embeddedartists 0:6b68dac0d986 1187 isRoot = true;
embeddedartists 0:6b68dac0d986 1188 this->dirname[0] = '\0';
embeddedartists 0:6b68dac0d986 1189 } else {
embeddedartists 0:6b68dac0d986 1190 isRoot = false;
embeddedartists 0:6b68dac0d986 1191 memcpy(this->dirname, dirname, len+1);
embeddedartists 0:6b68dac0d986 1192 if (dirname[len - 1] != '/') {
embeddedartists 0:6b68dac0d986 1193 this->dirname[len] = '/';
embeddedartists 0:6b68dac0d986 1194 this->dirname[len+1] = '\0';
embeddedartists 0:6b68dac0d986 1195 }
embeddedartists 0:6b68dac0d986 1196 }
embeddedartists 0:6b68dac0d986 1197 cur_entry.d_name[HEADER_FNAME_STRLEN] = '\0';
embeddedartists 0:6b68dac0d986 1198 rewinddir();
embeddedartists 0:6b68dac0d986 1199 }
embeddedartists 0:6b68dac0d986 1200 }
embeddedartists 0:6b68dac0d986 1201
embeddedartists 0:6b68dac0d986 1202 QSPIDirHandle::~QSPIDirHandle()
embeddedartists 0:6b68dac0d986 1203 {
embeddedartists 0:6b68dac0d986 1204 if (dirname != NULL) {
embeddedartists 0:6b68dac0d986 1205 delete dirname;
embeddedartists 0:6b68dac0d986 1206 dirname = NULL;
embeddedartists 0:6b68dac0d986 1207 }
embeddedartists 0:6b68dac0d986 1208 }
embeddedartists 0:6b68dac0d986 1209
embeddedartists 0:6b68dac0d986 1210 QSPIDirHandle* QSPIDirHandle::openDir(const char* dirname)
embeddedartists 0:6b68dac0d986 1211 {
embeddedartists 0:6b68dac0d986 1212 QSPIDirHandle* d = new QSPIDirHandle(dirname);
embeddedartists 0:6b68dac0d986 1213 if (d->dirname == NULL) {
embeddedartists 0:6b68dac0d986 1214 // failed to allocate memory for the folder name
embeddedartists 0:6b68dac0d986 1215 delete d;
embeddedartists 0:6b68dac0d986 1216 d = NULL;
embeddedartists 0:6b68dac0d986 1217 } else if (!d->isRoot) {
embeddedartists 0:6b68dac0d986 1218 if (d->findFileWithPrefix(d->dirname, 0, NUM_BLOCKS) == NUM_BLOCKS) {
embeddedartists 0:6b68dac0d986 1219 // There are no files in this directory, i.e. it does not exist
embeddedartists 0:6b68dac0d986 1220 delete d;
embeddedartists 0:6b68dac0d986 1221 d = NULL;
embeddedartists 0:6b68dac0d986 1222 }
embeddedartists 0:6b68dac0d986 1223 }
embeddedartists 0:6b68dac0d986 1224 return d;
embeddedartists 0:6b68dac0d986 1225 }
embeddedartists 0:6b68dac0d986 1226
embeddedartists 0:6b68dac0d986 1227 int QSPIDirHandle::closedir() {
embeddedartists 0:6b68dac0d986 1228 delete this;
embeddedartists 0:6b68dac0d986 1229 return 0;
embeddedartists 0:6b68dac0d986 1230 }
embeddedartists 0:6b68dac0d986 1231
embeddedartists 0:6b68dac0d986 1232 int QSPIDirHandle::findFileWithPrefix(const char* prefix, int startTOCIdx, int maxTOCIdx) const
embeddedartists 0:6b68dac0d986 1233 {
embeddedartists 0:6b68dac0d986 1234 for (int i = startTOCIdx; i < maxTOCIdx; i++) {
embeddedartists 0:6b68dac0d986 1235 if (TOC_IS_FILE(TOC[i])) {
embeddedartists 0:6b68dac0d986 1236 const char* filename = (const char*) (SPIFI_MEM_BASE + i * ERASE_SIZE);
embeddedartists 0:6b68dac0d986 1237 if (qspifs_startsWith(prefix, filename)) {
embeddedartists 0:6b68dac0d986 1238 return i;
embeddedartists 0:6b68dac0d986 1239 }
embeddedartists 0:6b68dac0d986 1240 }
embeddedartists 0:6b68dac0d986 1241 }
embeddedartists 0:6b68dac0d986 1242 return NUM_BLOCKS; // no match
embeddedartists 0:6b68dac0d986 1243 }
embeddedartists 0:6b68dac0d986 1244
embeddedartists 0:6b68dac0d986 1245
embeddedartists 0:6b68dac0d986 1246 struct dirent *QSPIDirHandle::readdir() {
embeddedartists 0:6b68dac0d986 1247 if (nextTocIdx < NUM_BLOCKS) {
embeddedartists 0:6b68dac0d986 1248 for (int i = nextTocIdx; i < NUM_BLOCKS; i++) {
embeddedartists 0:6b68dac0d986 1249 int possible = findFileWithPrefix(dirname, i, NUM_BLOCKS);
embeddedartists 0:6b68dac0d986 1250 if (possible < NUM_BLOCKS) {
embeddedartists 0:6b68dac0d986 1251 const char* fullfilename = (const char*) (SPIFI_MEM_BASE + possible * ERASE_SIZE);
embeddedartists 0:6b68dac0d986 1252 const char* filename = fullfilename + strlen(dirname);
embeddedartists 0:6b68dac0d986 1253
embeddedartists 0:6b68dac0d986 1254 if (strchr(filename, '/') == NULL) {
embeddedartists 0:6b68dac0d986 1255 // file is not in any sub folder so it is truly in the wanted dir
embeddedartists 0:6b68dac0d986 1256 nextTocIdx = possible + 1;
embeddedartists 0:6b68dac0d986 1257 strcpy(cur_entry.d_name, filename);
embeddedartists 0:6b68dac0d986 1258 return &cur_entry;
embeddedartists 0:6b68dac0d986 1259 }
embeddedartists 0:6b68dac0d986 1260
embeddedartists 0:6b68dac0d986 1261 // this is a file in a subfolder and should not be reported,
embeddedartists 0:6b68dac0d986 1262 // but the folder name itself should
embeddedartists 0:6b68dac0d986 1263 strcpy(cur_entry.d_name, fullfilename);
embeddedartists 0:6b68dac0d986 1264 char* pSlash = strchr(cur_entry.d_name + strlen(dirname), '/');
embeddedartists 0:6b68dac0d986 1265 pSlash++;
embeddedartists 0:6b68dac0d986 1266 *pSlash = '\0';
embeddedartists 0:6b68dac0d986 1267
embeddedartists 0:6b68dac0d986 1268 // now that cur_entry.d_name contains the folder's complete
embeddedartists 0:6b68dac0d986 1269 // path with a trailing '/', see if it has occurred earlier
embeddedartists 0:6b68dac0d986 1270 int older = findFileWithPrefix(cur_entry.d_name, 0, i);
embeddedartists 0:6b68dac0d986 1271 if (older < possible) {
embeddedartists 0:6b68dac0d986 1272 // already reported, move past this entry
embeddedartists 0:6b68dac0d986 1273 i = possible;
embeddedartists 0:6b68dac0d986 1274 } else {
embeddedartists 0:6b68dac0d986 1275 // found a new subfolder
embeddedartists 0:6b68dac0d986 1276 nextTocIdx = possible + 1;
embeddedartists 0:6b68dac0d986 1277 strcpy(cur_entry.d_name, filename);
embeddedartists 0:6b68dac0d986 1278 char* pSlash = strchr(cur_entry.d_name, '/');
embeddedartists 0:6b68dac0d986 1279 // pSlash++; //with ++ the returned dir name is "mydir/" without ++ "mydir" is returned
embeddedartists 0:6b68dac0d986 1280 *pSlash = '\0';
embeddedartists 0:6b68dac0d986 1281 return &cur_entry;
embeddedartists 0:6b68dac0d986 1282 }
embeddedartists 0:6b68dac0d986 1283 }
embeddedartists 0:6b68dac0d986 1284 }
embeddedartists 0:6b68dac0d986 1285 }
embeddedartists 0:6b68dac0d986 1286 return NULL;
embeddedartists 0:6b68dac0d986 1287 }
embeddedartists 0:6b68dac0d986 1288
embeddedartists 0:6b68dac0d986 1289 void QSPIDirHandle::rewinddir() {
embeddedartists 0:6b68dac0d986 1290 nextTocIdx = 0;
embeddedartists 0:6b68dac0d986 1291 }
embeddedartists 0:6b68dac0d986 1292
embeddedartists 0:6b68dac0d986 1293
embeddedartists 0:6b68dac0d986 1294 QSPIFileSystem::QSPIFileSystem(const char* name) :
embeddedartists 0:6b68dac0d986 1295 FileSystemLike(name) {
embeddedartists 0:6b68dac0d986 1296
embeddedartists 0:6b68dac0d986 1297 activeTOC = -1;
embeddedartists 0:6b68dac0d986 1298 spifi = NULL;
embeddedartists 0:6b68dac0d986 1299 }
embeddedartists 0:6b68dac0d986 1300
embeddedartists 0:6b68dac0d986 1301 // All modes are supported but:
embeddedartists 0:6b68dac0d986 1302 //
embeddedartists 0:6b68dac0d986 1303 // 1) All writes are treated as appends
embeddedartists 0:6b68dac0d986 1304 // 2) Truncation is only to size 0, i.e. effectively a delete
embeddedartists 0:6b68dac0d986 1305 // 3) File position operations work like this:
embeddedartists 0:6b68dac0d986 1306 // ReadOnly - dictates where to read from
embeddedartists 0:6b68dac0d986 1307 // WriteOnly - ignored, writes are always at the end
embeddedartists 0:6b68dac0d986 1308 // ReadWrite - dictates where to read from, writes ignore it but
embeddedartists 0:6b68dac0d986 1309 // sets the position to the end afterwards
embeddedartists 0:6b68dac0d986 1310 //
embeddedartists 0:6b68dac0d986 1311 FileHandle *QSPIFileSystem::open(const char *filename, int flags)
embeddedartists 0:6b68dac0d986 1312 {
embeddedartists 0:6b68dac0d986 1313 fresult res = qspifs_init();
embeddedartists 0:6b68dac0d986 1314 // if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1315 // if ((flags & O_ACCMODE) == O_RDONLY) {
embeddedartists 0:6b68dac0d986 1316 // // ok
embeddedartists 0:6b68dac0d986 1317 // } else if (flags & O_APPEND) {
embeddedartists 0:6b68dac0d986 1318 // // ok
embeddedartists 0:6b68dac0d986 1319 // } else {
embeddedartists 0:6b68dac0d986 1320 // // not supported yet, this includes all combination of flags
embeddedartists 0:6b68dac0d986 1321 // // allowing writing at specific positions in the file. This file system
embeddedartists 0:6b68dac0d986 1322 // // only allows appending
embeddedartists 0:6b68dac0d986 1323 // res = FS_ERR_INVALID_PARAM;
embeddedartists 0:6b68dac0d986 1324 // }
embeddedartists 0:6b68dac0d986 1325 // }
embeddedartists 0:6b68dac0d986 1326 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1327 if (strlen(filename) > HEADER_FNAME_STRLEN) {
embeddedartists 0:6b68dac0d986 1328 // Filename is too long
embeddedartists 0:6b68dac0d986 1329 res = FS_ERR_INVALID_PARAM;
embeddedartists 0:6b68dac0d986 1330 }
embeddedartists 0:6b68dac0d986 1331 }
embeddedartists 0:6b68dac0d986 1332 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1333 // Handle truncation by silently deleting the file before
embeddedartists 0:6b68dac0d986 1334 // attempting to open it
embeddedartists 0:6b68dac0d986 1335 if (flags & O_TRUNC) {
embeddedartists 0:6b68dac0d986 1336 remove(filename);
embeddedartists 0:6b68dac0d986 1337 }
embeddedartists 0:6b68dac0d986 1338 }
embeddedartists 0:6b68dac0d986 1339 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1340 fileHandle_t fh = {0,0,0};
embeddedartists 0:6b68dac0d986 1341 res = qspifs_findFile(filename, &fh);
embeddedartists 0:6b68dac0d986 1342 if ((res == FS_ERR_NO_FILE) && (flags & O_CREAT)) {
embeddedartists 0:6b68dac0d986 1343 res = qspifs_allocateFile(filename, 1, &fh.tocIdx);
embeddedartists 0:6b68dac0d986 1344 }
embeddedartists 0:6b68dac0d986 1345 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1346 res = qspifs_saveTOC();
embeddedartists 0:6b68dac0d986 1347 }
embeddedartists 0:6b68dac0d986 1348 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1349 return new QSPIFileHandle(&fh, flags);
embeddedartists 0:6b68dac0d986 1350 }
embeddedartists 0:6b68dac0d986 1351 }
embeddedartists 0:6b68dac0d986 1352 debug_if(QSPI_DBG, "QSPIFS: Failed to open: %d\n", res);
embeddedartists 0:6b68dac0d986 1353 return NULL;
embeddedartists 0:6b68dac0d986 1354 }
embeddedartists 0:6b68dac0d986 1355
embeddedartists 0:6b68dac0d986 1356 int QSPIFileSystem::remove(const char *filename)
embeddedartists 0:6b68dac0d986 1357 {
embeddedartists 0:6b68dac0d986 1358 fileHandle_t fh = {0,0,0};
embeddedartists 0:6b68dac0d986 1359 fresult res = qspifs_init();
embeddedartists 0:6b68dac0d986 1360 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1361 res = qspifs_findFile(filename, &fh);
embeddedartists 0:6b68dac0d986 1362 }
embeddedartists 0:6b68dac0d986 1363 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1364 qspifs_deleteFile(&fh);
embeddedartists 0:6b68dac0d986 1365 res = qspifs_saveTOC();
embeddedartists 0:6b68dac0d986 1366 }
embeddedartists 0:6b68dac0d986 1367 else if (res == FS_ERR_NO_FILE) {
embeddedartists 0:6b68dac0d986 1368 // file does not exist so treat it as a successful deletion
embeddedartists 0:6b68dac0d986 1369 res = FS_OK;
embeddedartists 0:6b68dac0d986 1370 }
embeddedartists 0:6b68dac0d986 1371 if (res != FS_OK) {
embeddedartists 0:6b68dac0d986 1372 debug_if(QSPI_DBG, "QSPIFS: Failed to delete %s: %d\n", filename, res);
embeddedartists 0:6b68dac0d986 1373 return -1;
embeddedartists 0:6b68dac0d986 1374 }
embeddedartists 0:6b68dac0d986 1375 return 0;
embeddedartists 0:6b68dac0d986 1376 }
embeddedartists 0:6b68dac0d986 1377
embeddedartists 0:6b68dac0d986 1378 int QSPIFileSystem::rename(const char *oldname, const char *newname)
embeddedartists 0:6b68dac0d986 1379 {
embeddedartists 0:6b68dac0d986 1380 fileHandle_t fhOld = {0,0,0};
embeddedartists 0:6b68dac0d986 1381 fileHandle_t fhNew = {0,0,0};
embeddedartists 0:6b68dac0d986 1382
embeddedartists 0:6b68dac0d986 1383 fresult res = qspifs_init();
embeddedartists 0:6b68dac0d986 1384 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1385 res = qspifs_findFile(oldname, &fhOld);
embeddedartists 0:6b68dac0d986 1386 }
embeddedartists 0:6b68dac0d986 1387 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1388 // Make sure the destination file doesn't exist
embeddedartists 0:6b68dac0d986 1389 res = qspifs_findFile(newname, &fhNew);
embeddedartists 0:6b68dac0d986 1390 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1391 res = FS_ERR_FILE_EXIST;
embeddedartists 0:6b68dac0d986 1392 } else if (res == FS_ERR_NO_FILE) {
embeddedartists 0:6b68dac0d986 1393 res = FS_OK;
embeddedartists 0:6b68dac0d986 1394 }
embeddedartists 0:6b68dac0d986 1395 }
embeddedartists 0:6b68dac0d986 1396 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1397 int numNeededBlocks = 1 + ((fhOld.size + HEADER_LEN) / ERASE_SIZE);
embeddedartists 0:6b68dac0d986 1398 res = qspifs_allocateFile(newname, numNeededBlocks, &fhNew.tocIdx);
embeddedartists 0:6b68dac0d986 1399 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1400 const uint8_t* pData = (const uint8_t*)(SPIFI_MEM_BASE + fhOld.tocIdx*ERASE_SIZE + HEADER_LEN);
embeddedartists 0:6b68dac0d986 1401 res = qspifs_write(&fhNew, pData, fhOld.size);
embeddedartists 0:6b68dac0d986 1402 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1403 qspifs_deleteFile(&fhOld);
embeddedartists 0:6b68dac0d986 1404 } else {
embeddedartists 0:6b68dac0d986 1405 qspifs_deleteFile(&fhNew);
embeddedartists 0:6b68dac0d986 1406 }
embeddedartists 0:6b68dac0d986 1407 }
embeddedartists 0:6b68dac0d986 1408 qspifs_saveTOC();
embeddedartists 0:6b68dac0d986 1409 }
embeddedartists 0:6b68dac0d986 1410 if (res != FS_OK) {
embeddedartists 0:6b68dac0d986 1411 debug_if(QSPI_DBG, "QSPIFS: Failed to rename '%s' to '%s': %d\n", oldname, newname, res);
embeddedartists 0:6b68dac0d986 1412 return -1;
embeddedartists 0:6b68dac0d986 1413 }
embeddedartists 0:6b68dac0d986 1414 return 0;
embeddedartists 0:6b68dac0d986 1415 }
embeddedartists 0:6b68dac0d986 1416
embeddedartists 0:6b68dac0d986 1417 DirHandle *QSPIFileSystem::opendir(const char *name)
embeddedartists 0:6b68dac0d986 1418 {
embeddedartists 14:c21497031b1f 1419 if (isformatted()) {
embeddedartists 14:c21497031b1f 1420 FileHandle* fh = open(name, O_RDONLY);
embeddedartists 14:c21497031b1f 1421 if (fh != NULL) {
embeddedartists 14:c21497031b1f 1422 // Attempting to open a file as a dir
embeddedartists 14:c21497031b1f 1423 delete fh;
embeddedartists 14:c21497031b1f 1424 return NULL;
embeddedartists 14:c21497031b1f 1425 }
embeddedartists 14:c21497031b1f 1426
embeddedartists 14:c21497031b1f 1427 // printf("opendir: name '%s'\n", name);
embeddedartists 14:c21497031b1f 1428 if (strlen(name) <= HEADER_DNAME_MAXLEN) {
embeddedartists 14:c21497031b1f 1429 return QSPIDirHandle::openDir(name);
embeddedartists 14:c21497031b1f 1430 }
embeddedartists 0:6b68dac0d986 1431 }
embeddedartists 0:6b68dac0d986 1432 return NULL;
embeddedartists 0:6b68dac0d986 1433 }
embeddedartists 0:6b68dac0d986 1434
embeddedartists 0:6b68dac0d986 1435 int QSPIFileSystem::mkdir(const char *name, mode_t mode)
embeddedartists 0:6b68dac0d986 1436 {
embeddedartists 0:6b68dac0d986 1437 // Creating folders is always successful as there are no folders in this filesystem
embeddedartists 0:6b68dac0d986 1438 return 0;
embeddedartists 0:6b68dac0d986 1439 }
embeddedartists 0:6b68dac0d986 1440
embeddedartists 0:6b68dac0d986 1441 int QSPIFileSystem::format(unsigned int fsSizeInMB)
embeddedartists 0:6b68dac0d986 1442 {
embeddedartists 0:6b68dac0d986 1443 fresult res = qspifs_init();
embeddedartists 0:6b68dac0d986 1444 if (res == FS_OK || res == FS_ERR_NOT_FORMATTED) {
embeddedartists 0:6b68dac0d986 1445 if (((fsSizeInMB<<20) > memInfo.memSize) || (fsSizeInMB < 1)) {
embeddedartists 0:6b68dac0d986 1446 debug_if(QSPI_DBG, "QSPIFS: Failed to format to size %d MByte: error %d\n", fsSizeInMB, res);
embeddedartists 0:6b68dac0d986 1447 return -1;
embeddedartists 0:6b68dac0d986 1448 }
embeddedartists 0:6b68dac0d986 1449 activeTOC = -1;
embeddedartists 0:6b68dac0d986 1450 res = qspifs_format(memInfo.memSize - (fsSizeInMB<<20));
embeddedartists 0:6b68dac0d986 1451 }
embeddedartists 0:6b68dac0d986 1452
embeddedartists 0:6b68dac0d986 1453 if (res != FS_OK) {
embeddedartists 0:6b68dac0d986 1454 debug_if(QSPI_DBG, "QSPIFS: Failed to format: %d\n", res);
embeddedartists 0:6b68dac0d986 1455 return -1;
embeddedartists 0:6b68dac0d986 1456 }
embeddedartists 0:6b68dac0d986 1457 return 0;
embeddedartists 0:6b68dac0d986 1458 }
embeddedartists 0:6b68dac0d986 1459
embeddedartists 0:6b68dac0d986 1460 bool QSPIFileSystem::isformatted()
embeddedartists 0:6b68dac0d986 1461 {
embeddedartists 0:6b68dac0d986 1462 fresult res = qspifs_init();
embeddedartists 0:6b68dac0d986 1463 if (res == FS_OK) {
embeddedartists 0:6b68dac0d986 1464 return true;
embeddedartists 0:6b68dac0d986 1465 } else if (res == FS_ERR_NOT_FORMATTED) {
embeddedartists 0:6b68dac0d986 1466 return false;
embeddedartists 0:6b68dac0d986 1467 }
embeddedartists 0:6b68dac0d986 1468 debug_if(QSPI_DBG, "QSPIFS: Failed to detect status: %d\n", res);
embeddedartists 0:6b68dac0d986 1469 return false;
embeddedartists 0:6b68dac0d986 1470 }
embeddedartists 0:6b68dac0d986 1471
embeddedartists 0:6b68dac0d986 1472 bool QSPIFileSystem::getMemoryBoundaries(uint32_t* pStartAddr, uint32_t* pEndAddr)
embeddedartists 0:6b68dac0d986 1473 {
embeddedartists 0:6b68dac0d986 1474 if (isformatted())
embeddedartists 0:6b68dac0d986 1475 {
embeddedartists 0:6b68dac0d986 1476 *pEndAddr = 0x28000000 + memInfo.memSize;
embeddedartists 0:6b68dac0d986 1477
embeddedartists 0:6b68dac0d986 1478 // Look at all blocks except for the reserved ones
embeddedartists 0:6b68dac0d986 1479 for (int i = 0; i < NUM_BLOCKS; i++)
embeddedartists 0:6b68dac0d986 1480 {
embeddedartists 0:6b68dac0d986 1481 if (!TOC_IS_RESERVED(TOC[i]))
embeddedartists 0:6b68dac0d986 1482 {
embeddedartists 0:6b68dac0d986 1483 // Found first non-reserved erase block, indicating the start of
embeddedartists 0:6b68dac0d986 1484 // the file system.
embeddedartists 0:6b68dac0d986 1485 *pStartAddr = SPIFI_MEM_BASE + i*ERASE_SIZE;
embeddedartists 0:6b68dac0d986 1486 return true;
embeddedartists 0:6b68dac0d986 1487 }
embeddedartists 0:6b68dac0d986 1488 }
embeddedartists 0:6b68dac0d986 1489
embeddedartists 0:6b68dac0d986 1490 // The entire file system seems to be reserved which should never happen
embeddedartists 0:6b68dac0d986 1491 // but just in case, report it as beeing 1MB in size.
embeddedartists 0:6b68dac0d986 1492 *pStartAddr = *pEndAddr - 1024*1024;
embeddedartists 0:6b68dac0d986 1493 return true;
embeddedartists 0:6b68dac0d986 1494 }
embeddedartists 0:6b68dac0d986 1495 return false;
embeddedartists 0:6b68dac0d986 1496 }