Root/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c

1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2007 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14const char *yaffs_mtdif_c_version =
15    "$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $";
16
17#include "yportenv.h"
18
19
20#include "yaffs_mtdif.h"
21
22#include "linux/mtd/mtd.h"
23#include "linux/types.h"
24#include "linux/time.h"
25#include "linux/mtd/nand.h"
26
27#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
28static struct nand_oobinfo yaffs_oobinfo = {
29    .useecc = 1,
30    .eccbytes = 6,
31    .eccpos = {8, 9, 10, 13, 14, 15}
32};
33
34static struct nand_oobinfo yaffs_noeccinfo = {
35    .useecc = 0,
36};
37#endif
38
39#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
40static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
41{
42    oob[0] = spare->tagByte0;
43    oob[1] = spare->tagByte1;
44    oob[2] = spare->tagByte2;
45    oob[3] = spare->tagByte3;
46    oob[4] = spare->tagByte4;
47    oob[5] = spare->tagByte5 & 0x3f;
48    oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
49    oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
50    oob[6] = spare->tagByte6;
51    oob[7] = spare->tagByte7;
52}
53
54static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
55{
56    struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
57    spare->tagByte0 = oob[0];
58    spare->tagByte1 = oob[1];
59    spare->tagByte2 = oob[2];
60    spare->tagByte3 = oob[3];
61    spare->tagByte4 = oob[4];
62    spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
63    spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
64    spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
65    spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
66    spare->tagByte6 = oob[6];
67    spare->tagByte7 = oob[7];
68    spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
69
70    nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
71}
72#endif
73
74int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
75                 const __u8 * data, const yaffs_Spare * spare)
76{
77    struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
78#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
79    struct mtd_oob_ops ops;
80#endif
81    size_t dummy;
82    int retval = 0;
83
84    loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
85#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
86    __u8 spareAsBytes[8]; /* OOB */
87
88    if (data && !spare)
89        retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
90                &dummy, data);
91    else if (spare) {
92        if (dev->useNANDECC) {
93            translate_spare2oob(spare, spareAsBytes);
94            ops.mode = MTD_OOB_AUTO;
95            ops.ooblen = 8; /* temp hack */
96        } else {
97            ops.mode = MTD_OOB_RAW;
98            ops.ooblen = YAFFS_BYTES_PER_SPARE;
99        }
100        ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
101        ops.datbuf = (u8 *)data;
102        ops.ooboffs = 0;
103        ops.oobbuf = spareAsBytes;
104        retval = mtd->write_oob(mtd, addr, &ops);
105    }
106#else
107    __u8 *spareAsBytes = (__u8 *) spare;
108
109    if (data && spare) {
110        if (dev->useNANDECC)
111            retval =
112                mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
113                       &dummy, data, spareAsBytes,
114                       &yaffs_oobinfo);
115        else
116            retval =
117                mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
118                       &dummy, data, spareAsBytes,
119                       &yaffs_noeccinfo);
120    } else {
121        if (data)
122            retval =
123                mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
124                       data);
125        if (spare)
126            retval =
127                mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
128                       &dummy, spareAsBytes);
129    }
130#endif
131
132    if (retval == 0)
133        return YAFFS_OK;
134    else
135        return YAFFS_FAIL;
136}
137
138int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
139                  yaffs_Spare * spare)
140{
141    struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
142#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
143    struct mtd_oob_ops ops;
144#endif
145    size_t dummy;
146    int retval = 0;
147
148    loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
149#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
150    __u8 spareAsBytes[8]; /* OOB */
151
152    if (data && !spare)
153        retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
154                &dummy, data);
155    else if (spare) {
156        if (dev->useNANDECC) {
157            ops.mode = MTD_OOB_AUTO;
158            ops.ooblen = 8; /* temp hack */
159        } else {
160            ops.mode = MTD_OOB_RAW;
161            ops.ooblen = YAFFS_BYTES_PER_SPARE;
162        }
163        ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
164        ops.datbuf = data;
165        ops.ooboffs = 0;
166        ops.oobbuf = spareAsBytes;
167        retval = mtd->read_oob(mtd, addr, &ops);
168        if (dev->useNANDECC)
169            translate_oob2spare(spare, spareAsBytes);
170    }
171#else
172    __u8 *spareAsBytes = (__u8 *) spare;
173
174    if (data && spare) {
175        if (dev->useNANDECC) {
176            /* Careful, this call adds 2 ints */
177            /* to the end of the spare data. Calling function */
178            /* should allocate enough memory for spare, */
179            /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
180            retval =
181                mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
182                      &dummy, data, spareAsBytes,
183                      &yaffs_oobinfo);
184        } else {
185            retval =
186                mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
187                      &dummy, data, spareAsBytes,
188                      &yaffs_noeccinfo);
189        }
190    } else {
191        if (data)
192            retval =
193                mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
194                      data);
195        if (spare)
196            retval =
197                mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
198                      &dummy, spareAsBytes);
199    }
200#endif
201
202    if (retval == 0)
203        return YAFFS_OK;
204    else
205        return YAFFS_FAIL;
206}
207
208int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
209{
210    struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
211    __u32 addr =
212        ((loff_t) blockNumber) * dev->nDataBytesPerChunk
213        * dev->nChunksPerBlock;
214    struct erase_info ei;
215    int retval = 0;
216
217    ei.mtd = mtd;
218    ei.addr = addr;
219    ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
220    ei.time = 1000;
221    ei.retries = 2;
222    ei.callback = NULL;
223    ei.priv = (u_long) dev;
224
225    /* Todo finish off the ei if required */
226
227    sema_init(&dev->sem, 0);
228
229    retval = mtd->erase(mtd, &ei);
230
231    if (retval == 0)
232        return YAFFS_OK;
233    else
234        return YAFFS_FAIL;
235}
236
237int nandmtd_InitialiseNAND(yaffs_Device * dev)
238{
239    return YAFFS_OK;
240}
241
242

Archive Download this file



interactive