8c2952457
김태훈
응용 프로그램 추가
|
1
2
3
|
/**
@file mtd-nand.c
@date 2010/05/27
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
4
5
6
7
8
|
@author 오재경 freefrug@falinux.com FALinux.Co.,Ltd.
@brief mtd를 통해 nand 플래시를 제어한다
2011/03/25 오재경 ezboot 1.x 를 지원을 추가
2011/04/13 오재경 배드블럭에 대한 에러를 수정
2011/06/13 오재경 배드블럭에 대한 에러를 수정
|
8c2952457
김태훈
응용 프로그램 추가
|
9
|
@todo
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
10
|
MTD_NANDECC_OFF 옵션도 있으니 구현하자
|
8c2952457
김태훈
응용 프로그램 추가
|
11
12
13
14
15
|
@bug
@remark
@warning
*/
//
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
16
17
|
// 저작권 에프에이리눅스(주)
// 외부공개 금지
|
8c2952457
김태훈
응용 프로그램 추가
|
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
//
//----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/mman.h>
#include <mtd-abi.h>
#include <mtd-nand.h>
#include <util.h>
char desc_mtd_nand[] = "falinux mtd-nand ver 0.3.4";
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
41
42
43
|
/** @brief mtd-nand 생성함수
@param fname mtd 노드파일이름
@return mtdnand_t 구조체 포인터
|
8c2952457
김태훈
응용 프로그램 추가
|
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
*///----------------------------------------------------------------------------
mtdnand_t *mtdnand_create( char *fname )
{
mtdnand_t *mtd;
mtd = malloc( sizeof(mtdnand_t) );
memset( (void *)mtd, 0, sizeof(mtdnand_t) );
sprintf( mtd->node_name, "%s", fname );
mtd->fd = open( mtd->node_name, O_RDWR ); // O_RDONLY
if ( 0 > mtd->fd )
{
perror( "mtd open error" );
free( mtd );
return NULL;
}
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
61
|
// 난드플래시의 정보를 얻는다.
|
8c2952457
김태훈
응용 프로그램 추가
|
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
if ( 0 == ioctl( mtd->fd, MEMGETINFO, &mtd->info) )
{
printf( " mtd=%s
", mtd->node_name );
printf( " * total size %dMB
", mtd->info.size/(1024*1024) );
printf( " * erase size %d
" , mtd->info.erasesize );
printf( " * write size %d
" , mtd->info.writesize );
printf( " * oob size %d
" , mtd->info.oobsize );
printf( " * ecc type %d
" , mtd->info.ecctype );
printf( "
" );
}
else
{
perror( "unable to get mtd-info" );
free( mtd );
return NULL;
}
return mtd;
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
89
90
|
/** @brief mtd-nand 해제함수
@param mtd mtdnand_t 구조체 포인터
|
8c2952457
김태훈
응용 프로그램 추가
|
91
92
93
94
95
96
97
98
99
100
|
*///----------------------------------------------------------------------------
void mtdnand_free( mtdnand_t *mtd )
{
if ( mtd )
{
close( mtd->fd );
free( mtd );
}
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
101
102
103
104
105
|
/** @brief mtd-nand 의 엑세스 위치를 이동한다.
@param mtd mtdnand_t 구조체 포인터
@param offset 이동크기
@param origin 기준위치
@return 파일포인터의 위치, 에러일경우 음수
|
8c2952457
김태훈
응용 프로그램 추가
|
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
*///----------------------------------------------------------------------------
int mtdnand_seek( mtdnand_t *mtd, int offset, int origin )
{
int pos;
pos = lseek( mtd->fd, offset, origin );
//printf( "seek=0x%08x (%d)
", rtn, rtn );
if ( 0 > pos )
{
perror( "mtd seek error" );
return -1;
}
else
{
mtd->pos = pos;
//switch( origin )
//{
//case SEEK_SET : mtd->pos = offset; break;
//case SEEK_CUR : mtd->pos += offset; break;
//case SEEK_END : mtd->pos = mtd->info.size + offset; break;
//}
}
return pos;
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
136
137
138
139
140
|
/** @brief mtd-nand 의 oob 영역을 읽는다.
@param mtd mtdnand_t 구조체 포인터
@param buf 데이타를 담을 버퍼
@param count 버퍼의 크기
@return 성공0
|
8c2952457
김태훈
응용 프로그램 추가
|
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
*///----------------------------------------------------------------------------
int mtdnand_read_oob( mtdnand_t *mtd, unsigned char *buf, int count )
{
struct mtd_oob_buf oob_buf;
int rtn;
oob_buf.start = mtd->pos;
oob_buf.length = (count > mtd->info.oobsize) ? mtd->info.oobsize : count;
oob_buf.ptr = buf;
rtn = ioctl( mtd->fd, MEMREADOOB, &oob_buf );
if ( 0 > rtn )
{
perror( "mtd read-oob error" );
}
return rtn;
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
160
161
162
|
/** @brief mtd-nand 의 oob 영역을 읽는다.
@param mtd mtdnand_t 구조체 포인터
@return -1 : badblock 0:정상블럭
|
8c2952457
김태훈
응용 프로그램 추가
|
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
*///----------------------------------------------------------------------------
int mtdnand_is_bad( mtdnand_t *mtd )
{
unsigned char buf[256], cmp;
cmp = 0x00;
if ( 0 == mtdnand_read_oob( mtd, buf, 6 ) )
{
if ( 512 == mtd->info.writesize )
{
cmp = buf[5];
}
else
{
cmp = buf[0];
}
}
if ( cmp != 0xff )
{
printf( "%s bad block 0x%08x
", mtd->node_name, mtd->pos );
return -1;
}
return 0;
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
190
191
192
|
/** @brief mtd-nand 의 한블럭을 지운다.
@param mtd mtdnand_t 구조체 포인터
@return 성공0
|
8c2952457
김태훈
응용 프로그램 추가
|
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
|
*///----------------------------------------------------------------------------
int mtdnand_erase( mtdnand_t *mtd )
{
int rtn;
struct erase_info_user erase_info;
erase_info.start = (mtd->pos/mtd->info.erasesize)*mtd->info.erasesize;
erase_info.length = mtd->info.erasesize;
rtn = ioctl( mtd->fd, MEMERASE, &erase_info);
if ( 0 != rtn )
{
perror( "mtd erase error" );
}
return rtn;
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
210
211
212
213
214
215
|
/** @brief mtd-nand 에서 데이타를 읽는다.
@param mtd mtdnand_t 구조체 포인터
@param buf 데이타를 담을 버퍼
@param count 버퍼의 크기
@return 읽은 데이타의 크기
@remark 배드블럭을 만나면
|
8c2952457
김태훈
응용 프로그램 추가
|
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
*///----------------------------------------------------------------------------
int mtdnand_read( mtdnand_t *mtd, unsigned char *buf, int count )
{
int rtn;
rtn = read( mtd->fd, buf, count );
if ( 0 > rtn )
{
perror( "mtd read error" );
}
else
{
mtd->pos += rtn;
}
return rtn;
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
234
235
236
237
238
239
|
/** @brief mtd-nand 에서 데이타를 읽는다.
@param mtd mtdnand_t 구조체 포인터
@param buf 데이타를 담을 버퍼
@param count 버퍼의 크기
@return 읽은 데이타의 크기
@remark 배드블럭을 만나면 다음블럭으로 자동으로 점프한다.
|
8c2952457
김태훈
응용 프로그램 추가
|
240
241
242
243
244
245
246
247
248
|
*///----------------------------------------------------------------------------
int mtdnand_read_skip_bad( mtdnand_t *mtd, unsigned char *buf, int count )
{
int rtn, esize, bad_cnt;
int rdcnt, remain;
esize = mtd->info.erasesize;
bad_cnt = 0;
remain = count;
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
249
|
// 페이지 단위로 정렬한다.
|
8c2952457
김태훈
응용 프로그램 추가
|
250
251
252
253
254
|
mtd->pos = ALIGN_SIZE( mtd->pos, mtd->info.writesize );
mtdnand_seek( mtd, mtd->pos, SEEK_SET );
while( 0 < remain )
{
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
255
|
// 블럭의 시작인가?
|
8c2952457
김태훈
응용 프로그램 추가
|
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
|
if ( 0 == (mtd->pos % esize) )
{
while( mtdnand_is_bad( mtd ) )
{
printf( "
bad block offset-page=%d
", mtd->pos/mtd->info.writesize );
mtd->pos += esize;
mtdnand_seek( mtd, mtd->pos, SEEK_SET );
bad_cnt ++;
if ( MAX_BADBLOCK_COUNT <= bad_cnt )
{
printf( "mtd read error : many bad block over %d
", MAX_BADBLOCK_COUNT );
return RDERR_MANY_BADBLOCK ;
}
}
}
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
274
|
// 읽을 갯수를 결정한다.
|
8c2952457
김태훈
응용 프로그램 추가
|
275
276
|
rdcnt = (remain > esize) ? esize : remain;
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
277
|
// 데이타 읽기
|
8c2952457
김태훈
응용 프로그램 추가
|
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
|
rtn = read( mtd->fd, buf, rdcnt );
if ( 0 > rtn )
{
perror( "mtd read error" );
return rtn;
}
else
{
mtd->pos += rdcnt;
}
remain -= rdcnt;
buf += rdcnt;
}
return count;
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
298
299
300
301
302
303
304
305
|
/** @brief mtd-nand 에 데이타를 쓴다.
@param mtd mtdnand_t 구조체 포인터
@param buf 데이타 버퍼
@param count 버퍼의 크기
@return 쓴 데이타의 크기
@remark 데이타의 크기는 writesize 크기의 배수만 쓰여진다.
erase 는 자동으로 이루어지며 erasesize 배수의 위치일 경우 지운다.
배드블럭이 있으면 다음블럭으로 넘긴다.
|
8c2952457
김태훈
응용 프로그램 추가
|
306
307
308
309
310
311
312
313
314
315
316
|
*///----------------------------------------------------------------------------
int mtdnand_write( mtdnand_t *mtd, unsigned char *buf, int count )
{
int wrcnt, esize, wsize, wr_total, remain;
char wbuf[1024*256], *getp;
getp = buf;
wr_total = 0;
remain = count;
esize = mtd->info.erasesize;
wsize = mtd->info.writesize;
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
317
|
// 쓰기의 위치는 항상 writesize의 배수이어야 한다.
|
8c2952457
김태훈
응용 프로그램 추가
|
318
319
320
321
322
323
324
|
if ( 0 != ( mtd->pos % wsize ) )
{
mtdnand_seek( mtd, (mtd->pos/wsize)*wsize, SEEK_SET );
}
while( 0 < remain )
{
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
325
|
// 블럭을 지워야 하는가?
|
8c2952457
김태훈
응용 프로그램 추가
|
326
327
328
329
330
331
332
333
|
if ( 0 == (mtd->pos % esize) )
{
if ( mtdnand_is_bad( mtd ) )
{
mtd->pos += esize;
mtdnand_seek( mtd, mtd->pos, SEEK_SET );
continue;
}
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
334
|
// 지워서 에러가 있다면 배드블럭이다(?)
|
8c2952457
김태훈
응용 프로그램 추가
|
335
336
337
338
339
340
341
342
343
|
// mtdnand_erase( mtd );
if ( 0 != mtdnand_erase( mtd ) )
{
mtd->pos += esize;
mtdnand_seek( mtd, mtd->pos, SEEK_SET );
continue;
}
}
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
344
|
// writesize 만큼 쓴다.
|
8c2952457
김태훈
응용 프로그램 추가
|
345
346
|
wrcnt = (remain >= wsize) ? wsize : remain;
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
347
|
// writesize 보다 작다면 나머지를 0xff 로 채운다.
|
8c2952457
김태훈
응용 프로그램 추가
|
348
349
350
351
352
353
|
memcpy( wbuf, getp, wrcnt );
if ( wrcnt < wsize )
{
memset( wbuf+wrcnt, 0xff, wsize-wrcnt );
}
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
354
|
// 쓰기는 항상 writesize 이어야 한다.
|
8c2952457
김태훈
응용 프로그램 추가
|
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
|
wrcnt = write( mtd->fd, wbuf, wsize );
if ( wrcnt < 0 )
{
perror( "mtd write error" );
return -1;
}
mtd->pos += wrcnt;
getp += wrcnt;
wr_total += wrcnt;
remain -= wrcnt;
}
return wr_total;
}
//------------------------------------------------------------------------------
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
374
375
|
/** @brief mtd-nand 를 모두 지운다.
@param mtd mtdnand_t 구조체 포인터
|
8c2952457
김태훈
응용 프로그램 추가
|
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
|
*///----------------------------------------------------------------------------
void mtdnand_erase_all( mtdnand_t *mtd )
{
int remain, esize;
char str[256];
void progress_msg( char *msg )
{
printf( "%s", msg ); fflush( stdout );
}
sprintf( str, " erase all mtd=%s size=%dMB
", mtd->node_name, mtd->info.size/(1024*1024) );
progress_msg( str );
|
3061c73f6
김태훈
인코딩 변경 EUC-KR -> ...
|
391
|
// mtd 어프셋을 설정한다.
|
8c2952457
김태훈
응용 프로그램 추가
|
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
|
mtdnand_seek( mtd, 0, SEEK_SET );
remain = mtd->info.size;
esize = mtd->info.erasesize;
while( 0 < remain )
{
mtdnand_erase( mtd );
mtdnand_seek( mtd, esize, SEEK_CUR );
remain -= esize;
if ( 0 == (remain % (1024*1024)) )
{
progress_msg( "." );
}
}
progress_msg( ".end
" );
}
|