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