diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2009-03-26 03:42:41 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-04-04 09:29:07 -0400 |
commit | 1f24b5a8ecbb2a3c7080f418974d40e3ffedb221 (patch) | |
tree | 07dfc44f62dac78bdf4a8cdb4d91d60f73c04ff4 /drivers/mtd/mtdcore.c | |
parent | 9d63287a461c269edb39941744f4ff22223cf349 (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>
Diffstat (limited to 'drivers/mtd/mtdcore.c')
-rw-r--r-- | drivers/mtd/mtdcore.c | 115 |
1 files changed, 115 insertions, 0 deletions
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 | |||
27 | static 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 */ |
28 | DEFINE_MUTEX(mtd_table_mutex); | 31 | DEFINE_MUTEX(mtd_table_mutex); |
@@ -33,6 +36,82 @@ EXPORT_SYMBOL_GPL(mtd_table); | |||
33 | 36 | ||
34 | static LIST_HEAD(mtd_notifiers); | 37 | static 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 | */ | ||
49 | static 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 | |||
58 | static 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 | } | ||
92 | static DEVICE_ATTR(mtd_type, S_IRUGO, mtd_type_show, NULL); | ||
93 | |||
94 | static struct attribute *mtd_attrs[] = { | ||
95 | &dev_attr_mtd_type.attr, | ||
96 | /* FIXME provide a /proc/mtd superset */ | ||
97 | NULL, | ||
98 | }; | ||
99 | |||
100 | struct attribute_group mtd_group = { | ||
101 | .attrs = mtd_attrs, | ||
102 | }; | ||
103 | |||
104 | struct attribute_group *mtd_groups[] = { | ||
105 | &mtd_group, | ||
106 | NULL, | ||
107 | }; | ||
108 | |||
109 | static 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 | ||
46 | int add_mtd_device(struct mtd_info *mtd) | 126 | int 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); | |||
358 | EXPORT_SYMBOL_GPL(unregister_mtd_user); | 455 | EXPORT_SYMBOL_GPL(unregister_mtd_user); |
359 | EXPORT_SYMBOL_GPL(default_mtd_writev); | 456 | EXPORT_SYMBOL_GPL(default_mtd_writev); |
360 | 457 | ||
458 | static 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 | } | ||
468 | core_initcall(mtd_setup); | ||
469 | |||
470 | static 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 | /*====================================================================*/ |