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