⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bon.c

📁 比较好的VIVI开发源码
💻 C
字号:
/*
 * vivi/drivers/mtd/nand/bon.c 
 *
 * Based on vivi/util/imagewrite
 *
 * $Id: bon.c,v 1.13 2003/06/12 11:14:01 nandy Exp $
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Description: Simple management routines for the bon file system.
 *
 */

#include <config.h>
#include <mtd/mtd.h>
#include <mtd/nand_ecc.h>
#include <printk.h>
#include <errno.h>
#include <heap.h>
#include <string.h>
#include <command.h>
#include <ctype.h>

extern struct mtd_info *mymtd;

#if defined(CONFIG_S3C2410_MPORT3) || defined(CONFIG_S3C2410_MPORT1)
#  define MAX_PART 		9
#else
#  define MAX_PART		5
#endif
#define MAX_RETRY		5
#define PARTITION_OFFSET	(~0)

#define IS_MTD  1
#define IS_BON  0

typedef struct {
	ulong offset;
	ulong size;
	ulong flag;
	ulong num_bad_block;
	unsigned short *bad_blocks;
} bon_partition_t;

const char bon_part_magic[8] = {'M', 0, 0, 'I', 0, 'Z', 'I', 0};

bon_partition_t parts[MAX_PART];
int num_part;

/* sector size啊 256牢 2M捞窍狼 NAND device绰 贸府窍瘤 给窃 */
#define NAND_SECTOR_SIZE	512
#define NAND_OOB_SIZE		16


static void
mark_bad(struct mtd_info *mtd, ulong offset)
{
	char oobbuf[NAND_OOB_SIZE];
	memset (oobbuf, 0xff, NAND_OOB_SIZE);
	oobbuf[5] = 0;
	mtd->write_oob(mtd, offset, NAND_OOB_SIZE, NULL, oobbuf);
}


static int
is_bad_block(struct mtd_info *mtd, ulong offset)
{
	unsigned char oobbuf[NAND_OOB_SIZE];
	char buf[NAND_SECTOR_SIZE];
	struct erase_info erase;
	size_t retlen;

	erase.addr = offset;
	erase.len = mtd->erasesize;

	if (mtd->erase(mtd, &erase) < 0) return 1;

	if (mtd->read_oob(mtd, offset, NAND_OOB_SIZE, &retlen, oobbuf)) {
		return -1;
	}
	if (oobbuf[5] != 0xFF) return -1;
	if (mtd->read(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf)) {
		return -1;
	}
	if (retlen != NAND_SECTOR_SIZE) {
		printk("read error\n");
		mark_bad(mtd, offset);
		return -1;
	}
	return 0;
}

void
check_bad_block(struct mtd_info *mtd)
{
	int i;
	unsigned short bad_block[1024];
	for (i = 0; i < num_part; i++) {
		ulong offset = parts[i].offset;
		ulong end = (i + 1 < num_part) ? parts[i+1].offset : mtd->size;
		int num_bad = 0;
		int bad;
		printk("part = %d end = %ld\n", i, end);
		while (offset < end) {
			bad = is_bad_block(mtd, offset);
			if (bad) {
				bad_block[num_bad] = (offset - parts[i].offset) /\
							mtd->erasesize;
				num_bad++;
				printk("%lX: is bad\n", offset);
			}
			offset += mtd->erasesize;
		}
		parts[i].num_bad_block = num_bad;
#if 0 //  ???? - bushi
		parts[i].flag = 0;
#endif
		if (num_bad) {
			parts[i].bad_blocks = mmalloc(num_bad * sizeof(unsigned short));
			memcpy(parts[i].bad_blocks, bad_block, num_bad * 2);
		}
		parts[i].size = end - parts[i].offset - num_bad * mtd->erasesize;
	}
	parts[num_part - 1].size -= mtd->erasesize;
}

static ulong
calc_ecc(char *buf, unsigned char *ecc)
{
	nand_calculate_ecc(buf, ecc);
	return 0;
}

static int
write_oob(struct mtd_info *mtd, char *buf, ulong offset)
{
	char oob_buf[NAND_OOB_SIZE];
	unsigned char ecc[3];

	memset(oob_buf, 0xFF, NAND_OOB_SIZE);

	calc_ecc(buf, ecc);
	memcpy(oob_buf + 8, ecc, 3);

	calc_ecc(buf + 256, ecc);
	memcpy(oob_buf + 11, ecc, 3);

	if (mtd->write_oob(mtd, offset, NAND_OOB_SIZE, NULL, oob_buf))
		return 1;
	else
		return 0;
}

