Allow use of page zero
[yaffs2.git] / yaffs_ramem.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  * yaffs_ramem.c  NAND emulation on top of a chunk of RAM
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
6  *   for Toby Churchill Ltd and Brightstar Engineering
7  *
8  * Created by Charles Manning <charles@aleph1.co.uk>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15  //yaffs_ramem.c
16  // Since this creates the RAM block at start up it is pretty useless for testing the scanner.
17
18 const char *yaffs_ramem_c_version = "$Id: yaffs_ramem.c,v 1.1 2004-12-17 04:39:04 charles Exp $";
19
20 #ifndef __KERNEL__
21 #define CONFIG_YAFFS_RAM_ENABLED
22 #endif
23
24 #ifdef CONFIG_YAFFS_RAM_ENABLED
25
26 #include "yportenv.h"
27
28 #include "yaffs_nandemul.h"
29 #include "yaffs_guts.h"
30 #include "yaffsinterface.h"
31 #include "devextras.h"
32
33
34 #define EM_SIZE_IN_MEG 2
35
36 #define BLOCK_SIZE (32 * 528)
37 #define BLOCKS_PER_MEG ((1024*1024)/(32 * 512))
38 #define FILE_SIZE_IN_BLOCKS (FILE_SIZE_IN_MEG * BLOCKS_PER_MEG)
39 #define FILE_SIZE_IN_BYTES (FILE_SIZE_IN_BLOCKS * BLOCK_SIZE)
40
41
42
43 #define DEFAULT_SIZE_IN_MB 2
44
45 typedef struct 
46 {
47         __u8 data[528]; // Data + spare
48         int count[3];   // The programming count for each area of
49                         // the page (0..255,256..511,512..527
50         int empty;      // is this empty?
51 } nandemul_Page;
52
53 typedef struct
54 {
55         nandemul_Page page[32]; // The pages in the block
56         __u8 damaged;           // Is the block damaged?
57         
58 } nandemul_Block;
59
60
61
62 typedef struct
63 {
64         nandemul_Block **block;
65         int nBlocks;
66 } nandemul_Device;
67
68 static nandemul_Device ned;
69
70 static int sizeInMB = DEFAULT_SIZE_IN_MB;
71
72
73 static void nandemul_yield(int n)
74 {
75 #ifdef __KERNEL__
76         if(n > 0) schedule_timeout(n);
77 #endif
78
79 }
80
81
82 static void nandemul_ReallyEraseBlock(int blockNumber)
83 {
84         int i;
85         
86         nandemul_Block *theBlock = ned.block[blockNumber];
87         
88         for(i = 0; i < 32; i++)
89         {
90                 memset(theBlock->page[i].data,0xff,528);
91                 theBlock->page[i].count[0] = 0;
92                 theBlock->page[i].count[1] = 0;
93                 theBlock->page[i].count[2] = 0;
94                 theBlock->page[i].empty = 1;
95                 nandemul_yield(2);
96         }
97
98 }
99
100
101 int nandemul_CalcNBlocks(void)
102 {
103         switch(sizeInMB)
104         {
105                 case 8:
106                 case 16:
107                 case 32:
108                 case 64:
109                 case 128:
110                 case 256:
111                 case 512:
112                         break;
113                 default:
114                         sizeInMB = DEFAULT_SIZE_IN_MB;
115         }
116         return sizeInMB * 64;
117 }
118
119
120
121 static int  CheckInit(void)
122 {
123         static int initialised = 0;
124         
125         int i;
126         int fail = 0;
127         int nBlocks; 
128         int nAllocated = 0;
129         
130         if(initialised) 
131         {
132                 return YAFFS_OK;
133         }
134         
135         
136         nBlocks = nandemul_CalcNBlocks();
137         
138         ned.block = YMALLOC(sizeof(nandemul_Block *) * nBlocks);
139         
140         if(!ned.block) return 0;
141         
142         for(i=0; i <nBlocks; i++)
143         {
144                 ned.block[i] = NULL;
145         }
146         
147         for(i=0; i <nBlocks && !fail; i++)
148         {
149                 if((ned.block[i] = YMALLOC(sizeof(nandemul_Block))) == 0)
150                 {
151                         fail = 1;
152                 }
153                 else
154                 {
155                         nandemul_ReallyEraseBlock(i);
156                         ned.block[i]->damaged = 0;
157                         nAllocated++;
158                 }
159         }
160         
161         if(fail)
162         {
163                 for(i = 0; i < nAllocated; i++)
164                 {
165                         YFREE(ned.block[i]);
166                 }
167                 YFREE(ned.block);
168                 
169                 T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n",
170                    nAllocated/64,sizeInMB));
171                 return 0;
172         }
173         
174         ned.nBlocks = nBlocks;
175         
176         initialised = 1;
177         
178         return 1;
179 }
180
181 int nandemul_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_Spare *spare)
182 {
183         int blk;
184         int pg;
185         int i;
186         
187         __u8 *x;
188         
189         __u8 *spareAsBytes = (__u8 *)spare;
190
191         
192         CheckInit();
193         
194         blk = chunkInNAND/32;
195         pg = chunkInNAND%32;
196         
197         
198         if(data)
199         {
200                 x = ned.block[blk]->page[pg].data;
201                 
202                 for(i = 0; i < 512; i++)
203                 {
204                         x[i] &=data[i];
205                 }
206                 
207                 ned.block[blk]->page[pg].count[0]++;
208                 ned.block[blk]->page[pg].count[1]++;
209                 ned.block[blk]->page[pg].empty = 0;
210         }
211         
212         
213         if(spare)
214         {
215                 x = &ned.block[blk]->page[pg].data[512];
216                         
217                 for(i = 0; i < 16; i++)
218                 {
219                         x[i] &=spareAsBytes[i];
220                 }
221                 ned.block[blk]->page[pg].count[2]++;
222         }
223         
224         if(spare || data)
225         {
226                 nandemul_yield(1);
227         }
228
229         return YAFFS_OK;
230 }
231
232
233 int nandemul_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
234 {
235         int blk;
236         int pg;
237
238         
239         CheckInit();
240         
241         blk = chunkInNAND/32;
242         pg = chunkInNAND%32;
243         
244         
245         if(data)
246         {
247                 memcpy(data,ned.block[blk]->page[pg].data,512);
248         }
249         
250         
251         if(spare)
252         {
253                 memcpy(spare,&ned.block[blk]->page[pg].data[512],16);
254         }
255
256         return YAFFS_OK;
257 }
258
259
260 int nandemul_CheckChunkErased(yaffs_Device *dev,int chunkInNAND)
261 {
262         int blk;
263         int pg;
264         int i;
265
266         
267         CheckInit();
268         
269         blk = chunkInNAND/32;
270         pg = chunkInNAND%32;
271         
272         
273         for(i = 0; i < 528; i++)
274         {
275                 if(ned.block[blk]->page[pg].data[i] != 0xFF)
276                 {
277                         return YAFFS_FAIL;
278                 }
279         }
280
281         return YAFFS_OK;
282
283 }
284
285 int nandemul_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
286 {
287         
288         CheckInit();
289         
290         if(blockNumber < 0 || blockNumber >= ned.nBlocks)
291         {
292                 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
293         }
294         else if(ned.block[blockNumber]->damaged)
295         {
296                 T(YAFFS_TRACE_ALWAYS,("Attempt to erase damaged block %d\n",blockNumber));
297         }
298         else
299         {
300                 nandemul_ReallyEraseBlock(blockNumber);
301         }
302         
303         return YAFFS_OK;
304 }
305
306 int nandemul_InitialiseNAND(yaffs_Device *dev)
307 {
308         return YAFFS_OK;
309 }
310
311 #endif //YAFFS_RAM_ENABLED
312