📄 bon.c
字号:
/* * vivi/drivers/mtd/nand/bon.c * * Based on linux/drivers/mtd/nand/bon.c * * (C) 2002-2004 Mizi Research Inc. * Author: Hwang, Chideok <hwang@mizi.co.kr> */#include <config.h>#include <types.h>#include <mtd/mtd.h>#include <mtd/partitions.h>#include <mtd/nand_ecc.h>#include <errno.h>#include <vstring.h>#include <vmalloc.h>#include <progressbar.h>#include <command.h>#include <serial.h>#if BON_DEBUG#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) (void)(0)#endifstatic int PARTITION_OFFSET = (~0);#define BONFS_OOB_ECCPOS0 8#define BONFS_OOB_ECCPOS1 9#define BONFS_OOB_ECCPOS2 10#define BONFS_OOB_ECCPOS3 11#define BONFS_OOB_ECCPOS4 12#define BONFS_OOB_ECCPOS5 13static struct nand_oobinfo bonfs_oob_8 = { .useecc = MTD_NANDECC_AUTOPLACE,};static struct nand_oobinfo bonfs_oob_16 = { .useecc = MTD_NANDECC_PLACE, .eccbytes = 6, .eccpos = {BONFS_OOB_ECCPOS0, BONFS_OOB_ECCPOS1, BONFS_OOB_ECCPOS2, BONFS_OOB_ECCPOS3, BONFS_OOB_ECCPOS4, BONFS_OOB_ECCPOS5}, .oobfree = { {0,4}, {6,2}, {14,2}},};static struct nand_oobinfo bonfs_oob_64 = { .useecc = MTD_NANDECC_AUTOPLACE,};static struct nand_oobinfo yaffs_oobinfo = { useecc: 1, eccpos: {8, 9, 10, 13, 14, 15}};#define MAX_RETRY (80)#define MAX_PART (10)#define MAX_OOB_BUF (16)typedef struct { ulong offset; ulong size; ulong flag; ulong num_bad_block; ushort *bad_blocks;} partition_t;static struct { struct mtd_info *mtd; int num_part; int num_mtd_part; struct nand_oobinfo *oobinfo; partition_t parts[MAX_PART];} bon;static const char BON_MAGIC[8] = {'M', 0, 0, 'I', 0, 'Z', 'I', 0};intbon_do_read(int npart, char *buf, unsigned long pos, size_t size){ int ret, retlen; partition_t *part = &bon.parts[npart]; while(size > 0) { unsigned long block = pos / bon.mtd->erasesize; unsigned long start, start_in_block; size_t this_size; if (part->bad_blocks) { unsigned short *bad = part->bad_blocks; while(*bad++ <= block) { block++; } } start_in_block = pos % bon.mtd->erasesize; start = block * bon.mtd->erasesize + start_in_block; this_size = bon.mtd->erasesize - start_in_block; if (this_size > size) this_size = size; ret = MTD_READECC(bon.mtd, part->offset + start, this_size, &retlen, buf, NULL, bon.oobinfo); if (ret != 0) { printk("%s(): retlen = %d, ECC error ? - [%d]\n", __FUNCTION__, retlen, ret); return ret; } if (this_size != retlen) { printk("%s(): this_size = %d, retlen = %d\n", __FUNCTION__, this_size, retlen); return -EIO; } size -= this_size; buf += this_size; pos += this_size; } return 0;}intbon_do_write(int npart, char *buf, unsigned long pos, size_t size){ int ret, retlen; partition_t *part = &bon.parts[npart]; /* allign by page size */ if (size % 512) size = (((size >> 9)+1) << 9); printk("writting... "); progressbar_set_total(size); while(size > 0) { unsigned long block = pos / bon.mtd->erasesize; unsigned long start, start_in_block; size_t this_size; struct erase_info ei; if (part->bad_blocks) { unsigned short *bad = part->bad_blocks; while(*bad++ <= block) { block++; } } start_in_block = pos % bon.mtd->erasesize; start = block * bon.mtd->erasesize + start_in_block; this_size = bon.mtd->erasesize - start_in_block; if (this_size > size) this_size = size; ei.mtd = bon.mtd; ei.addr = part->offset + start; ei.len = bon.mtd->erasesize; ei.time = 1000; ei.retries = 0; ei.callback = NULL; ret = MTD_ERASE(bon.mtd, &ei); ret = MTD_WRITEECC(bon.mtd, part->offset + start, this_size, &retlen, buf, NULL, bon.oobinfo); if (ret != 0) { printk("\n%s(): retlen = %d, ECC error ? - [%d]\n", __FUNCTION__, retlen, ret); return ret; } if (this_size != retlen) { printk("\n%s(): this_size = %d, retlen = %d\n", __FUNCTION__, this_size, retlen); return -EIO; } size -= this_size; buf += this_size; pos += this_size; progressbar(size, BAR_DECREASE); } printk("ok\n"); return 0;}static void bon_display_info(void){ int i, j; printk(" position size flag\n"); for (i = 0; i < bon.num_part; i++) { partition_t *this = (partition_t *)&bon.parts[i]; printk("bon%d: %8.8lx-%8.8lx (%8.8lx) %8.8lx\n", i, this->offset, this->offset + this->size, this->size, this->flag); printk(" bad blocks: %d\n", this->num_bad_block); for (j = 0; j < this->num_bad_block; j++) { printk(" %d\n", this->bad_blocks[j]); } }}static inline void partinfo2buf(char *buf){ int i, j; unsigned int *s; memcpy(buf, BON_MAGIC, 8); s = (unsigned int *)(buf + 8); *s++ = bon.num_part; for (i = 0; i < bon.num_part; i++) { *s++ = bon.parts[i].offset; *s++ = bon.parts[i].size; *s++ = bon.parts[i].flag; } for (i = 0; i < bon.num_part; i++) { *s++ = bon.parts[i].num_bad_block; for (j = 0; j < bon.parts[i].num_bad_block; j++) { *s++ = bon.parts[i].bad_blocks[j]; } }}static inline int buf2partinfo(char *buf){ int i, j; unsigned int *s; s = (unsigned int *)(buf + 8); bon.num_part = *s++; if (bon.num_part > MAX_PART) { printk("bon: too many partitions (%d)\n", bon.num_part); return 1; } for (i = 0; i < bon.num_part; i++) { bon.parts[i].offset = *s++; bon.parts[i].size = *s++; bon.parts[i].flag = *s++; } for (i = 0; i < bon.num_part; i++) { partition_t *p = &bon.parts[i]; p->num_bad_block = *s++; if (p->num_bad_block) { p->bad_blocks = vmalloc(p->num_bad_block * sizeof(unsigned short)); if (!(p->bad_blocks)) return 1; for (j = 0; j < p->num_bad_block; j++) { p->bad_blocks[j] = *s++; } } else { p->bad_blocks = NULL; } } return 0;}static int_read_partition_info(struct mtd_info *mtd, char *buf, int verb){ unsigned long offset = PARTITION_OFFSET; unsigned char oobbuf[MAX_OOB_BUF]; int retlen; int retry_count = MAX_RETRY; if (offset > mtd->size - mtd->erasesize) offset = mtd->size - mtd->erasesize;#if 1 DPRINTK("%s(): OOBSIZE = %d\n", __FUNCTION__, mtd->oobsize); switch (mtd->oobsize) { case 8: bon.oobinfo = &bonfs_oob_8; break; case 16: bon.oobinfo = &bonfs_oob_16; break; case 64: bon.oobinfo = &bonfs_oob_64; break; default: printk("BON does not yet know how to handle ECC\n"); return -EINVAL; }#endif while(retry_count-- > 0) { if (MTD_READOOB(mtd, offset, 8, &retlen, oobbuf) < 0) { goto next_block; } if (oobbuf[5] != 0xff) { goto next_block; } if (MTD_READ(mtd, offset, 512, &retlen, buf) < 0) { goto next_block; } if (strncmp(buf, BON_MAGIC, 8) == 0) break; printk("bon:cannot find partition table\n"); return -1;next_block: offset -= mtd->erasesize; } if (retry_count <= 0) { printk("bon:cannot find partition table\n"); return -1; } buf2partinfo(buf);#if 0 for (i = 0; i < bon.num_part; i++) { if (verb) { printk("bon%d: %8.8lx-%8.8lx (%8.8lx) %8.8lx\n", i, bon.parts[i].offset, bon.parts[i].offset + bon.parts[i].size, bon.parts[i].size, bon.parts[i].flag); } }#endif return bon.num_part;}intbon_read_partition_info(struct mtd_info *mtd){ char buf[512]; if (_read_partition_info(mtd, &buf[0], 1) < 0) return -1; return 0;}intbon_write_partition_info(struct mtd_info *mtd){ unsigned long offset = PARTITION_OFFSET; unsigned char oobbuf[MAX_OOB_BUF]; u_char infobuf[512]; int retry_count = MAX_RETRY; partition_t *p = NULL; if (offset > mtd->size - mtd->erasesize) offset = mtd->size - mtd->erasesize; memset(infobuf, 0xff, 512); partinfo2buf(infobuf); while(retry_count-- > 0) { struct erase_info ei; int ret, retlen; if (MTD_READOOB(mtd, offset, 8, &retlen, oobbuf) < 0) { goto next_block; } if (oobbuf[5] != 0xff) { goto next_block; } ei.mtd = bon.mtd; ei.addr = offset; ei.len = bon.mtd->erasesize; ei.time = 1000; ei.retries = 0; ei.callback = NULL; ret = MTD_ERASE(mtd, &ei); ret = MTD_WRITEECC(mtd, offset, 512, &retlen, infobuf, NULL, bon.oobinfo); if (ret != 0) { printk("\n%s(): retlen = %d, ECC error ? - [%d]\n", __FUNCTION__, retlen, ret); goto next_block; } else { break; }next_block: offset -= mtd->erasesize; } if (retry_count <= 0) { printk("too many bad blocks in this flash.\n"); return 1; } /* refresh size of last partition */ p = &bon.parts[bon.num_part-1]; if (offset < (p->offset + p->size)) { p->size = (offset - p->offset); } return 0;}static voidcheck_bad_block(struct mtd_info *mtd){ int i; unsigned short bad_block[1024]; int retlen; ulong offset; if ((bon.num_part <= 0) || (bon.num_part >= MAX_PART)) return; offset = 0; for (i = 0; i < bon.num_part; i++) { ulong size = bon.parts[i].size; int num_bad = 0; offset = bon.parts[i].offset; while (size > 0) { u_char oobbuf[MAX_OOB_BUF]; if (MTD_READOOB(mtd, offset, 8, &retlen, oobbuf) < 0) { goto found_bad; } if (oobbuf[5] != 0xff) { goto found_bad; } size -= mtd->erasesize; offset += mtd->erasesize; continue;found_bad: bad_block[num_bad] = (offset - bon.parts[i].offset) / mtd->erasesize; num_bad++; printk("%lX: is bad\n", offset); offset += mtd->erasesize; } bon.parts[i].num_bad_block = num_bad; if (num_bad) { bon.parts[i].bad_blocks = vmalloc(num_bad * sizeof(unsigned short)); memcpy(bon.parts[i].bad_blocks, bad_block, num_bad * 2); } }}static intbon_partitioning(int argc, const char **argv){ int i, ret; u_char c; unsigned long max_bad_block; printk("Doing partitioning...\n"); bon.mtd = mymtd; bon.num_part = argc; for (i = 0; i < bon.num_part; i++) { char *s; s = strchr((char *)argv[i], ':'); if (s) { s++; if (*s == 'm' || *s == 'M') bon.parts[i].flag = 1; } else { bon.parts[i].flag = 0; } bon.parts[i].offset = simple_hstrtoul((char *)argv[i]); } max_bad_block = (((bon.mtd->size * 2UL) / 100UL) / bon.mtd->erasesize) * bon.mtd->erasesize; printk("ttt = %d\n", max_bad_block); for (i = 0; i < bon.num_part; i++) { if (i == (bon.num_part - 1)) { bon.parts[i].size = bon.mtd->size - max_bad_block; bon.parts[i].size -= (bon.parts[i-1].offset + bon.parts[i-1].size); break; } bon.parts[i].size = bon.parts[i+1].offset - bon.parts[i].offset; } printk("number of partitions: %d\n", bon.num_part); for (i = 0; i < bon.num_part; i++) { printk("[%d]: ofs = 0x%x, size = 0x%x, flag = %d\n", i, bon.parts[i].offset, bon.parts[i].size, bon.parts[i].flag); } printk("\nAre you sure (y/n) ? "); c = getc(); printk("%s\n\n", c == 'y' ? "yes" : "no"); if (c != 'y') return 0; printk("checking bad blocks...\n"); check_bad_block(bon.mtd); printk("writing partition table...\n"); ret = bon_write_partition_info(bon.mtd);#ifdef CONFIG_MTD_PARTITIONS_PARSER printk("refresing partition table...\n"); mtdpart_refresh();#endif return ret;}int bon_part_parser(void *ptr){ int i; char name[16]; mtd_partition_t *tmp = (mtd_partition_t *)ptr; if (bon_read_partition_info(bon.mtd)) { printk("bon: invalid partition table\n"); return -1; } else printk("bon: found partition table\n"); for (i = 0; i < bon.num_part; i++) { sprintf(name, "bon%d", i); strcpy((tmp+i)->name, name); (tmp+i)->offset = bon.parts[i].offset; (tmp+i)->size = bon.parts[i].size; if (bon.parts[i].flag == 1) { (tmp+i)->flag = MF_YAFFS; (tmp+i)->oobsel = &yaffs_oobinfo; } else { (tmp+i)->flag = MF_BON; (tmp+i)->oobsel = bon.oobinfo; } (tmp+i)->priv = vmalloc(sizeof(int)); *(int *)(tmp+i)->priv = i; } strcpy((tmp+0)->name, "vivi"); strcpy((tmp+1)->name, "kernel"); strcpy((tmp+2)->name, "root");#ifdef CONFIG_S3C2440_MPORT3S strcpy((tmp+3)->name, "module"); strcpy((tmp+4)->name, "disp"); strcpy((tmp+5)->name, "rp"); strcpy((tmp+6)->name, "bmp"); strcpy((tmp+7)->name, "xlib"); strcpy((tmp+8)->name, "usr");#endif#ifdef CONFIG_S3C2440_MPORT1S strcpy((tmp+3)->name, "module"); strcpy((tmp+4)->name, "disp"); strcpy((tmp+5)->name, "network"); strcpy((tmp+6)->name, "guide"); strcpy((tmp+7)->name, "image"); strcpy((tmp+8)->name, "usr");#endif return bon.num_part;}static void display_help(void){ printk("Usage:\n"); printk("\tbon info -- Display bon partition info.\n"); printk("\tbon part <offsets> -- Initialize bon partition info.\n"); printk("\tbon help -- Display this message.\n");}static voidcommand_bon(int argc, const char **argv){ if (mymtd == NULL) { printk("No mtd\n"); return; } switch (argc) { case 2: if (strncmp("help", argv[1], 4) == 0) { display_help(); return; } if (strncmp("info", argv[1], 4) == 0) { bon_display_info(); return; } break; case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: if (strncmp("part", argv[1], 4) == 0) { bon_partitioning(argc-2, argv+2); return; } break; default: break; } display_help();}user_command_t bon_cmd = { "bon", command_bon, NULL};int bon_init(void){ memset(&bon, 0, sizeof(bon)); bon.mtd = mymtd;#ifdef CONFIG_MTD_PARTITIONS_PARSER if (mtdpart_add_parser(bon_part_parser)) return 1;#else if (bon_read_partition_info(bon.mtd)) { printk("bon: invalid partition table\n"); return -1; }#endif add_command(&bon_cmd); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -