1 /*
2 This file is part of UFFS, the Ultra-low-cost Flash File System.
3
4 Copyright (C) 2005-2009 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_share.c
35 * \brief emulate uffs file system, shared functions
36 * \author Ricky Zheng, created Nov, 2010
37 */
38
39
40 #include <sys/types.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include "uffs_config.h"
45 #include "uffs/uffs_device.h"
46 #include "uffs_fileem.h"
47
48 #define PFX "femu: "
49
50 /****************************************************************/
51 /* Shared flash driver functions: */
52 /* */
53 /* femu_InitFlash(), femu_ReleaseFlash(), femu_EraseBlock() */
54 /* */
55 /****************************************************************/
56
57 static u8 g_page_buf[UFFS_MAX_PAGE_SIZE + UFFS_MAX_SPARE_SIZE];
58
59 /*
60 * Create emulator disk, initialise monitors, inject manufacture bad blocks, etc.
61 *
62 */
femu_InitFlash(uffs_Device * dev)63 int femu_InitFlash(uffs_Device *dev)
64 {
65 int i;
66 int fSize;
67 int written;
68 u8 * p = g_page_buf;
69 uffs_FileEmu *emu;
70
71 struct uffs_StorageAttrSt *attr = dev->attr;
72
73 int full_page_size = attr->page_data_size + attr->spare_size;
74 int total_pages = attr->total_blocks * attr->pages_per_block;
75
76 emu = (uffs_FileEmu *)(dev->attr->_private);
77
78 if (emu->initCount > 0) {
79 emu->initCount++;
80 return 0;
81 }
82
83 if (emu->emu_filename == NULL)
84 emu->emu_filename = UFFS_FEMU_FILE_NAME;
85
86 uffs_Perror(UFFS_MSG_NORMAL, "femu device init.");
87
88 emu->em_monitor_page = (u8 *) malloc(sizeof(emu->em_monitor_page[0]) * total_pages);
89 if (!emu->em_monitor_page)
90 return -1;
91 emu->em_monitor_spare = (u8 *) malloc(sizeof(emu->em_monitor_spare[0]) * total_pages);
92 if (!emu->em_monitor_spare)
93 return -1;
94
95 emu->em_monitor_block = (u32 *) malloc(sizeof(emu->em_monitor_block[0]) * attr->total_blocks);
96 if (!emu->em_monitor_block)
97 return -1;
98
99 //clear monitor
100 memset(emu->em_monitor_page, 0, sizeof(emu->em_monitor_page[0]) * total_pages);
101 memset(emu->em_monitor_spare, 0, sizeof(emu->em_monitor_spare[0]) * total_pages);
102 memset(emu->em_monitor_block, 0, sizeof(emu->em_monitor_block[0]) * attr->total_blocks);
103
104 emu->fp = fopen(emu->emu_filename, "rb");
105 if (emu->fp == NULL) {
106 emu->fp = fopen(emu->emu_filename, "ab+");
107 if (emu->fp == NULL) {
108 printf(PFX"Failed to create uffs emulation file.");
109 return -1;
110 }
111
112 fseek(emu->fp, 0, SEEK_END);
113 fSize = ftell(emu->fp);
114
115 if (fSize < total_pages * full_page_size) {
116 printf("Creating uffs emulation file\n");
117 fseek(emu->fp, 0, SEEK_SET);
118 memset(p, 0xff, full_page_size);
119 for (i = 0; i < total_pages; i++) {
120 written = fwrite(p, 1, full_page_size, emu->fp);
121 if (written != full_page_size) {
122 printf("Write failed\n");
123 fclose(emu->fp);
124 emu->fp = NULL;
125 return -1;
126 }
127 }
128 }
129 }
130
131 fflush(emu->fp);
132 fclose(emu->fp);
133
134 emu->fp = fopen(emu->emu_filename, "rb+");
135 if (emu->fp == NULL) {
136 printf(PFX"Can't open emulation file.\n");
137 return -1;
138 }
139
140 emu->initCount++;
141
142 return 0;
143 }
144
145 /*
146 * Release resources
147 */
femu_ReleaseFlash(uffs_Device * dev)148 int femu_ReleaseFlash(uffs_Device *dev)
149 {
150 uffs_FileEmu *emu;
151
152 emu = (uffs_FileEmu *)(dev->attr->_private);
153
154 emu->initCount--;
155
156 if (emu->initCount == 0) {
157
158 uffs_Perror(UFFS_MSG_NORMAL, "femu device release.");
159
160 if (emu->fp) {
161 fclose(emu->fp);
162 emu->fp = NULL;
163 }
164
165 if (emu->em_monitor_page)
166 free(emu->em_monitor_page);
167 if (emu->em_monitor_spare)
168 free(emu->em_monitor_spare);
169 if (emu->em_monitor_block)
170 free(emu->em_monitor_block);
171 emu->em_monitor_page = NULL;
172 emu->em_monitor_spare = NULL;
173 emu->em_monitor_block = NULL;
174 }
175
176 return 0;
177 }
178
femu_EraseBlock(uffs_Device * dev,u32 blockNumber)179 int femu_EraseBlock(uffs_Device *dev, u32 blockNumber)
180 {
181
182 int i;
183 u8 * pg = g_page_buf;
184 int pg_size, pgd_size, sp_size, blks, blk_pgs, blk_size;
185 uffs_FileEmu *emu;
186 emu = (uffs_FileEmu *)(dev->attr->_private);
187 if (!emu || !(emu->fp))
188 goto err;
189
190 pg_size = dev->attr->page_data_size + dev->attr->spare_size;
191 pgd_size = dev->attr->page_data_size;
192 sp_size = dev->attr->spare_size;
193 blk_pgs = dev->attr->pages_per_block;
194 blks = dev->attr->total_blocks;
195 blk_size = dev->attr->page_data_size * dev->attr->pages_per_block;
196
197 printf("femu: erase block %d\n", blockNumber);
198
199 if ((int)blockNumber >= blks) {
200 printf("Attempt to erase non-existant block %d\n",blockNumber);
201 goto err;
202 }
203 else {
204
205 //clear this block monitors
206 memset(emu->em_monitor_page + (blockNumber * blk_pgs),
207 0,
208 blk_pgs * sizeof(u8));
209 memset(emu->em_monitor_spare + (blockNumber * blk_pgs),
210 0,
211 blk_pgs * sizeof(u8));
212
213 emu->em_monitor_block[blockNumber]++;
214
215 memset(pg, 0xff, (pgd_size + sp_size));
216
217 fseek(emu->fp, blockNumber * blk_pgs * (pgd_size + sp_size), SEEK_SET);
218
219 for (i = 0; i < blk_pgs; i++) {
220 fwrite(pg, 1, (pgd_size + sp_size), emu->fp);
221 }
222
223 fflush(emu->fp);
224 dev->st.block_erase_count++;
225 }
226
227 return UFFS_FLASH_NO_ERR;
228 err:
229 return UFFS_FLASH_IO_ERR;
230
231 }
232
233