yaffs Refactor yaffs direct device list management, add nand abstraction, divide...
[yaffs2.git] / direct / basic-test / yramsim.c
1 // NAND Simulator for testing YAFFS\r
2 \r
3 #include <string.h>\r
4 \r
5 #include "yramsim.h"\r
6 \r
7 #include "yaffs_nandif.h"\r
8 \r
9 \r
10 #ifdef __WINCE__\r
11 #include <windows.h>\r
12 #else\r
13 #define DebugBreak() do { } while(0)\r
14 #endif\r
15 \r
16 \r
17 #define DATA_SIZE       2048\r
18 #define SPARE_SIZE      64\r
19 #define PAGE_SIZE       (DATA_SIZE + SPARE_SIZE)\r
20 #define PAGES_PER_BLOCK 64\r
21 \r
22 \r
23 typedef struct {\r
24         unsigned char page[PAGES_PER_BLOCK][PAGE_SIZE];\r
25         unsigned blockOk;\r
26 } Block;\r
27 \r
28 typedef struct {\r
29         Block **blockList;\r
30         int nBlocks;\r
31 } SymData;\r
32 \r
33 \r
34 static SymData *DevToSym(yaffs_Device *dev)\r
35 {\r
36         ynandif_Geometry *geom = (ynandif_Geometry *)(dev->driverContext);\r
37         SymData * sym = (SymData*)(geom->privateData);\r
38         return sym;\r
39\r
40 \r
41 \r
42 static void CheckInitialised(void)\r
43 {\r
44 \r
45 }\r
46 \r
47 static int yramsim_EraseBlockInternal(SymData *sym, unsigned blockId,int force)\r
48 {\r
49         if(blockId < 0 || blockId >= sym->nBlocks){\r
50                 DebugBreak();\r
51                 return 0;\r
52         }\r
53 \r
54         if(!sym->blockList[blockId]){\r
55                 DebugBreak();\r
56                 return 0;\r
57         }\r
58 \r
59         if(!force && !sym->blockList[blockId]->blockOk){\r
60                 DebugBreak();\r
61                 return 0;\r
62         }\r
63 \r
64         memset(sym->blockList[blockId],0xff,sizeof(Block));\r
65         sym->blockList[blockId]->blockOk = 1;\r
66 \r
67         return 1;\r
68 }\r
69 \r
70 \r
71 \r
72 \r
73 static int yramsim_Initialise(yaffs_Device *dev)\r
74 {\r
75         SymData *sym = DevToSym(dev);\r
76         Block **blockList = sym->blockList;\r
77         return blockList != NULL;\r
78 }\r
79 \r
80 \r
81 static int yramsim_Deinitialise(yaffs_Device *dev)\r
82 {\r
83         return 1;\r
84 }\r
85 \r
86 static int yramsim_ReadChunk (yaffs_Device *dev, unsigned pageId, \r
87                                           unsigned char *data, unsigned dataLength,\r
88                                           unsigned char *spare, unsigned spareLength,\r
89                                           int *eccStatus)\r
90 {\r
91         SymData *sym = DevToSym(dev);\r
92         Block **blockList = sym->blockList;\r
93 \r
94         unsigned blockId = pageId / PAGES_PER_BLOCK;\r
95         unsigned pageOffset = pageId % PAGES_PER_BLOCK;\r
96         unsigned char * d;\r
97         unsigned char *s;\r
98         if(blockId >= sym->nBlocks ||\r
99            pageOffset >= PAGES_PER_BLOCK ||\r
100            dataLength >DATA_SIZE ||\r
101            spareLength > SPARE_SIZE ||\r
102            !eccStatus ||\r
103            !blockList[blockId]->blockOk){\r
104                    DebugBreak();\r
105                    return 0;\r
106         }\r
107 \r
108         d = blockList[blockId]->page[pageOffset];\r
109         s = d + DATA_SIZE;\r
110 \r
111         if(data)\r
112                 memcpy(data,d,dataLength);\r
113 \r
114         if(spare)\r
115                 memcpy(spare,s,spareLength);\r
116 \r
117         *eccStatus = 0; // 0 = no error, -1 = unfixable error, 1 = fixable\r
118 \r
119         return 1;\r
120         \r
121 }\r
122 \r
123 static int yramsim_WriteChunk (yaffs_Device *dev,unsigned pageId, \r
124                                            const unsigned char *data, unsigned dataLength,\r
125                                            const unsigned char *spare, unsigned spareLength)\r
126 {\r
127         SymData *sym = DevToSym(dev);\r
128         Block **blockList = sym->blockList;\r
129 \r
130         unsigned blockId = pageId / PAGES_PER_BLOCK;\r
131         unsigned pageOffset = pageId % PAGES_PER_BLOCK;\r
132         unsigned char * d;\r
133         unsigned char *s;\r
134         if(blockId >= sym->nBlocks ||\r
135            pageOffset >= PAGES_PER_BLOCK ||\r
136            dataLength >DATA_SIZE ||\r
137            spareLength > SPARE_SIZE ||\r
138            !blockList[blockId]->blockOk){\r
139                    DebugBreak();\r
140                    return 0;\r
141         }\r
142 \r
143         d = blockList[blockId]->page[pageOffset];\r
144         s = d + DATA_SIZE;\r
145 \r
146         if(data)\r
147                 memcpy(d,data,dataLength);\r
148 \r
149         if(spare)\r
150                 memcpy(s,spare,spareLength);\r
151 \r
152         return 1;\r
153         \r
154 }\r
155 \r
156 \r
157 static int yramsim_EraseBlock(yaffs_Device *dev,unsigned blockId)\r
158 {\r
159         SymData *sym = DevToSym(dev);\r
160 \r
161         CheckInitialised();\r
162         return yramsim_EraseBlockInternal(sym,blockId,0);\r
163 }\r
164 \r
165 static int yramsim_CheckBlockOk(yaffs_Device *dev,unsigned blockId)\r
166 {\r
167         SymData *sym = DevToSym(dev);\r
168         Block **blockList = sym->blockList;\r
169         if(blockId >= sym->nBlocks){\r
170                 DebugBreak();\r
171                 return 0;\r
172         }\r
173 \r
174         return blockList[blockId]->blockOk ? 1 : 0;\r
175 }\r
176 \r
177 static int yramsim_MarkBlockBad(yaffs_Device *dev,unsigned blockId)\r
178 {\r
179         SymData *sym = DevToSym(dev);\r
180         Block **blockList = sym->blockList;\r
181         if(blockId >= sym->nBlocks){\r
182                 DebugBreak();\r
183                 return 0;\r
184         }\r
185 \r
186         blockList[blockId]->blockOk = 0;\r
187 \r
188         return 1;\r
189 }\r
190 \r
191 \r
192 static SymData *yramsim_AllocSymData(int nBlocks)\r
193 {\r
194         int ok = 1;\r
195 \r
196         Block **blockList;\r
197         SymData *sym;\r
198         Block *b;\r
199         int i;\r
200 \r
201         sym = malloc(sizeof (SymData));\r
202         if(!sym)\r
203                 return NULL;\r
204 \r
205         blockList = malloc(nBlocks * sizeof(Block *));\r
206         \r
207         sym->blockList = blockList;\r
208         sym->nBlocks = nBlocks;\r
209         if(!blockList){\r
210                 free(sym);\r
211                 return NULL;\r
212         }\r
213 \r
214         for(i = 0; i < nBlocks; i++)\r
215                 blockList[i] = NULL;\r
216 \r
217         for(i = 0; i < nBlocks && ok; i++){\r
218                 b=  malloc(sizeof(Block));\r
219                 if(b){\r
220                         blockList[i] = b;\r
221                         yramsim_EraseBlockInternal(sym,i,1);\r
222                 }\r
223                 else\r
224                         ok = 0;\r
225         }\r
226 \r
227         if(!ok){\r
228                 for(i = 0; i < nBlocks; i++)\r
229                         if(blockList[i]){\r
230                                 free(blockList[i]);\r
231                                 blockList[i] = NULL;\r
232                         }\r
233                 free(blockList);\r
234                 blockList = NULL;\r
235                 free(sym);\r
236                 sym = NULL;\r
237         }\r
238 \r
239         return sym;\r
240 }\r
241 \r
242 \r
243 struct yaffs_DeviceStruct *yramsim_CreateSim(const YCHAR *name,int nBlocks)\r
244 {\r
245         void *sym = (void *)yramsim_AllocSymData(nBlocks);\r
246         ynandif_Geometry *g;\r
247 \r
248         g = YMALLOC(sizeof(ynandif_Geometry));\r
249         \r
250         if(!sym || !g){\r
251                 if(sym)\r
252                         YFREE(sym);\r
253                 if(g)\r
254                         YFREE(g);\r
255                 return NULL;\r
256         }\r
257 \r
258         memset(g,0,sizeof(ynandif_Geometry));\r
259         g->startBlock = 0;\r
260         g->endBlock = nBlocks - 1;\r
261         g->dataSize = DATA_SIZE;\r
262         g->spareSize= SPARE_SIZE;\r
263         g->pagesPerBlock = PAGES_PER_BLOCK;\r
264         g->hasECC = 1;\r
265         g->inbandTags = 0;\r
266         g->useYaffs2 = 1;\r
267         g->initialise = yramsim_Initialise;\r
268         g->deinitialise = yramsim_Deinitialise; \r
269         g->readChunk = yramsim_ReadChunk, \r
270         g->writeChunk = yramsim_WriteChunk,\r
271         g->eraseBlock = yramsim_EraseBlock,\r
272         g->checkBlockOk = yramsim_CheckBlockOk,\r
273         g->markBlockBad = yramsim_MarkBlockBad,\r
274         g->privateData = sym;\r
275 \r
276         return yaffs_AddDeviceFromGeometry(name,g);\r
277 }