Add experimental yaffs_nandif.[ch]
[yaffs2.git] / direct / yaffs_nandif.c
1 \r
2 /*\r
3  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.\r
4  *\r
5  * Copyright (C) 2002-2007 Aleph One Ltd.\r
6  *   for Toby Churchill Ltd and Brightstar Engineering\r
7  *\r
8  * Created by Charles Manning <charles@aleph1.co.uk>\r
9  *\r
10  * This program is free software; you can redistribute it and/or modify\r
11  * it under the terms of the GNU General Public License version 2 as\r
12  * published by the Free Software Foundation.\r
13  */\r
14 \r
15 \r
16 \r
17 \r
18 #include "yportenv.h"\r
19 #include "yaffs_guts.h"\r
20 #include "devextras.h"\r
21 \r
22 \r
23 #include "yaffs_nandif.h"\r
24 #include "yaffs_packedtags2.h"\r
25 \r
26 \r
27 #if 0\r
28 \r
29 \r
30 static unsigned char *DevBufferIn(yaffs_Device *dev)\r
31 {\r
32         yfsd_WinCEDevice *cedev = (yfsd_WinCEDevice *)(dev->genericDevice);\r
33         return cedev->bufferIn;\r
34 }\r
35 static unsigned char *DevBufferOut(yaffs_Device *dev)\r
36 {\r
37         yfsd_WinCEDevice *cedev = (yfsd_WinCEDevice *)(dev->genericDevice);\r
38         return cedev->bufferOut;\r
39 }\r
40 \r
41 static unsigned DevBufferSize(yaffs_Device *dev)\r
42 {\r
43         yfsd_WinCEDevice *cedev = (yfsd_WinCEDevice *)(dev->genericDevice);\r
44         return cedev->bufferSize;\r
45 }\r
46 \r
47 #endif\r
48 \r
49 /* NB For use with inband tags....\r
50  * We assume that the data buffer is of size totalBytersPerChunk so that we can also\r
51  * use it to load the tags.\r
52  */\r
53 int ynandif_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,\r
54                                       const __u8 * data,\r
55                                       const yaffs_ExtendedTags * tags)\r
56 {\r
57 \r
58         int retval = 0;\r
59         yaffs_PackedTags2 pt;\r
60         void *spare;\r
61         unsigned spareSize = 0;\r
62 \r
63         unsigned char *bufferIn   = DevBufferIn(dev);\r
64         unsigned char *bufferOut  = DevBufferOut(dev);\r
65         unsigned       bufferSize = DevBufferSize(dev);\r
66 \r
67         T(YAFFS_TRACE_MTD,\r
68           (TSTR\r
69            ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"\r
70             TENDSTR), chunkInNAND, data, tags));\r
71             \r
72 \r
73         /* For yaffs2 writing there must be both data and tags.\r
74          * If we're using inband tags, then the tags are stuffed into\r
75          * the end of the data buffer.\r
76          */\r
77 \r
78         if(dev->inbandTags){\r
79                 yaffs_PackedTags2TagsPart *pt2tp;\r
80                 pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);\r
81                 yaffs_PackTags2TagsPart(pt2tp,tags);\r
82                 spare = NULL;\r
83                 spareSize = 0;\r
84         }\r
85         else{\r
86                 yaffs_PackTags2(&pt, tags);\r
87                 spare = &pt;\r
88                 spareSize = sizeof(yaffs_PackedTags2);\r
89         }\r
90         \r
91         yramsim_WritePage(chunkInNAND,\r
92                                           data, dev->totalBytesPerChunk, spare, spareSize);\r
93 \r
94         return YAFFS_OK;\r
95 }\r
96 \r
97 int ynandif_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,\r
98                                        __u8 * data, yaffs_ExtendedTags * tags)\r
99 {\r
100         yaffs_PackedTags2 pt;\r
101         int localData = 0;\r
102         void *spare = NULL;\r
103         unsigned spareSize;\r
104         int eccStatus; //0 = ok, 1 = fixed, -1 = unfixed\r
105 \r
106         unsigned char *bufferIn   = DevBufferIn(dev);\r
107         unsigned char *bufferOut  = DevBufferOut(dev);\r
108         unsigned       bufferSize = DevBufferSize(dev);\r
109 \r
110         T(YAFFS_TRACE_MTD,\r
111           (TSTR\r
112            ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"\r
113             TENDSTR), chunkInNAND, data, tags));\r
114             \r
115         if(!tags){\r
116                 spare = NULL;\r
117                 spareSize = 0;\r
118         }else if(dev->inbandTags){\r
119                 \r
120                 if(!data) {\r
121                         localData = 1;\r
122                         data = yaffs_GetTempBuffer(dev,__LINE__);\r
123                 }\r
124                 spare = NULL;\r
125                 spareSize = 0;\r
126         }\r
127         else {\r
128                 spare = &pt;\r
129                 spareSize = sizeof(yaffs_PackedTags2);\r
130         }\r
131 \r
132         yramsim_ReadPage(chunkInNAND,\r
133                                          data,data ? dev->totalBytesPerChunk : 0,\r
134                                          spare,spareSize,\r
135                                          &eccStatus);\r
136 \r
137 \r
138 \r
139         if(dev->inbandTags){\r
140                 if(tags){\r
141                         yaffs_PackedTags2TagsPart * pt2tp;\r
142                         pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];    \r
143                         yaffs_UnpackTags2TagsPart(tags,pt2tp);\r
144                 }\r
145         }\r
146         else {\r
147                 if (tags){\r
148                         yaffs_UnpackTags2(tags, &pt);\r
149                 }\r
150         }\r
151 \r
152         if(tags && tags->chunkUsed){\r
153                 if(eccStatus == 0)\r
154                         tags->eccResult = YAFFS_ECC_RESULT_NO_ERROR;\r
155                 else if(eccStatus < 0)\r
156                         tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;\r
157                 else\r
158                         tags->eccResult = YAFFS_ECC_RESULT_FIXED;\r
159         }\r
160 \r
161         if(localData)\r
162                 yaffs_ReleaseTempBuffer(dev,data,__LINE__);\r
163         \r
164         return YAFFS_OK;\r
165 }\r
166 \r
167 int ynandif_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockId)\r
168 {\r
169 \r
170         yramsim_MarkBlockBad(blockId);\r
171 \r
172         return YAFFS_OK;\r
173 }\r
174 \r
175 int ynandif_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, int blockId)\r
176 {\r
177 \r
178         yramsim_EraseBlock(blockId);\r
179 \r
180         return YAFFS_OK;\r
181 }\r
182 \r
183 \r
184 static int ynandif_IsBlockOk(struct yaffs_DeviceStruct *dev, int blockId)\r
185 {\r
186         return yramsim_CheckBlockOk(blockId);\r
187 }\r
188 \r
189 int ynandif_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockId, yaffs_BlockState *state, __u32 *sequenceNumber)\r
190 {\r
191         unsigned chunkNo;\r
192         yaffs_ExtendedTags tags;\r
193 \r
194         *sequenceNumber = 0;\r
195         \r
196         chunkNo = blockId * dev->nChunksPerBlock;\r
197         \r
198         if(!ynandif_IsBlockOk(dev,blockId)){\r
199                 *state = YAFFS_BLOCK_STATE_DEAD;\r
200         } \r
201         else \r
202         {\r
203                 ynandif_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);\r
204 \r
205                 if(!tags.chunkUsed)\r
206                 {\r
207                         *state = YAFFS_BLOCK_STATE_EMPTY;\r
208                 }\r
209                 else \r
210                 {\r
211                         *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;\r
212                         *sequenceNumber = tags.sequenceNumber;\r
213                 }\r
214         }\r
215 \r
216         return YAFFS_OK;\r
217 }\r
218 \r
219 \r
220 int ynandif_GetGeometry(yaffs_Device *dev, ynandif_Geometry *geometry)\r
221 {\r
222 \r
223         yramsim_Geometry g;\r
224 \r
225         yramsim_GetGeometry(&g);\r
226         geometry->startBlock = g.startBlock;\r
227         geometry->endBlock = g.endBlock;\r
228         geometry->dataSize = g.dataSize;\r
229         geometry->spareSize = g.spareSize;\r
230         geometry->pagesPerBlock = g.pagesPerBlock;\r
231         geometry->hasECC = g.hasECC;\r
232         geometry->inbandTags = g.inbandTags;\r
233         geometry->useYaffs2 = g.useYaffs2;\r
234 \r
235         return YAFFS_OK;\r
236 \r
237 }\r
238 \r
239 int ynandif_InitialiseNAND(yaffs_Device *dev)\r
240 {\r
241 \r
242         yramsim_Initialise();\r
243 \r
244         return YAFFS_OK;\r
245 }\r