Add Sergey's patch
[yaffs2.git] / yaffs_mtdif.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  * yaffs_mtdif.c  NAND mtd wrapper functions.
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
16 const char *yaffs_mtdif_c_version =
17     "$Id: yaffs_mtdif.c,v 1.13 2005-11-07 07:13:33 charles Exp $";
18
19 #include "yportenv.h"
20
21
22 #include "yaffs_mtdif.h"
23
24 #include "linux/mtd/mtd.h"
25 #include "linux/types.h"
26 #include "linux/time.h"
27 #include "linux/mtd/nand.h"
28
29 static struct nand_oobinfo yaffs_oobinfo = {
30         .useecc = 1,
31         .eccbytes = 6,
32         .eccpos = {8, 9, 10, 13, 14, 15}
33 };
34
35 static struct nand_oobinfo yaffs_noeccinfo = {
36         .useecc = 0,
37 };
38
39 int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
40                              const __u8 * data, const yaffs_Spare * spare)
41 {
42         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
43         size_t dummy;
44         int retval = 0;
45
46         loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
47
48         __u8 *spareAsBytes = (__u8 *) spare;
49
50         if (data && spare) {
51                 if (dev->useNANDECC)
52                         retval =
53                             mtd->write_ecc(mtd, addr, dev->nBytesPerChunk,
54                                            &dummy, data, spareAsBytes,
55                                            &yaffs_oobinfo);
56                 else
57                         retval =
58                             mtd->write_ecc(mtd, addr, dev->nBytesPerChunk,
59                                            &dummy, data, spareAsBytes,
60                                            &yaffs_noeccinfo);
61         } else {
62                 if (data)
63                         retval =
64                             mtd->write(mtd, addr, dev->nBytesPerChunk, &dummy,
65                                        data);
66                 if (spare)
67                         retval =
68                             mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
69                                            &dummy, spareAsBytes);
70         }
71
72         if (retval == 0)
73                 return YAFFS_OK;
74         else
75                 return YAFFS_FAIL;
76 }
77
78 int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
79                               yaffs_Spare * spare)
80 {
81         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
82         size_t dummy;
83         int retval = 0;
84
85         loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
86
87         __u8 *spareAsBytes = (__u8 *) spare;
88
89         if (data && spare) {
90                 if (dev->useNANDECC) {  
91                         /* Careful, this call adds 2 ints */
92                         /* to the end of the spare data.  Calling function */
93                         /* should allocate enough memory for spare, */
94                         /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
95                         retval =
96                             mtd->read_ecc(mtd, addr, dev->nBytesPerChunk,
97                                           &dummy, data, spareAsBytes,
98                                           &yaffs_oobinfo);
99                 } else {
100                         retval =
101                             mtd->read_ecc(mtd, addr, dev->nBytesPerChunk,
102                                           &dummy, data, spareAsBytes,
103                                           &yaffs_noeccinfo);
104                 }
105         } else {
106                 if (data)
107                         retval =
108                             mtd->read(mtd, addr, dev->nBytesPerChunk, &dummy,
109                                       data);
110                 if (spare)
111                         retval =
112                             mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
113                                           &dummy, spareAsBytes);
114         }
115
116         if (retval == 0)
117                 return YAFFS_OK;
118         else
119                 return YAFFS_FAIL;
120 }
121
122 int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
123 {
124         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
125         __u32 addr =
126             ((loff_t) blockNumber) * dev->nBytesPerChunk
127                 * dev->nChunksPerBlock;
128         struct erase_info ei;
129         int retval = 0;
130
131         ei.mtd = mtd;
132         ei.addr = addr;
133         ei.len = dev->nBytesPerChunk * dev->nChunksPerBlock;
134         ei.time = 1000;
135         ei.retries = 2;
136         ei.callback = NULL;
137         ei.priv = (u_long) dev;
138
139         /* Todo finish off the ei if required */
140
141         sema_init(&dev->sem, 0);
142
143         retval = mtd->erase(mtd, &ei);
144
145         if (retval == 0)
146                 return YAFFS_OK;
147         else
148                 return YAFFS_FAIL;
149 }
150
151 int nandmtd_InitialiseNAND(yaffs_Device * dev)
152 {
153         return YAFFS_OK;
154 }
155