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

📄 gluebi.c

📁 基于linux-2.6.28的mtd驱动
💻 C
字号:
/* * Copyright (c) International Business Machines Corp., 2006 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Artem Bityutskiy (Битюцкий Артём), Joern Engel *//* * This file includes implementation of fake MTD devices for each UBI volume. * This sounds strange, but it is in fact quite useful to make MTD-oriented * software (including all the legacy software) to work on top of UBI. * * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit * size (mtd->writesize) is equivalent to the UBI minimal I/O unit. The * eraseblock size is equivalent to the logical eraseblock size of the volume. */#include <asm/div64.h>#include "ubi.h"/** * gluebi_get_device - get MTD device reference. * @mtd: the MTD device description object * * This function is called every time the MTD device is being opened and * implements the MTD get_device() operation. Returns zero in case of success * and a negative error code in case of failure. */static int gluebi_get_device(struct mtd_info *mtd){	struct ubi_volume *vol;	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);	/*	 * We do not introduce locks for gluebi reference count because the	 * get_device()/put_device() calls are already serialized at MTD.	 */	if (vol->gluebi_refcount > 0) {		/*		 * The MTD device is already referenced and this is just one		 * more reference. MTD allows many users to open the same		 * volume simultaneously and do not distinguish between		 * readers/writers/exclusive openers as UBI does. So we do not		 * open the UBI volume again - just increase the reference		 * counter and return.		 */		vol->gluebi_refcount += 1;		return 0;	}	/*	 * This is the first reference to this UBI volume via the MTD device	 * interface. Open the corresponding volume in read-write mode.	 */	vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id,					   UBI_READWRITE);	if (IS_ERR(vol->gluebi_desc))		return PTR_ERR(vol->gluebi_desc);	vol->gluebi_refcount += 1;	return 0;}/** * gluebi_put_device - put MTD device reference. * @mtd: the MTD device description object * * This function is called every time the MTD device is being put. Returns * zero in case of success and a negative error code in case of failure. */static void gluebi_put_device(struct mtd_info *mtd){	struct ubi_volume *vol;	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);	vol->gluebi_refcount -= 1;	ubi_assert(vol->gluebi_refcount >= 0);	if (vol->gluebi_refcount == 0)		ubi_close_volume(vol->gluebi_desc);}/** * gluebi_read - read operation of emulated MTD devices. * @mtd: MTD device description object * @from: absolute offset from where to read * @len: how many bytes to read * @retlen: count of read bytes is returned here * @buf: buffer to store the read data * * This function returns zero in case of success and a negative error code in * case of failure. */static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,		       size_t *retlen, unsigned char *buf){	int err = 0, lnum, offs, total_read;	struct ubi_volume *vol;	struct ubi_device *ubi;	uint64_t tmp = from;	dbg_gen("read %zd bytes from offset %lld", len, from);	if (len < 0 || from < 0 || from + len > mtd->size)		return -EINVAL;	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);	ubi = vol->ubi;	offs = do_div(tmp, mtd->erasesize);	lnum = tmp;	total_read = len;	while (total_read) {		size_t to_read = mtd->erasesize - offs;		if (to_read > total_read)			to_read = total_read;		err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0);		if (err)			break;		lnum += 1;		offs = 0;		total_read -= to_read;		buf += to_read;	}	*retlen = len - total_read;	return err;}/** * gluebi_write - write operation of emulated MTD devices. * @mtd: MTD device description object * @to: absolute offset where to write * @len: how many bytes to write * @retlen: count of written bytes is returned here * @buf: buffer with data to write * * This function returns zero in case of success and a negative error code in * case of failure. */static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,		       size_t *retlen, const u_char *buf){	int err = 0, lnum, offs, total_written;	struct ubi_volume *vol;	struct ubi_device *ubi;	uint64_t tmp = to;	dbg_gen("write %zd bytes to offset %lld", len, to);	if (len < 0 || to < 0 || len + to > mtd->size)		return -EINVAL;	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);	ubi = vol->ubi;	if (ubi->ro_mode)		return -EROFS;	offs = do_div(tmp, mtd->erasesize);	lnum = tmp;	if (len % mtd->writesize || offs % mtd->writesize)		return -EINVAL;	total_written = len;	while (total_written) {		size_t to_write = mtd->erasesize - offs;		if (to_write > total_written)			to_write = total_written;		err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write,					UBI_UNKNOWN);		if (err)			break;		lnum += 1;		offs = 0;		total_written -= to_write;		buf += to_write;	}	*retlen = len - total_written;	return err;}/** * gluebi_erase - erase operation of emulated MTD devices. * @mtd: the MTD device description object * @instr: the erase operation description * * This function calls the erase callback when finishes. Returns zero in case * of success and a negative error code in case of failure. */static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr){	int err, i, lnum, count;	struct ubi_volume *vol;	struct ubi_device *ubi;	dbg_gen("erase %u bytes at offset %u", instr->len, instr->addr);	if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)		return -EINVAL;	if (instr->len < 0 || instr->addr + instr->len > mtd->size)		return -EINVAL;	if (instr->addr % mtd->writesize || instr->len % mtd->writesize)		return -EINVAL;	lnum = instr->addr / mtd->erasesize;	count = instr->len / mtd->erasesize;	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);	ubi = vol->ubi;	if (ubi->ro_mode)		return -EROFS;	for (i = 0; i < count; i++) {		err = ubi_eba_unmap_leb(ubi, vol, lnum + i);		if (err)			goto out_err;	}	/*	 * MTD erase operations are synchronous, so we have to make sure the	 * physical eraseblock is wiped out.	 */	err = ubi_wl_flush(ubi);	if (err)		goto out_err;	instr->state = MTD_ERASE_DONE;	mtd_erase_callback(instr);	return 0;out_err:	instr->state = MTD_ERASE_FAILED;	instr->fail_addr = lnum * mtd->erasesize;	return err;}/** * ubi_create_gluebi - initialize gluebi for an UBI volume. * @ubi: UBI device description object * @vol: volume description object * * This function is called when an UBI volume is created in order to create * corresponding fake MTD device. Returns zero in case of success and a * negative error code in case of failure. */int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol){	struct mtd_info *mtd = &vol->gluebi_mtd;	mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL);	if (!mtd->name)		return -ENOMEM;	mtd->type = MTD_UBIVOLUME;	if (!ubi->ro_mode)		mtd->flags = MTD_WRITEABLE;	mtd->writesize  = ubi->min_io_size;	mtd->owner      = THIS_MODULE;	mtd->erasesize  = vol->usable_leb_size;	mtd->read       = gluebi_read;	mtd->write      = gluebi_write;	mtd->erase      = gluebi_erase;	mtd->get_device = gluebi_get_device;	mtd->put_device = gluebi_put_device;	/*	 * In case of dynamic volume, MTD device size is just volume size. In	 * case of a static volume the size is equivalent to the amount of data	 * bytes.	 */	if (vol->vol_type == UBI_DYNAMIC_VOLUME)		mtd->size = vol->usable_leb_size * vol->reserved_pebs;	else		mtd->size = vol->used_bytes;	if (add_mtd_device(mtd)) {		ubi_err("cannot not add MTD device");		kfree(mtd->name);		return -ENFILE;	}	dbg_gen("added mtd%d (\"%s\"), size %u, EB size %u",		mtd->index, mtd->name, mtd->size, mtd->erasesize);	return 0;}/** * ubi_destroy_gluebi - close gluebi for an UBI volume. * @vol: volume description object * * This function is called when an UBI volume is removed in order to remove * corresponding fake MTD device. Returns zero in case of success and a * negative error code in case of failure. */int ubi_destroy_gluebi(struct ubi_volume *vol){	int err;	struct mtd_info *mtd = &vol->gluebi_mtd;	dbg_gen("remove mtd%d", mtd->index);	err = del_mtd_device(mtd);	if (err)		return err;	kfree(mtd->name);	return 0;}/** * ubi_gluebi_updated - UBI volume was updated notifier. * @vol: volume description object * * This function is called every time an UBI volume is updated. This function * does nothing if volume @vol is dynamic, and changes MTD device size if the * volume is static. This is needed because static volumes cannot be read past * data they contain. */void ubi_gluebi_updated(struct ubi_volume *vol){	struct mtd_info *mtd = &vol->gluebi_mtd;	if (vol->vol_type == UBI_STATIC_VOLUME)		mtd->size = vol->used_bytes;}

⌨️ 快捷键说明

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