Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f24b5a8 authored by David Brownell's avatar David Brownell Committed by David Woodhouse
Browse files

[MTD] driver model updates



Update driver model support in the MTD framework, so it fits
better into the current udev-based hotplug framework:

 - Each mtd_info now has a device node.  MTD drivers should set
   the dev.parent field to point to the physical device, before
   setting up partitions or otherwise declaring MTDs.

 - Those device nodes always map to /sys/class/mtdX device nodes,
   which no longer depend on MTD_CHARDEV.

 - Those mtdX sysfs nodes have a "starter set" of attributes;
   it's not yet sufficient to replace /proc/mtd.

 - Enabling MTD_CHARDEV provides /sys/class/mtdXro/ nodes and the
   /sys/class/mtd*/dev attributes (for udev, mdev, etc).

 - Include a MODULE_ALIAS_CHARDEV_MAJOR macro.  It'll work with
   udev creating the /dev/mtd* nodes, not just a static rootfs.

So the sysfs structure is pretty much what you'd expect, except
that readonly chardev nodes are a bit quirky.

Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 9d63287a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -286,6 +286,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
	gd->private_data = new;
	new->blkcore_priv = gd;
	gd->queue = tr->blkcore_priv->rq;
	gd->driverfs_dev = new->mtd->dev.parent;

	if (new->readonly)
		set_disk_ro(gd, 1);
+6 −41
Original line number Diff line number Diff line
@@ -20,33 +20,6 @@

#include <asm/uaccess.h>

static struct class *mtd_class;

static void mtd_notify_add(struct mtd_info* mtd)
{
	if (!mtd)
		return;

	device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
		      NULL, "mtd%d", mtd->index);

	device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
		      NULL, "mtd%dro", mtd->index);
}

static void mtd_notify_remove(struct mtd_info* mtd)
{
	if (!mtd)
		return;

	device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
	device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
}

static struct mtd_notifier notifier = {
	.add	= mtd_notify_add,
	.remove	= mtd_notify_remove,
};

/*
 * Data structure to hold the pointer to the mtd device as well
@@ -854,34 +827,26 @@ static const struct file_operations mtd_fops = {

static int __init init_mtdchar(void)
{
	if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {
	int status;

	status = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops);
	if (status < 0) {
		printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
		       MTD_CHAR_MAJOR);
		return -EAGAIN;
	}

	mtd_class = class_create(THIS_MODULE, "mtd");

	if (IS_ERR(mtd_class)) {
		printk(KERN_ERR "Error creating mtd class.\n");
		unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
		return PTR_ERR(mtd_class);
	}

	register_mtd_user(&notifier);
	return 0;
	return status;
}

static void __exit cleanup_mtdchar(void)
{
	unregister_mtd_user(&notifier);
	class_destroy(mtd_class);
	unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
}

module_init(init_mtdchar);
module_exit(cleanup_mtdchar);

MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+115 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@

#include "mtdcore.h"


static struct class *mtd_class;

/* These are exported solely for the purpose of mtd_blkdevs.c. You
   should not use them for _anything_ else */
DEFINE_MUTEX(mtd_table_mutex);
@@ -33,6 +36,82 @@ EXPORT_SYMBOL_GPL(mtd_table);

static LIST_HEAD(mtd_notifiers);


#if defined(CONFIG_MTD_CHAR) || defined(CONFIG_MTD_CHAR_MODULE)
#define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
#else
#define MTD_DEVT(index) 0
#endif

/* REVISIT once MTD uses the driver model better, whoever allocates
 * the mtd_info will probably want to use the release() hook...
 */
static void mtd_release(struct device *dev)
{
	struct mtd_info *mtd = dev_to_mtd(dev);

	/* remove /dev/mtdXro node if needed */
	if (MTD_DEVT(mtd->index))
		device_destroy(mtd_class, MTD_DEVT(mtd->index) + 1);
}

static ssize_t mtd_type_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct mtd_info *mtd = dev_to_mtd(dev);
	char *type;

	switch (mtd->type) {
	case MTD_ABSENT:
		type = "absent";
		break;
	case MTD_RAM:
		type = "ram";
		break;
	case MTD_ROM:
		type = "rom";
		break;
	case MTD_NORFLASH:
		type = "nor";
		break;
	case MTD_NANDFLASH:
		type = "nand";
		break;
	case MTD_DATAFLASH:
		type = "dataflash";
		break;
	case MTD_UBIVOLUME:
		type = "ubi";
		break;
	default:
		type = "unknown";
	}

	return snprintf(buf, PAGE_SIZE, "%s\n", type);
}
static DEVICE_ATTR(mtd_type, S_IRUGO, mtd_type_show, NULL);

