aboutsummaryrefslogtreecommitdiff
path: root/drivers/mtd/mtdcore.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/mtdcore.c')
-rw-r--r--drivers/mtd/mtdcore.c86
1 files changed, 50 insertions, 36 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index ec794a72975..d201feeb3ca 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -36,11 +36,13 @@
#include <linux/idr.h>
#include <linux/backing-dev.h>
#include <linux/gfp.h>
+#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include "mtdcore.h"
+
/*
* backing device capabilities for non-mappable devices (such as NAND flash)
* - permits private mappings, copies are taken of the data
@@ -96,11 +98,7 @@ EXPORT_SYMBOL_GPL(__mtd_next_device);
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...
@@ -159,6 +157,9 @@ static ssize_t mtd_type_show(struct device *dev,
case MTD_UBIVOLUME:
type = "ubi";
break;
+ case MTD_MLCNANDFLASH:
+ type = "mlc-nand";
+ break;
default:
type = "unknown";
}
@@ -287,6 +288,16 @@ static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
mtd_bitflip_threshold_show,
mtd_bitflip_threshold_store);
+static ssize_t mtd_ecc_step_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_step_size);
+
+}
+static DEVICE_ATTR(ecc_step_size, S_IRUGO, mtd_ecc_step_size_show, NULL);
+
static struct attribute *mtd_attrs[] = {
&dev_attr_type.attr,
&dev_attr_flags.attr,
@@ -298,18 +309,11 @@ static struct attribute *mtd_attrs[] = {
&dev_attr_numeraseregions.attr,
&dev_attr_name.attr,
&dev_attr_ecc_strength.attr,
+ &dev_attr_ecc_step_size.attr,
&dev_attr_bitflip_threshold.attr,
NULL,
};
-
-static struct attribute_group mtd_group = {
- .attrs = mtd_attrs,
-};
-
-static const struct attribute_group *mtd_groups[] = {
- &mtd_group,
- NULL,
-};
+ATTRIBUTE_GROUPS(mtd);
static struct device_type mtd_devtype = {
.name = "mtd",
@@ -349,13 +353,8 @@ int add_mtd_device(struct mtd_info *mtd)
BUG_ON(mtd->writesize == 0);
mutex_lock(&mtd_table_mutex);
- do {
- if (!idr_pre_get(&mtd_idr, GFP_KERNEL))
- goto fail_locked;
- error = idr_get_new(&mtd_idr, mtd, &i);
- } while (error == -EAGAIN);
-
- if (error)
+ i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
+ if (i < 0)
goto fail_locked;
mtd->index = i;
@@ -497,7 +496,7 @@ out_error:
*
* Returns zero in case of success and a negative error code in case of failure.
*/
-int mtd_device_parse_register(struct mtd_info *mtd, const char **types,
+int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
struct mtd_part_parser_data *parser_data,
const struct mtd_partition *parts,
int nr_parts)
@@ -884,14 +883,14 @@ EXPORT_SYMBOL_GPL(mtd_read_oob);
* devices. The user data is one time programmable but the factory data is read
* only.
*/
-int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
- size_t len)
+int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
+ struct otp_info *buf)
{
if (!mtd->_get_fact_prot_info)
return -EOPNOTSUPP;
if (!len)
return 0;
- return mtd->_get_fact_prot_info(mtd, buf, len);
+ return mtd->_get_fact_prot_info(mtd, len, retlen, buf);
}
EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info);
@@ -907,14 +906,14 @@ int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
}
EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg);
-int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
- size_t len)
+int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
+ struct otp_info *buf)
{
if (!mtd->_get_user_prot_info)
return -EOPNOTSUPP;
if (!len)
return 0;
- return mtd->_get_user_prot_info(mtd, buf, len);
+ return mtd->_get_user_prot_info(mtd, len, retlen, buf);
}
EXPORT_SYMBOL_GPL(mtd_get_user_prot_info);
@@ -933,12 +932,22 @@ EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, u_char *buf)
{
+ int ret;
+
*retlen = 0;
if (!mtd->_write_user_prot_reg)
return -EOPNOTSUPP;
if (!len)
return 0;
- return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
+ ret = mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
+ if (ret)
+ return ret;
+
+ /*
+ * If no data could be written at all, we are out of memory and
+ * must return -ENOSPC.
+ */
+ return (*retlen) ? 0 : -ENOSPC;
}
EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);
@@ -1121,8 +1130,6 @@ EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to);
/*====================================================================*/
/* Support for /proc/mtd */
-static struct proc_dir_entry *proc_mtd;
-
static int mtd_proc_show(struct seq_file *m, void *v)
{
struct mtd_info *mtd;
@@ -1160,7 +1167,7 @@ static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
ret = bdi_init(bdi);
if (!ret)
- ret = bdi_register(bdi, NULL, name);
+ ret = bdi_register(bdi, NULL, "%s", name);
if (ret)
bdi_destroy(bdi);
@@ -1168,6 +1175,8 @@ static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
return ret;
}
+static struct proc_dir_entry *proc_mtd;
+
static int __init init_mtd(void)
{
int ret;
@@ -1188,11 +1197,17 @@ static int __init init_mtd(void)
if (ret)
goto err_bdi3;
-#ifdef CONFIG_PROC_FS
proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
-#endif /* CONFIG_PROC_FS */
+
+ ret = init_mtdchar();
+ if (ret)
+ goto out_procfs;
+
return 0;
+out_procfs:
+ if (proc_mtd)
+ remove_proc_entry("mtd", NULL);
err_bdi3:
bdi_destroy(&mtd_bdi_ro_mappable);
err_bdi2:
@@ -1206,10 +1221,9 @@ err_reg:
static void __exit cleanup_mtd(void)
{
-#ifdef CONFIG_PROC_FS
+ cleanup_mtdchar();
if (proc_mtd)
- remove_proc_entry( "mtd", NULL);
-#endif /* CONFIG_PROC_FS */
+ remove_proc_entry("mtd", NULL);
class_unregister(&mtd_class);
bdi_destroy(&mtd_bdi_unmappable);
bdi_destroy(&mtd_bdi_ro_mappable);