]> rtime.felk.cvut.cz Git - arc.git/blob - memory/Fee/Fee.c
5d398fb10f61e70d6d87ea7a85a5f7cf47a60c33
[arc.git] / memory / Fee / Fee.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 \r
17 \r
18 \r
19 \r
20 \r
21 \r
22 \r
23 \r
24 #include <string.h>\r
25 #include "Fee.h"\r
26 #include "Fee_Cbk.h"\r
27 #include "NvM.h"\r
28 #include "Fls.h"\r
29 #include "Rte.h" // ???\r
30 #if defined(USE_DEM)\r
31 #include "Dem.h"\r
32 #endif\r
33 //#include "SchM_NvM.h"\r
34 #include "MemMap.h"\r
35 \r
36 /*\r
37  * Local definitions\r
38  */\r
39 \r
40 /*\r
41  *  Validation macros\r
42  */\r
43 #if  ( FEE_DEV_ERROR_DETECT == STD_ON )\r
44 #include "Det.h"\r
45 #define VALIDATE(_exp,_api,_err ) \\r
46         if( !(_exp) ) { \\r
47           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
48         }\r
49 \r
50 #define VALIDATE_RV(_exp,_api,_err,_rv ) \\r
51         if( !(_exp) ) { \\r
52           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
53           return _rv; \\r
54         }\r
55 \r
56 #define VALIDATE_NO_RV(_exp,_api,_err ) \\r
57   if( !(_exp) ) { \\r
58           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
59           return; \\r
60         }\r
61 \r
62 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)\r
63 \r
64 #else\r
65 #define VALIDATE(_exp,_api,_err )\r
66 #define VALIDATE_RV(_exp,_api,_err,_rv )\r
67 #define VALIDATE_NO_RV(_exp,_api,_err )\r
68 #define DET_REPORTERROR(_module,_instance,_api,_err)\r
69 #endif\r
70 \r
71 \r
72 /*\r
73  * Block numbering recalculation macros
74  */\r
75 #define GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(_blocknr)     (((_blocknr) >> NVM_DATASET_SELECTION_BITS) - 1)\r
76 #define GET_DATASET_FROM_BLOCK_NUMBER(_blocknr) ((_blocknr) & ((1 << NVM_DATASET_SELECTION_BITS) - 1))\r
77 #define BLOCK_INDEX_AND_SET_TO_BLOCKNR(_blocknr, _set)  ((_blocknr + 1) << NVM_DATASET_SELECTION_BITS | set)\r
78 \r
79 /*\r
80  * Page alignment macros
81  */\r
82 #define PAGE_ALIGN(_size)       ((((_size) + FEE_VIRTUAL_PAGE_SIZE - 1) / FEE_VIRTUAL_PAGE_SIZE) * FEE_VIRTUAL_PAGE_SIZE)\r
83 \r
84 /*\r
85  * Bank properties list
86  */\r
87 #define NUM_OF_BANKS    2\r
88 typedef struct {\r
89         Fls_AddressType         Start;\r
90         Fls_LengthType          End;\r
91 } BankPropType;\r
92 \r
93 static const BankPropType BankProp[NUM_OF_BANKS] = {\r
94                 {\r
95                                 .Start = FEE_BANK1_OFFSET,\r
96                                 .End = FEE_BANK1_OFFSET + FEE_BANK1_LENGTH\r
97                 },\r
98                 {\r
99                                 .Start = FEE_BANK2_OFFSET,\r
100                                 .End = FEE_BANK2_OFFSET + FEE_BANK2_LENGTH\r
101                 },\r
102 };\r
103 \r
104 \r
105 \r
106 /*\r
107  * Macros and variables for flash bank administration
108  */\r
109 typedef enum {\r
110         BANK_STATUS_OLD = 0x00,\r
111         BANK_STATUS_NEW = 0xFF\r
112 } FlsBankStatusEnumType;\r
113 typedef uint8 FlsBankStatusType;\r
114 \r
115 #define BANK_CTRL_PAGE_SIZE             PAGE_ALIGN(sizeof(FlsBankStatusType))\r
116 \r
117 typedef union {\r
118         FlsBankStatusType       BankStatus;\r
119         uint8                           Data[BANK_CTRL_PAGE_SIZE];\r
120 } FlsBankCtrlPageType;\r
121 \r
122 \r
123 /*\r
124  * Macros and variables for flash block administration in flash
125  */\r
126 typedef enum {\r
127         BLOCK_STATUS_INUSE = 0x00,\r
128         BLOCK_STATUS_INVALIDATED = 0x02,\r
129         BLOCK_STATUS_EMPTY = 0xFF\r
130 } BlockStatusEnumType;\r
131 typedef uint8 BlockStatusType;\r
132 \r
133 typedef struct {\r
134         BlockStatusType         Status;\r
135         uint16                          BlockNo;\r
136         Fls_AddressType         BlockDataAddress;\r
137         uint16                          BlockDataLength;\r
138 } FlsBlockDataType;\r
139 \r
140 #define BLOCK_DATA_PAGE_SIZE            PAGE_ALIGN(sizeof(FlsBlockDataType))\r
141 \r
142 typedef union {\r
143         FlsBlockDataType        Data;\r
144         uint8                           Byte[BLOCK_DATA_PAGE_SIZE];\r
145 } FlsBlockDataPageType;\r
146 \r
147 \r
148 #define BLOCK_MAGIC_LEN         4\r
149 static const uint8 MagicMaster[BLOCK_MAGIC_LEN] = { 0xeb, 0xba, 0xba, 0xbe };\r
150 #define BLOCK_MAGIC_PAGE_SIZE   PAGE_ALIGN(BLOCK_MAGIC_LEN)\r
151 \r
152 \r
153 typedef union {\r
154         uint8           Magic[BLOCK_MAGIC_LEN];\r
155         uint8           Byte[BLOCK_MAGIC_PAGE_SIZE];\r
156 } FlsBlockMagicPageType;\r
157 \r
158 typedef struct {\r
159         FlsBlockDataPageType    DataPage;\r
160         FlsBlockMagicPageType   MagicPage;\r
161 } FlsBlockControlType;\r
162 \r
163 #define BLOCK_CTRL_PAGE_SIZE    PAGE_ALIGN(sizeof(FlsBlockControlType))\r
164 \r
165 #define BLOCK_CTRL_DATA_POS_OFFSET              0\r
166 #define BLOCK_CTRL_MAGIC_POS_OFFSET             BLOCK_DATA_PAGE_SIZE\r
167 \r
168 typedef union {\r
169         FlsBlockControlType     BlockCtrl;\r
170         FlsBankCtrlPageType BankCtrl;\r
171         uint8                           Byte[BLOCK_CTRL_PAGE_SIZE];\r
172 } ReadWriteBufferType;\r
173 \r
174 static ReadWriteBufferType RWBuffer;\r
175 \r
176 #define RWBUFFER_SIZE   sizeof(ReadWriteBufferType)\r
177 \r
178 \r
179 /*\r
180  * Variables for flash administration\r
181  */\r
182 typedef struct {\r
183         BlockStatusType         Status;\r
184         Fls_AddressType         BlockAdminAddress;\r
185         Fls_AddressType         BlockDataAddress;\r
186 } AdminFlsBlockType;\r
187 \r
188 typedef struct {\r
189         uint8                           BankNumber;\r
190         Fls_AddressType         NewBlockAdminAddress;\r
191         Fls_AddressType         NewBlockDataAddress;\r
192         FlsBankStatusType       BankStatus[NUM_OF_BANKS];\r
193         AdminFlsBlockType       BlockDescrTbl[FEE_NUM_OF_BLOCKS][FEE_MAX_NUM_SETS];\r
194 } AdminFlsType;\r
195 \r
196 static AdminFlsType AdminFls;\r
197 \r
198 \r
199 /*\r
200  * Variables for quick reporting of status and job result
201  */\r
202 static MemIf_StatusType ModuleStatus = MEMIF_UNINIT;\r
203 static MemIf_JobResultType JobResult = MEMIF_JOB_OK;\r
204 \r
205 /*\r
206  * Variables for the current job
207  */\r
208 typedef enum {\r
209   FEE_UNINITIALIZED = 0,\r
210   FEE_STARTUP_REQUESTED,\r
211   FEE_STARTUP_READ_BANK1_STATUS,\r
212   FEE_STARTUP_READ_BANK2_STATUS_REQUESTED,\r
213   FEE_STARTUP_READ_BANK2_STATUS,\r
214   FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED,\r
215   FEE_STARTUP_READ_BLOCK_ADMIN,\r
216 \r
217   FEE_IDLE,\r
218 \r
219   FEE_WRITE_REQUESTED,\r
220   FEE_WRITE_MARK_BANK_OLD,\r
221   FEE_WRITE_HEADER_REQUESTED,\r
222   FEE_WRITE_HEADER,\r
223   FEE_WRITE_DATA_REQUESTED,\r
224   FEE_WRITE_DATA,\r
225   FEE_WRITE_MAGIC_REQUESTED,\r
226   FEE_WRITE_MAGIC,\r
227 \r
228   FEE_READ_REQUESTED,\r
229   FEE_READ,\r
230 \r
231   FEE_CANCEL_REQUESTED,\r
232   FEE_CANCEL_PENDING,\r
233 \r
234   FEE_INVALIDATE_REQUESTED,\r
235   FEE_INVALIDATE_MARK_BANK_OLD,\r
236   FEE_WRITE_INVALIDATE_HEADER_REQUESTED,\r
237   FEE_WRITE_INVALIDATE_HEADER,\r
238 \r
239   FEE_GARBAGE_COLLECT_REQUESTED,\r
240   FEE_GARBAGE_COLLECT_HEADER_WRITE,\r
241   FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED,\r
242   FEE_GARBAGE_COLLECT_DATA_READ,\r
243   FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED,\r
244   FEE_GARBAGE_COLLECT_DATA_WRITE,\r
245   FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED,\r
246   FEE_GARBAGE_COLLECT_MAGIC_WRITE,\r
247   FEE_GARBAGE_COLLECT_ERASE,\r
248 } CurrentJobStateType;\r
249 \r
250 typedef struct {\r
251         CurrentJobStateType                     State;\r
252         uint16                                          InStateCounter;\r
253         uint16                                          BlockNumber;\r
254         uint16                                          Length;\r
255         const Fee_BlockConfigType       *BlockConfigPtr;\r
256         AdminFlsBlockType                       *AdminFlsBlockPtr;\r
257         union {\r
258                 struct {\r
259                         uint16                          NrOfBanks;\r
260                         uint16                          BankNumber;\r
261                         Fls_AddressType         BlockAdminAddress;\r
262                 }Startup;\r
263                 struct {\r
264                         uint16                          Offset;\r
265                         uint8                           *RamPtr;\r
266                 }Read;\r
267                 struct {\r
268                         uint8                           *RamPtr;\r
269                         Fls_AddressType         WriteAdminAddress;\r
270                         Fls_AddressType         WriteDataAddress;\r
271                 }Write;\r
272                 struct {\r
273                         Fls_AddressType         WriteAdminAddress;\r
274                         Fls_AddressType         WriteDataAddress;\r
275                 }Invalidate;\r
276                 struct {\r
277                         uint16                          NrOfBanks;\r
278                         uint16                          BankNumber;\r
279                         Fls_AddressType         WriteAdminAddress;\r
280                         Fls_AddressType         WriteDataAddress;\r
281                         sint16                          BytesLeft;\r
282                         uint16                          DataOffset;\r
283                 }GarbageCollect;\r
284         } Op;\r
285 } CurrentJobType;\r
286 \r
287 static CurrentJobType CurrentJob = {\r
288                 .State = FEE_IDLE,\r
289                 .InStateCounter = 0\r
290 };\r
291 \r
292 /*\r
293  * Misc definitions
294  */\r
295 #define STATE_COUNTER_MAX                               0xffff\r
296 #define GARBAGE_COLLECTION_DELAY                10\r
297 \r
298 /***************************************\r
299  *           Local functions           *\r
300  ***************************************/\r
301 \r
302 #if (FEE_POLLING_MODE == STD_ON)\r
303 static void SetFlsJobBusy()\r
304 {\r
305         /* Nothing needed here */\r
306 }\r
307 \r
308 static boolean CheckFlsJobFinnished(void)\r
309 {\r
310         MemIf_JobResultType flsJobResult;\r
311 \r
312         flsJobResult = Fls_GetJobResult();\r
313         return (flsJobResult != MEMIF_JOB_PENDING);\r
314 }\r
315 #else\r
316 static boolean FlsJobReady = TRUE;\r
317 \r
318 static void SetFlsJobBusy()\r
319 {\r
320         FlsJobReady = FALSE;\r
321 }\r
322 \r
323 static boolean CheckFlsJobFinnished(void)\r
324 {\r
325         return (FlsJobReady);\r
326 }\r
327 \r
328 #endif\r
329 \r
330 \r
331 static void FinnishStartup(void)\r
332 {\r
333         CurrentJob.State = FEE_IDLE;\r
334         ModuleStatus = MEMIF_IDLE;\r
335         JobResult = MEMIF_JOB_OK;\r
336 }\r
337 \r
338 \r
339 static void AbortStartup(MemIf_JobResultType result)\r
340 {\r
341         CurrentJob.State = FEE_IDLE;\r
342         ModuleStatus = MEMIF_IDLE;\r
343         JobResult = result;\r
344 }\r
345 \r
346 \r
347 static void FinnishJob(void)\r
348 {\r
349         CurrentJob.State = FEE_IDLE;\r
350         ModuleStatus = MEMIF_IDLE;\r
351         JobResult = MEMIF_JOB_OK;\r
352 \r
353         if (Fee_Config.General.NvmJobEndCallbackNotificationCallback != NULL) {\r
354                 Fee_Config.General.NvmJobEndCallbackNotificationCallback();\r
355         }\r
356 }\r
357 \r
358 \r
359 static void AbortJob(MemIf_JobResultType result)\r
360 {\r
361         CurrentJob.State = FEE_IDLE;\r
362         ModuleStatus = MEMIF_IDLE;\r
363         JobResult = result;\r
364 \r
365         if (Fee_Config.General.NvmJobErrorCallbackNotificationCallback != NULL) {\r
366                 Fee_Config.General.NvmJobErrorCallbackNotificationCallback();\r
367         }\r
368 }\r
369 \r
370 \r
371 /*\r
372  * Start of bank status 1 read\r
373  */\r
374 static void StartupStartJob(void)\r
375 {\r
376         if (Fls_GetStatus() == MEMIF_IDLE) {\r
377                 CurrentJob.State = FEE_STARTUP_READ_BANK1_STATUS;\r
378                 /* Read bank status of bank 1 */\r
379                 if (Fls_Read(BankProp[0].End - BANK_CTRL_PAGE_SIZE, (uint8*)&AdminFls.BankStatus[0], sizeof(FlsBankStatusType)) == E_OK) {\r
380                         SetFlsJobBusy();\r
381                 } else {\r
382                         AbortStartup(Fls_GetJobResult());\r
383                 }\r
384         }\r
385 }\r
386 \r
387 \r
388 /*\r
389  *  Check job result of bank 1 status read, if ok request for bank 2 status read\r
390  */\r
391 static void StartupReadBank1Status(void)\r
392 {\r
393         if (CheckFlsJobFinnished()) {\r
394                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
395                         CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS_REQUESTED;\r
396                 } else {\r
397                         AbortStartup(Fls_GetJobResult());\r
398                 }\r
399         }\r
400 }\r
401 \r
402 \r
403 /*\r
404  * Start of bank status 2 read\r
405  */\r
406 static void StartupReadBank2StatusRequested(void)\r
407 {\r
408         if (Fls_GetStatus() == MEMIF_IDLE) {\r
409                 /* Read bank status of bank 2 */\r
410                 CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS;\r
411                 if (Fls_Read(BankProp[1].End - BANK_CTRL_PAGE_SIZE, (uint8*)&AdminFls.BankStatus[1], sizeof(FlsBankStatusType)) == E_OK) {\r
412                         SetFlsJobBusy();\r
413                 } else {\r
414                         AbortStartup(Fls_GetJobResult());\r
415                 }\r
416         }\r
417 }\r
418 \r
419 \r
420 /*\r
421  * Check job result of bank status 2 read - request for block status reading
422  */\r
423 static void StartupReadBank2Status(void)\r
424 {\r
425         MemIf_JobResultType jobResult;\r
426 \r
427         if (CheckFlsJobFinnished()) {\r
428                 jobResult = Fls_GetJobResult();\r
429                 if (jobResult == MEMIF_JOB_OK) {\r
430                         /* Select which bank to start with */\r
431                         if ((AdminFls.BankStatus[0] != BANK_STATUS_OLD) && (AdminFls.BankStatus[1] != BANK_STATUS_OLD)){\r
432                                 /* None is marked as old, just start with one of them */\r
433                                 CurrentJob.Op.Startup.BankNumber = 0;\r
434                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
435                         } else if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) && (AdminFls.BankStatus[1] == BANK_STATUS_OLD) ) {\r
436                                 /* Both banks are marked as old, this shall not be possible */\r
437                                 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
438                                 jobResult = MEMIF_JOB_FAILED;\r
439                         } else if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
440                                 CurrentJob.Op.Startup.BankNumber = 0;\r
441                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
442                         } else {\r
443                                 CurrentJob.Op.Startup.BankNumber = 1;\r
444                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
445                         }\r
446                 }\r
447 \r
448                 if (jobResult != MEMIF_JOB_OK) {\r
449                         AbortStartup(jobResult);\r
450                 } else {\r
451                         CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;\r
452                         CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
453                 }\r
454         }\r
455 }\r
456 \r
457 /*\r
458  * Start of block admin read
459  */\r
460 static void StartupReadBlockAdminRequested(void)\r
461 {\r
462         if (Fls_GetStatus() == MEMIF_IDLE) {\r
463                 /* Start reading the banks */\r
464                 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN;\r
465                 if (Fls_Read(CurrentJob.Op.Startup.BlockAdminAddress, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
466                         SetFlsJobBusy();\r
467                 } else {\r
468                         AbortStartup(Fls_GetJobResult());\r
469                 }\r
470         }\r
471 }\r
472 \r
473 \r
474 /*\r
475  * Check job result of block admin read, if all block processed finish\r
476  * otherwise request for a new block admin read
477  */\r
478 static void StartupReadBlockAdmin(void)\r
479 {\r
480         if (CheckFlsJobFinnished()) {\r
481                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
482                         if (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_EMPTY) {\r
483                                 VALIDATE(CurrentJob.Op.Startup.NrOfBanks != 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
484                                 CurrentJob.Op.Startup.NrOfBanks--;\r
485                                 CurrentJob.Op.Startup.BankNumber = (CurrentJob.Op.Startup.BankNumber + 1) % 2;\r
486                                 CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;\r
487                         } else { /* Block not empty */\r
488                                 if ((memcmp(RWBuffer.BlockCtrl.MagicPage.Byte, MagicMaster, BLOCK_MAGIC_LEN) == 0) &&\r
489                                                 ((RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INUSE) || (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INVALIDATED))) {\r
490                                         /* This is a valid admin block */\r
491                                         uint16 blockIndex;\r
492                                         uint16 dataSet;\r
493 \r
494                                         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
495                                         dataSet = GET_DATASET_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
496 \r
497                                         if ((blockIndex < FEE_NUM_OF_BLOCKS) && (dataSet < FEE_MAX_NUM_SETS)) {\r
498                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
499                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress;\r
500                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].Status = RWBuffer.BlockCtrl.DataPage.Data.Status;\r
501 \r
502                                                 AdminFls.BankNumber = CurrentJob.Op.Startup.BankNumber;\r
503                                                 AdminFls.NewBlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress + RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength;\r
504                                                 if (CurrentJob.Op.Startup.BlockAdminAddress <= AdminFls.NewBlockDataAddress) {\r
505                                                         /* This shall never happen */\r
506                                                         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
507                                                 }\r
508                                         }\r
509                                 }\r
510                                 CurrentJob.Op.Startup.BlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
511                                 AdminFls.NewBlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
512                         }\r
513 \r
514                         if (CurrentJob.Op.Startup.NrOfBanks == 0) {\r
515                                 /* If current bank is marked as old we need to switch to a new bank */\r
516                                 if (AdminFls.BankStatus[AdminFls.BankNumber] == BANK_STATUS_OLD) {\r
517                                         AdminFls.BankNumber = (AdminFls.BankNumber + 1) % 2;\r
518                                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;\r
519                                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
520                                 }\r
521                                 /* We are done! */\r
522                                 FinnishStartup();\r
523                         } else {\r
524                                 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
525                         }\r
526 \r
527 \r
528                 } else { /* ErrorStatus not E_OK */\r
529                         AbortStartup(Fls_GetJobResult());\r
530                 }\r
531         }\r
532 }\r
533 \r
534 \r
535 /*\r
536  * Start of read block data\r
537  */\r
538 static void ReadStartJob(void)\r
539 {\r
540         if (Fls_GetStatus() == MEMIF_IDLE) {\r
541                 if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_EMPTY) {\r
542                         if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_INVALIDATED) {\r
543                                 CurrentJob.State = FEE_READ;\r
544                                 /* Read the actual data */\r
545                                 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.Read.Offset, CurrentJob.Op.Read.RamPtr, CurrentJob.Length) == E_OK) {\r
546                                         SetFlsJobBusy();\r
547                                 } else {\r
548                                         AbortJob(Fls_GetJobResult());\r
549                                 }\r
550                         } else {\r
551                                 /* Invalid */\r
552                                 AbortJob(MEMIF_BLOCK_INVALID);\r
553                         }\r
554                 } else {\r
555                         /* Inconsistent */\r
556                         AbortJob(MEMIF_BLOCK_INCONSISTENT);\r
557                 }\r
558         }\r
559 }\r
560 \r
561 /*\r
562  * Check job result of block data read
563  */\r
564 static void Reading(void)\r
565 {\r
566         if (CheckFlsJobFinnished()) {\r
567                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
568                         FinnishJob();\r
569                 } else {\r
570                         AbortJob(Fls_GetJobResult());\r
571                 }\r
572         }\r
573 }\r
574 \r
575 \r
576 /*\r
577  * Write bank header\r
578  */\r
579 static void BankHeaderOldWrite(uint8 bank)\r
580 {\r
581         /* Mark the bank as old */\r
582         memset(RWBuffer.BankCtrl.Data, 0xff, BLOCK_DATA_PAGE_SIZE);\r
583         RWBuffer.BankCtrl.BankStatus = BANK_STATUS_OLD;\r
584         if (Fls_Write(BankProp[bank].End - BANK_CTRL_PAGE_SIZE, RWBuffer.BankCtrl.Data, BANK_CTRL_PAGE_SIZE) == E_OK) {\r
585                 SetFlsJobBusy();\r
586         } else {\r
587                 AbortJob(Fls_GetJobResult());\r
588         }\r
589 }\r
590 \r
591 \r
592 /*\r
593  * Write block header\r
594  */\r
595 static void BlockHeaderDataWrite(void)\r
596 {\r
597         /* Write the header excluding the magic */\r
598         memset(RWBuffer.BlockCtrl.DataPage.Byte, 0xff, BLOCK_DATA_PAGE_SIZE);\r
599         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INUSE;\r
600         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
601         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
602         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = CurrentJob.Length;\r
603         if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_DATA_PAGE_SIZE) == E_OK) {\r
604                 SetFlsJobBusy();\r
605                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
606                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
607         } else {\r
608                 AbortJob(Fls_GetJobResult());\r
609         }\r
610 }\r
611 \r
612 \r
613 /*\r
614  * Check if bank switch needed:\r
615  * - Yes, start mark current bank as old\r
616  * - No, start of header write\r
617  */\r
618 static void WriteStartJob(void)\r
619 {\r
620         if (Fls_GetStatus() == MEMIF_IDLE) {\r
621                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
622                         /* Bank switch needed, mark current bank as "old" */\r
623                         CurrentJob.State = FEE_WRITE_MARK_BANK_OLD;\r
624                         BankHeaderOldWrite(AdminFls.BankNumber);\r
625                 } else {\r
626                         CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
627                         CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
628 \r
629                         CurrentJob.State = FEE_WRITE_HEADER;\r
630                         BlockHeaderDataWrite();\r
631                 }\r
632         }\r
633 }\r
634 \r
635 \r
636 /*\r
637  * Check job result of mark bank as old, if ok request for header write\r
638  */\r
639 static void WriteMarkBankOldState(void)\r
640 {\r
641         if (CheckFlsJobFinnished()) {\r
642                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
643                         /* Mark for garbage collection */\r
644                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
645 \r
646                         /* Change of bank */\r
647                         AdminFls.BankNumber ^= 0x1;\r
648                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
649                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;\r
650 \r
651                         CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
652                         CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
653 \r
654                         CurrentJob.State = FEE_WRITE_HEADER_REQUESTED;\r
655                 } else {\r
656                         AbortJob(Fls_GetJobResult());\r
657                 }\r
658         }\r
659 }\r
660 \r
661 \r
662 /*\r
663  * Start of header write
664  */\r
665 static void WriteHeaderRequested()\r
666 {\r
667         if (Fls_GetStatus() == MEMIF_IDLE) {\r
668                 CurrentJob.State = FEE_WRITE_HEADER;\r
669                 BlockHeaderDataWrite();\r
670         }\r
671 }\r
672 \r
673 \r
674 /*\r
675  * Check job result of write header, if ok request for block data write\r
676  */\r
677 static void WriteHeaderState(void)\r
678 {\r
679         if (CheckFlsJobFinnished()) {\r
680                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
681                         CurrentJob.State = FEE_WRITE_DATA_REQUESTED;\r
682                 } else {\r
683                         AbortJob(Fls_GetJobResult());\r
684                 }\r
685         }\r
686 }\r
687 \r
688 \r
689 /*\r
690  * Start block data write
691  */\r
692 static void WriteDataRequested(void)\r
693 {\r
694         if (Fls_GetStatus() == MEMIF_IDLE) {\r
695                 CurrentJob.State = FEE_WRITE_DATA;\r
696                 /* Write the actual data */\r
697                 if (Fls_Write(CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length) == E_OK) {\r
698                         SetFlsJobBusy();\r
699                 } else {\r
700                         AbortJob(Fls_GetJobResult());\r
701                 }\r
702         }\r
703 }\r
704 \r
705 \r
706 /*\r
707  * Check job result of data write - request for magic write\r
708  */\r
709 static void WriteDataState(void)\r
710 {\r
711         if (CheckFlsJobFinnished()) {\r
712                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
713                         CurrentJob.State = FEE_WRITE_MAGIC_REQUESTED;\r
714                 } else {\r
715                         AbortJob(Fls_GetJobResult());\r
716                 }\r
717         }\r
718 }\r
719 \r
720 \r
721 /*\r
722  * Start magic write
723  */\r
724 static void WriteMagicRequested(void)\r
725 {\r
726         if (Fls_GetStatus() == MEMIF_IDLE) {\r
727                 CurrentJob.State = FEE_WRITE_MAGIC;\r
728                 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_MAGIC_PAGE_SIZE);\r
729                 memcpy(RWBuffer.BlockCtrl.MagicPage.Byte, MagicMaster, BLOCK_MAGIC_LEN);\r
730                 if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_MAGIC_PAGE_SIZE) == E_OK) {\r
731                         SetFlsJobBusy();\r
732                 } else {\r
733                         AbortJob(Fls_GetJobResult());\r
734                 }\r
735         }\r
736 }\r
737 \r
738 \r
739 /*\r
740  * Check job result of write magic, if ok update the block admin table and finish\r
741  */\r
742 static void WriteMagicState(void)\r
743 {\r
744         if (CheckFlsJobFinnished()) {\r
745                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
746                         /* Update the block admin table */\r
747                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INUSE;\r
748                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Write.WriteAdminAddress;\r
749                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Write.WriteDataAddress;\r
750 \r
751                         FinnishJob();\r
752                 } else {\r
753                         AbortJob(Fls_GetJobResult());\r
754                 }\r
755         }\r
756 }\r
757 \r
758 \r
759 /*\r
760  * Check if any bank is marked as old\r
761  */\r
762 static void CheckIfGarbageCollectionNeeded(void)\r
763 {\r
764         if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
765                 ModuleStatus = MEMIF_BUSY_INTERNAL;\r
766                 JobResult = MEMIF_JOB_PENDING;\r
767 \r
768                 CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;\r
769         }\r
770 }\r
771 \r
772 \r
773 /*\r
774  * Checks if any blocks needs to be moved if so start with writing a new header\r
775  * or if no blocks needs to be moved request for bank erase.\r
776  */\r
777 static void GarbageCollectStartJob(void)\r
778 {\r
779         uint16 blockIndex,set;\r
780         boolean found = FALSE;\r
781         uint8 sourceBank, destBank;\r
782 \r
783         if (Fls_GetStatus() == MEMIF_IDLE) {\r
784                 if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
785                         sourceBank = 0;\r
786                         destBank = 1;\r
787                 } else if (AdminFls.BankStatus[1] == BANK_STATUS_OLD) {\r
788                         sourceBank = 1;\r
789                         destBank = 0;\r
790                 } else {\r
791                         CurrentJob.State = FEE_IDLE;\r
792                         return;\r
793                 }\r
794 \r
795                 for (blockIndex = 0; (blockIndex < FEE_NUM_OF_BLOCKS) && !found; blockIndex++) {\r
796                         for (set = 0; (set < FEE_MAX_NUM_SETS) && !found; set++) {\r
797                                 if (AdminFls.BlockDescrTbl[blockIndex][set].Status != BLOCK_STATUS_EMPTY) {\r
798                                         if ((AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress >= BankProp[sourceBank].Start) && (AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress < (BankProp[sourceBank].End))) {\r
799                                                 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][set];\r
800                                                 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
801                                                 CurrentJob.BlockNumber = BLOCK_INDEX_AND_SET_TO_BLOCKNR(blockIndex, set);\r
802                                                 if (AdminFls.BlockDescrTbl[blockIndex][set].Status == BLOCK_STATUS_INVALIDATED) {\r
803                                                         CurrentJob.Length = 0;\r
804                                                 } else {\r
805                                                         CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
806                                                 }\r
807 \r
808                                                 found = TRUE;\r
809                                         }\r
810                                 }\r
811                         }\r
812                 }\r
813 \r
814                 if (found) {\r
815                         CurrentJob.Op.GarbageCollect.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
816                         CurrentJob.Op.GarbageCollect.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
817 \r
818                         CurrentJob.State = FEE_GARBAGE_COLLECT_HEADER_WRITE;\r
819                         BlockHeaderDataWrite();\r
820                 } else {\r
821                         if (Fls_Erase(BankProp[sourceBank].Start, BankProp[sourceBank].End - BankProp[sourceBank].Start) == E_OK) {\r
822                                 SetFlsJobBusy();\r
823                         } else {\r
824                                 AbortJob(Fls_GetJobResult());\r
825                         }\r
826                         CurrentJob.Op.GarbageCollect.BankNumber = sourceBank;\r
827                         CurrentJob.State = FEE_GARBAGE_COLLECT_ERASE;\r
828                 }\r
829         }\r
830 }\r
831 \r
832 \r
833 /*\r
834  * Check job result of write header, if ok request for read block data\r
835  */\r
836 static void GarbageCollectWriteHeader(void)\r
837 {\r
838         if (CheckFlsJobFinnished()) {\r
839                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
840                         if (CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INUSE) {\r
841                                 CurrentJob.Op.GarbageCollect.BytesLeft = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
842                                 CurrentJob.Op.GarbageCollect.DataOffset = 0;\r
843                                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
844                         } else {\r
845                                 /* Yes, we are finished */\r
846                                 VALIDATE_NO_RV(CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_EMPTY, FEE_GARBAGE_WRITE_HEADER_ID, FEE_UNEXPECTED_STATUS);\r
847                                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
848                         }\r
849                 } else {\r
850                         AbortJob(Fls_GetJobResult());\r
851                 }\r
852         }\r
853 }\r
854 \r
855 \r
856 /*\r
857  * Start of read block data, if data length is more than buffer size\r
858  * the reading is segmented.\r
859  */\r
860 static void GarbageCollectReadDataRequested(void)\r
861 {\r
862         if (Fls_GetStatus() == MEMIF_IDLE) {\r
863                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ;\r
864                 if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
865                         CurrentJob.Length = CurrentJob.Op.GarbageCollect.BytesLeft;\r
866                 } else {\r
867                         CurrentJob.Length = RWBUFFER_SIZE;\r
868                 }\r
869                 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
870                         SetFlsJobBusy();\r
871                 } else {\r
872                         AbortJob(Fls_GetJobResult());\r
873                 }\r
874         }\r
875 }\r
876 \r
877 \r
878 /*\r
879  * Check job result of read block data, if ok request for a data write\r
880  */\r
881 static void GarbageCollectReadData(void)\r
882 {\r
883         if (CheckFlsJobFinnished()) {\r
884                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
885                         CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED;\r
886                 } else {\r
887                         AbortJob(Fls_GetJobResult());\r
888                 }\r
889         }\r
890 }\r
891 \r
892 \r
893 /*\r
894  * Start of write block data\r
895  */\r
896 static void GarbageCollectWriteDataRequested(void)\r
897 {\r
898         if (Fls_GetStatus() == MEMIF_IDLE) {\r
899                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE;\r
900                 /* Write the actual data */\r
901                 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
902                         SetFlsJobBusy();\r
903                 } else {\r
904                         AbortJob(Fls_GetJobResult());\r
905                 }\r
906         } else {\r
907                 AbortJob(Fls_GetJobResult());\r
908         }\r
909 }\r
910 \r
911 \r
912 /*\r
913  * Check job result of write data, if ok request for write magic or\r
914  * next data read depending on if there are more block data to move.\r
915  */\r
916 static void GarbageCollectWriteData(void)\r
917 {\r
918         if (CheckFlsJobFinnished()) {\r
919                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
920                         CurrentJob.Op.GarbageCollect.DataOffset += RWBUFFER_SIZE;\r
921                         CurrentJob.Op.GarbageCollect.BytesLeft -= RWBUFFER_SIZE;\r
922                         if (CurrentJob.Op.GarbageCollect.BytesLeft <= 0) {\r
923                                 /* Yes, we are finished */\r
924                                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
925                         } else {\r
926                                 /* More data to move */\r
927                                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
928                         }\r
929                 } else {\r
930                         AbortJob(Fls_GetJobResult());\r
931                 }\r
932         }\r
933 }\r
934 \r
935 \r
936 /*\r
937  * Start write magic\r
938  */\r
939 static void GarbageCollectWriteMagicRequested(void)\r
940 {\r
941         if (Fls_GetStatus() == MEMIF_IDLE) {\r
942                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE;\r
943                 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_MAGIC_PAGE_SIZE);\r
944                 memcpy(RWBuffer.BlockCtrl.MagicPage.Byte, MagicMaster, BLOCK_MAGIC_LEN);\r
945                 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_MAGIC_PAGE_SIZE) == E_OK) {\r
946                         SetFlsJobBusy();\r
947                 } else {\r
948                         AbortJob(Fls_GetJobResult());\r
949                 }\r
950         }\r
951 }\r
952 \r
953 \r
954 /*\r
955  * Check the job result of write magic, if ok update the admin table with the new position of data.\r
956  */\r
957 static void GarbageCollectWriteMagic(void)\r
958 {\r
959         if (CheckFlsJobFinnished()) {\r
960                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
961                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.GarbageCollect.WriteAdminAddress;\r
962                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.GarbageCollect.WriteDataAddress;\r
963                         FinnishJob();\r
964                 } else {\r
965                         AbortJob(Fls_GetJobResult());\r
966                 }\r
967         }\r
968 }\r
969 \r
970 \r
971 /*\r
972  * Check the result of the erase job\r
973  */\r
974 static void GarbageCollectErase(void)\r
975 {\r
976         if (CheckFlsJobFinnished()) {\r
977                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
978                         AdminFls.BankStatus[CurrentJob.Op.GarbageCollect.BankNumber] = BANK_STATUS_NEW;\r
979                         FinnishJob();\r
980                 } else {\r
981                         AbortJob(Fls_GetJobResult());\r
982                 }\r
983         }\r
984 }\r
985 \r
986 \r
987 /*\r
988  * Write an "Invalidated" block header\r
989  */\r
990 static void BlockHeaderInvalidWrite(void)\r
991 {\r
992         // Write the header including the magic\r
993         memset(RWBuffer.Byte, 0xff, BLOCK_CTRL_PAGE_SIZE);\r
994         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INVALIDATED;\r
995         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
996         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = 0;\r
997         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = 0;\r
998         memcpy(RWBuffer.BlockCtrl.MagicPage.Byte, MagicMaster, BLOCK_MAGIC_LEN);\r
999 \r
1000         if (Fls_Write(CurrentJob.Op.Invalidate.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_DATA_PAGE_SIZE) == E_OK) {\r
1001                 SetFlsJobBusy();\r
1002                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
1003                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
1004         } else {\r
1005                 AbortJob(Fls_GetJobResult());\r
1006         }\r
1007 }\r
1008 \r
1009 \r
1010 /*\r
1011  * Check if bank switch is needed, if yes request for marking current bank as old,\r
1012  * if no request for writing a header with "Invalid" status set.\r
1013  */\r
1014 static void InvalidateStartJob(void)\r
1015 {\r
1016         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1017                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
1018                         /* Bank switch needed, mark current bank as "old" */\r
1019                         CurrentJob.State = FEE_INVALIDATE_MARK_BANK_OLD;\r
1020                         BankHeaderOldWrite(AdminFls.BankNumber);\r
1021                 } else {\r
1022                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1023                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1024 \r
1025                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1026                         BlockHeaderInvalidWrite();\r
1027                 }\r
1028         }\r
1029 }\r
1030 \r
1031 \r
1032 /*\r
1033  * Check job result of mark bank old, if ok continue with request for writing\r
1034  * a header with "Invalid" status set.\r
1035  */\r
1036 static void InvalidateMarkBankOld(void)\r
1037 {\r
1038         if (CheckFlsJobFinnished()) {\r
1039                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1040                         // Mark for garbage collection\r
1041                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
1042 \r
1043                         // Change of bank\r
1044                         AdminFls.BankNumber ^= 0x1;\r
1045                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1046                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;\r
1047 \r
1048                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1049                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1050 \r
1051                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER_REQUESTED;\r
1052                         BlockHeaderInvalidWrite();\r
1053                 } else {\r
1054                         AbortJob(Fls_GetJobResult());\r
1055                 }\r
1056         }\r
1057 }\r
1058 \r
1059 /*\r
1060  * Start the writing of the "Invalid" header.
1061  */\r
1062 static void InvalidateWriteInvalidateHeaderRequested(void)\r
1063 {\r
1064         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1065                 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1066                 BlockHeaderInvalidWrite();\r
1067         } else {\r
1068                 AbortJob(Fls_GetJobResult());\r
1069         }\r
1070 }\r
1071 \r
1072 \r
1073 /*\r
1074  * Check the job result of "Invalid" header write, if ok update the block admin table\r
1075  */\r
1076 static void InvalidateWriteInvalidateHeader(void)\r
1077 {\r
1078         if (CheckFlsJobFinnished()) {\r
1079                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1080                         // Update the block admin table\r
1081                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INUSE;\r
1082                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Invalidate.WriteAdminAddress;\r
1083                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Invalidate.WriteDataAddress;\r
1084 \r
1085                         FinnishJob();\r
1086                 } else {\r
1087                         AbortJob(Fls_GetJobResult());\r
1088                 }\r
1089         }\r
1090 }\r
1091 \r
1092 \r
1093 /***************************************\r
1094  *    External accessible functions    *\r
1095  ***************************************/\r
1096 /*\r
1097  * Procedure:   Fee_Init\r
1098  * Reentrant:   No\r
1099  */\r
1100 void Fee_Init(void)\r
1101 {\r
1102         uint16 i,j;\r
1103 #if 0\r
1104         uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11;\r
1105         t1 = sizeof(FlsBankStatusType);\r
1106         t2 = BANK_CTRL_PAGE_SIZE;\r
1107         t3 = sizeof(FlsBankCtrlPageType);\r
1108 \r
1109         t4 = sizeof(BlockStatusType);\r
1110         t5 = sizeof(FlsBlockDataType);\r
1111         t6 = BLOCK_DATA_PAGE_SIZE;\r
1112         t7 = sizeof(FlsBlockDataPageType);\r
1113 \r
1114 \r
1115         t8 = sizeof(FlsBlockMagicPageType);\r
1116         t9 = BLOCK_MAGIC_PAGE_SIZE;\r
1117         t10 = sizeof(FlsBlockControlType);\r
1118         t11 = BLOCK_CTRL_PAGE_SIZE;\r
1119 #endif\r
1120 \r
1121 \r
1122 \r
1123         /* Reporting information */\r
1124         ModuleStatus = MEMIF_BUSY_INTERNAL;\r
1125         JobResult = MEMIF_JOB_OK;\r
1126 \r
1127         /* State of device */\r
1128         CurrentJob.State = FEE_STARTUP_REQUESTED;\r
1129         CurrentJob.InStateCounter = 0;\r
1130 #if (FEE_POLLING_MODE == STD_OFF)\r
1131         FlsJobReady = TRUE;\r
1132 #endif\r
1133 \r
1134         AdminFls.BankNumber = 0;\r
1135         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1136         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;\r
1137 \r
1138         for (i = 0; i < NUM_OF_BANKS; i++) {\r
1139                 AdminFls.BankStatus[i] = BANK_STATUS_NEW;\r
1140         }\r
1141 \r
1142         for (i = 0; i < FEE_NUM_OF_BLOCKS; i++) {\r
1143                 for (j = 0; j < FEE_MAX_NUM_SETS; j++) {\r
1144                         AdminFls.BlockDescrTbl[i][j].Status = BLOCK_STATUS_EMPTY;\r
1145                         AdminFls.BlockDescrTbl[i][j].BlockAdminAddress= 0;\r
1146                         AdminFls.BlockDescrTbl[i][j].BlockDataAddress = 0;\r
1147                 }\r
1148         }\r
1149 }\r
1150 \r
1151 \r
1152 /*\r
1153  * Procedure:   Fee_SetMode\r
1154  * Reentrant:   No\r
1155  */\r
1156 void Fee_SetMode(MemIf_ModeType mode)\r
1157 {\r
1158 #if ( FLS_SET_MODE_API == STD_ON )\r
1159         Fls_SetMode(mode);\r
1160 #else\r
1161         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_SET_MODE_ID, FEE_E_NOT_SUPPORTED);\r
1162 #endif\r
1163 }\r
1164 \r
1165 /*\r
1166  * Procedure:   Fee_Read\r
1167  * Reentrant:   No\r
1168  */\r
1169 Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBufferPtr, uint16 length)\r
1170 {\r
1171         uint16 blockIndex;\r
1172         uint16 dataset;\r
1173 \r
1174         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);\r
1175         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1176 \r
1177         VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1178         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1179         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1180         VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1181         VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);\r
1182         VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);\r
1183 \r
1184         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1185         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1186 \r
1187 \r
1188         /** @req FEE022 */\r
1189         ModuleStatus = MEMIF_BUSY;\r
1190         JobResult = MEMIF_JOB_PENDING;\r
1191 \r
1192         CurrentJob.BlockNumber = blockNumber;\r
1193         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1194         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1195         CurrentJob.Length = length;\r
1196         CurrentJob.Op.Read.Offset = blockOffset;\r
1197         CurrentJob.Op.Read.RamPtr = dataBufferPtr;\r
1198         CurrentJob.State = FEE_READ_REQUESTED;\r
1199 \r
1200         return E_OK;\r
1201 }\r
1202 \r
1203 \r
1204 /*\r
1205  * Procedure:   Fee_Write\r
1206  * Reentrant:   No\r
1207  */\r
1208 Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)\r
1209 {\r
1210         uint16 blockIndex;\r
1211         uint16 dataset;\r
1212 \r
1213         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);\r
1214         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_WRITE_ID, FEE_E_BUSY, E_NOT_OK);\r
1215 \r
1216         VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1217         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1218         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1219         VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1220 \r
1221         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1222         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1223 \r
1224 \r
1225         /** @req FEE025 */\r
1226         ModuleStatus = MEMIF_BUSY;\r
1227         JobResult = MEMIF_JOB_PENDING;\r
1228 \r
1229         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1230         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1231         CurrentJob.BlockNumber = blockNumber;\r
1232         CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
1233         CurrentJob.Op.Write.RamPtr = dataBufferPtr;\r
1234         CurrentJob.State = FEE_WRITE_REQUESTED;\r
1235 \r
1236         return E_OK;\r
1237 }\r
1238 \r
1239 \r
1240 /*\r
1241  * Procedure:   Fee_Cancel\r
1242  * Reentrant:   No\r
1243  */\r
1244 void Fee_Cancel(void)\r
1245 {\r
1246         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_CANCEL_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1247 }\r
1248 \r
1249 \r
1250 /*\r
1251  * Procedure:   Fee_GetStatus\r
1252  * Reentrant:   No\r
1253  */\r
1254 MemIf_StatusType Fee_GetStatus(void)\r
1255 {\r
1256         return ModuleStatus;\r
1257 }\r
1258 \r
1259 \r
1260 /*\r
1261  * Procedure:   Fee_GetJobResult\r
1262  * Reentrant:   No\r
1263  */\r
1264 MemIf_JobResultType Fee_GetJobResult(void)\r
1265 {\r
1266         return JobResult;\r
1267 }\r
1268 \r
1269 \r
1270 /*\r
1271  * Procedure:   Fee_InvalidateBlock\r
1272  * Reentrant:   No\r
1273  */\r
1274 Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)\r
1275 {\r
1276         uint16 blockIndex;\r
1277         uint16 dataset;\r
1278 \r
1279         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);\r
1280         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_INVALIDATE_BLOCK_ID, FEE_E_BUSY, E_NOT_OK);\r
1281 \r
1282         VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1283         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1284         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1285 \r
1286         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1287         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1288 \r
1289 \r
1290         ModuleStatus = MEMIF_BUSY;\r
1291         JobResult = MEMIF_JOB_PENDING;\r
1292 \r
1293         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1294         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1295         CurrentJob.BlockNumber = blockNumber;\r
1296         CurrentJob.State = FEE_INVALIDATE_REQUESTED;\r
1297 \r
1298         return E_OK;\r
1299 }\r
1300 \r
1301 \r
1302 /*\r
1303  * Procedure:   Fee_EraseImmediateBlock\r
1304  * Reentrant:   No\r
1305  */\r
1306 Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)\r
1307 {\r
1308         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_ERASE_IMMEDIATE_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1309 \r
1310         return E_NOT_OK;\r
1311 }\r
1312 \r
1313 \r
1314 /***************************************\r
1315  *         Scheduled functions         *\r
1316  ***************************************/\r
1317 /*\r
1318  * Procedure:   Fee_MainFunction\r
1319  * Reentrant:   No\r
1320  */\r
1321 void Fee_MainFunction(void)\r
1322 {\r
1323         static CurrentJobStateType LastState = FEE_UNINITIALIZED;\r
1324 \r
1325         if (CurrentJob.State == LastState) {\r
1326                 if (CurrentJob.InStateCounter < STATE_COUNTER_MAX) {\r
1327                         CurrentJob.InStateCounter++;\r
1328                 }\r
1329         } else {\r
1330                 LastState = CurrentJob.State;\r
1331                 CurrentJob.InStateCounter = 0;\r
1332         }\r
1333 \r
1334         switch (CurrentJob.State) {\r
1335         case FEE_UNINITIALIZED:\r
1336                 break;\r
1337 \r
1338         case FEE_IDLE:\r
1339                 if (CurrentJob.InStateCounter > GARBAGE_COLLECTION_DELAY) {\r
1340                         CheckIfGarbageCollectionNeeded();\r
1341                 }\r
1342                 break;\r
1343 \r
1344                 /*\r
1345                  * Startup states\r
1346                  */\r
1347         case FEE_STARTUP_REQUESTED:\r
1348                 StartupStartJob();\r
1349                 break;\r
1350 \r
1351         case FEE_STARTUP_READ_BANK1_STATUS:\r
1352                 StartupReadBank1Status();\r
1353                 break;\r
1354 \r
1355         case FEE_STARTUP_READ_BANK2_STATUS_REQUESTED:\r
1356                 StartupReadBank2StatusRequested();\r
1357                 break;\r
1358 \r
1359         case FEE_STARTUP_READ_BANK2_STATUS:\r
1360                 StartupReadBank2Status();\r
1361                 break;\r
1362 \r
1363         case FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED:\r
1364                 StartupReadBlockAdminRequested();\r
1365                 break;\r
1366 \r
1367         case FEE_STARTUP_READ_BLOCK_ADMIN:\r
1368                 StartupReadBlockAdmin();\r
1369                 break;\r
1370 \r
1371         /*\r
1372          *  Read states\r
1373          */\r
1374         case FEE_READ_REQUESTED:\r
1375                 ReadStartJob();\r
1376                 break;\r
1377 \r
1378         case FEE_READ:\r
1379                 Reading();\r
1380                 break;\r
1381 \r
1382         /*\r
1383          * Write states
1384          */\r
1385         case FEE_WRITE_REQUESTED:\r
1386                 WriteStartJob();\r
1387                 break;\r
1388 \r
1389         case FEE_WRITE_MARK_BANK_OLD:\r
1390                 WriteMarkBankOldState();\r
1391                 break;\r
1392 \r
1393         case FEE_WRITE_HEADER_REQUESTED:\r
1394                 WriteHeaderRequested();\r
1395                 break;\r
1396 \r
1397         case FEE_WRITE_HEADER:\r
1398                 WriteHeaderState();\r
1399                 break;\r
1400 \r
1401         case FEE_WRITE_DATA_REQUESTED:\r
1402                 WriteDataRequested();\r
1403                 break;\r
1404 \r
1405         case FEE_WRITE_DATA:\r
1406                 WriteDataState();\r
1407                 break;\r
1408 \r
1409         case FEE_WRITE_MAGIC_REQUESTED:\r
1410                 WriteMagicRequested();\r
1411                 break;\r
1412 \r
1413         case FEE_WRITE_MAGIC:\r
1414                 WriteMagicState();\r
1415                 break;\r
1416 \r
1417         /*\r
1418          * Garbage collection states
1419          */\r
1420         case FEE_GARBAGE_COLLECT_REQUESTED:\r
1421                 GarbageCollectStartJob();\r
1422                 break;\r
1423 \r
1424         case FEE_GARBAGE_COLLECT_HEADER_WRITE:\r
1425                 GarbageCollectWriteHeader();\r
1426                 break;\r
1427 \r
1428         case FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED:\r
1429                 GarbageCollectReadDataRequested();\r
1430                 break;\r
1431 \r
1432         case FEE_GARBAGE_COLLECT_DATA_READ:\r
1433                 GarbageCollectReadData();\r
1434                 break;\r
1435 \r
1436         case FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED:\r
1437                 GarbageCollectWriteDataRequested();\r
1438                 break;\r
1439 \r
1440         case FEE_GARBAGE_COLLECT_DATA_WRITE:\r
1441                 GarbageCollectWriteData();\r
1442                 break;\r
1443 \r
1444         case FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED:\r
1445                 GarbageCollectWriteMagicRequested();\r
1446                 break;\r
1447 \r
1448         case FEE_GARBAGE_COLLECT_MAGIC_WRITE:\r
1449                 GarbageCollectWriteMagic();\r
1450                 break;\r
1451 \r
1452         case FEE_GARBAGE_COLLECT_ERASE:\r
1453                 GarbageCollectErase();\r
1454                 break;\r
1455 \r
1456         /*\r
1457          * Invalidate states
1458          */\r
1459         case FEE_INVALIDATE_REQUESTED:\r
1460                 InvalidateStartJob();\r
1461                 break;\r
1462 \r
1463         case FEE_INVALIDATE_MARK_BANK_OLD:\r
1464                 InvalidateMarkBankOld();\r
1465                 break;\r
1466 \r
1467         case FEE_WRITE_INVALIDATE_HEADER_REQUESTED:\r
1468                 InvalidateWriteInvalidateHeaderRequested();\r
1469                 break;\r
1470 \r
1471         case FEE_WRITE_INVALIDATE_HEADER:\r
1472                 InvalidateWriteInvalidateHeader();\r
1473                 break;\r
1474 \r
1475 \r
1476         /*\r
1477          * Other
1478          */\r
1479         default:\r
1480                 break;\r
1481         }\r
1482 }\r
1483 \r
1484 \r
1485 /***************************************\r
1486  *  Call-back notifications functions  *\r
1487  ***************************************/\r
1488 #if (FEE_POLLING_MODE == STD_OFF)\r
1489 /*\r
1490  * Procedure:   Fee_JobEndNotification\r
1491  * Reentrant:   No\r
1492  */\r
1493 void Fee_JobEndNotification(void)\r
1494 {\r
1495         FlsJobReady = TRUE;\r
1496 }\r
1497 \r
1498 \r
1499 /*\r
1500  * Procedure:   Fee_JobErrorNotification\r
1501  * Reentrant:   No\r
1502  */\r
1503 void Fee_JobErrorNotification(void)\r
1504 {\r
1505         FlsJobReady = TRUE;\r
1506 }\r
1507 #endif\r