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