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