1
2
3
4
5
6
7
8
9
10
11#ifndef __UBOOT__
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/ptrace.h>
15#include <linux/seq_file.h>
16#include <linux/string.h>
17#include <linux/timer.h>
18#include <linux/major.h>
19#include <linux/fs.h>
20#include <linux/err.h>
21#include <linux/ioctl.h>
22#include <linux/init.h>
23#include <linux/proc_fs.h>
24#include <linux/idr.h>
25#include <linux/backing-dev.h>
26#include <linux/gfp.h>
27#include <linux/slab.h>
28#else
29#include <linux/bitops.h>
30#include <linux/bug.h>
31#include <linux/err.h>
32#include <ubi_uboot.h>
33#endif
34
35#include <linux/log2.h>
36#include <linux/mtd/mtd.h>
37#include <linux/mtd/partitions.h>
38
39#include "mtdcore.h"
40
41#ifndef __UBOOT__
42
43
44
45
46static struct backing_dev_info mtd_bdi_unmappable = {
47 .capabilities = BDI_CAP_MAP_COPY,
48};
49
50
51
52
53
54
55static struct backing_dev_info mtd_bdi_ro_mappable = {
56 .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
57 BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP),
58};
59
60
61
62
63
64
65static struct backing_dev_info mtd_bdi_rw_mappable = {
66 .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
67 BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP |
68 BDI_CAP_WRITE_MAP),
69};
70
71static int mtd_cls_suspend(struct device *dev, pm_message_t state);
72static int mtd_cls_resume(struct device *dev);
73
74static struct class mtd_class = {
75 .name = "mtd",
76 .owner = THIS_MODULE,
77 .suspend = mtd_cls_suspend,
78 .resume = mtd_cls_resume,
79};
80#else
81#define MAX_IDR_ID 64
82
83struct idr_layer {
84 int used;
85 void *ptr;
86};
87
88struct idr {
89 struct idr_layer id[MAX_IDR_ID];
90 bool updated;
91};
92
93#define DEFINE_IDR(name) struct idr name;
94
95void idr_remove(struct idr *idp, int id)
96{
97 if (idp->id[id].used) {
98 idp->id[id].used = 0;
99 idp->updated = true;
100 }
101
102 return;
103}
104void *idr_find(struct idr *idp, int id)
105{
106 if (idp->id[id].used)
107 return idp->id[id].ptr;
108
109 return NULL;
110}
111
112void *idr_get_next(struct idr *idp, int *next)
113{
114 void *ret;
115 int id = *next;
116
117 ret = idr_find(idp, id);
118 if (ret) {
119 id ++;
120 if (!idp->id[id].used)
121 id = 0;
122 *next = id;
123 } else {
124 *next = 0;
125 }
126
127 return ret;
128}
129
130int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask)
131{
132 struct idr_layer *idl;
133 int i = 0;
134
135 while (i < MAX_IDR_ID) {
136 idl = &idp->id[i];
137 if (idl->used == 0) {
138 idl->used = 1;
139 idl->ptr = ptr;
140 idp->updated = true;
141 return i;
142 }
143 i++;
144 }
145 return -ENOSPC;
146}
147#endif
148
149static DEFINE_IDR(mtd_idr);
150
151
152
153DEFINE_MUTEX(mtd_table_mutex);
154EXPORT_SYMBOL_GPL(mtd_table_mutex);
155
156struct mtd_info *__mtd_next_device(int i)
157{
158 return idr_get_next(&mtd_idr, &i);
159}
160EXPORT_SYMBOL_GPL(__mtd_next_device);
161
162bool mtd_dev_list_updated(void)
163{
164 if (mtd_idr.updated) {
165 mtd_idr.updated = false;
166 return true;
167 }
168
169 return false;
170}
171
172#ifndef __UBOOT__
173static LIST_HEAD(mtd_notifiers);
174
175
176#define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
177
178
179
180
181static void mtd_release(struct device *dev)
182{
183 struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev);
184 dev_t index = MTD_DEVT(mtd->index);
185
186
187 if (index)
188 device_destroy(&mtd_class, index + 1);
189}
190
191static int mtd_cls_suspend(struct device *dev, pm_message_t state)
192{
193 struct mtd_info *mtd = dev_get_drvdata(dev);
194
195 return mtd ? mtd_suspend(mtd) : 0;
196}
197
198static int mtd_cls_resume(struct device *dev)
199{
200 struct mtd_info *mtd = dev_get_drvdata(dev);
201
202 if (mtd)
203 mtd_resume(mtd);
204 return 0;
205}
206
207static ssize_t mtd_type_show(struct device *dev,
208 struct device_attribute *attr, char *buf)
209{
210 struct mtd_info *mtd = dev_get_drvdata(dev);
211 char *type;
212
213 switch (mtd->type) {
214 case MTD_ABSENT:
215 type = "absent";
216 break;
217 case MTD_RAM:
218 type = "ram";
219 break;
220 case MTD_ROM:
221 type = "rom";
222 break;
223 case MTD_NORFLASH:
224 type = "nor";
225 break;
226 case MTD_NANDFLASH:
227 type = "nand";
228 break;
229 case MTD_DATAFLASH:
230 type = "dataflash";
231 break;
232 case MTD_UBIVOLUME:
233 type = "ubi";
234 break;
235 case MTD_MLCNANDFLASH:
236 type = "mlc-nand";
237 break;
238 default:
239 type = "unknown";
240 }
241
242 return snprintf(buf, PAGE_SIZE, "%s\n", type);
243}
244static DEVICE_ATTR(type, S_IRUGO, mtd_type_show, NULL);
245
246static ssize_t mtd_flags_show(struct device *dev,
247 struct device_attribute *attr, char *buf)
248{
249 struct mtd_info *mtd = dev_get_drvdata(dev);
250
251 return snprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)mtd->flags);
252
253}
254static DEVICE_ATTR(flags, S_IRUGO, mtd_flags_show, NULL);
255
256static ssize_t mtd_size_show(struct device *dev,
257 struct device_attribute *attr, char *buf)
258{
259 struct mtd_info *mtd = dev_get_drvdata(dev);
260
261 return snprintf(buf, PAGE_SIZE, "%llu\n",
262 (unsigned long long)mtd->size);
263
264}
265static DEVICE_ATTR(size, S_IRUGO, mtd_size_show, NULL);
266
267static ssize_t mtd_erasesize_show(struct device *dev,
268 struct device_attribute *attr, char *buf)
269{
270 struct mtd_info *mtd = dev_get_drvdata(dev);
271
272 return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->erasesize);
273
274}
275static DEVICE_ATTR(erasesize, S_IRUGO, mtd_erasesize_show, NULL);
276
277static ssize_t mtd_writesize_show(struct device *dev,
278 struct device_attribute *attr, char *buf)
279{
280 struct mtd_info *mtd = dev_get_drvdata(dev);
281
282 return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->writesize);
283
284}
285static DEVICE_ATTR(writesize, S_IRUGO, mtd_writesize_show, NULL);
286
287static ssize_t mtd_subpagesize_show(struct device *dev,
288 struct device_attribute *attr, char *buf)
289{
290 struct mtd_info *mtd = dev_get_drvdata(dev);
291 unsigned int subpagesize = mtd->writesize >> mtd->subpage_sft;
292
293 return snprintf(buf, PAGE_SIZE, "%u\n", subpagesize);
294
295}
296static DEVICE_ATTR(subpagesize, S_IRUGO, mtd_subpagesize_show, NULL);
297
298static ssize_t mtd_oobsize_show(struct device *dev,
299 struct device_attribute *attr, char *buf)
300{
301 struct mtd_info *mtd = dev_get_drvdata(dev);
302
303 return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->oobsize);
304
305}
306static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL);
307
308static ssize_t mtd_numeraseregions_show(struct device *dev,
309 struct device_attribute *attr, char *buf)
310{
311 struct mtd_info *mtd = dev_get_drvdata(dev);
312
313 return snprintf(buf, PAGE_SIZE, "%u\n", mtd->numeraseregions);
314
315}
316static DEVICE_ATTR(numeraseregions, S_IRUGO, mtd_numeraseregions_show,
317 NULL);
318
319static ssize_t mtd_name_show(struct device *dev,
320 struct device_attribute *attr, char *buf)
321{
322 struct mtd_info *mtd = dev_get_drvdata(dev);
323
324 return snprintf(buf, PAGE_SIZE, "%s\n", mtd->name);
325
326}
327static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
328
329static ssize_t mtd_ecc_strength_show(struct device *dev,
330 struct device_attribute *attr, char *buf)
331{
332 struct mtd_info *mtd = dev_get_drvdata(dev);
333
334 return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_strength);
335}
336static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL);
337
338static ssize_t mtd_bitflip_threshold_show(struct device *dev,
339 struct device_attribute *attr,
340 char *buf)
341{
342 struct mtd_info *mtd = dev_get_drvdata(dev);
343
344 return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold);
345}
346
347static ssize_t mtd_bitflip_threshold_store(struct device *dev,
348 struct device_attribute *attr,
349 const char *buf, size_t count)
350{
351 struct mtd_info *mtd = dev_get_drvdata(dev);
352 unsigned int bitflip_threshold;
353 int retval;
354
355 retval = kstrtouint(buf, 0, &bitflip_threshold);
356 if (retval)
357 return retval;
358
359 mtd->bitflip_threshold = bitflip_threshold;
360 return count;
361}
362static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
363 mtd_bitflip_threshold_show,
364 mtd_bitflip_threshold_store);
365
366static ssize_t mtd_ecc_step_size_show(struct device *dev,
367 struct device_attribute *attr, char *buf)
368{
369 struct mtd_info *mtd = dev_get_drvdata(dev);
370
371 return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_step_size);
372
373}
374static DEVICE_ATTR(ecc_step_size, S_IRUGO, mtd_ecc_step_size_show, NULL);
375
376static struct attribute *mtd_attrs[] = {
377 &dev_attr_type.attr,
378 &dev_attr_flags.attr,
379 &dev_attr_size.attr,
380 &dev_attr_erasesize.attr,
381 &dev_attr_writesize.attr,
382 &dev_attr_subpagesize.attr,
383 &dev_attr_oobsize.attr,
384 &dev_attr_numeraseregions.attr,
385 &dev_attr_name.attr,
386 &dev_attr_ecc_strength.attr,
387 &dev_attr_ecc_step_size.attr,
388 &dev_attr_bitflip_threshold.attr,
389 NULL,
390};
391ATTRIBUTE_GROUPS(mtd);
392
393static struct device_type mtd_devtype = {
394 .name = "mtd",
395 .groups = mtd_groups,
396 .release = mtd_release,
397};
398#endif
399
400
401
402
403
404
405
406
407
408
409
410int add_mtd_device(struct mtd_info *mtd)
411{
412#ifndef __UBOOT__
413 struct mtd_notifier *not;
414#endif
415 int i, error;
416
417#ifndef __UBOOT__
418 if (!mtd->backing_dev_info) {
419 switch (mtd->type) {
420 case MTD_RAM:
421 mtd->backing_dev_info = &mtd_bdi_rw_mappable;
422 break;
423 case MTD_ROM:
424 mtd->backing_dev_info = &mtd_bdi_ro_mappable;
425 break;
426 default:
427 mtd->backing_dev_info = &mtd_bdi_unmappable;
428 break;
429 }
430 }
431#endif
432
433 BUG_ON(mtd->writesize == 0);
434 mutex_lock(&mtd_table_mutex);
435
436 i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
437 if (i < 0)
438 goto fail_locked;
439
440 mtd->index = i;
441 mtd->usecount = 0;
442
443 INIT_LIST_HEAD(&mtd->partitions);
444
445
446 if (mtd->bitflip_threshold == 0)
447 mtd->bitflip_threshold = mtd->ecc_strength;
448
449 if (is_power_of_2(mtd->erasesize))
450 mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
451 else
452 mtd->erasesize_shift = 0;
453
454 if (is_power_of_2(mtd->writesize))
455 mtd->writesize_shift = ffs(mtd->writesize) - 1;
456 else
457 mtd->writesize_shift = 0;
458
459 mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
460 mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
461
462
463 if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) {
464 error = mtd_unlock(mtd, 0, mtd->size);
465 if (error && error != -EOPNOTSUPP)
466 printk(KERN_WARNING
467 "%s: unlock failed, writes may not work\n",
468 mtd->name);
469 }
470
471#ifndef __UBOOT__
472
473
474
475 mtd->dev.type = &mtd_devtype;
476 mtd->dev.class = &mtd_class;
477 mtd->dev.devt = MTD_DEVT(i);
478 dev_set_name(&mtd->dev, "mtd%d", i);
479 dev_set_drvdata(&mtd->dev, mtd);
480 if (device_register(&mtd->dev) != 0)
481 goto fail_added;
482
483 if (MTD_DEVT(i))
484 device_create(&mtd_class, mtd->dev.parent,
485 MTD_DEVT(i) + 1,
486 NULL, "mtd%dro", i);
487
488 pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
489
490
491 list_for_each_entry(not, &mtd_notifiers, list)
492 not->add(mtd);
493#else
494 pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
495#endif
496
497 mutex_unlock(&mtd_table_mutex);
498
499
500
501
502 __module_get(THIS_MODULE);
503 return 0;
504
505#ifndef __UBOOT__
506fail_added:
507 idr_remove(&mtd_idr, i);
508#endif
509fail_locked:
510 mutex_unlock(&mtd_table_mutex);
511 return 1;
512}
513
514
515
516
517
518
519
520
521
522
523
524int del_mtd_device(struct mtd_info *mtd)
525{
526 int ret;
527#ifndef __UBOOT__
528 struct mtd_notifier *not;
529#endif
530
531 ret = del_mtd_partitions(mtd);
532 if (ret) {
533 debug("Failed to delete MTD partitions attached to %s (err %d)\n",
534 mtd->name, ret);
535 return ret;
536 }
537
538 mutex_lock(&mtd_table_mutex);
539
540 if (idr_find(&mtd_idr, mtd->index) != mtd) {
541 ret = -ENODEV;
542 goto out_error;
543 }
544
545#ifndef __UBOOT__
546
547
548 list_for_each_entry(not, &mtd_notifiers, list)
549 not->remove(mtd);
550#endif
551
552 if (mtd->usecount) {
553 printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
554 mtd->index, mtd->name, mtd->usecount);
555 ret = -EBUSY;
556 } else {
557#ifndef __UBOOT__
558 device_unregister(&mtd->dev);
559#endif
560
561 idr_remove(&mtd_idr, mtd->index);
562
563 module_put(THIS_MODULE);
564 ret = 0;
565 }
566
567out_error:
568 mutex_unlock(&mtd_table_mutex);
569 return ret;
570}
571
572#ifndef __UBOOT__
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
602 struct mtd_part_parser_data *parser_data,
603 const struct mtd_partition *parts,
604 int nr_parts)
605{
606 int err;
607 struct mtd_partition *real_parts;
608
609 err = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
610 if (err <= 0 && nr_parts && parts) {
611 real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
612 GFP_KERNEL);
613 if (!real_parts)
614 err = -ENOMEM;
615 else
616 err = nr_parts;
617 }
618
619 if (err > 0) {
620 err = add_mtd_partitions(mtd, real_parts, err);
621 kfree(real_parts);
622 } else if (err == 0) {
623 err = add_mtd_device(mtd);
624 if (err == 1)
625 err = -ENODEV;
626 }
627
628 return err;
629}
630EXPORT_SYMBOL_GPL(mtd_device_parse_register);
631
632
633
634
635
636
637
638int mtd_device_unregister(struct mtd_info *master)
639{
640 int err;
641
642 err = del_mtd_partitions(master);
643 if (err)
644 return err;
645
646 if (!device_is_registered(&master->dev))
647 return 0;
648
649 return del_mtd_device(master);
650}
651EXPORT_SYMBOL_GPL(mtd_device_unregister);
652
653
654
655
656
657
658
659
660
661void register_mtd_user (struct mtd_notifier *new)
662{
663 struct mtd_info *mtd;
664
665 mutex_lock(&mtd_table_mutex);
666
667 list_add(&new->list, &mtd_notifiers);
668
669 __module_get(THIS_MODULE);
670
671 mtd_for_each_device(mtd)
672 new->add(mtd);
673
674 mutex_unlock(&mtd_table_mutex);
675}
676EXPORT_SYMBOL_GPL(register_mtd_user);
677
678
679
680
681
682
683
684
685
686
687int unregister_mtd_user (struct mtd_notifier *old)
688{
689 struct mtd_info *mtd;
690
691 mutex_lock(&mtd_table_mutex);
692
693 module_put(THIS_MODULE);
694
695 mtd_for_each_device(mtd)
696 old->remove(mtd);
697
698 list_del(&old->list);
699 mutex_unlock(&mtd_table_mutex);
700 return 0;
701}
702EXPORT_SYMBOL_GPL(unregister_mtd_user);
703#endif
704
705
706
707
708
709
710
711
712
713
714
715
716struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
717{
718 struct mtd_info *ret = NULL, *other;
719 int err = -ENODEV;
720
721 mutex_lock(&mtd_table_mutex);
722
723 if (num == -1) {
724 mtd_for_each_device(other) {
725 if (other == mtd) {
726 ret = mtd;
727 break;
728 }
729 }
730 } else if (num >= 0) {
731 ret = idr_find(&mtd_idr, num);
732 if (mtd && mtd != ret)
733 ret = NULL;
734 }
735
736 if (!ret) {
737 ret = ERR_PTR(err);
738 goto out;
739 }
740
741 err = __get_mtd_device(ret);
742 if (err)
743 ret = ERR_PTR(err);
744out:
745 mutex_unlock(&mtd_table_mutex);
746 return ret;
747}
748EXPORT_SYMBOL_GPL(get_mtd_device);
749
750
751int __get_mtd_device(struct mtd_info *mtd)
752{
753 int err;
754
755 if (!try_module_get(mtd->owner))
756 return -ENODEV;
757
758 if (mtd->_get_device) {
759 err = mtd->_get_device(mtd);
760
761 if (err) {
762 module_put(mtd->owner);
763 return err;
764 }
765 }
766 mtd->usecount++;
767 return 0;
768}
769EXPORT_SYMBOL_GPL(__get_mtd_device);
770
771#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL)
772static bool mtd_device_matches_name(struct mtd_info *mtd, const char *name)
773{
774 struct udevice *dev = NULL;
775 bool is_part;
776
777
778
779
780
781 if (*name == '/')
782 device_get_global_by_ofnode(ofnode_path(name), &dev);
783
784 is_part = mtd_is_partition(mtd);
785
786 return (!is_part && dev && mtd->dev == dev) ||
787 !strcmp(name, mtd->name) ||
788 (is_part && mtd->dev && !strcmp(name, mtd->dev->name));
789}
790#else
791static bool mtd_device_matches_name(struct mtd_info *mtd, const char *name)
792{
793 return !strcmp(name, mtd->name);
794}
795#endif
796
797
798
799
800
801
802
803
804
805struct mtd_info *get_mtd_device_nm(const char *name)
806{
807 int err = -ENODEV;
808 struct mtd_info *mtd = NULL, *other;
809
810 mutex_lock(&mtd_table_mutex);
811
812 mtd_for_each_device(other) {
813#ifdef __UBOOT__
814 if (mtd_device_matches_name(other, name)) {
815 if (mtd)
816 printf("\nWarning: MTD name \"%s\" is not unique!\n\n",
817 name);
818 mtd = other;
819 }
820#else
821 if (!strcmp(name, other->name)) {
822 mtd = other;
823 break;
824 }
825#endif
826 }
827
828 if (!mtd)
829 goto out_unlock;
830
831 err = __get_mtd_device(mtd);
832 if (err)
833 goto out_unlock;
834
835 mutex_unlock(&mtd_table_mutex);
836 return mtd;
837
838out_unlock:
839 mutex_unlock(&mtd_table_mutex);
840 return ERR_PTR(err);
841}
842EXPORT_SYMBOL_GPL(get_mtd_device_nm);
843
844#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
845
846
847
848
849
850
851
852
853
854
855
856void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
857 const uint64_t length, uint64_t *len_incl_bad,
858 int *truncated)
859{
860 *truncated = 0;
861 *len_incl_bad = 0;
862
863 if (!mtd->_block_isbad) {
864 *len_incl_bad = length;
865 return;
866 }
867
868 uint64_t len_excl_bad = 0;
869 uint64_t block_len;
870
871 while (len_excl_bad < length) {
872 if (offset >= mtd->size) {
873 *truncated = 1;
874 return;
875 }
876
877 block_len = mtd->erasesize - (offset & (mtd->erasesize - 1));
878
879 if (!mtd->_block_isbad(mtd, offset & ~(mtd->erasesize - 1)))
880 len_excl_bad += block_len;
881
882 *len_incl_bad += block_len;
883 offset += block_len;
884 }
885}
886#endif
887
888void put_mtd_device(struct mtd_info *mtd)
889{
890 mutex_lock(&mtd_table_mutex);
891 __put_mtd_device(mtd);
892 mutex_unlock(&mtd_table_mutex);
893
894}
895EXPORT_SYMBOL_GPL(put_mtd_device);
896
897void __put_mtd_device(struct mtd_info *mtd)
898{
899 --mtd->usecount;
900 BUG_ON(mtd->usecount < 0);
901
902 if (mtd->_put_device)
903 mtd->_put_device(mtd);
904
905 module_put(mtd->owner);
906}
907EXPORT_SYMBOL_GPL(__put_mtd_device);
908
909int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
910{
911 if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
912 return -EINVAL;
913 if (!(mtd->flags & MTD_WRITEABLE))
914 return -EROFS;
915 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
916 if (!instr->len) {
917 instr->state = MTD_ERASE_DONE;
918 return 0;
919 }
920 return mtd->_erase(mtd, instr);
921}
922EXPORT_SYMBOL_GPL(mtd_erase);
923
924#ifndef __UBOOT__
925
926
927
928int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
929 void **virt, resource_size_t *phys)
930{
931 *retlen = 0;
932 *virt = NULL;
933 if (phys)
934 *phys = 0;
935 if (!mtd->_point)
936 return -EOPNOTSUPP;
937 if (from < 0 || from > mtd->size || len > mtd->size - from)
938 return -EINVAL;
939 if (!len)
940 return 0;
941 return mtd->_point(mtd, from, len, retlen, virt, phys);
942}
943EXPORT_SYMBOL_GPL(mtd_point);
944
945
946int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
947{
948 if (!mtd->_point)
949 return -EOPNOTSUPP;
950 if (from < 0 || from > mtd->size || len > mtd->size - from)
951 return -EINVAL;
952 if (!len)
953 return 0;
954 return mtd->_unpoint(mtd, from, len);
955}
956EXPORT_SYMBOL_GPL(mtd_unpoint);
957#endif
958
959
960
961
962
963
964unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
965 unsigned long offset, unsigned long flags)
966{
967 if (!mtd->_get_unmapped_area)
968 return -EOPNOTSUPP;
969 if (offset > mtd->size || len > mtd->size - offset)
970 return -EINVAL;
971 return mtd->_get_unmapped_area(mtd, len, offset, flags);
972}
973EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
974
975int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
976 u_char *buf)
977{
978 int ret_code;
979 *retlen = 0;
980 if (from < 0 || from > mtd->size || len > mtd->size - from)
981 return -EINVAL;
982 if (!len)
983 return 0;
984
985
986
987
988
989
990 if (mtd->_read) {
991 ret_code = mtd->_read(mtd, from, len, retlen, buf);
992 } else if (mtd->_read_oob) {
993 struct mtd_oob_ops ops = {
994 .len = len,
995 .datbuf = buf,
996 };
997
998 ret_code = mtd->_read_oob(mtd, from, &ops);
999 *retlen = ops.retlen;
1000 } else {
1001 return -ENOTSUPP;
1002 }
1003
1004 if (unlikely(ret_code < 0))
1005 return ret_code;
1006 if (mtd->ecc_strength == 0)
1007 return 0;
1008 return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
1009}
1010EXPORT_SYMBOL_GPL(mtd_read);
1011
1012int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
1013 const u_char *buf)
1014{
1015 *retlen = 0;
1016 if (to < 0 || to > mtd->size || len > mtd->size - to)
1017 return -EINVAL;
1018 if ((!mtd->_write && !mtd->_write_oob) ||
1019 !(mtd->flags & MTD_WRITEABLE))
1020 return -EROFS;
1021 if (!len)
1022 return 0;
1023
1024 if (!mtd->_write) {
1025 struct mtd_oob_ops ops = {
1026 .len = len,
1027 .datbuf = (u8 *)buf,
1028 };
1029 int ret;
1030
1031 ret = mtd->_write_oob(mtd, to, &ops);
1032 *retlen = ops.retlen;
1033 return ret;
1034 }
1035
1036 return mtd->_write(mtd, to, len, retlen, buf);
1037}
1038EXPORT_SYMBOL_GPL(mtd_write);
1039
1040
1041
1042
1043
1044
1045
1046
1047int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
1048 const u_char *buf)
1049{
1050 *retlen = 0;
1051 if (!mtd->_panic_write)
1052 return -EOPNOTSUPP;
1053 if (to < 0 || to > mtd->size || len > mtd->size - to)
1054 return -EINVAL;
1055 if (!(mtd->flags & MTD_WRITEABLE))
1056 return -EROFS;
1057 if (!len)
1058 return 0;
1059 return mtd->_panic_write(mtd, to, len, retlen, buf);
1060}
1061EXPORT_SYMBOL_GPL(mtd_panic_write);
1062
1063static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
1064 struct mtd_oob_ops *ops)
1065{
1066
1067
1068
1069
1070
1071 if (!ops->datbuf)
1072 ops->len = 0;
1073
1074 if (!ops->oobbuf)
1075 ops->ooblen = 0;
1076
1077 if (offs < 0 || offs + ops->len > mtd->size)
1078 return -EINVAL;
1079
1080 if (ops->ooblen) {
1081 size_t maxooblen;
1082
1083 if (ops->ooboffs >= mtd_oobavail(mtd, ops))
1084 return -EINVAL;
1085
1086 maxooblen = ((size_t)(mtd_div_by_ws(mtd->size, mtd) -
1087 mtd_div_by_ws(offs, mtd)) *
1088 mtd_oobavail(mtd, ops)) - ops->ooboffs;
1089 if (ops->ooblen > maxooblen)
1090 return -EINVAL;
1091 }
1092
1093 return 0;
1094}
1095
1096int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
1097{
1098 int ret_code;
1099 ops->retlen = ops->oobretlen = 0;
1100
1101 ret_code = mtd_check_oob_ops(mtd, from, ops);
1102 if (ret_code)
1103 return ret_code;
1104
1105
1106 if (!mtd->_read_oob && (!mtd->_read || ops->oobbuf))
1107 return -EOPNOTSUPP;
1108
1109 if (mtd->_read_oob)
1110 ret_code = mtd->_read_oob(mtd, from, ops);
1111 else
1112 ret_code = mtd->_read(mtd, from, ops->len, &ops->retlen,
1113 ops->datbuf);
1114
1115
1116
1117
1118
1119
1120
1121 if (unlikely(ret_code < 0))
1122 return ret_code;
1123 if (mtd->ecc_strength == 0)
1124 return 0;
1125 return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
1126}
1127EXPORT_SYMBOL_GPL(mtd_read_oob);
1128
1129int mtd_write_oob(struct mtd_info *mtd, loff_t to,
1130 struct mtd_oob_ops *ops)
1131{
1132 int ret;
1133
1134 ops->retlen = ops->oobretlen = 0;
1135
1136 if (!(mtd->flags & MTD_WRITEABLE))
1137 return -EROFS;
1138
1139 ret = mtd_check_oob_ops(mtd, to, ops);
1140 if (ret)
1141 return ret;
1142
1143
1144 if (!mtd->_write_oob && (!mtd->_write || ops->oobbuf))
1145 return -EOPNOTSUPP;
1146
1147 if (mtd->_write_oob)
1148 return mtd->_write_oob(mtd, to, ops);
1149 else
1150 return mtd->_write(mtd, to, ops->len, &ops->retlen,
1151 ops->datbuf);
1152}
1153EXPORT_SYMBOL_GPL(mtd_write_oob);
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
1172 struct mtd_oob_region *oobecc)
1173{
1174 memset(oobecc, 0, sizeof(*oobecc));
1175
1176 if (!mtd || section < 0)
1177 return -EINVAL;
1178
1179 if (!mtd->ooblayout || !mtd->ooblayout->ecc)
1180 return -ENOTSUPP;
1181
1182 return mtd->ooblayout->ecc(mtd, section, oobecc);
1183}
1184EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203int mtd_ooblayout_free(struct mtd_info *mtd, int section,
1204 struct mtd_oob_region *oobfree)
1205{
1206 memset(oobfree, 0, sizeof(*oobfree));
1207
1208 if (!mtd || section < 0)
1209 return -EINVAL;
1210
1211 if (!mtd->ooblayout || !mtd->ooblayout->rfree)
1212 return -ENOTSUPP;
1213
1214 return mtd->ooblayout->rfree(mtd, section, oobfree);
1215}
1216EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte,
1236 int *sectionp, struct mtd_oob_region *oobregion,
1237 int (*iter)(struct mtd_info *,
1238 int section,
1239 struct mtd_oob_region *oobregion))
1240{
1241 int pos = 0, ret, section = 0;
1242
1243 memset(oobregion, 0, sizeof(*oobregion));
1244
1245 while (1) {
1246 ret = iter(mtd, section, oobregion);
1247 if (ret)
1248 return ret;
1249
1250 if (pos + oobregion->length > byte)
1251 break;
1252
1253 pos += oobregion->length;
1254 section++;
1255 }
1256
1257
1258
1259
1260
1261 oobregion->offset += byte - pos;
1262 oobregion->length -= byte - pos;
1263 *sectionp = section;
1264
1265 return 0;
1266}
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
1282 int *section,
1283 struct mtd_oob_region *oobregion)
1284{
1285 return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion,
1286 mtd_ooblayout_ecc);
1287}
1288EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion);
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
1305 const u8 *oobbuf, int start, int nbytes,
1306 int (*iter)(struct mtd_info *,
1307 int section,
1308 struct mtd_oob_region *oobregion))
1309{
1310 struct mtd_oob_region oobregion;
1311 int section, ret;
1312
1313 ret = mtd_ooblayout_find_region(mtd, start, §ion,
1314 &oobregion, iter);
1315
1316 while (!ret) {
1317 int cnt;
1318
1319 cnt = min_t(int, nbytes, oobregion.length);
1320 memcpy(buf, oobbuf + oobregion.offset, cnt);
1321 buf += cnt;
1322 nbytes -= cnt;
1323
1324 if (!nbytes)
1325 break;
1326
1327 ret = iter(mtd, ++section, &oobregion);
1328 }
1329
1330 return ret;
1331}
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
1348 u8 *oobbuf, int start, int nbytes,
1349 int (*iter)(struct mtd_info *,
1350 int section,
1351 struct mtd_oob_region *oobregion))
1352{
1353 struct mtd_oob_region oobregion;
1354 int section, ret;
1355
1356 ret = mtd_ooblayout_find_region(mtd, start, §ion,
1357 &oobregion, iter);
1358
1359 while (!ret) {
1360 int cnt;
1361
1362 cnt = min_t(int, nbytes, oobregion.length);
1363 memcpy(oobbuf + oobregion.offset, buf, cnt);
1364 buf += cnt;
1365 nbytes -= cnt;
1366
1367 if (!nbytes)
1368 break;
1369
1370 ret = iter(mtd, ++section, &oobregion);
1371 }
1372
1373 return ret;
1374}
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
1386 int (*iter)(struct mtd_info *,
1387 int section,
1388 struct mtd_oob_region *oobregion))
1389{
1390 struct mtd_oob_region oobregion;
1391 int section = 0, ret, nbytes = 0;
1392
1393 while (1) {
1394 ret = iter(mtd, section++, &oobregion);
1395 if (ret) {
1396 if (ret == -ERANGE)
1397 ret = nbytes;
1398 break;
1399 }
1400
1401 nbytes += oobregion.length;
1402 }
1403
1404 return ret;
1405}
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
1420 const u8 *oobbuf, int start, int nbytes)
1421{
1422 return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes,
1423 mtd_ooblayout_ecc);
1424}
1425EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes);
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
1440 u8 *oobbuf, int start, int nbytes)
1441{
1442 return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes,
1443 mtd_ooblayout_ecc);
1444}
1445EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes);
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
1460 const u8 *oobbuf, int start, int nbytes)
1461{
1462 return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes,
1463 mtd_ooblayout_free);
1464}
1465EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes);
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
1480 u8 *oobbuf, int start, int nbytes)
1481{
1482 return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes,
1483 mtd_ooblayout_free);
1484}
1485EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes);
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495int mtd_ooblayout_count_freebytes(struct mtd_info *mtd)
1496{
1497 return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free);
1498}
1499EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes);
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
1510{
1511 return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc);
1512}
1513EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
1514
1515
1516
1517
1518
1519
1520int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
1521 struct otp_info *buf)
1522{
1523 if (!mtd->_get_fact_prot_info)
1524 return -EOPNOTSUPP;
1525 if (!len)
1526 return 0;
1527 return mtd->_get_fact_prot_info(mtd, len, retlen, buf);
1528}
1529EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info);
1530
1531int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
1532 size_t *retlen, u_char *buf)
1533{
1534 *retlen = 0;
1535 if (!mtd->_read_fact_prot_reg)
1536 return -EOPNOTSUPP;
1537 if (!len)
1538 return 0;
1539 return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf);
1540}
1541EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg);
1542
1543int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
1544 struct otp_info *buf)
1545{
1546 if (!mtd->_get_user_prot_info)
1547 return -EOPNOTSUPP;
1548 if (!len)
1549 return 0;
1550 return mtd->_get_user_prot_info(mtd, len, retlen, buf);
1551}
1552EXPORT_SYMBOL_GPL(mtd_get_user_prot_info);
1553
1554int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
1555 size_t *retlen, u_char *buf)
1556{
1557 *retlen = 0;
1558 if (!mtd->_read_user_prot_reg)
1559 return -EOPNOTSUPP;
1560 if (!len)
1561 return 0;
1562 return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf);
1563}
1564EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
1565
1566int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
1567 size_t *retlen, u_char *buf)
1568{
1569 int ret;
1570
1571 *retlen = 0;
1572 if (!mtd->_write_user_prot_reg)
1573 return -EOPNOTSUPP;
1574 if (!len)
1575 return 0;
1576 ret = mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
1577 if (ret)
1578 return ret;
1579
1580
1581
1582
1583
1584 return (*retlen) ? 0 : -ENOSPC;
1585}
1586EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);
1587
1588int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
1589{
1590 if (!mtd->_lock_user_prot_reg)
1591 return -EOPNOTSUPP;
1592 if (!len)
1593 return 0;
1594 return mtd->_lock_user_prot_reg(mtd, from, len);
1595}
1596EXPORT_SYMBOL_GPL(mtd_lock_user_prot_reg);
1597
1598
1599int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1600{
1601 if (!mtd->_lock)
1602 return -EOPNOTSUPP;
1603 if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
1604 return -EINVAL;
1605 if (!len)
1606 return 0;
1607 return mtd->_lock(mtd, ofs, len);
1608}
1609EXPORT_SYMBOL_GPL(mtd_lock);
1610
1611int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1612{
1613 if (!mtd->_unlock)
1614 return -EOPNOTSUPP;
1615 if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
1616 return -EINVAL;
1617 if (!len)
1618 return 0;
1619 return mtd->_unlock(mtd, ofs, len);
1620}
1621EXPORT_SYMBOL_GPL(mtd_unlock);
1622
1623int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1624{
1625 if (!mtd->_is_locked)
1626 return -EOPNOTSUPP;
1627 if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
1628 return -EINVAL;
1629 if (!len)
1630 return 0;
1631 return mtd->_is_locked(mtd, ofs, len);
1632}
1633EXPORT_SYMBOL_GPL(mtd_is_locked);
1634
1635int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs)
1636{
1637 if (ofs < 0 || ofs > mtd->size)
1638 return -EINVAL;
1639 if (!mtd->_block_isreserved)
1640 return 0;
1641 return mtd->_block_isreserved(mtd, ofs);
1642}
1643EXPORT_SYMBOL_GPL(mtd_block_isreserved);
1644
1645int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
1646{
1647 if (ofs < 0 || ofs > mtd->size)
1648 return -EINVAL;
1649 if (!mtd->_block_isbad)
1650 return 0;
1651 return mtd->_block_isbad(mtd, ofs);
1652}
1653EXPORT_SYMBOL_GPL(mtd_block_isbad);
1654
1655int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
1656{
1657 if (!mtd->_block_markbad)
1658 return -EOPNOTSUPP;
1659 if (ofs < 0 || ofs > mtd->size)
1660 return -EINVAL;
1661 if (!(mtd->flags & MTD_WRITEABLE))
1662 return -EROFS;
1663 return mtd->_block_markbad(mtd, ofs);
1664}
1665EXPORT_SYMBOL_GPL(mtd_block_markbad);
1666
1667#ifndef __UBOOT__
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679static int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
1680 unsigned long count, loff_t to, size_t *retlen)
1681{
1682 unsigned long i;
1683 size_t totlen = 0, thislen;
1684 int ret = 0;
1685
1686 for (i = 0; i < count; i++) {
1687 if (!vecs[i].iov_len)
1688 continue;
1689 ret = mtd_write(mtd, to, vecs[i].iov_len, &thislen,
1690 vecs[i].iov_base);
1691 totlen += thislen;
1692 if (ret || thislen != vecs[i].iov_len)
1693 break;
1694 to += vecs[i].iov_len;
1695 }
1696 *retlen = totlen;
1697 return ret;
1698}
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
1712 unsigned long count, loff_t to, size_t *retlen)
1713{
1714 *retlen = 0;
1715 if (!(mtd->flags & MTD_WRITEABLE))
1716 return -EROFS;
1717 if (!mtd->_writev)
1718 return default_mtd_writev(mtd, vecs, count, to, retlen);
1719 return mtd->_writev(mtd, vecs, count, to, retlen);
1720}
1721EXPORT_SYMBOL_GPL(mtd_writev);
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size)
1748{
1749 gfp_t flags = __GFP_NOWARN | __GFP_WAIT |
1750 __GFP_NORETRY | __GFP_NO_KSWAPD;
1751 size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE);
1752 void *kbuf;
1753
1754 *size = min_t(size_t, *size, KMALLOC_MAX_SIZE);
1755
1756 while (*size > min_alloc) {
1757 kbuf = kmalloc(*size, flags);
1758 if (kbuf)
1759 return kbuf;
1760
1761 *size >>= 1;
1762 *size = ALIGN(*size, mtd->writesize);
1763 }
1764
1765
1766
1767
1768
1769 return kmalloc(*size, GFP_KERNEL);
1770}
1771EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to);
1772#endif
1773
1774#ifdef CONFIG_PROC_FS
1775
1776
1777
1778
1779static int mtd_proc_show(struct seq_file *m, void *v)
1780{
1781 struct mtd_info *mtd;
1782
1783 seq_puts(m, "dev: size erasesize name\n");
1784 mutex_lock(&mtd_table_mutex);
1785 mtd_for_each_device(mtd) {
1786 seq_printf(m, "mtd%d: %8.8llx %8.8x \"%s\"\n",
1787 mtd->index, (unsigned long long)mtd->size,
1788 mtd->erasesize, mtd->name);
1789 }
1790 mutex_unlock(&mtd_table_mutex);
1791 return 0;
1792}
1793
1794static int mtd_proc_open(struct inode *inode, struct file *file)
1795{
1796 return single_open(file, mtd_proc_show, NULL);
1797}
1798
1799static const struct file_operations mtd_proc_ops = {
1800 .open = mtd_proc_open,
1801 .read = seq_read,
1802 .llseek = seq_lseek,
1803 .release = single_release,
1804};
1805#endif
1806
1807
1808
1809
1810#ifndef __UBOOT__
1811static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
1812{
1813 int ret;
1814
1815 ret = bdi_init(bdi);
1816 if (!ret)
1817 ret = bdi_register(bdi, NULL, "%s", name);
1818
1819 if (ret)
1820 bdi_destroy(bdi);
1821
1822 return ret;
1823}
1824
1825static struct proc_dir_entry *proc_mtd;
1826
1827static int __init init_mtd(void)
1828{
1829 int ret;
1830
1831 ret = class_register(&mtd_class);
1832 if (ret)
1833 goto err_reg;
1834
1835 ret = mtd_bdi_init(&mtd_bdi_unmappable, "mtd-unmap");
1836 if (ret)
1837 goto err_bdi1;
1838
1839 ret = mtd_bdi_init(&mtd_bdi_ro_mappable, "mtd-romap");
1840 if (ret)
1841 goto err_bdi2;
1842
1843 ret = mtd_bdi_init(&mtd_bdi_rw_mappable, "mtd-rwmap");
1844 if (ret)
1845 goto err_bdi3;
1846
1847 proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
1848
1849 ret = init_mtdchar();
1850 if (ret)
1851 goto out_procfs;
1852
1853 return 0;
1854
1855out_procfs:
1856 if (proc_mtd)
1857 remove_proc_entry("mtd", NULL);
1858err_bdi3:
1859 bdi_destroy(&mtd_bdi_ro_mappable);
1860err_bdi2:
1861 bdi_destroy(&mtd_bdi_unmappable);
1862err_bdi1:
1863 class_unregister(&mtd_class);
1864err_reg:
1865 pr_err("Error registering mtd class or bdi: %d\n", ret);
1866 return ret;
1867}
1868
1869static void __exit cleanup_mtd(void)
1870{
1871 cleanup_mtdchar();
1872 if (proc_mtd)
1873 remove_proc_entry("mtd", NULL);
1874 class_unregister(&mtd_class);
1875 bdi_destroy(&mtd_bdi_unmappable);
1876 bdi_destroy(&mtd_bdi_ro_mappable);
1877 bdi_destroy(&mtd_bdi_rw_mappable);
1878}
1879
1880module_init(init_mtd);
1881module_exit(cleanup_mtd);
1882#endif
1883
1884MODULE_LICENSE("GPL");
1885MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1886MODULE_DESCRIPTION("Core MTD registration and access routines");
1887