static struct attribute *mtd_attrs[] = {
	&dev_attr_mtd_type.attr,
	/* FIXME provide a /proc/mtd superset */
	NULL,
};

struct attribute_group mtd_group = {
	.attrs		= mtd_attrs,
};

struct attribute_group *mtd_groups[] = {
	&mtd_group,
	NULL,
};

static struct device_type mtd_devtype = {
	.name		= "mtd",
	.groups		= mtd_groups,
	.release	= mtd_release,
};

/**
 *	add_mtd_device - register an MTD device
 *	@mtd: pointer to new MTD device info structure
@@ -41,6 +120,7 @@ static LIST_HEAD(mtd_notifiers);
 *	notify each currently active MTD 'user' of its arrival. Returns
 *	zero on success or 1 on failure, which currently will only happen
 *	if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16)
 *	or there's a sysfs error.
 */

int add_mtd_device(struct mtd_info *mtd)
@@ -95,6 +175,23 @@ int add_mtd_device(struct mtd_info *mtd)
					       mtd->name);
			}

			/* Caller should have set dev.parent to match the
			 * physical device.
			 */
			mtd->dev.type = &mtd_devtype;
			mtd->dev.class = mtd_class;
			mtd->dev.devt = MTD_DEVT(i);
			dev_set_name(&mtd->dev, "mtd%d", i);
			if (device_register(&mtd->dev) != 0) {
				mtd_table[i] = NULL;
				break;
			}

			if (MTD_DEVT(i))
				device_create(mtd_class, mtd->dev.parent,
						MTD_DEVT(i) + 1,
						NULL, "mtd%dro", i);

			DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
			/* No need to get a refcount on the module containing
			   the notifier, since we hold the mtd_table_mutex */
@@ -358,6 +455,24 @@ EXPORT_SYMBOL_GPL(register_mtd_user);
EXPORT_SYMBOL_GPL(unregister_mtd_user);
EXPORT_SYMBOL_GPL(default_mtd_writev);

static int __init mtd_setup(void)
{
	mtd_class = class_create(THIS_MODULE, "mtd");

	if (IS_ERR(mtd_class)) {
		pr_err("Error creating mtd class.\n");
		return PTR_ERR(mtd_class);
	}
	return 0;
}
core_initcall(mtd_setup);

static void __exit mtd_teardown(void)
{
	class_destroy(mtd_class);
}
__exitcall(mtd_teardown);

#ifdef CONFIG_PROC_FS

/*====================================================================*/
+8 −1
Original line number Diff line number Diff line
@@ -356,6 +356,11 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
	slave->mtd.owner = master->owner;
	slave->mtd.backing_dev_info = master->backing_dev_info;

	/* NOTE:  we don't arrange MTDs as a tree; it'd be error-prone
	 * to have the same data be in two different partitions.
	 */
	slave->mtd.dev.parent = master->dev.parent;

	slave->mtd.read = part_read;
	slave->mtd.write = part_write;

@@ -508,7 +513,9 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
 * This function, given a master MTD object and a partition table, creates
 * and registers slave MTD objects which are bound to the master according to
 * the partition definitions.
 * (Q: should we register the master MTD object as well?)
 *
 * We don't register the master, or expect the caller to have done so,
 * for reasons of data integrity.
 */

int add_mtd_partitions(struct mtd_info *master,
+7 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/uio.h>
#include <linux/notifier.h>
#include <linux/device.h>

#include <linux/mtd/compatmac.h>
#include <mtd/mtd-abi.h>
@@ -237,6 +238,7 @@ struct mtd_info {
	void *priv;

	struct module *owner;
	struct device dev;
	int usecount;

	/* If the driver is something smart, like UBI, it may need to maintain
@@ -247,6 +249,11 @@ struct mtd_info {
	void (*put_device) (struct mtd_info *mtd);
};

static inline struct mtd_info *dev_to_mtd(struct device *dev)
{
	return dev ? container_of(dev, struct mtd_info, dev) : NULL;
}

static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
{
	if (mtd->erasesize_shift)