*** empty log message ***
[yaffs/.git] / yaffs_fileem.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  * yaffs_fileem.c  NAND emulation on top of files
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_fileem.c
16
17 #include "yaffs_fileem.h"
18 #include "yaffs_guts.h"
19 #include "yaffsinterface.h"
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <string.h>
28
29 #define FILE_SIZE_IN_MEG 32
30
31 #define BLOCK_SIZE (32 * 528)
32 #define BLOCKS_PER_MEG ((1024*1024)/(32 * 512))
33 #define FILE_SIZE_IN_BLOCKS (FILE_SIZE_IN_MEG * BLOCKS_PER_MEG)
34 #define FILE_SIZE_IN_BYTES (FILE_SIZE_IN_BLOCKS * BLOCK_SIZE)
35
36
37 static int h;
38 static __u8 ffChunk[528];
39
40 static int eraseDisplayEnabled;
41
42 static int markedBadBlocks[] = { 1, 4, -1};
43
44 static int IsAMarkedBadBlock(int blk)
45 {
46         int *m = markedBadBlocks;
47         
48         while(*m >= 0)
49         {
50                 if(*m == blk) return 1;
51                 m++;
52         }
53         return 0;
54 }
55
56
57 static __u8 yaffs_WriteFailCorruption(int chunkInNAND)
58 {
59
60         // Whole blocks that fail
61         switch(chunkInNAND/YAFFS_CHUNKS_PER_BLOCK)
62         {
63                 case 50:
64                 case 52:
65                                         return 7;
66         }
67         
68         // Single blocks that fail
69         switch(chunkInNAND)
70         {
71                 case 2000:
72                 case 2003:
73                 case 3000:
74                 case 3001:
75                                         return 3;// ding two bits
76                 case 2001:
77                 case 3003:
78                 case 3004:
79                 case 3005:
80                 case 3006:
81                 case 3007:  return 1;// ding one bit
82                 
83                 
84         }
85
86         return 0;
87 }
88
89 static void yaffs_ModifyWriteData(int chunkInNAND,__u8 *data)
90 {
91         if(data)
92         {
93                 *data ^= yaffs_WriteFailCorruption(chunkInNAND);        
94         }
95 }
96
97 static __u8 yaffs_ReadFailCorruption(int chunkInNAND)
98 {
99         switch(chunkInNAND)
100         {
101                 case 500:
102                                         return 3;// ding two bits
103                 case 700:
104                 case 750:
105                                         return 1;// ding one bit
106                 
107                 default: return 0;
108                 
109         }
110 }
111
112 static void yaffs_ModifyReadData(int chunkInNAND,__u8 *data)
113 {
114         if(data)
115         {
116                 *data ^= yaffs_ReadFailCorruption(chunkInNAND); 
117         }
118 }
119
120
121
122
123
124 static void  CheckInit(yaffs_Device *dev)
125 {
126         static int initialised = 0;
127
128         int length;
129
130         
131         if(!initialised)
132         {
133                 memset(ffChunk,0xFF,528);
134                 
135                 h = open("yaffs-em-file" , O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
136                 if(h < 0)
137                 {
138                         perror("Fatal error opening yaffs emulation file");
139                         exit(1);
140                 }
141                 initialised = 1;
142                 
143                 length = lseek(h,0,SEEK_END);
144                 if(length !=  FILE_SIZE_IN_BYTES)
145                 {
146                         // Create file contents
147                         int i;
148                         
149                         printf("Creating emulation file...\n");
150                         for(i = 0; i < FILE_SIZE_IN_BLOCKS; i++)
151                         {
152                                 yaffs_FEEraseBlockInNAND(dev,i);
153                                 
154                                 if(IsAMarkedBadBlock(i))
155                                 {
156                                         yaffs_Spare spare;
157                                         memset(&spare,0xff,sizeof(spare));
158                                         spare.blockStatus = 1;
159                                         
160                                         yaffs_FEWriteChunkToNAND(dev, i * 32,NULL,&spare);
161                                 }
162                         }
163                 }
164                 eraseDisplayEnabled = 1;
165         }
166 }
167
168 int yaffs_FEWriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_Spare *spare)
169 {
170         __u8 localData[512];
171         
172         int pos;
173         
174         pos = chunkInNAND * 528;
175         
176         CheckInit(dev);
177         
178         
179         if(data)
180         {
181                 memcpy(localData,data,512);
182                 yaffs_ModifyWriteData(chunkInNAND,localData);
183                 lseek(h,pos,SEEK_SET);
184                 write(h,localData,512);
185         }
186         
187         pos += 512;
188         
189         if(spare)
190         {
191                 lseek(h,pos,SEEK_SET);
192                 write(h,spare,16);      
193         }
194
195         return YAFFS_OK;
196 }
197
198
199 int yaffs_FEReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
200 {
201         int pos;
202
203         pos = chunkInNAND * 528;
204         
205         
206         CheckInit(dev);
207         
208         if(data)
209         {
210                 lseek(h,pos,SEEK_SET);
211                 read(h,data,512);
212                 yaffs_ModifyReadData(chunkInNAND,data);
213         }
214         
215         pos += 512;
216         
217         if(spare)
218         {
219                 lseek(h,pos,SEEK_SET);
220                 read(h,spare,16);       
221         }
222
223         return YAFFS_OK;
224 }
225
226
227 int yaffs_FEEraseBlockInNAND(yaffs_Device *dev,int blockInNAND)
228 {
229         int i;
230         
231         CheckInit(dev);
232         
233         if(eraseDisplayEnabled)
234         {
235                 printf("Erasing block %d\n",blockInNAND);
236         }
237         
238         lseek(h,blockInNAND * BLOCK_SIZE,SEEK_SET);
239         for(i = 0; i < 32; i++)
240         {
241                 write(h,ffChunk,528);
242         }
243         
244         switch(blockInNAND)
245         {
246                 case 10: 
247                 case 15: return YAFFS_FAIL;
248                 
249         }
250         return YAFFS_OK;
251 }
252
253 int yaffs_FEInitialiseNAND(yaffs_Device *dev)
254 {
255         return YAFFS_OK;
256 }