]> rtime.felk.cvut.cz Git - arc.git/blob - memory/Fee/Fee.c
dd78574e0ee7e766f6eb9ee18131c6f1a824f46a
[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                                          InStateCounter;\r
303         uint16                                          BlockNumber;\r
304         uint16                                          Length;\r
305         const Fee_BlockConfigType       *BlockConfigPtr;\r
306         AdminFlsBlockType                       *AdminFlsBlockPtr;\r
307         union {\r
308                 struct {\r
309                         uint8                           NrOfBanks;\r
310                         uint8                           BankNumber;\r
311                         Fls_AddressType         BlockAdminAddress;\r
312                 }Startup;\r
313                 struct {\r
314                         uint16                          Offset;\r
315                         uint8                           *RamPtr;\r
316                 }Read;\r
317                 struct {\r
318                         uint8                           *RamPtr;\r
319                         Fls_AddressType         WriteAdminAddress;\r
320                         Fls_AddressType         WriteDataAddress;\r
321                 }Write;\r
322                 struct {\r
323                         Fls_AddressType         WriteAdminAddress;\r
324                         Fls_AddressType         WriteDataAddress;\r
325                 }Invalidate;\r
326                 struct {\r
327                         uint8                           BankNumber;\r
328                         Fls_AddressType         WriteAdminAddress;\r
329                         Fls_AddressType         WriteDataAddress;\r
330                         uint16                          BytesLeft;\r
331                         uint16                          DataOffset;\r
332                 }GarbageCollect;\r
333         } Op;\r
334 } CurrentJobType;\r
335 \r
336 static CurrentJobType CurrentJob = {\r
337                 .State = FEE_IDLE,\r
338                 .InStateCounter = 0\r
339                 //lint -e{785}          PC-Lint (785) - rest of structure members is initialized when used.\r
340 };\r
341 \r
342 /*\r
343  * Misc definitions\r
344  */\r
345 #define STATE_COUNTER_MAX                               0xffff\r
346 #define GARBAGE_COLLECTION_DELAY                10\r
347 #define MAX_NOF_FAILED_GC_ATTEMPTS              5\r
348 /***************************************\r
349  *           Local functions           *\r
350  ***************************************/\r
351 uint16 GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(uint16 blockNumber) {\r
352         const Fee_BlockConfigType *FeeBlockCon;\r
353         uint16 BlockIndex = FEE_NUM_OF_BLOCKS + 1; // An invalid block\r
354 \r
355         FeeBlockCon = Fee_Config.BlockConfig;\r
356         for (uint16 i = 0; i < FEE_NUM_OF_BLOCKS; i++)\r
357         {\r
358                 if (FeeBlockCon[i].BlockNumber == blockNumber)\r
359                 {\r
360                         BlockIndex = i;\r
361                         break;\r
362                 }\r
363         }\r
364 \r
365         return BlockIndex;\r
366 }\r
367 \r
368 \r
369 #if (FEE_POLLING_MODE == STD_ON)\r
370 #define SetFlsJobBusy()                 /* Nothing needs to be done here */\r
371 \r
372 static boolean CheckFlsJobFinnished(void)\r
373 {\r
374         MemIf_JobResultType flsJobResult;\r
375 \r
376         flsJobResult = Fls_GetJobResult();\r
377         return (flsJobResult != MEMIF_JOB_PENDING);\r
378 }\r
379 #else\r
380 static boolean FlsJobReady = TRUE;\r
381 \r
382 static void SetFlsJobBusy()\r
383 {\r
384         FlsJobReady = FALSE;\r
385 }\r
386 \r
387 static boolean CheckFlsJobFinnished(void)\r
388 {\r
389         return (FlsJobReady);\r
390 }\r
391 \r
392 #endif\r
393 \r
394 \r
395 static void FinnishStartup(void)\r
396 {\r
397         CurrentJob.State = FEE_IDLE;\r
398         ModuleStatus = MEMIF_IDLE;\r
399         JobResult = MEMIF_JOB_OK;\r
400 }\r
401 \r
402 \r
403 static void AbortStartup(MemIf_JobResultType result)\r
404 {\r
405         CurrentJob.State = FEE_IDLE;\r
406         ModuleStatus = MEMIF_IDLE;\r
407         JobResult = result;\r
408 }\r
409 \r
410 \r
411 static void FinnishJob(void)\r
412 {\r
413         CurrentJob.State = FEE_IDLE;\r
414         ModuleStatus = MEMIF_IDLE;\r
415         JobResult = MEMIF_JOB_OK;\r
416         if(!AdminFls.ForceGarbageCollect){\r
417                 if (Fee_Config.General.NvmJobEndCallbackNotificationCallback != NULL) {\r
418                         Fee_Config.General.NvmJobEndCallbackNotificationCallback();\r
419                 }\r
420         }\r
421 }\r
422 \r
423 \r
424 static void AbortJob(MemIf_JobResultType result)\r
425 {\r
426         if(AdminFls.NofFailedGarbageCollect >= MAX_NOF_FAILED_GC_ATTEMPTS){\r
427                 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_GLOBAL_ID, FEE_FLASH_CORRUPT);\r
428                 AdminFls.ForceGarbageCollect = 0;\r
429                 CurrentJob.State = FEE_CORRUPTED;\r
430         } else {\r
431                 CurrentJob.State = FEE_IDLE;\r
432         }\r
433         ModuleStatus = MEMIF_IDLE;\r
434         JobResult = result;\r
435 \r
436         if (Fee_Config.General.NvmJobErrorCallbackNotificationCallback != NULL) {\r
437                 Fee_Config.General.NvmJobErrorCallbackNotificationCallback();\r
438         }\r
439 }\r
440 \r
441 \r
442 /*\r
443  * Start of bank status 1 read\r
444  */\r
445 static void StartupStartJob(void)\r
446 {\r
447         if (Fls_GetStatus() == MEMIF_IDLE) {\r
448                 CurrentJob.State = FEE_STARTUP_READ_BANK1_STATUS;\r
449                 /* Read bank status of bank 1 */\r
450                 // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR\r
451                 if (Fls_Read(BankProp[0].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[0], sizeof(FlsBankStatusType)) == E_OK) {\r
452                         SetFlsJobBusy();\r
453                 } else {\r
454                         AbortStartup(Fls_GetJobResult());\r
455                 }\r
456         }\r
457 }\r
458 \r
459 \r
460 /*\r
461  *  Check job result of bank 1 status read, if ok request for bank 2 status read\r
462  */\r
463 static void StartupReadBank1Status(void)\r
464 {\r
465         if (CheckFlsJobFinnished()) {\r
466                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
467                         CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS_REQUESTED;\r
468                 } else {\r
469                         AbortStartup(Fls_GetJobResult());\r
470                 }\r
471         }\r
472 }\r
473 \r
474 \r
475 /*\r
476  * Start of bank status 2 read\r
477  */\r
478 static void StartupReadBank2StatusRequested(void)\r
479 {\r
480         if (Fls_GetStatus() == MEMIF_IDLE) {\r
481                 /* Read bank status of bank 2 */\r
482                 CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS;\r
483                 // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR\r
484                 if (Fls_Read(BankProp[1].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[1], sizeof(FlsBankStatusType)) == E_OK) {\r
485                         SetFlsJobBusy();\r
486                 } else {\r
487                         AbortStartup(Fls_GetJobResult());\r
488                 }\r
489         }\r
490 }\r
491 \r
492 \r
493 /*\r
494  * Check job result of bank status 2 read - request for block status reading\r
495  */\r
496 static void StartupReadBank2Status(void)\r
497 {\r
498         MemIf_JobResultType jobResult;\r
499 \r
500         if (CheckFlsJobFinnished()) {\r
501                 jobResult = Fls_GetJobResult();\r
502                 if (jobResult == MEMIF_JOB_OK) {\r
503                         /* Select which bank to start with */\r
504                         if ((AdminFls.BankStatus[0] != BANK_STATUS_OLD) && (AdminFls.BankStatus[1] != BANK_STATUS_OLD)){\r
505                                 /* None is marked as old, just start with one of them */\r
506                                 CurrentJob.Op.Startup.BankNumber = 0;\r
507                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
508                         } else if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) && (AdminFls.BankStatus[1] == BANK_STATUS_OLD) ) {\r
509                                 /* Both banks are marked as old, this shall not be possible */\r
510                                 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
511                                 jobResult = MEMIF_JOB_FAILED;\r
512                         } else if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
513                                 CurrentJob.Op.Startup.BankNumber = 0;\r
514                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
515                         } else {\r
516                                 CurrentJob.Op.Startup.BankNumber = 1;\r
517                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
518                         }\r
519                 }\r
520 \r
521                 if (jobResult != MEMIF_JOB_OK) {\r
522                         AbortStartup(jobResult);\r
523                 } else {\r
524                         CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
525                         CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
526                 }\r
527         }\r
528 }\r
529 \r
530 /*\r
531  * Start of block admin read\r
532  */\r
533 static void StartupReadBlockAdminRequested(void)\r
534 {\r
535         if (Fls_GetStatus() == MEMIF_IDLE) {\r
536                 /* Start reading the banks */\r
537                 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN;\r
538                 if (Fls_Read(CurrentJob.Op.Startup.BlockAdminAddress, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
539                         SetFlsJobBusy();\r
540                 } else {\r
541                         AbortStartup(Fls_GetJobResult());\r
542                 }\r
543         }\r
544 }\r
545 \r
546 \r
547 /*\r
548  * Check job result of block admin read, if all block processed finish\r
549  * otherwise request for a new block admin read\r
550  */\r
551 static void StartupReadBlockAdmin(void)\r
552 {\r
553         if (CheckFlsJobFinnished()) {\r
554                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
555                         if (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_EMPTY) {\r
556                                 DET_VALIDATE(CurrentJob.Op.Startup.NrOfBanks != 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
557                                 CurrentJob.Op.Startup.NrOfBanks--;\r
558                                 CurrentJob.Op.Startup.BankNumber = (CurrentJob.Op.Startup.BankNumber + 1) % 2;\r
559                                 CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
560                         } else { /* Block not empty */\r
561                                 if ((memcmp(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN) == 0) &&\r
562                                                 ((RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INUSE) || (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INVALIDATED))) {\r
563                                         /* This is a valid admin block */\r
564                                         uint16 blockIndex;\r
565                                         uint16 dataSet;\r
566 \r
567                                         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
568                                         dataSet = GET_DATASET_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
569 \r
570                                         if ((blockIndex < FEE_NUM_OF_BLOCKS) && (dataSet < FEE_MAX_NUM_SETS)) {\r
571                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
572                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress;\r
573                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].Status = RWBuffer.BlockCtrl.DataPage.Data.Status;\r
574 \r
575                                                 AdminFls.BankNumber = CurrentJob.Op.Startup.BankNumber;\r
576                                                 AdminFls.NewBlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress + RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength;\r
577                                                 if (CurrentJob.Op.Startup.BlockAdminAddress <= AdminFls.NewBlockDataAddress) {\r
578                                                         /* This shall never happen */\r
579                                                         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
580                                                 }\r
581                                         }\r
582                                 }\r
583                                 // TODO Check wrap around here\r
584                                 CurrentJob.Op.Startup.BlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
585                                 AdminFls.NewBlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
586                         }\r
587 \r
588                         if (CurrentJob.Op.Startup.NrOfBanks == 0) {\r
589                                 /* If current bank is marked as old we need to switch to a new bank */\r
590                                 if (AdminFls.BankStatus[AdminFls.BankNumber] == BANK_STATUS_OLD) {\r
591                                         AdminFls.BankNumber = (AdminFls.BankNumber + 1) % 2;\r
592                                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
593                                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
594                                 }\r
595                                 /* We are done! */\r
596                                 FinnishStartup();\r
597                         } else {\r
598                                 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
599                         }\r
600 \r
601 \r
602                 } else { /* ErrorStatus not E_OK */\r
603                         AbortStartup(Fls_GetJobResult());\r
604                 }\r
605         }\r
606 }\r
607 \r
608 \r
609 /*\r
610  * Start of read block data\r
611  */\r
612 static void ReadStartJob(void)\r
613 {\r
614         if (Fls_GetStatus() == MEMIF_IDLE) {\r
615                 if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_EMPTY) {\r
616                         if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_INVALIDATED) {\r
617                                 CurrentJob.State = FEE_READ;\r
618                                 /* Read the actual data */\r
619                                 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.Read.Offset, CurrentJob.Op.Read.RamPtr, CurrentJob.Length) == E_OK) {\r
620                                         SetFlsJobBusy();\r
621                                 } else {\r
622                                         AbortJob(Fls_GetJobResult());\r
623                                 }\r
624                         } else {\r
625                                 /* Invalid */\r
626                                 AbortJob(MEMIF_BLOCK_INVALID);\r
627                         }\r
628                 } else {\r
629                         /* Inconsistent */\r
630                         AbortJob(MEMIF_BLOCK_INCONSISTENT);\r
631                 }\r
632         }\r
633 }\r
634 \r
635 /*\r
636  * Check job result of block data read\r
637  */\r
638 static void Reading(void)\r
639 {\r
640         if (CheckFlsJobFinnished()) {\r
641                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
642                         FinnishJob();\r
643                 } else {\r
644                         AbortJob(Fls_GetJobResult());\r
645                 }\r
646         }\r
647 }\r
648 \r
649 \r
650 /*\r
651  * Write bank header\r
652  */\r
653 static void BankHeaderOldWrite(uint8 bank)\r
654 {\r
655         /* Need to collect garbage */\r
656         AdminFls.ForceGarbageCollect = 1;\r
657         /* Mark the bank as old */\r
658         memset(RWBuffer.BankCtrl.Data, 0xff, BANK_CTRL_PAGE_SIZE);\r
659         RWBuffer.BankCtrl.BankStatus = BANK_STATUS_OLD;\r
660         if (Fls_Write(BankProp[bank].End - BANK_CTRL_PAGE_SIZE, RWBuffer.BankCtrl.Data, BANK_CTRL_PAGE_SIZE) == E_OK) {\r
661                 SetFlsJobBusy();\r
662         } else {\r
663                 AbortJob(Fls_GetJobResult());\r
664         }\r
665 }\r
666 \r
667 \r
668 /*\r
669  * Write block header\r
670  */\r
671 static void BlockHeaderDataWrite(void)\r
672 {\r
673         /* Write the header excluding the magic */\r
674         memset(RWBuffer.BlockCtrl.DataPage.Byte, 0xff, BLOCK_CTRL_DATA_PAGE_SIZE);\r
675         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INUSE;\r
676         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
677         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
678         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = CurrentJob.Length;\r
679         if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_DATA_PAGE_SIZE) == E_OK) {\r
680                 SetFlsJobBusy();\r
681                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
682                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
683         } else {\r
684                 AbortJob(Fls_GetJobResult());\r
685         }\r
686 }\r
687 \r
688 \r
689 /*\r
690  * Check if bank switch needed:\r
691  * - Yes, start mark current bank as old\r
692  * - No, start of header write\r
693  */\r
694 static void WriteStartJob(void)\r
695 {\r
696         if (Fls_GetStatus() == MEMIF_IDLE) {\r
697                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
698                         /* Bank switch needed, mark current bank as "old" */\r
699                         CurrentJob.State = FEE_WRITE_MARK_BANK_OLD;\r
700                         BankHeaderOldWrite(AdminFls.BankNumber);\r
701                 } else {\r
702                         CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
703                         CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
704 \r
705                         CurrentJob.State = FEE_WRITE_HEADER;\r
706                         BlockHeaderDataWrite();\r
707                 }\r
708         }\r
709 }\r
710 \r
711 \r
712 /*\r
713  * Check job result of mark bank as old, if ok request for header write\r
714  */\r
715 static void WriteMarkBankOldState(void)\r
716 {\r
717         if (CheckFlsJobFinnished()) {\r
718                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
719                         /* Mark for garbage collection */\r
720                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
721 \r
722                         /* Change of bank */\r
723                         AdminFls.BankNumber ^= 0x1u;\r
724                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
725                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
726 \r
727                         CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
728                         CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
729 \r
730                         CurrentJob.State = FEE_WRITE_HEADER_REQUESTED;\r
731                 } else {\r
732                         AbortJob(Fls_GetJobResult());\r
733                 }\r
734         }\r
735 }\r
736 \r
737 \r
738 /*\r
739  * Start of header write\r
740  */\r
741 static void WriteHeaderRequested()\r
742 {\r
743         if (Fls_GetStatus() == MEMIF_IDLE) {\r
744                 CurrentJob.State = FEE_WRITE_HEADER;\r
745                 BlockHeaderDataWrite();\r
746         }\r
747 }\r
748 \r
749 \r
750 /*\r
751  * Check job result of write header, if ok request for block data write\r
752  */\r
753 static void WriteHeaderState(void)\r
754 {\r
755         if (CheckFlsJobFinnished()) {\r
756                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
757                         CurrentJob.State = FEE_WRITE_DATA_REQUESTED;\r
758                 } else {\r
759                         AbortJob(Fls_GetJobResult());\r
760                 }\r
761         }\r
762 }\r
763 \r
764 \r
765 /*\r
766  * Start block data write\r
767  */\r
768 static void WriteDataRequested(void)\r
769 {\r
770         if (Fls_GetStatus() == MEMIF_IDLE) {\r
771                 CurrentJob.State = FEE_WRITE_DATA;\r
772                 /* Write the actual data */\r
773                 DEBUG_PRINTF("WriteDataRequested: 0x%x 0x%x %d  ",CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length );\r
774 \r
775                 if (Fls_Write(CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length) == E_OK) {\r
776                         SetFlsJobBusy();\r
777                 } else {\r
778                         AbortJob(Fls_GetJobResult());\r
779                 }\r
780         }\r
781 }\r
782 \r
783 \r
784 /*\r
785  * Check job result of data write - request for magic write\r
786  */\r
787 static void WriteDataState(void)\r
788 {\r
789         if (CheckFlsJobFinnished()) {\r
790                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
791                         CurrentJob.State = FEE_WRITE_MAGIC_REQUESTED;\r
792                 } else {\r
793                         AbortJob(Fls_GetJobResult());\r
794                 }\r
795         }\r
796 }\r
797 \r
798 \r
799 /*\r
800  * Start magic write\r
801  */\r
802 static void WriteMagicRequested(void)\r
803 {\r
804         if (Fls_GetStatus() == MEMIF_IDLE) {\r
805                 CurrentJob.State = FEE_WRITE_MAGIC;\r
806                 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
807                 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
808                 if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {\r
809                         SetFlsJobBusy();\r
810                 } else {\r
811                         AbortJob(Fls_GetJobResult());\r
812                 }\r
813         }\r
814 }\r
815 \r
816 \r
817 /*\r
818  * Check job result of write magic, if ok update the block admin table and finish\r
819  */\r
820 static void WriteMagicState(void)\r
821 {\r
822         if (CheckFlsJobFinnished()) {\r
823                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
824                         /* Update the block admin table */\r
825                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INUSE;\r
826                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Write.WriteAdminAddress;\r
827                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Write.WriteDataAddress;\r
828 \r
829                         FinnishJob();\r
830                 } else {\r
831                         AbortJob(Fls_GetJobResult());\r
832                 }\r
833         }\r
834 }\r
835 \r
836 \r
837 /*\r
838  * Check if any bank is marked as old\r
839  */\r
840 static void CheckIfGarbageCollectionNeeded(void)\r
841 {\r
842         if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
843                 ModuleStatus = MEMIF_BUSY_INTERNAL;\r
844                 JobResult = MEMIF_JOB_PENDING;\r
845 \r
846                 CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;\r
847         }\r
848 }\r
849 \r
850 \r
851 /*\r
852  * Checks if any blocks needs to be moved if so start with writing a new header\r
853  * or if no blocks needs to be moved request for bank erase.\r
854  */\r
855 static void GarbageCollectStartJob(void)\r
856 {\r
857         uint16 blockIndex;\r
858         uint16 set;\r
859         boolean found = FALSE;\r
860         uint8 sourceBank;\r
861 \r
862         if (Fls_GetStatus() == MEMIF_IDLE) {\r
863                 if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
864                         if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
865                                 sourceBank = 0;\r
866                         } else {\r
867                                 sourceBank = 1;\r
868                         }\r
869 \r
870                         for (blockIndex = 0; (blockIndex < FEE_NUM_OF_BLOCKS) && (!found); blockIndex++) {\r
871                                 for (set = 0; (set < FEE_MAX_NUM_SETS) && (!found); set++) {\r
872                                         if (AdminFls.BlockDescrTbl[blockIndex][set].Status != BLOCK_STATUS_EMPTY) {\r
873                                                 if ((AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress >= BankProp[sourceBank].Start) && (AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress < (BankProp[sourceBank].End))) {\r
874                                                         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][set];\r
875                                                         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
876                                                         CurrentJob.BlockNumber = Fee_Config.BlockConfig[blockIndex].BlockNumber;\r
877                                                         if (AdminFls.BlockDescrTbl[blockIndex][set].Status == BLOCK_STATUS_INVALIDATED) {\r
878                                                                 CurrentJob.Length = 0;\r
879                                                         } else {\r
880                                                                 CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
881                                                         }\r
882 \r
883                                                         found = TRUE;\r
884                                                 }\r
885                                         }\r
886                                 }\r
887                         }\r
888 \r
889                         if (found) {\r
890                                 CurrentJob.Op.GarbageCollect.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
891                                 CurrentJob.Op.GarbageCollect.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
892 \r
893                                 CurrentJob.State = FEE_GARBAGE_COLLECT_HEADER_WRITE;\r
894                                 BlockHeaderDataWrite();\r
895                         } else {\r
896                                 if (Fls_Erase(BankProp[sourceBank].Start, BankProp[sourceBank].End - BankProp[sourceBank].Start) == E_OK) {\r
897                                         SetFlsJobBusy();\r
898                                         CurrentJob.Op.GarbageCollect.BankNumber = sourceBank;\r
899                                         CurrentJob.State = FEE_GARBAGE_COLLECT_ERASE;\r
900                                 } else {\r
901                                         AdminFls.NofFailedGarbageCollect++;\r
902                                         AbortJob(Fls_GetJobResult());\r
903                                 }\r
904                         }\r
905                 } else {\r
906                         CurrentJob.State = FEE_IDLE;\r
907                 }\r
908         }\r
909 }\r
910 \r
911 \r
912 /*\r
913  * Check job result of write header, if ok request for read block data\r
914  */\r
915 static void GarbageCollectWriteHeader(void)\r
916 {\r
917         if (CheckFlsJobFinnished()) {\r
918                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
919                         if (CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INUSE) {\r
920                                 CurrentJob.Op.GarbageCollect.BytesLeft = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
921                                 CurrentJob.Op.GarbageCollect.DataOffset = 0;\r
922                                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
923                         } else {\r
924                                 /* Yes, we are finished */\r
925                                 DET_VALIDATE_NO_RV(CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INVALIDATED, FEE_GARBAGE_WRITE_HEADER_ID, FEE_UNEXPECTED_STATUS);\r
926                                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
927                         }\r
928                 } else {\r
929                         AdminFls.NofFailedGarbageCollect++;\r
930                         AbortJob(Fls_GetJobResult());\r
931                 }\r
932         }\r
933 }\r
934 \r
935 \r
936 /*\r
937  * Start of read block data, if data length is more than buffer size\r
938  * the reading is segmented.\r
939  */\r
940 static void GarbageCollectReadDataRequested(void)\r
941 {\r
942         if (Fls_GetStatus() == MEMIF_IDLE) {\r
943                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ;\r
944                 if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
945                         CurrentJob.Length = CurrentJob.Op.GarbageCollect.BytesLeft;\r
946                 } else {\r
947                         CurrentJob.Length = RWBUFFER_SIZE;\r
948                 }\r
949                 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
950                         SetFlsJobBusy();\r
951                 } else {\r
952                         AdminFls.NofFailedGarbageCollect++;\r
953                         AbortJob(Fls_GetJobResult());\r
954                 }\r
955         }\r
956 }\r
957 \r
958 \r
959 /*\r
960  * Check job result of read block data, if ok request for a data write\r
961  */\r
962 static void GarbageCollectReadData(void)\r
963 {\r
964         if (CheckFlsJobFinnished()) {\r
965                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
966                         CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED;\r
967                 } else {\r
968                         AdminFls.NofFailedGarbageCollect++;\r
969                         AbortJob(Fls_GetJobResult());\r
970                 }\r
971         }\r
972 }\r
973 \r
974 \r
975 /*\r
976  * Start of write block data\r
977  */\r
978 static void GarbageCollectWriteDataRequested(void)\r
979 {\r
980         if (Fls_GetStatus() == MEMIF_IDLE) {\r
981                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE;\r
982                 /* Write the actual data */\r
983                 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
984                         SetFlsJobBusy();\r
985                 } else {\r
986                         AdminFls.NofFailedGarbageCollect++;\r
987                         AbortJob(Fls_GetJobResult());\r
988                 }\r
989         } else {\r
990                 AdminFls.NofFailedGarbageCollect++;\r
991                 AbortJob(Fls_GetJobResult());\r
992         }\r
993 }\r
994 \r
995 \r
996 /*\r
997  * Check job result of write data, if ok request for write magic or\r
998  * next data read depending on if there are more block data to move.\r
999  */\r
1000 static void GarbageCollectWriteData(void)\r
1001 {\r
1002         if (CheckFlsJobFinnished()) {\r
1003                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1004                         if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
1005                                 /* Yes, we are finished */\r
1006                                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
1007                         } else {\r
1008                                 /* More data to move */\r
1009                                 CurrentJob.Op.GarbageCollect.DataOffset += RWBUFFER_SIZE;\r
1010                                 CurrentJob.Op.GarbageCollect.BytesLeft -= RWBUFFER_SIZE;\r
1011                                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
1012                         }\r
1013                 } else {\r
1014                         AdminFls.NofFailedGarbageCollect++;\r
1015                         AbortJob(Fls_GetJobResult());\r
1016                 }\r
1017         }\r
1018 }\r
1019 \r
1020 \r
1021 /*\r
1022  * Start write magic\r
1023  */\r
1024 static void GarbageCollectWriteMagicRequested(void)\r
1025 {\r
1026         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1027                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE;\r
1028                 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
1029                 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
1030                 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {\r
1031                         SetFlsJobBusy();\r
1032                 } else {\r
1033                         AdminFls.NofFailedGarbageCollect++;\r
1034                         AbortJob(Fls_GetJobResult());\r
1035                 }\r
1036         }\r
1037 }\r
1038 \r
1039 \r
1040 /*\r
1041  * Check the job result of write magic, if ok update the admin table with the new position of data.\r
1042  */\r
1043 static void GarbageCollectWriteMagic(void)\r
1044 {\r
1045         if (CheckFlsJobFinnished()) {\r
1046                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1047                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.GarbageCollect.WriteAdminAddress;\r
1048                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.GarbageCollect.WriteDataAddress;\r
1049                         CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;\r
1050                 } else {\r
1051                         AdminFls.NofFailedGarbageCollect++;\r
1052                         AbortJob(Fls_GetJobResult());\r
1053                 }\r
1054         }\r
1055 }\r
1056 \r
1057 \r
1058 /*\r
1059  * Check the result of the erase job\r
1060  */\r
1061 static void GarbageCollectErase(void)\r
1062 {\r
1063         if (CheckFlsJobFinnished()) {\r
1064                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1065                         AdminFls.BankStatus[CurrentJob.Op.GarbageCollect.BankNumber] = BANK_STATUS_NEW;\r
1066                         AdminFls.ForceGarbageCollect = 0;\r
1067                         AdminFls.NofFailedGarbageCollect = 0;\r
1068                         FinnishJob();\r
1069                 } else {\r
1070                         AdminFls.NofFailedGarbageCollect++;\r
1071                         AbortJob(Fls_GetJobResult());\r
1072                 }\r
1073         }\r
1074 }\r
1075 \r
1076 \r
1077 /*\r
1078  * Write an "Invalidated" block header\r
1079  */\r
1080 static void BlockHeaderInvalidWrite(void)\r
1081 {\r
1082         // Write the header including the magic\r
1083         memset(RWBuffer.Byte, 0xff, BLOCK_CTRL_PAGE_SIZE);\r
1084         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INVALIDATED;\r
1085         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
1086         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
1087         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = 0;\r
1088         memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
1089         memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
1090 \r
1091         if (Fls_Write(CurrentJob.Op.Invalidate.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
1092                 SetFlsJobBusy();\r
1093                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
1094                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
1095         } else {\r
1096                 AbortJob(Fls_GetJobResult());\r
1097         }\r
1098 }\r
1099 \r
1100 \r
1101 /*\r
1102  * Check if bank switch is needed, if yes request for marking current bank as old,\r
1103  * if no request for writing a header with "Invalid" status set.\r
1104  */\r
1105 static void InvalidateStartJob(void)\r
1106 {\r
1107         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1108                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
1109                         /* Bank switch needed, mark current bank as "old" */\r
1110                         CurrentJob.State = FEE_INVALIDATE_MARK_BANK_OLD;\r
1111                         BankHeaderOldWrite(AdminFls.BankNumber);\r
1112                 } else {\r
1113                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1114                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1115 \r
1116                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1117                         BlockHeaderInvalidWrite();\r
1118                 }\r
1119         }\r
1120 }\r
1121 \r
1122 \r
1123 /*\r
1124  * Check job result of mark bank old, if ok continue with request for writing\r
1125  * a header with "Invalid" status set.\r
1126  */\r
1127 static void InvalidateMarkBankOld(void)\r
1128 {\r
1129         if (CheckFlsJobFinnished()) {\r
1130                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1131                         // Mark for garbage collection\r
1132                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
1133 \r
1134                         // Change of bank\r
1135                         AdminFls.BankNumber ^= 0x1u;\r
1136                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1137                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
1138 \r
1139                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1140                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1141 \r
1142                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER_REQUESTED;\r
1143                 } else {\r
1144                         AbortJob(Fls_GetJobResult());\r
1145                 }\r
1146         }\r
1147 }\r
1148 \r
1149 /*\r
1150  * Start the writing of the "Invalid" header.\r
1151  */\r
1152 static void InvalidateWriteInvalidateHeaderRequested(void)\r
1153 {\r
1154         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1155                 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1156                 BlockHeaderInvalidWrite();\r
1157         }\r
1158 }\r
1159 \r
1160 \r
1161 /*\r
1162  * Check the job result of "Invalid" header write, if ok update the block admin table\r
1163  */\r
1164 static void InvalidateWriteInvalidateHeader(void)\r
1165 {\r
1166         if (CheckFlsJobFinnished()) {\r
1167                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1168                         // Update the block admin table\r
1169                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INVALIDATED;\r
1170                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Invalidate.WriteAdminAddress;\r
1171                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Invalidate.WriteDataAddress;\r
1172 \r
1173                         FinnishJob();\r
1174                 } else {\r
1175                         AbortJob(Fls_GetJobResult());\r
1176                 }\r
1177         }\r
1178 }\r
1179 \r
1180 \r
1181 /***************************************\r
1182  *    External accessible functions    *\r
1183  ***************************************/\r
1184 /*\r
1185  * Procedure:   Fee_Init\r
1186  * Reentrant:   No\r
1187  */\r
1188 void Fee_Init(void)\r
1189 {\r
1190         uint16 i,j;\r
1191 \r
1192         /* Reporting information */\r
1193         ModuleStatus = MEMIF_BUSY_INTERNAL;\r
1194         JobResult = MEMIF_JOB_OK;\r
1195 \r
1196         /* State of device */\r
1197         CurrentJob.State = FEE_STARTUP_REQUESTED;\r
1198         CurrentJob.InStateCounter = 0;\r
1199 #if (FEE_POLLING_MODE == STD_OFF)\r
1200         FlsJobReady = TRUE;\r
1201 #endif\r
1202 \r
1203         AdminFls.BankNumber = 0;\r
1204         AdminFls.ForceGarbageCollect = 0;\r
1205         AdminFls.NofFailedGarbageCollect = 0;\r
1206         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1207         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
1208 \r
1209         for (i = 0; i < NUM_OF_BANKS; i++) {\r
1210                 AdminFls.BankStatus[i] = BANK_STATUS_NEW;\r
1211         }\r
1212 \r
1213         for (i = 0; i < FEE_NUM_OF_BLOCKS; i++) {\r
1214                 for (j = 0; j < FEE_MAX_NUM_SETS; j++) {\r
1215                         AdminFls.BlockDescrTbl[i][j].Status = BLOCK_STATUS_EMPTY;\r
1216                         AdminFls.BlockDescrTbl[i][j].BlockAdminAddress= 0;\r
1217                         AdminFls.BlockDescrTbl[i][j].BlockDataAddress = 0;\r
1218                 }\r
1219         }\r
1220 }\r
1221 \r
1222 \r
1223 /*\r
1224  * Procedure:   Fee_SetMode\r
1225  * Reentrant:   No\r
1226  */\r
1227 void Fee_SetMode(MemIf_ModeType mode)\r
1228 {\r
1229 #if ( FLS_SET_MODE_API == STD_ON )\r
1230         Fls_SetMode(mode);\r
1231 #else\r
1232         //lint --e{715} PC-Lint (715) - variable "mode" not used in this case\r
1233         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_SET_MODE_ID, FEE_E_NOT_SUPPORTED);\r
1234 #endif\r
1235 }\r
1236 \r
1237 /*\r
1238  * Procedure:   Fee_Read\r
1239  * Reentrant:   No\r
1240  */\r
1241 Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBufferPtr, uint16 length)\r
1242 {\r
1243         uint16 blockIndex;\r
1244         uint16 dataset;\r
1245 \r
1246         DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);\r
1247         if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
1248                 return E_NOT_OK;\r
1249         }\r
1250         if( !(ModuleStatus == MEMIF_IDLE) ) {\r
1251                 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1252                 return E_NOT_OK;\r
1253         }\r
1254 \r
1255         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1256         DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1257         DET_VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1258         DET_VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);\r
1259         DET_VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);\r
1260 \r
1261         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1262         DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1263 \r
1264 \r
1265         /** @req FEE022 */\r
1266         ModuleStatus = MEMIF_BUSY;\r
1267         JobResult = MEMIF_JOB_PENDING;\r
1268 \r
1269         CurrentJob.BlockNumber = blockNumber;\r
1270         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1271         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1272         CurrentJob.Length = length;\r
1273         CurrentJob.Op.Read.Offset = blockOffset;\r
1274         CurrentJob.Op.Read.RamPtr = dataBufferPtr;\r
1275         CurrentJob.State = FEE_READ_REQUESTED;\r
1276 \r
1277         return E_OK;\r
1278 }\r
1279 \r
1280 \r
1281 /*\r
1282  * Procedure:   Fee_Write\r
1283  * Reentrant:   No\r
1284  */\r
1285 Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)\r
1286 {\r
1287         uint16 blockIndex;\r
1288         uint16 dataset;\r
1289 \r
1290         DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);\r
1291         if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
1292                 return E_NOT_OK;\r
1293         }\r
1294         if( !(ModuleStatus == MEMIF_IDLE) ) {\r
1295                 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1296                 return E_NOT_OK;\r
1297         }\r
1298 \r
1299         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1300         DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1301         DET_VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1302 \r
1303         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1304         DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1305 \r
1306 \r
1307         /** @req FEE025 */\r
1308         ModuleStatus = MEMIF_BUSY;\r
1309         JobResult = MEMIF_JOB_PENDING;\r
1310 \r
1311         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1312         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1313         CurrentJob.BlockNumber = blockNumber;\r
1314         CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
1315         CurrentJob.Op.Write.RamPtr = dataBufferPtr;\r
1316         CurrentJob.State = FEE_WRITE_REQUESTED;\r
1317 \r
1318         return E_OK;\r
1319 }\r
1320 \r
1321 \r
1322 /*\r
1323  * Procedure:   Fee_Cancel\r
1324  * Reentrant:   No\r
1325  */\r
1326 void Fee_Cancel(void)\r
1327 {\r
1328         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_CANCEL_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1329 }\r
1330 \r
1331 \r
1332 /*\r
1333  * Procedure:   Fee_GetStatus\r
1334  * Reentrant:   No\r
1335  */\r
1336 MemIf_StatusType Fee_GetStatus(void)\r
1337 {\r
1338         if(AdminFls.ForceGarbageCollect && (FEE_IDLE == CurrentJob.State)){\r
1339                 return MEMIF_BUSY_INTERNAL;\r
1340         } else {\r
1341                 return ModuleStatus;\r
1342         }\r
1343 }\r
1344 \r
1345 \r
1346 /*\r
1347  * Procedure:   Fee_GetJobResult\r
1348  * Reentrant:   No\r
1349  */\r
1350 MemIf_JobResultType Fee_GetJobResult(void)\r
1351 {\r
1352         return JobResult;\r
1353 }\r
1354 \r
1355 \r
1356 /*\r
1357  * Procedure:   Fee_InvalidateBlock\r
1358  * Reentrant:   No\r
1359  */\r
1360 Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)\r
1361 {\r
1362         uint16 blockIndex;\r
1363         uint16 dataset;\r
1364 \r
1365         DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);\r
1366         if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
1367                 return E_NOT_OK;\r
1368         }\r
1369         if( !(ModuleStatus == MEMIF_IDLE) ) {\r
1370                 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1371                 return E_NOT_OK;\r
1372         }\r
1373 \r
1374         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1375         DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1376 \r
1377         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1378         DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1379 \r
1380 \r
1381         ModuleStatus = MEMIF_BUSY;\r
1382         JobResult = MEMIF_JOB_PENDING;\r
1383 \r
1384         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1385         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1386         CurrentJob.BlockNumber = blockNumber;\r
1387         CurrentJob.State = FEE_INVALIDATE_REQUESTED;\r
1388 \r
1389         return E_OK;\r
1390 }\r
1391 \r
1392 \r
1393 /*\r
1394  * Procedure:   Fee_EraseImmediateBlock\r
1395  * Reentrant:   No\r
1396  */\r
1397 Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)\r
1398 {\r
1399         //lint --e{715} PC-Lint (715) - function is not implemented and thus variable "blockNumber" is not used yet\r
1400 \r
1401         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_ERASE_IMMEDIATE_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1402 \r
1403 \r
1404         return E_NOT_OK;\r
1405 }\r
1406 \r
1407 \r
1408 /***************************************\r
1409  *         Scheduled functions         *\r
1410  ***************************************/\r
1411 /*\r
1412  * Procedure:   Fee_MainFunction\r
1413  * Reentrant:   No\r
1414  */\r
1415 void Fee_MainFunction(void)\r
1416 {\r
1417         static CurrentJobStateType LastState = FEE_UNINITIALIZED;\r
1418 \r
1419         if (CurrentJob.State == LastState) {\r
1420                 if (CurrentJob.InStateCounter < STATE_COUNTER_MAX) {\r
1421                         CurrentJob.InStateCounter++;\r
1422                 }\r
1423         } else {\r
1424                 LastState = CurrentJob.State;\r
1425                 CurrentJob.InStateCounter = 0;\r
1426         }\r
1427 \r
1428         switch (CurrentJob.State) {\r
1429         case FEE_UNINITIALIZED:\r
1430                 break;\r
1431 \r
1432         case FEE_IDLE:\r
1433                 if (AdminFls.ForceGarbageCollect) {\r
1434                         CheckIfGarbageCollectionNeeded();\r
1435                 }\r
1436                 break;\r
1437 \r
1438                 /*\r
1439                  * Startup states\r
1440                  */\r
1441         case FEE_STARTUP_REQUESTED:\r
1442                 StartupStartJob();\r
1443                 break;\r
1444 \r
1445         case FEE_STARTUP_READ_BANK1_STATUS:\r
1446                 StartupReadBank1Status();\r
1447                 break;\r
1448 \r
1449         case FEE_STARTUP_READ_BANK2_STATUS_REQUESTED:\r
1450                 StartupReadBank2StatusRequested();\r
1451                 break;\r
1452 \r
1453         case FEE_STARTUP_READ_BANK2_STATUS:\r
1454                 StartupReadBank2Status();\r
1455                 break;\r
1456 \r
1457         case FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED:\r
1458                 StartupReadBlockAdminRequested();\r
1459                 break;\r
1460 \r
1461         case FEE_STARTUP_READ_BLOCK_ADMIN:\r
1462                 StartupReadBlockAdmin();\r
1463                 break;\r
1464 \r
1465         /*\r
1466          *  Read states\r
1467          */\r
1468         case FEE_READ_REQUESTED:\r
1469                 ReadStartJob();\r
1470                 break;\r
1471 \r
1472         case FEE_READ:\r
1473                 Reading();\r
1474                 break;\r
1475 \r
1476         /*\r
1477          * Write states\r
1478          */\r
1479         case FEE_WRITE_REQUESTED:\r
1480                 WriteStartJob();\r
1481                 break;\r
1482 \r
1483         case FEE_WRITE_MARK_BANK_OLD:\r
1484                 WriteMarkBankOldState();\r
1485                 break;\r
1486 \r
1487         case FEE_WRITE_HEADER_REQUESTED:\r
1488                 WriteHeaderRequested();\r
1489                 break;\r
1490 \r
1491         case FEE_WRITE_HEADER:\r
1492                 WriteHeaderState();\r
1493                 break;\r
1494 \r
1495         case FEE_WRITE_DATA_REQUESTED:\r
1496                 WriteDataRequested();\r
1497                 break;\r
1498 \r
1499         case FEE_WRITE_DATA:\r
1500                 WriteDataState();\r
1501                 break;\r
1502 \r
1503         case FEE_WRITE_MAGIC_REQUESTED:\r
1504                 WriteMagicRequested();\r
1505                 break;\r
1506 \r
1507         case FEE_WRITE_MAGIC:\r
1508                 WriteMagicState();\r
1509                 break;\r
1510 \r
1511         /*\r
1512          * Garbage collection states\r
1513          */\r
1514         case FEE_GARBAGE_COLLECT_REQUESTED:\r
1515                 GarbageCollectStartJob();\r
1516                 break;\r
1517 \r
1518         case FEE_GARBAGE_COLLECT_HEADER_WRITE:\r
1519                 GarbageCollectWriteHeader();\r
1520                 break;\r
1521 \r
1522         case FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED:\r
1523                 GarbageCollectReadDataRequested();\r
1524                 break;\r
1525 \r
1526         case FEE_GARBAGE_COLLECT_DATA_READ:\r
1527                 GarbageCollectReadData();\r
1528                 break;\r
1529 \r
1530         case FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED:\r
1531                 GarbageCollectWriteDataRequested();\r
1532                 break;\r
1533 \r
1534         case FEE_GARBAGE_COLLECT_DATA_WRITE:\r
1535                 GarbageCollectWriteData();\r
1536                 break;\r
1537 \r
1538         case FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED:\r
1539                 GarbageCollectWriteMagicRequested();\r
1540                 break;\r
1541 \r
1542         case FEE_GARBAGE_COLLECT_MAGIC_WRITE:\r
1543                 GarbageCollectWriteMagic();\r
1544                 break;\r
1545 \r
1546         case FEE_GARBAGE_COLLECT_ERASE:\r
1547                 GarbageCollectErase();\r
1548                 break;\r
1549 \r
1550         /*\r
1551          * Invalidate states\r
1552          */\r
1553         case FEE_INVALIDATE_REQUESTED:\r
1554                 InvalidateStartJob();\r
1555                 break;\r
1556 \r
1557         case FEE_INVALIDATE_MARK_BANK_OLD:\r
1558                 InvalidateMarkBankOld();\r
1559                 break;\r
1560 \r
1561         case FEE_WRITE_INVALIDATE_HEADER_REQUESTED:\r
1562                 InvalidateWriteInvalidateHeaderRequested();\r
1563                 break;\r
1564 \r
1565         case FEE_WRITE_INVALIDATE_HEADER:\r
1566                 InvalidateWriteInvalidateHeader();\r
1567                 break;\r
1568 \r
1569         /*\r
1570          * Corrupted state\r
1571          */\r
1572         case FEE_CORRUPTED:\r
1573                 break;\r
1574 \r
1575         /*\r
1576          * Other\r
1577          */\r
1578         default:\r
1579                 break;\r
1580         }\r
1581 }\r
1582 \r
1583 \r
1584 /***************************************\r
1585  *  Call-back notifications functions  *\r
1586  ***************************************/\r
1587 #if (FEE_POLLING_MODE == STD_OFF)\r
1588 /*\r
1589  * Procedure:   Fee_JobEndNotification\r
1590  * Reentrant:   No\r
1591  */\r
1592 void Fee_JobEndNotification(void)\r
1593 {\r
1594         FlsJobReady = TRUE;\r
1595 }\r
1596 \r
1597 \r
1598 /*\r
1599  * Procedure:   Fee_JobErrorNotification\r
1600  * Reentrant:   No\r
1601  */\r
1602 void Fee_JobErrorNotification(void)\r
1603 {\r
1604         FlsJobReady = TRUE;\r
1605 }\r
1606 #endif\r