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

📄 rfd_ftl.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		rc = rfd_ftl_writesect((struct mtd_blktrans_dev*)part,				entry, sector_data);		if (rc)			goto err;	}err:	kfree(map);err2:	kfree(sector_data);err3:	part->is_reclaiming = 0;	return rc;}static int reclaim_block(struct partition *part, u_long *old_sector){	int block, best_block, score, old_sector_block;	int rc;	/* we have a race if sync doesn't exist */	if (part->mbd.mtd->sync)		part->mbd.mtd->sync(part->mbd.mtd);	score = 0x7fffffff; /* MAX_INT */	best_block = -1;	if (*old_sector != -1)		old_sector_block = *old_sector / part->block_size;	else		old_sector_block = -1;	for (block=0; block<part->total_blocks; block++) {		int this_score;		if (block == part->reserved_block)			continue;		/*		 * Postpone reclaiming if there is a free sector as		 * more removed sectors is more efficient (have to move		 * less).		 */		if (part->blocks[block].free_sectors)			return 0;		this_score = part->blocks[block].used_sectors;		if (block == old_sector_block)			this_score--;		else {			/* no point in moving a full block */			if (part->blocks[block].used_sectors ==					part->data_sectors_per_block)				continue;		}		this_score += part->blocks[block].erases;		if (this_score < score) {			best_block = block;			score = this_score;		}	}	if (best_block == -1)		return -ENOSPC;	part->current_block = -1;	part->reserved_block = best_block;	pr_debug("reclaim_block: reclaiming block #%d with %d used "		 "%d free sectors\n", best_block,		 part->blocks[best_block].used_sectors,		 part->blocks[best_block].free_sectors);	if (part->blocks[best_block].used_sectors)		rc = move_block_contents(part, best_block, old_sector);	else		rc = erase_block(part, best_block);	return rc;}/* * IMPROVE: It would be best to choose the block with the most deleted sectors, * because if we fill that one up first it'll have the most chance of having * the least live sectors at reclaim. */static int find_free_block(struct partition *part){	int block, stop;	block = part->current_block == -1 ?			jiffies % part->total_blocks : part->current_block;	stop = block;	do {		if (part->blocks[block].free_sectors &&				block != part->reserved_block)			return block;		if (part->blocks[block].state == BLOCK_UNUSED)			erase_block(part, block);		if (++block >= part->total_blocks)			block = 0;	} while (block != stop);	return -1;}static int find_writable_block(struct partition *part, u_long *old_sector){	int rc, block;	size_t retlen;	block = find_free_block(part);	if (block == -1) {		if (!part->is_reclaiming) {			rc = reclaim_block(part, old_sector);			if (rc)				goto err;			block = find_free_block(part);		}		if (block == -1) {			rc = -ENOSPC;			goto err;		}	}	rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset,		part->header_size, &retlen, (u_char*)part->header_cache);	if (!rc && retlen != part->header_size)		rc = -EIO;	if (rc) {		printk(KERN_ERR PREFIX "'%s': unable to read header at "				"0x%lx\n", part->mbd.mtd->name,				part->blocks[block].offset);		goto err;	}	part->current_block = block;err:	return rc;}static int mark_sector_deleted(struct partition *part, u_long old_addr){	int block, offset, rc;	u_long addr;	size_t retlen;	u16 del = const_cpu_to_le16(SECTOR_DELETED);	block = old_addr / part->block_size;	offset = (old_addr % part->block_size) / SECTOR_SIZE -		part->header_sectors_per_block;	addr = part->blocks[block].offset +			(HEADER_MAP_OFFSET + offset) * sizeof(u16);	rc = part->mbd.mtd->write(part->mbd.mtd, addr,		sizeof(del), &retlen, (u_char*)&del);	if (!rc && retlen != sizeof(del))		rc = -EIO;	if (rc) {		printk(KERN_ERR PREFIX "error writing '%s' at "			"0x%lx\n", part->mbd.mtd->name, addr);		if (rc)			goto err;	}	if (block == part->current_block)		part->header_cache[offset + HEADER_MAP_OFFSET] = del;	part->blocks[block].used_sectors--;	if (!part->blocks[block].used_sectors &&	    !part->blocks[block].free_sectors)		rc = erase_block(part, block);err:	return rc;}static int find_free_sector(const struct partition *part, const struct block *block){	int i, stop;	i = stop = part->data_sectors_per_block - block->free_sectors;	do {		if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i])				== SECTOR_FREE)			return i;		if (++i == part->data_sectors_per_block)			i = 0;	}	while(i != stop);	return -1;}static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ulong *old_addr){	struct partition *part = (struct partition*)dev;	struct block *block;	u_long addr;	int i;	int rc;	size_t retlen;	u16 entry;	if (part->current_block == -1 ||		!part->blocks[part->current_block].free_sectors) {		rc = find_writable_block(part, old_addr);		if (rc)			goto err;	}	block = &part->blocks[part->current_block];	i = find_free_sector(part, block);	if (i < 0) {		rc = -ENOSPC;		goto err;	}	addr = (i + part->header_sectors_per_block) * SECTOR_SIZE +		block->offset;	rc = part->mbd.mtd->write(part->mbd.mtd,		addr, SECTOR_SIZE, &retlen, (u_char*)buf);	if (!rc && retlen != SECTOR_SIZE)		rc = -EIO;	if (rc) {		printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n",				part->mbd.mtd->name, addr);		if (rc)			goto err;	}	part->sector_map[sector] = addr;	entry = cpu_to_le16(sector == 0 ? SECTOR_ZERO : sector);	part->header_cache[i + HEADER_MAP_OFFSET] = entry;	addr = block->offset + (HEADER_MAP_OFFSET + i) * sizeof(u16);	rc = part->mbd.mtd->write(part->mbd.mtd, addr,			sizeof(entry), &retlen, (u_char*)&entry);	if (!rc && retlen != sizeof(entry))		rc = -EIO;	if (rc) {		printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n",				part->mbd.mtd->name, addr);		if (rc)			goto err;	}	block->used_sectors++;	block->free_sectors--;err:	return rc;}static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf){	struct partition *part = (struct partition*)dev;	u_long old_addr;	int i;	int rc = 0;	pr_debug("rfd_ftl_writesect(sector=0x%lx)\n", sector);	if (part->reserved_block == -1) {		rc = -EACCES;		goto err;	}	if (sector >= part->sector_count) {		rc = -EIO;		goto err;	}	old_addr = part->sector_map[sector];	for (i=0; i<SECTOR_SIZE; i++) {		if (!buf[i])			continue;		rc = do_writesect(dev, sector, buf, &old_addr);		if (rc)			goto err;		break;	}	if (i == SECTOR_SIZE)		part->sector_map[sector] = -1;	if (old_addr != -1)		rc = mark_sector_deleted(part, old_addr);err:	return rc;}static int rfd_ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo){	struct partition *part = (struct partition*)dev;	geo->heads = 1;	geo->sectors = SECTORS_PER_TRACK;	geo->cylinders = part->cylinders;	return 0;}static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd){	struct partition *part;	if (mtd->type != MTD_NORFLASH)		return;	part = kzalloc(sizeof(struct partition), GFP_KERNEL);	if (!part)		return;	part->mbd.mtd = mtd;	if (block_size)		part->block_size = block_size;	else {		if (!mtd->erasesize) {			printk(KERN_WARNING PREFIX "please provide block_size");			goto out;		} else			part->block_size = mtd->erasesize;	}	if (scan_header(part) == 0) {		part->mbd.size = part->sector_count;		part->mbd.tr = tr;		part->mbd.devnum = -1;		if (!(mtd->flags & MTD_WRITEABLE))			part->mbd.readonly = 1;		else if (part->errors) {			printk(KERN_WARNING PREFIX "'%s': errors found, "					"setting read-only\n", mtd->name);			part->mbd.readonly = 1;		}		printk(KERN_INFO PREFIX "name: '%s' type: %d flags %x\n",				mtd->name, mtd->type, mtd->flags);		if (!add_mtd_blktrans_dev((void*)part))			return;	}out:	kfree(part);}static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev){	struct partition *part = (struct partition*)dev;	int i;	for (i=0; i<part->total_blocks; i++) {		pr_debug("rfd_ftl_remove_dev:'%s': erase unit #%02d: %d erases\n",			part->mbd.mtd->name, i, part->blocks[i].erases);	}	del_mtd_blktrans_dev(dev);	vfree(part->sector_map);	kfree(part->header_cache);	kfree(part->blocks);	kfree(part);}static struct mtd_blktrans_ops rfd_ftl_tr = {	.name		= "rfd",	.major		= RFD_FTL_MAJOR,	.part_bits	= PART_BITS,	.blksize 	= SECTOR_SIZE,	.readsect	= rfd_ftl_readsect,	.writesect	= rfd_ftl_writesect,	.getgeo		= rfd_ftl_getgeo,	.add_mtd	= rfd_ftl_add_mtd,	.remove_dev	= rfd_ftl_remove_dev,	.owner		= THIS_MODULE,};static int __init init_rfd_ftl(void){	return register_mtd_blktrans(&rfd_ftl_tr);}static void __exit cleanup_rfd_ftl(void){	deregister_mtd_blktrans(&rfd_ftl_tr);}module_init(init_rfd_ftl);module_exit(cleanup_rfd_ftl);MODULE_LICENSE("GPL");MODULE_AUTHOR("Sean Young <sean@mess.org>");MODULE_DESCRIPTION("Support code for RFD Flash Translation Layer, "		"used by General Software's Embedded BIOS");

⌨️ 快捷键说明

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