*** 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         switch(chunkInNAND)
60         {
61                 case 2000:
62                 case 2003:
63                 case 3000:
64                 case 3001:
65                                         return 3;// ding two bits
66                 case 2001:
67                 case 3003:
68                 case 3004:
69                 case 3005:
70                 case 3006:
71                 case 3007:  return 1;// ding one bit
72                 
73                 default: return 0;
74                 
75         }
76 }
77
78 static void yaffs_ModifyWriteData(int chunkInNAND,__u8 *data)
79 {
80         if(data)
81         {
82                 *data ^= yaffs_WriteFailCorruption(chunkInNAND);        
83         }
84 }
85
86 static __u8 yaffs_ReadFailCorruption(int chunkInNAND)
87 {
88         switch(chunkInNAND)
89         {
90                 case 500:
91                                         return 3;// ding two bits
92                 case 700:
93                 case 750:
94                                         return 1;// ding one bit
95                 
96                 default: return 0;
97                 
98         }
99 }
100
101 static void yaffs_ModifyReadData(int chunkInNAND,__u8 *data)
102 {
103         if(data)
104         {
105                 *data ^= yaffs_ReadFailCorruption(chunkInNAND); 
106         }
107 }
108
109
110
111
112
113 static void  CheckInit(yaffs_Device *dev)
114 {
115         static int initialised = 0;
116
117         int length;
118
119         
120         if(!initialised)
121         {
122                 memset(ffChunk,0xFF,528);
123                 
124                 h = open("yaffs-em-file" , O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
125                 if(h < 0)
126                 {
127                         perror("Fatal error opening yaffs emulation file");
128                         exit(1);
129                 }
130                 initialised = 1;
131                 
132                 length = lseek(h,0,SEEK_END);
133                 if(length !=  FILE_SIZE_IN_BYTES)
134                 {
135                         // Create file contents
136                         int i;
137                         
138                         printf("Creating emulation file...\n");
139                         for(i = 0; i < FILE_SIZE_IN_BLOCKS; i++)
140                         {
141                                 yaffs_FEEraseBlockInNAND(dev,i);
142                                 
143                                 if(IsAMarkedBadBlock(i))
144                                 {
145                                         yaffs_Spare spare;
146                                         memset(&spare,0xff,sizeof(spare));
147                                         spare.blockStatus = 1;
148                                         
149                                         yaffs_FEWriteChunkToNAND(dev, i * 32,NULL,&spare);
150                                 }
151                         }
152                 }
153                 eraseDisplayEnabled = 1;
154         }
155 }
156
157 int yaffs_FEWriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_Spare *spare)
158 {
159         __u8 localData[512];
160         
161         int pos;
162         
163         pos = chunkInNAND * 528;
164         
165         CheckInit(dev);
166         
167         
168         if(data)
169         {
170                 memcpy(localData,data,512);
171                 yaffs_ModifyWriteData(chunkInNAND,localData);
172                 lseek(h,pos,SEEK_SET);
173                 write(h,localData,512);
174         }
175         
176         pos += 512;
177         
178         if(spare)
179         {
180                 lseek(h,pos,SEEK_SET);
181                 write(h,spare,16);      
182         }
183
184         return YAFFS_OK;
185 }
186
187
188 int yaffs_FEReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
189 {
190         int pos;
191
192         pos = chunkInNAND * 528;
193         
194         
195         CheckInit(dev);
196         
197         if(data)
198         {
199                 lseek(h,pos,SEEK_SET);
200                 read(h,data,512);
201                 yaffs_ModifyReadData(chunkInNAND,data);
202         }
203         
204         pos += 512;
205         
206         if(spare)
207         {
208                 lseek(h,pos,SEEK_SET);
209                 read(h,spare,16);       
210         }
211
212         return YAFFS_OK;
213 }
214
215
216 int yaffs_FEEraseBlockInNAND(yaffs_Device *dev,int blockInNAND)
217 {
218         int i;
219         
220         CheckInit(dev);
221         
222         if(eraseDisplayEnabled)
223         {
224                 printf("Erasing block %d\n",blockInNAND);
225         }
226         
227         lseek(h,blockInNAND * BLOCK_SIZE,SEEK_SET);
228         for(i = 0; i < 32; i++)
229         {
230                 write(h,ffChunk,528);
231         }
232         
233         switch(blockInNAND)
234         {
235                 case 10: 
236                 case 15: return YAFFS_FAIL;
237                 
238         }
239         return YAFFS_OK;
240 }
241
242 int yaffs_FEInitialiseNAND(yaffs_Device *dev)
243 {
244         return YAFFS_OK;
245 }