static int
write_block(struct mtd_info *mtd, ulong offset, char *buf)
{
	int i;
	size_t retlen = 0;

	if (is_bad_block(mtd, offset)) return 1;

	for (i = 0; i < (mtd->erasesize/NAND_SECTOR_SIZE); i++) {
		if (mtd->write(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf))
			return 1;
		if (retlen != NAND_SECTOR_SIZE)
			return 1;
		if (write_oob(mtd, buf, offset)) return 1;
		offset += NAND_SECTOR_SIZE;
		buf += NAND_SECTOR_SIZE;
	}
	return 0;
}

int 
write_bon_image(struct mtd_info *mtd, ulong offset, char *src, long size)
{
	int bad_block_nr = 0;
	/* NAND_SECTOR_SIZE*32 > meminfo.erasesize */
	char buf[NAND_SECTOR_SIZE*32];
	ulong block;
	unsigned short *bad;
	int i;

	printk("size = %ld\n", size);

	if (offset % mtd->erasesize) {
		printk("bad alignment\n");
		return -1;
	}

	for (i = 0; i < num_part; i++) {
		if (parts[i].offset >= offset) break;
	}
	if (i == num_part) i = num_part - 1;
	if (offset + size > parts[i].offset + parts[i].size) {
		printk("image is too big for this partition\n");
		return -1;
	}
	block = (offset - parts[i].offset) / mtd->erasesize;
	bad = parts[i].bad_blocks;
	if (bad) {
		while (*bad++ <= block) block++;
	}
	offset = parts[i].offset + block * mtd->erasesize;

	memcpy(buf, src, mtd->erasesize);
	while (size > 0) {
		if (write_block(mtd, offset, buf) == 0) {
			size -= mtd->erasesize;
			src += mtd->erasesize;
			if (size > 0)
				memcpy(buf, src, mtd->erasesize);
		} else {
			int k;
			int block_nr = (offset - parts[i].offset) / mtd->erasesize;
			for (k = 0; k < parts[i].num_bad_block; k++) {
				if (block_nr == parts[i].bad_blocks[k]) break;
			}
			if (k == parts[i].num_bad_block) {
				printk("*** warning: new bad block in %d\n", block_nr);
				return -2;
			}
			bad_block_nr++;
		}
		offset += mtd->erasesize;
	}
	printk("bad_block = %d\n", bad_block_nr);
	return 0;
}

int
read_bon_partition(struct mtd_info *mtd)
{
	int i, k;
	unsigned char oobbuf[NAND_OOB_SIZE];
	char buf[NAND_SECTOR_SIZE];
	unsigned int *s;
	ulong offset = PARTITION_OFFSET;
	ssize_t retlen;
	int ret;

	if (offset > mtd->size - mtd->erasesize)
		offset = mtd->size - mtd->erasesize;

	if (!mtd->read_oob)
		ret = -EOPNOTSUPP;
	ret = mtd->read_oob(mtd, offset, NAND_OOB_SIZE, &retlen, oobbuf);
	if (ret || oobbuf[5] != 0xFF)
		return -2;
	
	if (mtd->read(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf))
	   	return -3;

	if (strncmp(buf, bon_part_magic, 8) != 0)
		return -1;

	s = (unsigned int *)(buf + 8);
	num_part = *s++;

	for (i = 0; i < num_part; i++) {
		parts[i].offset = *s++;
		parts[i].size = *s++;
		parts[i].flag = *s++;
	}
	for (i = 0; i < num_part; i++) {
		parts[i].num_bad_block = *s++;
		if (parts[i].num_bad_block) {
			parts[i].bad_blocks = mmalloc(parts[i].num_bad_block * sizeof(unsigned int));
			for (k = 0; k < parts[i].num_bad_block;k++) {
				parts[i].bad_blocks[k] = *s++;
			}
		} else {
			parts[i].bad_blocks = 0;
		}
	}
	return 0;
}

ulong
read_size(char *s)
{
	ulong size = 0;
	while (isdigit(*s)) {
		size = size * 10 + *s - '0';
		s++;
	}
	if (*s == 'M' || *s == 'm') size *= 1024*1024;
	else if (*s == 'K' || *s == 'k') size *= 1024;
	else if (*s) {
		printk("hmm bad size %s\n", s);
	}
	return size;
}

ulong
read_flag(char *s)
{
	ulong flag = 0;
    
	while ( *s && *s != ':' )
		s++;

	if (*s == 0) 
		return IS_BON;

	s++;

	if (*s == 'm' || *s == 'M')
		flag |= IS_MTD;

	return flag;
}

