|
7
|
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$"; |
|
|
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 |