1 /*
2 This file is part of UFFS, the Ultra-low-cost Flash File System.
3
4 Copyright (C) 2005-2010 Ricky Zheng <[email protected]>
5
6 UFFS is free software; you can redistribute it and/or modify it under
7 the GNU Library General Public License as published by the Free Software
8 Foundation; either version 2 of the License, or (at your option) any
9 later version.
10
11 UFFS is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 or GNU Library General Public License, as applicable, for more details.
15
16 You should have received a copy of the GNU General Public License
17 and GNU Library General Public License along with UFFS; if not, write
18 to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 As a special exception, if other files instantiate templates or use
22 macros or inline functions from this file, or you compile this file
23 and link it with other works to produce a work based on this file,
24 this file does not by itself cause the resulting work to be covered
25 by the GNU General Public License. However the source code for this
26 file must still be made available in accordance with section (3) of
27 the GNU General Public License v2.
28
29 This exception does not invalidate any other reasons why a work based
30 on this file might be covered by the GNU General Public License.
31 */
32
33 /**
34 * \file uffs_fileem_ecc_soft.c
35 * \brief emulate uffs file system for software ECC
36 * \author Ricky Zheng @ Oct, 2010
37 */
38
39 #include <sys/types.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include "uffs_config.h"
44 #include "uffs/uffs_device.h"
45 #include "uffs/uffs_flash.h"
46 #include "uffs_fileem.h"
47
48 #define PFX "femu: "
49 #define MSG(msg,...) uffs_PerrorRaw(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
50 #define MSGLN(msg,...) uffs_Perror(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
51
femu_WritePage(uffs_Device * dev,u32 block,u32 page_num,const u8 * data,int data_len,const u8 * spare,int spare_len)52 static int femu_WritePage(uffs_Device *dev, u32 block, u32 page_num,
53 const u8 *data, int data_len, const u8 *spare, int spare_len)
54 {
55 int written;
56 int abs_page;
57 int full_page_size;
58 uffs_FileEmu *emu;
59 struct uffs_StorageAttrSt *attr = dev->attr;
60
61 emu = (uffs_FileEmu *)(dev->attr->_private);
62
63 if (!emu || !(emu->fp)) {
64 goto err;
65 }
66
67 abs_page = attr->pages_per_block * block + page_num;
68 full_page_size = attr->page_data_size + attr->spare_size;
69
70 if (data && data_len > 0) {
71 if (data_len > attr->page_data_size)
72 goto err;
73
74 emu->em_monitor_page[abs_page]++;
75 if (emu->em_monitor_page[abs_page] > PAGE_DATA_WRITE_COUNT_LIMIT) {
76 MSGLN("Warrning: block %d page %d exceed it's maximum write time!", block, page_num);
77 goto err;
78 }
79
80 fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
81
82 written = fwrite(data, 1, data_len, emu->fp);
83
84 if (written != data_len) {
85 MSGLN("write page I/O error ?");
86 goto err;
87 }
88
89 dev->st.page_write_count++;
90 dev->st.io_write += written;
91 }
92
93 if (spare && spare_len > 0) {
94 if (spare_len > attr->spare_size)
95 goto err;
96
97 emu->em_monitor_spare[abs_page]++;
98 if (emu->em_monitor_spare[abs_page] > PAGE_SPARE_WRITE_COUNT_LIMIT) {
99 MSGLN("Warrning: block %d page %d (spare) exceed it's maximum write time!", block, page_num);
100 goto err;
101 }
102
103 fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
104 written = fwrite(spare, 1, spare_len, emu->fp);
105 if (written != spare_len) {
106 MSGLN("write spare I/O error ?");
107 goto err;
108 }
109
110 dev->st.spare_write_count++;
111 dev->st.io_write += written;
112 }
113
114 if (data == NULL && spare == NULL) {
115 // mark bad block
116 fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
117 written = fwrite("\0", 1, 1, emu->fp);
118 if (written != 1) {
119 MSGLN("write bad block mark I/O error ?");
120 goto err;
121 }
122 dev->st.io_write++;
123 }
124
125 fflush(emu->fp);
126 return UFFS_FLASH_NO_ERR;
127 err:
128 fflush(emu->fp);
129 return UFFS_FLASH_IO_ERR;
130 }
131
132
femu_ReadPage(uffs_Device * dev,u32 block,u32 page_num,u8 * data,int data_len,u8 * ecc,u8 * spare,int spare_len)133 static URET femu_ReadPage(uffs_Device *dev, u32 block, u32 page_num, u8 *data, int data_len, u8 *ecc,
134 u8 *spare, int spare_len)
135 {
136 int nread;
137 uffs_FileEmu *emu;
138 int abs_page;
139 int full_page_size;
140 struct uffs_StorageAttrSt *attr = dev->attr;
141 unsigned char status;
142
143 emu = (uffs_FileEmu *)(dev->attr->_private);
144
145 if (!emu || !(emu->fp)) {
146 goto err;
147 }
148
149 abs_page = attr->pages_per_block * block + page_num;
150 full_page_size = attr->page_data_size + attr->spare_size;
151
152 if (data && data_len > 0) {
153 if (data_len > attr->page_data_size)
154 goto err;
155
156 fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
157 nread = fread(data, 1, data_len, emu->fp);
158
159 if (nread != data_len) {
160 MSGLN("read page I/O error ?");
161 goto err;
162 }
163 dev->st.io_read += nread;
164 dev->st.page_read_count++;
165 }
166
167 if (spare && spare_len > 0) {
168 if (spare_len > attr->spare_size)
169 goto err;
170
171 fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
172 nread = fread(spare, 1, spare_len, emu->fp);
173
174 if (nread != spare_len) {
175 MSGLN("read page spare I/O error ?");
176 goto err;
177 }
178 dev->st.io_read += nread;
179 dev->st.spare_read_count++;
180 }
181
182 if (data == NULL && spare == NULL) {
183 // read bad block mark
184 fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
185 nread = fread(&status, 1, 1, emu->fp);
186
187 if (nread != 1) {
188 MSGLN("read badblock mark I/O error ?");
189 goto err;
190 }
191 dev->st.io_read++;
192
193 return status == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
194 }
195
196 return UFFS_FLASH_NO_ERR;
197 err:
198 return UFFS_FLASH_IO_ERR;
199 }
200
201
202 uffs_FlashOps g_femu_ops_ecc_soft = {
203 femu_InitFlash, // InitFlash()
204 femu_ReleaseFlash, // ReleaseFlash()
205 femu_ReadPage, // ReadPage()
206 NULL, // ReadPageWithLayout
207 femu_WritePage, // WritePage()
208 NULL, // WirtePageWithLayout
209 NULL, // IsBadBlock(), let UFFS take care of it.
210 NULL, // MarkBadBlock(), let UFFS take care of it.
211 femu_EraseBlock, // EraseBlock()
212 };
213