int
write_partition(struct mtd_info *mtd, ulong offset)
{
	unsigned char oobbuf[NAND_OOB_SIZE];
	char buf[NAND_SECTOR_SIZE];
	struct erase_info erase;
	unsigned int *s;
	int i, k;
	size_t retlen;

#if 0 // BUSHI
	if (mtd->read_oob(mtd, offset, NAND_OOB_SIZE, &retlen, oobbuf))
		return -1;
	if (oobbuf[5] != 0xFF) return -1;
	if (mtd->read(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf)) {
		printk("read error: mark bad: offset = %lX\n", offset);
		mark_bad(mtd, offset);
		return -1;
	}
#endif

	erase.addr = offset;
	erase.len = mtd->erasesize;

	if (mtd->erase(mtd, &erase) < 0) {
		printk("erase error: mark bad: offset = %lX\n", offset);
		mark_bad(mtd, offset);
		return -1;
	}

	memcpy(buf, bon_part_magic, 8);
	s = (unsigned int *)(buf+8);
	*s++ = num_part;
	for (i = 0; i < num_part; i++) {
		*s++ = parts[i].offset;
		*s++ = parts[i].size;
		*s++ = parts[i].flag;
	}
	for (i = 0; i < num_part; i++) {
		*s++ = parts[i].num_bad_block;
		for (k = 0; k < parts[i].num_bad_block; k++) {
			*s++ = parts[i].bad_blocks[k];
			printk("k = %d block = %d\n", k, parts[i].bad_blocks[k]);
		}
	}


	if (mtd->write(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf))
		return -1;
	if (retlen != NAND_SECTOR_SIZE) {
		printk("write error: offset = %lu\n", offset);
		mark_bad(mtd, offset);
		return -1;
	}

	write_oob(mtd, buf, offset);

	return 0;
}

int
write_partition_table(struct mtd_info *mtd)
{
	int i, k;
	ulong offset = PARTITION_OFFSET;
	
	if (offset > mtd->size - mtd->erasesize)
		offset = mtd->size - mtd->erasesize;

	if (write_partition(mtd, offset) != 0) {
		printk("can not write bon partition info\n");
		return -1;
	}

	for (i = 0; i < num_part; i++) {
		printk("part%d:\n", i);
		printk("\toffset = %ld\n", parts[i].offset);
		printk("\tsize = %ld\n", parts[i].size);
		printk("\tbad_block = %ld\n", parts[i].num_bad_block);
		for (k = 0; k < parts[i].num_bad_block; k++) {
			printk(" %d\n", parts[i].bad_blocks[k]);
		}
	}
	return 0;
}

void display_partition_table(void)
{
	int i = 0, k;
	unsigned int size;

	if (read_bon_partition(mymtd)) {
	   	printk("Invalid partition table info\n");
		return;
	}
	printk("BON info. (%d partitions)\n", num_part);
	printk("No: offset    \tsize        \tflags     bad\n");
	printk("---------------------------------------------\n");
	for (i = 0; i < num_part; i++) {
	  printk("%2d: 0x%08lx\t0x%08lx\t%08lx  %3d",
		 i, parts[i].offset, parts[i].size,
		 parts[i].flag, parts[i].num_bad_block);

	  print_disk_size(parts[i].size, "  ", "\n");
	}
}

#ifdef CONFIG_CMD_BONFS

static void display_help(void)
{
	printk("Usage:\n");
	printk("\tbon part info\n");
	printk("\tbon part <offsets>\n");
}

static void 
command_part(int argc, const char **argv)
{
	int i;
	struct mtd_info *mtd = mymtd;
	unsigned long ret;

	if (mymtd == NULL) {
		printk("we have not mtd\n");
		return;
	}

	if ((argc == 3) &&
		((strncmp("info", argv[2], 4) == 0) ||
		 (strncmp("show", argv[2], 4) == 0))) {
		display_partition_table();
		return;
	}

	/* write partition table */
	num_part = (argc - 2);
	printk("doing partition\n");
	for (i = 0; i < num_part; i++) {
		parts[i].offset = read_size((char *)argv[2+i]);
		printk("offset = %ld\n", parts[i].offset);
		parts[i].flag = read_flag((char *)argv[2+i]);
		printk("flag = %ld\n", parts[i].flag);
	}
	printk("check bad block\n");
	check_bad_block(mtd);
	write_partition_table(mtd);
}

void command_bon(int argc, const char **argv)
{
	if (strncmp("help", argv[1], 4) == 0) {
		display_help();
		return;
	}

	if (strncmp("part", argv[1], 4) == 0) {
		if (argc == 2) { 
			display_help();
			return;
		}
		command_part(argc, argv);
		return;
	}

	display_help();
}

user_command_t bon_cmd = {
	"bon",
	command_bon,
	NULL,
	"bon [{cmds}]\t\t\t\t-- Manage the bon file system"
};

#endif /* CONFIG_CMD_BONFS */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -