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

📄 build.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) International Business Machines Corp., 2006 * Copyright (c) Nokia Corporation, 2007 * * 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 (Битюцкий Артём), *         Frank Haverkamp *//* * This file includes UBI initialization and building of UBI devices. * * When UBI is initialized, it attaches all the MTD devices specified as the * module load parameters or the kernel boot parameters. If MTD devices were * specified, UBI does not attach any MTD device, but it is possible to do * later using the "UBI control device". * * At the moment we only attach UBI devices by scanning, which will become a * bottleneck when flashes reach certain large size. Then one may improve UBI * and add other methods, although it does not seem to be easy to do. */#include <linux/err.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/stringify.h>#include <linux/stat.h>#include <linux/miscdevice.h>#include <linux/log2.h>#include <linux/kthread.h>#include "ubi.h"/* Maximum length of the 'mtd=' parameter */#define MTD_PARAM_LEN_MAX 64/** * struct mtd_dev_param - MTD device parameter description data structure. * @name: MTD device name or number string * @vid_hdr_offs: VID header offset */struct mtd_dev_param {	char name[MTD_PARAM_LEN_MAX];	int vid_hdr_offs;};/* Numbers of elements set in the @mtd_dev_param array */static int mtd_devs;/* MTD devices specification parameters */static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */struct class *ubi_class;/* Slab cache for wear-leveling entries */struct kmem_cache *ubi_wl_entry_slab;/* UBI control character device */static struct miscdevice ubi_ctrl_cdev = {	.minor = MISC_DYNAMIC_MINOR,	.name = "ubi_ctrl",	.fops = &ubi_ctrl_cdev_operations,};/* All UBI devices in system */static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];/* Serializes UBI devices creations and removals */DEFINE_MUTEX(ubi_devices_mutex);/* Protects @ubi_devices and @ubi->ref_count */static DEFINE_SPINLOCK(ubi_devices_lock);/* "Show" method for files in '/<sysfs>/class/ubi/' */static ssize_t ubi_version_show(struct class *class, char *buf){	return sprintf(buf, "%d\n", UBI_VERSION);}/* UBI version attribute ('/<sysfs>/class/ubi/version') */static struct class_attribute ubi_version =	__ATTR(version, S_IRUGO, ubi_version_show, NULL);static ssize_t dev_attribute_show(struct device *dev,				  struct device_attribute *attr, char *buf);/* UBI device attributes (correspond to files in '/<sysfs>/class/ubi/ubiX') */static struct device_attribute dev_eraseblock_size =	__ATTR(eraseblock_size, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_avail_eraseblocks =	__ATTR(avail_eraseblocks, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_total_eraseblocks =	__ATTR(total_eraseblocks, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_volumes_count =	__ATTR(volumes_count, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_max_ec =	__ATTR(max_ec, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_reserved_for_bad =	__ATTR(reserved_for_bad, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_bad_peb_count =	__ATTR(bad_peb_count, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_max_vol_count =	__ATTR(max_vol_count, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_min_io_size =	__ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_bgt_enabled =	__ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_mtd_num =	__ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);/** * ubi_get_device - get UBI device. * @ubi_num: UBI device number * * This function returns UBI device description object for UBI device number * @ubi_num, or %NULL if the device does not exist. This function increases the * device reference count to prevent removal of the device. In other words, the * device cannot be removed if its reference count is not zero. */struct ubi_device *ubi_get_device(int ubi_num){	struct ubi_device *ubi;	spin_lock(&ubi_devices_lock);	ubi = ubi_devices[ubi_num];	if (ubi) {		ubi_assert(ubi->ref_count >= 0);		ubi->ref_count += 1;		get_device(&ubi->dev);	}	spin_unlock(&ubi_devices_lock);	return ubi;}/** * ubi_put_device - drop an UBI device reference. * @ubi: UBI device description object */void ubi_put_device(struct ubi_device *ubi){	spin_lock(&ubi_devices_lock);	ubi->ref_count -= 1;	put_device(&ubi->dev);	spin_unlock(&ubi_devices_lock);}/** * ubi_get_by_major - get UBI device by character device major number. * @major: major number * * This function is similar to 'ubi_get_device()', but it searches the device * by its major number. */struct ubi_device *ubi_get_by_major(int major){	int i;	struct ubi_device *ubi;	spin_lock(&ubi_devices_lock);	for (i = 0; i < UBI_MAX_DEVICES; i++) {		ubi = ubi_devices[i];		if (ubi && MAJOR(ubi->cdev.dev) == major) {			ubi_assert(ubi->ref_count >= 0);			ubi->ref_count += 1;			get_device(&ubi->dev);			spin_unlock(&ubi_devices_lock);			return ubi;		}	}	spin_unlock(&ubi_devices_lock);	return NULL;}/** * ubi_major2num - get UBI device number by character device major number. * @major: major number * * This function searches UBI device number object by its major number. If UBI * device was not found, this function returns -ENODEV, otherwise the UBI device * number is returned. */int ubi_major2num(int major){	int i, ubi_num = -ENODEV;	spin_lock(&ubi_devices_lock);	for (i = 0; i < UBI_MAX_DEVICES; i++) {		struct ubi_device *ubi = ubi_devices[i];		if (ubi && MAJOR(ubi->cdev.dev) == major) {			ubi_num = ubi->ubi_num;			break;		}	}	spin_unlock(&ubi_devices_lock);	return ubi_num;}/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */static ssize_t dev_attribute_show(struct device *dev,				  struct device_attribute *attr, char *buf){	ssize_t ret;	struct ubi_device *ubi;	/*	 * The below code looks weird, but it actually makes sense. We get the	 * UBI device reference from the contained 'struct ubi_device'. But it	 * is unclear if the device was removed or not yet. Indeed, if the	 * device was removed before we increased its reference count,	 * 'ubi_get_device()' will return -ENODEV and we fail.	 *	 * Remember, 'struct ubi_device' is freed in the release function, so	 * we still can use 'ubi->ubi_num'.	 */	ubi = container_of(dev, struct ubi_device, dev);	ubi = ubi_get_device(ubi->ubi_num);	if (!ubi)		return -ENODEV;	if (attr == &dev_eraseblock_size)		ret = sprintf(buf, "%d\n", ubi->leb_size);	else if (attr == &dev_avail_eraseblocks)		ret = sprintf(buf, "%d\n", ubi->avail_pebs);	else if (attr == &dev_total_eraseblocks)		ret = sprintf(buf, "%d\n", ubi->good_peb_count);	else if (attr == &dev_volumes_count)		ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT);	else if (attr == &dev_max_ec)		ret = sprintf(buf, "%d\n", ubi->max_ec);	else if (attr == &dev_reserved_for_bad)		ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);	else if (attr == &dev_bad_peb_count)		ret = sprintf(buf, "%d\n", ubi->bad_peb_count);	else if (attr == &dev_max_vol_count)		ret = sprintf(buf, "%d\n", ubi->vtbl_slots);	else if (attr == &dev_min_io_size)		ret = sprintf(buf, "%d\n", ubi->min_io_size);	else if (attr == &dev_bgt_enabled)		ret = sprintf(buf, "%d\n", ubi->thread_enabled);	else if (attr == &dev_mtd_num)		ret = sprintf(buf, "%d\n", ubi->mtd->index);	else		ret = -EINVAL;	ubi_put_device(ubi);	return ret;}/* Fake "release" method for UBI devices */static void dev_release(struct device *dev) { }/** * ubi_sysfs_init - initialize sysfs for an UBI device. * @ubi: UBI device description object * * This function returns zero in case of success and a negative error code in * case of failure. */static int ubi_sysfs_init(struct ubi_device *ubi){	int err;	ubi->dev.release = dev_release;	ubi->dev.devt = ubi->cdev.dev;	ubi->dev.class = ubi_class;	sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num);	err = device_register(&ubi->dev);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_eraseblock_size);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_avail_eraseblocks);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_total_eraseblocks);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_volumes_count);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_max_ec);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_reserved_for_bad);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_bad_peb_count);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_max_vol_count);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_min_io_size);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_bgt_enabled);	if (err)		return err;	err = device_create_file(&ubi->dev, &dev_mtd_num);	return err;}/** * ubi_sysfs_close - close sysfs for an UBI device. * @ubi: UBI device description object */static void ubi_sysfs_close(struct ubi_device *ubi){	device_remove_file(&ubi->dev, &dev_mtd_num);	device_remove_file(&ubi->dev, &dev_bgt_enabled);	device_remove_file(&ubi->dev, &dev_min_io_size);	device_remove_file(&ubi->dev, &dev_max_vol_count);	device_remove_file(&ubi->dev, &dev_bad_peb_count);	device_remove_file(&ubi->dev, &dev_reserved_for_bad);	device_remove_file(&ubi->dev, &dev_max_ec);	device_remove_file(&ubi->dev, &dev_volumes_count);	device_remove_file(&ubi->dev, &dev_total_eraseblocks);	device_remove_file(&ubi->dev, &dev_avail_eraseblocks);	device_remove_file(&ubi->dev, &dev_eraseblock_size);	device_unregister(&ubi->dev);}/** * kill_volumes - destroy all volumes. * @ubi: UBI device description object */static void kill_volumes(struct ubi_device *ubi){	int i;	for (i = 0; i < ubi->vtbl_slots; i++)		if (ubi->volumes[i])			ubi_free_volume(ubi, ubi->volumes[i]);}/** * free_user_volumes - free all user volumes. * @ubi: UBI device description object * * Normally the volumes are freed at the release function of the volume device * objects. However, on error paths the volumes have to be freed before the * device objects have been initialized. */static void free_user_volumes(struct ubi_device *ubi){	int i;	for (i = 0; i < ubi->vtbl_slots; i++)		if (ubi->volumes[i]) {			kfree(ubi->volumes[i]->eba_tbl);			kfree(ubi->volumes[i]);		}}/** * uif_init - initialize user interfaces for an UBI device. * @ubi: UBI device description object * * This function returns zero in case of success and a negative error code in * case of failure. Note, this function destroys all volumes if it failes. */static int uif_init(struct ubi_device *ubi){	int i, err, do_free = 0;	dev_t dev;	sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);	/*	 * Major numbers for the UBI character devices are allocated	 * dynamically. Major numbers of volume character devices are	 * equivalent to ones of the corresponding UBI character device. Minor	 * numbers of UBI character devices are 0, while minor numbers of	 * volume character devices start from 1. Thus, we allocate one major	 * number and ubi->vtbl_slots + 1 minor numbers.	 */	err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name);	if (err) {		ubi_err("cannot register UBI character devices");		return err;	}	ubi_assert(MINOR(dev) == 0);	cdev_init(&ubi->cdev, &ubi_cdev_operations);	dbg_gen("%s major is %u", ubi->ubi_name, MAJOR(dev));	ubi->cdev.owner = THIS_MODULE;

⌨️ 快捷键说明

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