embox

Форк
0
/
flash_ops.c 
299 строк · 6.1 Кб
1
/**
2
 * @brief Common interface for flash subsystem
3
 *
4
 * @date 21.08.2013
5
 * @author Andrey Gazukin
6
 * @author Denis Deryugin
7
 */
8
#include <errno.h>
9
#include <errno.h>
10
#include <string.h>
11

12
#include <drivers/block_dev.h>
13
#include <drivers/flash/flash.h>
14

15
#include <util/math.h>
16

17
struct flash_block_info *
18
flash_block_info_by_block(struct flash_dev *flashdev, int block) {
19
	int i;
20
	int cur = 0;
21

22
	for (i = 0; i < flashdev->num_block_infos; i ++) {
23
		if (cur <= block && block < (cur + flashdev->block_info[i].blocks) ) {
24
			return &flashdev->block_info[i];
25
		}
26
		cur += flashdev->block_info[i].blocks;
27
	}
28

29
	return NULL;
30
}
31

32
int
33
flash_get_block_size(struct flash_dev *flashdev, int block) {
34
	int i;
35
	int cur = 0;
36

37
	for (i = 0; i < flashdev->num_block_infos; i ++) {
38
		if (cur <= block && block < (cur + flashdev->block_info[i].blocks) ) {
39
			return flashdev->block_info[i].block_size;
40
		}
41
		cur += flashdev->block_info[i].blocks;
42
	}
43

44
	return -EINVAL;
45
}
46

47
int
48
flash_get_block_by_offset(struct flash_dev *flashdev, unsigned long offset) {
49
	int i, j;
50
	int bl = 0;
51
	unsigned long cur = 0;
52

53
	for (i = 0; i < flashdev->num_block_infos; i++) {
54
		for (j = 0; j < flashdev->block_info[i].blocks; j++) {
55
			if (cur <= offset && 
56
						offset < (cur + flashdev->block_info[i].block_size) ) {
57
				return bl;
58
			}
59
			cur += flashdev->block_info[i].block_size;
60
			bl++;
61
		}
62
	}
63

64
	return -EINVAL;
65
}
66

67
int
68
flash_get_offset_by_block(struct flash_dev *flashdev, int block) {
69
	int i, j;
70
	int bl = 0;
71
	unsigned long cur = 0;
72

73
	for (i = 0; i < flashdev->num_block_infos; i++) {
74
		for (j = 0; j < flashdev->block_info[i].blocks; j++) {
75
			if (bl == block ) {
76
				return (int) cur;
77
			}
78
			cur += flashdev->block_info[i].block_size;
79
			bl++;
80
		}
81
	}
82

83
	return -EINVAL;
84
}
85

86
int
87
flash_get_blocks_num(struct flash_dev *flashdev) {
88
	int i;
89
	int num = 0;
90

91
	for (i = 0; i < flashdev->num_block_infos; i ++) {
92
		num += flashdev->block_info[i].blocks;
93
	}
94

95
	return num;
96
}
97

98
/* Handlers to check ranges and call device-specific functions */
99
int flash_read(struct flash_dev *flashdev, unsigned long offset, void *buf,
100
    size_t len) {
101
	assert(buf);
102
	assert(flashdev);
103
	assert(flashdev->drv);
104
	assert(flashdev->drv->flash_read);
105

106
	assert(offset + len <= flashdev->size);
107

108
	return flashdev->drv->flash_read(flashdev, offset, buf, len);
109
}
110

111
int flash_write(struct flash_dev *flashdev, unsigned long offset,
112
    const void *buf, size_t len) {
113
	assert(buf);
114
	assert(flashdev);
115
	assert(flashdev->drv);
116
	assert(flashdev->drv->flash_program);
117

118
	assert(offset + len <= flashdev->size);
119

120
	return flashdev->drv->flash_program(flashdev, offset, buf, len);
121
}
122

123
int flash_erase(struct flash_dev *flashdev, uint32_t block) {
124
	assert(flashdev);
125
	assert(flashdev->drv);
126
	assert(flashdev->drv->flash_erase_block);
127

128
	return flashdev->drv->flash_erase_block(flashdev, block);
129
}
130

131
struct flash_dev *flash_by_bdev(struct block_dev *bdev) {
132
	return bdev->dev_module.dev_priv;
133
}
134

135

