aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-03-26 03:42:41 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-04-04 09:29:07 -0400
commit1f24b5a8ecbb2a3c7080f418974d40e3ffedb221 (patch)
tree07dfc44f62dac78bdf4a8cdb4d91d60f73c04ff4
parent9d63287a461c269edb39941744f4ff22223cf349 (diff)
[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: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/mtd/mtd_blkdevs.c1
-rw-r--r--drivers/mtd/mtdchar.c47
-rw-r--r--drivers/mtd/mtdcore.c115
-rw-r--r--drivers/mtd/mtdpart.c9
-rw-r--r--include/linux/mtd/mtd.h7
5 files changed, 137 insertions, 42 deletions
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 4109e0bb94f5..a49a9c8f2cb1 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -286,6 +286,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
286 gd->private_data = new; 286 gd->private_data = new;
287 new->blkcore_priv = gd; 287 new->blkcore_priv = gd;
288 gd->queue = tr->blkcore_priv->rq; 288 gd->queue = tr->blkcore_priv->rq;
289 gd->driverfs_dev = new->mtd->dev.parent;
289 290
290 if (new->readonly) 291 if (new->readonly)
291 set_disk_ro(gd, 1); 292 set_disk_ro(gd, 1);
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index f478f1fc3949..763d3f0a1f42 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -20,33 +20,6 @@
20 20
21#include <asm/uaccess.h> 21#include <asm/uaccess.h>
22 22
23static struct class *mtd_class;
24
25static void mtd_notify_add(struct mtd_info* mtd)
26{
27 if (!mtd)
28 return;
29
30 device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
31 NULL, "mtd%d", mtd->index);
32
33 device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
34 NULL, "mtd%dro", mtd->index);
35}
36
37static void mtd_notify_remove(struct mtd_info* mtd)
38{
39 if (!mtd)
40 return;
41
42 device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
43 device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
44}
45
46static struct mtd_notifier notifier = {
47 .add = mtd_notify_add,
48 .remove = mtd_notify_remove,
49};
50 23
51/* 24/*
52 * Data structure to hold the pointer to the mtd device as well 25 * Data structure to hold the pointer to the mtd device as well
@@ -854,34 +827,26 @@ static const struct file_operations mtd_fops = {
854 827
855static int __init init_mtdchar(void) 828static int __init init_mtdchar(void)
856{ 829{
857 if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) { 830 int status;
831
832 status = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops);
833 if (status < 0) {
858 printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", 834 printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
859 MTD_CHAR_MAJOR); 835 MTD_CHAR_MAJOR);
860 return -EAGAIN;
861 }
862
863 mtd_class = class_create(THIS_MODULE, "mtd");
864
865 if (IS_ERR(mtd_class)) {
866 printk(KERN_ERR "Error creating mtd class.\n");
867 unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
868 return PTR_ERR(mtd_class);
869 } 836 }
870 837
871 register_mtd_user(&notifier); 838 return status;
872 return 0;
873} 839}
874 840
875static void __exit cleanup_mtdchar(void) 841static void __exit cleanup_mtdchar(void)
876{ 842{
877 unregister_mtd_user(&notifier);
878 class_destroy(mtd_class);
879 unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); 843 unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
880} 844}
881 845
882module_init(init_mtdchar); 846module_init(init_mtdchar);
883module_exit(cleanup_mtdchar); 847module_exit(cleanup_mtdchar);
884 848
849MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);
885 850
886MODULE_LICENSE("GPL"); 851MODULE_LICENSE("GPL");
887MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 852MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 65a7f3703881..a88f8bc9a534 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -23,6 +23,9 @@
23 23
24#include "mtdcore.h" 24#include "mtdcore.h"
25 25
26
27static struct class *mtd_class;
28
26/* These are exported solely for the purpose of mtd_blkdevs.c. You 29/* These are exported solely for the purpose of mtd_blkdevs.c. You
27 should not use them for _anything_ else */ 30 should not use them for _anything_ else */
28DEFINE_MUTEX(mtd_table_mutex); 31DEFINE_MUTEX(mtd_table_mutex);
@@ -33,6 +36,82 @@ EXPORT_SYMBOL_GPL(mtd_table);
33 36
34static LIST_HEAD(mtd_notifiers); 37static LIST_HEAD(mtd_notifiers);
35 38
39
40#if defined(CONFIG_MTD_CHAR) || defined(CONFIG_MTD_CHAR_MODULE)
41#define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
42#else
43#define MTD_DEVT(index) 0
44#endif
45
46/* REVISIT once MTD uses the driver model better, whoever allocates
47 * the mtd_info will probably want to use the release() hook...
48 */
49static void mtd_release(struct device *dev)
50{
51 struct mtd_info *mtd = dev_to_mtd(dev);
52
53 /* remove /dev/mtdXro node if needed */
54 if (MTD_DEVT(mtd->index))
55 device_destroy(mtd_class, MTD_DEVT(mtd->index) + 1);
56}
57
58static ssize_t mtd_type_show(struct device *dev,
59 struct device_attribute *attr, char *buf)
60{
61 struct mtd_info *mtd = dev_to_mtd(dev);
62 char *type;
63
64 switch (mtd->type) {
65 case MTD_ABSENT:
66 type = "absent";
67 break;
68 case MTD_RAM:
69 type = "ram";
70 break;
71 case MTD_ROM:
72 type = "rom";
73 break;
74 case MTD_NORFLASH:
75 type = "nor";
76 break;
77 case MTD_NANDFLASH:
78 type = "nand";
79 break;
80 case MTD_DATAFLASH:
81 type = "dataflash";
82 break;
83 case MTD_UBIVOLUME:
84 type = "ubi";
85 break;
86 default:
87 type = "unknown";
88 }
89
90 return snprintf(buf, PAGE_SIZE, "%s\n", type);
91}
92static DEVICE_ATTR(mtd_type, S_IRUGO, mtd_type_show, NULL);
93
94static struct attribute *mtd_attrs[] = {
95 &dev_attr_mtd_type.attr,
96 /* FIXME provide a /proc/mtd superset */
97 NULL,
98};
99
100struct attribute_group mtd_group = {
101 .attrs = mtd_attrs,
102};
103
104struct attribute_group *mtd_groups[] = {
105 &mtd_group,
106 NULL,
107};
108
109static struct device_type mtd_devtype = {
110 .name = "mtd",
111 .groups = mtd_groups,
112 .release = mtd_release,
113};
114
36/** 115/**
37 * add_mtd_device - register an MTD device 116 * add_mtd_device - register an MTD device
38 * @mtd: pointer to new MTD device info structure 117 * @mtd: pointer to new MTD device info structure
@@ -41,6 +120,7 @@ static LIST_HEAD(mtd_notifiers);
41 * notify each currently active MTD 'user' of its arrival. Returns 120 * notify each currently active MTD 'user' of its arrival. Returns
42 * zero on success or 1 on failure, which currently will only happen 121 * zero on success or 1 on failure, which currently will only happen
43 * if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16) 122 * if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16)
123 * or there's a sysfs error.
44 */ 124 */
45 125
46int add_mtd_device(struct mtd_info *mtd) 126int add_mtd_device(struct mtd_info *mtd)
@@ -95,6 +175,23 @@ int add_mtd_device(struct mtd_info *mtd)
95 mtd->name); 175 mtd->name);
96 } 176 }
97 177
178 /* Caller should have set dev.parent to match the
179 * physical device.
180 */
181 mtd->dev.type = &mtd_devtype;
182 mtd->dev.class = mtd_class;
183 mtd->dev.devt = MTD_DEVT(i);
184 dev_set_name(&mtd->dev, "mtd%d", i);
185 if (device_register(&mtd->dev) != 0) {
186 mtd_table[i] = NULL;
187 break;
188 }
189
190 if (MTD_DEVT(i))
191 device_create(mtd_class, mtd->dev.parent,
192 MTD_DEVT(i) + 1,
193 NULL, "mtd%dro", i);
194
98 DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name); 195 DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
99 /* No need to get a refcount on the module containing 196 /* No need to get a refcount on the module containing
100 the notifier, since we hold the mtd_table_mutex */ 197 the notifier, since we hold the mtd_table_mutex */
@@ -358,6 +455,24 @@ EXPORT_SYMBOL_GPL(register_mtd_user);
358EXPORT_SYMBOL_GPL(unregister_mtd_user); 455EXPORT_SYMBOL_GPL(unregister_mtd_user);
359EXPORT_SYMBOL_GPL(default_mtd_writev); 456EXPORT_SYMBOL_GPL(default_mtd_writev);
360 457
458static int __init mtd_setup(void)
459{
460 mtd_class = class_create(THIS_MODULE, "mtd");
461
462 if (IS_ERR(mtd_class)) {
463 pr_err("Error creating mtd class.\n");
464 return PTR_ERR(mtd_class);
465 }
466 return 0;
467}
468core_initcall(mtd_setup);
469
470static void __exit mtd_teardown(void)
471{
472 class_destroy(mtd_class);
473}
474__exitcall(mtd_teardown);
475
361#ifdef CONFIG_PROC_FS 476#ifdef CONFIG_PROC_FS
362 477
363/*====================================================================*/ 478/*====================================================================*/
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 06d5b9d8853a..02ce38fb1fc3 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -356,6 +356,11 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
356 slave->mtd.owner = master->owner; 356 slave->mtd.owner = master->owner;
357 slave->mtd.backing_dev_info = master->backing_dev_info; 357 slave->mtd.backing_dev_info = master->backing_dev_info;
358 358
359 /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone
360 * to have the same data be in two different partitions.
361 */
362 slave->mtd.dev.parent = master->dev.parent;
363
359 slave->mtd.read = part_read; 364 slave->mtd.read = part_read;
360 slave->mtd.write = part_write; 365 slave->mtd.write = part_write;
361 366
@@ -508,7 +513,9 @@ out_register:
508 * This function, given a master MTD object and a partition table, creates 513 * This function, given a master MTD object and a partition table, creates
509 * and registers slave MTD objects which are bound to the master according to 514 * and registers slave MTD objects which are bound to the master according to
510 * the partition definitions. 515 * the partition definitions.
511 * (Q: should we register the master MTD object as well?) 516 *
517 * We don't register the master, or expect the caller to have done so,
518 * for reasons of data integrity.
512 */ 519 */
513 520
514int add_mtd_partitions(struct mtd_info *master, 521int add_mtd_partitions(struct mtd_info *master,
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 0c079fd307a5..5675b63a0631 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -11,6 +11,7 @@
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/uio.h> 12#include <linux/uio.h>
13#include <linux/notifier.h> 13#include <linux/notifier.h>
14#include <linux/device.h>
14 15
15#include <linux/mtd/compatmac.h> 16#include <linux/mtd/compatmac.h>
16#include <mtd/mtd-abi.h> 17#include <mtd/mtd-abi.h>
@@ -237,6 +238,7 @@ struct mtd_info {
237 void *priv; 238 void *priv;
238 239
239 struct module *owner; 240 struct module *owner;
241 struct device dev;
240 int usecount; 242 int usecount;
241 243
242 /* If the driver is something smart, like UBI, it may need to maintain 244 /* If the driver is something smart, like UBI, it may need to maintain
@@ -247,6 +249,11 @@ struct mtd_info {
247 void (*put_device) (struct mtd_info *mtd); 249 void (*put_device) (struct mtd_info *mtd);
248}; 250};
249 251
252static inline struct mtd_info *dev_to_mtd(struct device *dev)
253{
254 return dev ? container_of(dev, struct mtd_info, dev) : NULL;
255}
256
250static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd) 257static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
251{ 258{
252 if (mtd->erasesize_shift) 259 if (mtd->erasesize_shift)