]> rtime.felk.cvut.cz Git - arc.git/blob - memory/Fee/Fee.c
Fee, changed type on for flag used to force garbage collection. Aborting job if memif...
[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         boolean                         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 = FALSE;\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 = TRUE;\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         } else {\r
1033                 AdminFls.NofFailedGarbageCollect++;\r
1034                 AbortJob(Fls_GetJobResult());\r
1035         }\r
1036 }\r
1037 \r
1038 \r
1039 /*\r
1040  * Check the job result of write magic, if ok update the admin table with the new position of data.\r
1041  */\r
1042 static void GarbageCollectWriteMagic(void)\r
1043 {\r
1044         if (CheckFlsJobFinnished()) {\r
1045                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1046                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.GarbageCollect.WriteAdminAddress;\r
1047                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.GarbageCollect.WriteDataAddress;\r
1048                         CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;\r
1049                 } else {\r
1050                         AdminFls.NofFailedGarbageCollect++;\r
1051                         AbortJob(Fls_GetJobResult());\r
1052                 }\r
1053         }\r
1054 }\r
1055 \r
1056 \r
1057 /*\r
1058  * Check the result of the erase job\r
1059  */\r
1060 static void GarbageCollectErase(void)\r
1061 {\r
1062         if (CheckFlsJobFinnished()) {\r
1063                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1064                         AdminFls.BankStatus[CurrentJob.Op.GarbageCollect.BankNumber] = BANK_STATUS_NEW;\r
1065                         AdminFls.ForceGarbageCollect = FALSE;\r
1066                         AdminFls.NofFailedGarbageCollect = 0;\r
1067                         FinnishJob();\r
1068                 } else {\r
1069                         AdminFls.NofFailedGarbageCollect++;\r
1070                         AbortJob(Fls_GetJobResult());\r
1071                 }\r
1072         }\r
1073 }\r
1074 \r
1075 \r
1076 /*\r
1077  * Write an "Invalidated" block header\r
1078  */\r
1079 static void BlockHeaderInvalidWrite(void)\r
1080 {\r
1081         // Write the header including the magic\r
1082         memset(RWBuffer.Byte, 0xff, BLOCK_CTRL_PAGE_SIZE);\r
1083         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INVALIDATED;\r
1084         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
1085         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
1086         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = 0;\r
1087         memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
1088         memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
1089 \r
1090         if (Fls_Write(CurrentJob.Op.Invalidate.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
1091                 SetFlsJobBusy();\r
1092                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
1093                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
1094         } else {\r
1095                 AbortJob(Fls_GetJobResult());\r
1096         }\r
1097 }\r
1098 \r
1099 \r
1100 /*\r
1101  * Check if bank switch is needed, if yes request for marking current bank as old,\r
1102  * if no request for writing a header with "Invalid" status set.\r
1103  */\r
1104 static void InvalidateStartJob(void)\r
1105 {\r
1106         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1107                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
1108                         /* Bank switch needed, mark current bank as "old" */\r
1109                         CurrentJob.State = FEE_INVALIDATE_MARK_BANK_OLD;\r
1110                         BankHeaderOldWrite(AdminFls.BankNumber);\r
1111                 } else {\r
1112                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1113                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1114 \r
1115                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1116                         BlockHeaderInvalidWrite();\r
1117                 }\r
1118         }\r
1119 }\r
1120 \r
1121 \r
1122 /*\r
1123  * Check job result of mark bank old, if ok continue with request for writing\r
1124  * a header with "Invalid" status set.\r
1125  */\r
1126 static void InvalidateMarkBankOld(void)\r
1127 {\r
1128         if (CheckFlsJobFinnished()) {\r
1129                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1130                         // Mark for garbage collection\r
1131                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
1132 \r
1133                         // Change of bank\r
1134                         AdminFls.BankNumber ^= 0x1u;\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                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1139                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1140 \r
1141                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER_REQUESTED;\r
1142                 } else {\r
1143                         AbortJob(Fls_GetJobResult());\r
1144                 }\r
1145         }\r
1146 }\r
1147 \r
1148 /*\r
1149  * Start the writing of the "Invalid" header.\r
1150  */\r
1151 static void InvalidateWriteInvalidateHeaderRequested(void)\r
1152 {\r
1153         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1154                 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1155                 BlockHeaderInvalidWrite();\r
1156         }\r
1157 }\r
1158 \r
1159 \r
1160 /*\r
1161  * Check the job result of "Invalid" header write, if ok update the block admin table\r
1162  */\r
1163 static void InvalidateWriteInvalidateHeader(void)\r
1164 {\r
1165         if (CheckFlsJobFinnished()) {\r
1166                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1167                         // Update the block admin table\r
1168                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INVALIDATED;\r
1169                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Invalidate.WriteAdminAddress;\r
1170                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Invalidate.WriteDataAddress;\r
1171 \r
1172                         FinnishJob();\r
1173                 } else {\r
1174                         AbortJob(Fls_GetJobResult());\r
1175                 }\r
1176         }\r
1177 }\r
1178 \r
1179 \r
1180 /***************************************\r
1181  *    External accessible functions    *\r
1182  ***************************************/\r
1183 /*\r
1184  * Procedure:   Fee_Init\r
1185  * Reentrant:   No\r
1186  */\r
1187 void Fee_Init(void)\r
1188 {\r
1189         uint16 i,j;\r
1190 \r
1191         /* Reporting information */\r
1192         ModuleStatus = MEMIF_BUSY_INTERNAL;\r
1193         JobResult = MEMIF_JOB_OK;\r
1194 \r
1195         /* State of device */\r
1196         CurrentJob.State = FEE_STARTUP_REQUESTED;\r
1197 #if (FEE_POLLING_MODE == STD_OFF)\r
1198         FlsJobReady = TRUE;\r
1199 #endif\r
1200 \r
1201         AdminFls.BankNumber = 0;\r
1202         AdminFls.ForceGarbageCollect = FALSE;\r
1203         AdminFls.NofFailedGarbageCollect = 0;\r
1204         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1205         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
1206 \r
1207         for (i = 0; i < NUM_OF_BANKS; i++) {\r
1208                 AdminFls.BankStatus[i] = BANK_STATUS_NEW;\r
1209         }\r
1210 \r
1211         for (i = 0; i < FEE_NUM_OF_BLOCKS; i++) {\r
1212                 for (j = 0; j < FEE_MAX_NUM_SETS; j++) {\r
1213                         AdminFls.BlockDescrTbl[i][j].Status = BLOCK_STATUS_EMPTY;\r
1214                         AdminFls.BlockDescrTbl[i][j].BlockAdminAddress= 0;\r
1215                         AdminFls.BlockDescrTbl[i][j].BlockDataAddress = 0;\r
1216                 }\r
1217         }\r
1218 }\r
1219 \r
1220 \r
1221 /*\r
1222  * Procedure:   Fee_SetMode\r
1223  * Reentrant:   No\r
1224  */\r
1225 void Fee_SetMode(MemIf_ModeType mode)\r
1226 {\r
1227 #if ( FLS_SET_MODE_API == STD_ON )\r
1228         Fls_SetMode(mode);\r
1229 #else\r
1230         //lint --e{715} PC-Lint (715) - variable "mode" not used in this case\r
1231         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_SET_MODE_ID, FEE_E_NOT_SUPPORTED);\r
1232 #endif\r
1233 }\r
1234 \r
1235 /*\r
1236  * Procedure:   Fee_Read\r
1237  * Reentrant:   No\r
1238  */\r
1239 Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBufferPtr, uint16 length)\r
1240 {\r
1241         uint16 blockIndex;\r
1242         uint16 dataset;\r
1243 \r
1244         DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);\r
1245         if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
1246                 return E_NOT_OK;\r
1247         }\r
1248         if( !(ModuleStatus == MEMIF_IDLE) ) {\r
1249                 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1250                 return E_NOT_OK;\r
1251         }\r
1252 \r
1253         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1254         DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1255         DET_VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1256         DET_VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);\r
1257         DET_VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);\r
1258 \r
1259         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1260         DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1261 \r
1262 \r
1263         /** @req FEE022 */\r
1264         ModuleStatus = MEMIF_BUSY;\r
1265         JobResult = MEMIF_JOB_PENDING;\r
1266 \r
1267         CurrentJob.BlockNumber = blockNumber;\r
1268         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1269         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1270         CurrentJob.Length = length;\r
1271         CurrentJob.Op.Read.Offset = blockOffset;\r
1272         CurrentJob.Op.Read.RamPtr = dataBufferPtr;\r
1273         CurrentJob.State = FEE_READ_REQUESTED;\r
1274 \r
1275         return E_OK;\r
1276 }\r
1277 \r
1278 \r
1279 /*\r
1280  * Procedure:   Fee_Write\r
1281  * Reentrant:   No\r
1282  */\r
1283 Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)\r
1284 {\r
1285         uint16 blockIndex;\r
1286         uint16 dataset;\r
1287 \r
1288         DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);\r
1289         if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
1290                 return E_NOT_OK;\r
1291         }\r
1292         if( !(ModuleStatus == MEMIF_IDLE) ) {\r
1293                 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1294                 return E_NOT_OK;\r
1295         }\r
1296 \r
1297         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1298         DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1299         DET_VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1300 \r
1301         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1302         DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1303 \r
1304 \r
1305         /** @req FEE025 */\r
1306         ModuleStatus = MEMIF_BUSY;\r
1307         JobResult = MEMIF_JOB_PENDING;\r
1308 \r
1309         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1310         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1311         CurrentJob.BlockNumber = blockNumber;\r
1312         CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
1313         CurrentJob.Op.Write.RamPtr = dataBufferPtr;\r
1314         CurrentJob.State = FEE_WRITE_REQUESTED;\r
1315 \r
1316         return E_OK;\r
1317 }\r
1318 \r
1319 \r
1320 /*\r
1321  * Procedure:   Fee_Cancel\r
1322  * Reentrant:   No\r
1323  */\r
1324 void Fee_Cancel(void)\r
1325 {\r
1326         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_CANCEL_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1327 }\r
1328 \r
1329 \r
1330 /*\r
1331  * Procedure:   Fee_GetStatus\r
1332  * Reentrant:   No\r
1333  */\r
1334 MemIf_StatusType Fee_GetStatus(void)\r
1335 {\r
1336         if(AdminFls.ForceGarbageCollect && (FEE_IDLE == CurrentJob.State)){\r
1337                 return MEMIF_BUSY_INTERNAL;\r
1338         } else {\r
1339                 return ModuleStatus;\r
1340         }\r
1341 }\r
1342 \r
1343 \r
1344 /*\r
1345  * Procedure:   Fee_GetJobResult\r
1346  * Reentrant:   No\r
1347  */\r
1348 MemIf_JobResultType Fee_GetJobResult(void)\r
1349 {\r
1350         return JobResult;\r
1351 }\r
1352 \r
1353 \r
1354 /*\r
1355  * Procedure:   Fee_InvalidateBlock\r
1356  * Reentrant:   No\r
1357  */\r
1358 Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)\r
1359 {\r
1360         uint16 blockIndex;\r
1361         uint16 dataset;\r
1362 \r
1363         DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);\r
1364         if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
1365                 return E_NOT_OK;\r
1366         }\r
1367         if( !(ModuleStatus == MEMIF_IDLE) ) {\r
1368                 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1369                 return E_NOT_OK;\r
1370         }\r
1371 \r
1372         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1373         DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1374 \r
1375         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1376         DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1377 \r
1378 \r
1379         ModuleStatus = MEMIF_BUSY;\r
1380         JobResult = MEMIF_JOB_PENDING;\r
1381 \r
1382         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1383         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1384         CurrentJob.BlockNumber = blockNumber;\r
1385         CurrentJob.State = FEE_INVALIDATE_REQUESTED;\r
1386 \r
1387         return E_OK;\r
1388 }\r
1389 \r
1390 \r
1391 /*\r
1392  * Procedure:   Fee_EraseImmediateBlock\r
1393  * Reentrant:   No\r
1394  */\r
1395 Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)\r
1396 {\r
1397         //lint --e{715} PC-Lint (715) - function is not implemented and thus variable "blockNumber" is not used yet\r
1398 \r
1399         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_ERASE_IMMEDIATE_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1400 \r
1401 \r
1402         return E_NOT_OK;\r
1403 }\r
1404 \r
1405 \r
1406 /***************************************\r
1407  *         Scheduled functions         *\r
1408  ***************************************/\r
1409 /*\r
1410  * Procedure:   Fee_MainFunction\r
1411  * Reentrant:   No\r
1412  */\r
1413 void Fee_MainFunction(void)\r
1414 {\r
1415 \r
1416         switch (CurrentJob.State) {\r
1417         case FEE_UNINITIALIZED:\r
1418                 break;\r
1419 \r
1420         case FEE_IDLE:\r
1421                 if (AdminFls.ForceGarbageCollect) {\r
1422                         CheckIfGarbageCollectionNeeded();\r
1423                 }\r
1424                 break;\r
1425 \r
1426                 /*\r
1427                  * Startup states\r
1428                  */\r
1429         case FEE_STARTUP_REQUESTED:\r
1430                 StartupStartJob();\r
1431                 break;\r
1432 \r
1433         case FEE_STARTUP_READ_BANK1_STATUS:\r
1434                 StartupReadBank1Status();\r
1435                 break;\r
1436 \r
1437         case FEE_STARTUP_READ_BANK2_STATUS_REQUESTED:\r
1438                 StartupReadBank2StatusRequested();\r
1439                 break;\r
1440 \r
1441         case FEE_STARTUP_READ_BANK2_STATUS:\r
1442                 StartupReadBank2Status();\r
1443                 break;\r
1444 \r
1445         case FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED:\r
1446                 StartupReadBlockAdminRequested();\r
1447                 break;\r
1448 \r
1449         case FEE_STARTUP_READ_BLOCK_ADMIN:\r
1450                 StartupReadBlockAdmin();\r
1451                 break;\r
1452 \r
1453         /*\r
1454          *  Read states\r
1455          */\r
1456         case FEE_READ_REQUESTED:\r
1457                 ReadStartJob();\r
1458                 break;\r
1459 \r
1460         case FEE_READ:\r
1461                 Reading();\r
1462                 break;\r
1463 \r
1464         /*\r
1465          * Write states\r
1466          */\r
1467         case FEE_WRITE_REQUESTED:\r
1468                 WriteStartJob();\r
1469                 break;\r
1470 \r
1471         case FEE_WRITE_MARK_BANK_OLD:\r
1472                 WriteMarkBankOldState();\r
1473                 break;\r
1474 \r
1475         case FEE_WRITE_HEADER_REQUESTED:\r
1476                 WriteHeaderRequested();\r
1477                 break;\r
1478 \r
1479         case FEE_WRITE_HEADER:\r
1480                 WriteHeaderState();\r
1481                 break;\r
1482 \r
1483         case FEE_WRITE_DATA_REQUESTED:\r
1484                 WriteDataRequested();\r
1485                 break;\r
1486 \r
1487         case FEE_WRITE_DATA:\r
1488                 WriteDataState();\r
1489                 break;\r
1490 \r
1491         case FEE_WRITE_MAGIC_REQUESTED:\r
1492                 WriteMagicRequested();\r
1493                 break;\r
1494 \r
1495         case FEE_WRITE_MAGIC:\r
1496                 WriteMagicState();\r
1497                 break;\r
1498 \r
1499         /*\r
1500          * Garbage collection states\r
1501          */\r
1502         case FEE_GARBAGE_COLLECT_REQUESTED:\r
1503                 GarbageCollectStartJob();\r
1504                 break;\r
1505 \r
1506         case FEE_GARBAGE_COLLECT_HEADER_WRITE:\r
1507                 GarbageCollectWriteHeader();\r
1508                 break;\r
1509 \r
1510         case FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED:\r
1511                 GarbageCollectReadDataRequested();\r
1512                 break;\r
1513 \r
1514         case FEE_GARBAGE_COLLECT_DATA_READ:\r
1515                 GarbageCollectReadData();\r
1516                 break;\r
1517 \r
1518         case FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED:\r
1519                 GarbageCollectWriteDataRequested();\r
1520                 break;\r
1521 \r
1522         case FEE_GARBAGE_COLLECT_DATA_WRITE:\r
1523                 GarbageCollectWriteData();\r
1524                 break;\r
1525 \r
1526         case FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED:\r
1527                 GarbageCollectWriteMagicRequested();\r
1528                 break;\r
1529 \r
1530         case FEE_GARBAGE_COLLECT_MAGIC_WRITE:\r
1531                 GarbageCollectWriteMagic();\r
1532                 break;\r
1533 \r
1534         case FEE_GARBAGE_COLLECT_ERASE:\r
1535                 GarbageCollectErase();\r
1536                 break;\r
1537 \r
1538         /*\r
1539          * Invalidate states\r
1540          */\r
1541         case FEE_INVALIDATE_REQUESTED:\r
1542                 InvalidateStartJob();\r
1543                 break;\r
1544 \r
1545         case FEE_INVALIDATE_MARK_BANK_OLD:\r
1546                 InvalidateMarkBankOld();\r
1547                 break;\r
1548 \r
1549         case FEE_WRITE_INVALIDATE_HEADER_REQUESTED:\r
1550                 InvalidateWriteInvalidateHeaderRequested();\r
1551                 break;\r
1552 \r
1553         case FEE_WRITE_INVALIDATE_HEADER:\r
1554                 InvalidateWriteInvalidateHeader();\r
1555                 break;\r
1556 \r
1557         /*\r
1558          * Corrupted state\r
1559          */\r
1560         case FEE_CORRUPTED:\r
1561                 break;\r
1562 \r
1563         /*\r
1564          * Other\r
1565          */\r
1566         default:\r
1567                 break;\r
1568         }\r
1569 }\r
1570 \r
1571 \r
1572 /***************************************\r
1573  *  Call-back notifications functions  *\r
1574  ***************************************/\r
1575 #if (FEE_POLLING_MODE == STD_OFF)\r
1576 /*\r
1577  * Procedure:   Fee_JobEndNotification\r
1578  * Reentrant:   No\r
1579  */\r
1580 void Fee_JobEndNotification(void)\r
1581 {\r
1582         FlsJobReady = TRUE;\r
1583 }\r
1584 \r
1585 \r
1586 /*\r
1587  * Procedure:   Fee_JobErrorNotification\r
1588  * Reentrant:   No\r
1589  */\r
1590 void Fee_JobErrorNotification(void)\r
1591 {\r
1592         FlsJobReady = TRUE;\r
1593 }\r
1594 #endif\r