136
int flash_read_aligned(struct flash_dev *flashdev, unsigned long offset,
137
    void *buff, size_t len) {
138
	int i;
139
	char *b;
140
	uint32_t word32;
141
	int head;
142
	int word_size;
143

144
	assert(buff);
145

146
	if (flashdev->fld_aligned_word) {
147
		b = flashdev->fld_aligned_word;
148
		word_size = flashdev->fld_word_size;
149
	}
150
	else {
151
		b = (void *)&word32;
152
		word_size = sizeof(word32);
153
	}
154

155
	head = offset % word_size;
156

157
	if (head) {
158
		size_t head_cnt = min(len, word_size - head);
159

160
		offset -= head;
161
		flash_read(flashdev, offset, b, word_size);
162
		memcpy(buff, b + head, head_cnt);
163

164
		if (len <= head_cnt) {
165
			return 0;
166
		}
167

168
		buff += head_cnt;
169
		offset += word_size;
170
		len -= head_cnt;
171
	}
172

173
	for (i = 0; len >= word_size; i++) {
174
		flash_read(flashdev, offset, b, word_size);
175
		memcpy(buff, b, word_size);
176

177
		offset += word_size;
178
		buff += word_size;
179
		len -= word_size;
180
	}
181

182
	if (len > 0) {
183
		flash_read(flashdev, offset, b, word_size);
184
		memcpy(buff, b, len);
185
	}
186

187
	return 0;
188
}
189

190
/* @brief Write non-aligned raw data to \b erased NAND flash
191
 * @param offset Start position on disk
192
 * @param buff   Source of the data
193
 * @param len    Length of the data in bytes
194
 *
195
 * @returns Bytes written or negative error code
196
 */
197
int flash_write_aligned(struct flash_dev *flashdev, unsigned long offset,
198
    const void *buff, size_t len) {
199
	int i;
200
	char *b;
201
	uint32_t word32;
202
	int head;
203
	int word_size;
204

205
	assert(buff);
206

207
	if (flashdev->fld_aligned_word) {
208
		b = flashdev->fld_aligned_word;
209
		word_size = flashdev->fld_word_size;
210
	}
211
	else {
212
		b = (void *)&word32;
213
		word_size = sizeof(word32);
214
	}
215

216
	head = offset % word_size;
217

218
	if (head) {
219
		size_t head_write_cnt = min(len, word_size - head);
220

221
		offset -= head;
222
		flash_read(flashdev, offset, b, word_size);
223
		memcpy(b + head, buff, head_write_cnt);
224
		flash_write(flashdev, offset, b, word_size);
225

226
		if (len <= head_write_cnt) {
227
			return 0;
228
		}
229

230
		buff += head_write_cnt;
231
		offset += word_size;
232
		len -= head_write_cnt;
233
	}
234

235
	for (i = 0; len >= word_size; i++) {
236
		memcpy(b, buff, word_size);
237
		flash_write(flashdev, offset, b, word_size);
238

239
		offset += word_size;
240
		buff += word_size;
241
		len -= word_size;
242
	}
243

244
	if (len > 0) {
245
		flash_read(flashdev, offset, b, word_size);
246
		memcpy(b, buff, len);
247
		flash_write(flashdev, offset, b, word_size);
248
	}
249

250
	return 0;
251
}
252

253
int flash_copy_aligned(struct flash_dev *flashdev, unsigned long to,
254
    unsigned long from, int len) {
255
	char b[32];
256

257
	while (len > 0) {
258
		int tmp_len;
259

260
		tmp_len = min(len, sizeof(b));
261

262
		if (0 > flash_read_aligned(flashdev, from, b, tmp_len)) {
263
			return -1;
264
		}
265
		if (0 > flash_write_aligned(flashdev, to, b, tmp_len)) {
266
			return -1;
267
		}
268

269
		len -= tmp_len;
270
		to += tmp_len;
271
		from += tmp_len;
272
	}
273

274
	return 0;
275
}
276

277
int flash_copy_block(struct flash_dev *flashdev, unsigned int to,
278
    unsigned long from) {
279
	uint32_t block_size;
280
	uint8_t buf[64];
281
	int off;
282
	unsigned long off_to;
283
	unsigned long off_from;
284

285
	block_size = flash_get_block_size(flashdev, to);
286
	assert(block_size == flash_get_block_size(flashdev, from));
287

288
	off_to = flash_get_offset_by_block(flashdev, to);
289
	off_from = flash_get_offset_by_block(flashdev, from);
290

291
	flash_erase(flashdev, to);
292

293
	for (off = 0; off < block_size; off += sizeof(buf)) {
294
		flash_read(flashdev, off_from + off, buf, sizeof(buf));
295
		flash_write(flashdev, off_to + off, buf, sizeof(buf));
296
	}
297

298
	return 0;
299
}
300

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.