1
2
3
4
5
6
7
8
9
10
11
12#ifndef __UBOOT__
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/ptrace.h>
16#include <linux/seq_file.h>
17#include <linux/string.h>
18#include <linux/timer.h>
19#include <linux/major.h>
20#include <linux/fs.h>
21#include <linux/err.h>
22#include <linux/ioctl.h>
23#include <linux/init.h>
24#include <linux/proc_fs.h>
25#include <linux/idr.h>
26#include <linux/backing-dev.h>
27#include <linux/gfp.h>
28#include <linux/slab.h>
29#else
30#include <linux/compat.h>
31#include <linux/err.h>
32#include <ubi_uboot.h>
33#endif
34
35#include <linux/mtd/mtd.h>
36#include <linux/mtd/partitions.h>
37
38#include "mtdcore.h"
39
40#ifndef __UBOOT__
41
42
43
44
45static struct backing_dev_info mtd_bdi_unmappable = {
46 .capabilities = BDI_CAP_MAP_COPY,
47};
48
49
50
51
52
53
54static struct backing_dev_info mtd_bdi_ro_mappable = {
55 .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
56 BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP),
57};
58
59
60
61
62
63
64static struct backing_dev_info mtd_bdi_rw_mappable = {
65 .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
66 BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP |
67 BDI_CAP_WRITE_MAP),
68};
69
70static int mtd_cls_suspend(struct device *dev, pm_message_t state);
71static int mtd_cls_resume(struct device *dev);
72
73static struct class mtd_class = {
74 .name = "mtd",
75 .owner = THIS_MODULE,
76 .suspend = mtd_cls_suspend,
77 .resume = mtd_cls_resume,
78};
79#else
80struct mtd_info *mtd_table[MAX_MTD_DEVICES];
81
82#define MAX_IDR_ID 64
83
84struct idr_layer {
85 int used;
86 void *ptr;
87};
88
89struct idr {
90 struct idr_layer id[MAX_IDR_ID];
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
100 return;
101}
102void *idr_find(struct idr *idp, int id)
103{
104 if (idp->id[id].used)
105 return idp->id[id].ptr;
106
107 return NULL;
108}
109
110void *idr_get_next(struct idr *idp, int *next)
111{
112 void *ret;
113 int id = *next;
114
115 ret = idr_find(idp, id);
116 if (ret) {
117 id ++;
118 if (!idp->id[id].used)
119 id = 0;
120 *next = id;
121 } else {
122 *next = 0;
123 }
124
125 return ret;
126}
127
128int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask)
129{
130 struct idr_layer *idl;
131 int i = 0;
132
133 while (i < MAX_IDR_ID) {
134 idl = &idp->id[i];
135 if (idl->used == 0) {
136 idl->used = 1;
137 idl->ptr = ptr;
138 return i;
139 }
140 i++;
141 }
142 return -ENOSPC;
143}
144#endif
145
146static DEFINE_IDR(mtd_idr);
147
148
149
150DEFINE_MUTEX(mtd_table_mutex);
151EXPORT_SYMBOL_GPL(mtd_table_mutex);
152
153struct mtd_info *__mtd_next_device(int i)
154{
155 return idr_get_next(&mtd_idr, &i);
156}
157EXPORT_SYMBOL_GPL(__mtd_next_device);
158
159#ifndef __UBOOT__
160static LIST_HEAD(mtd_notifiers);
161
162
163#define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
164
165
166
167
168static void mtd_release(struct device *dev)
169{
170 struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev);
171 dev_t index = MTD_DEVT(mtd->index);
172
173
174 if (index)
175 device_destroy(&mtd_class, index + 1);
176}
177
178static int mtd_cls_suspend(struct device *dev, pm_message_t state)
179{
180 struct mtd_info *mtd = dev_get_drvdata(dev);
181
182 return mtd ? mtd_suspend(mtd) : 0;
183}
184
185static int mtd_cls_resume(struct device *dev)
186{
187 struct mtd_info *mtd = dev_get_drvdata(dev);
188
189 if (mtd)
190 mtd_resume(mtd);
191 return 0;
192}
193
194static ssize_t mtd_type_show(struct device *dev,
195 struct device_attribute *attr, char *buf)
196{
197 struct mtd_info *mtd = dev_get_drvdata(dev);
198 char *type;
199
200 switch (mtd->type) {
201 case MTD_ABSENT:
202 type = "absent";
203 break;
204 case MTD_RAM:
205 type = "ram";
206 break;
207 case MTD_ROM:
208 type = "rom";
209 break;
210 case MTD_NORFLASH:
211 type = "nor";
212 break;
213 case MTD_NANDFLASH:
214 type = "nand";
215 break;
216 case MTD_DATAFLASH:
217 type = "dataflash";
218 break;
219 case MTD_UBIVOLUME:
220 type = "ubi";
221 break;
222 case MTD_MLCNANDFLASH:
223 type = "mlc-nand";
224 break;
225 default:
226 type = "unknown";
227 }
228
229 return snprintf(buf, PAGE_SIZE, "%s\n", type);
230}
231static DEVICE_ATTR(type, S_IRUGO, mtd_type_show, NULL);
232
233static ssize_t mtd_flags_show(struct device *dev,
234 struct device_attribute *attr, char *buf)
235{
236 struct mtd_info *mtd = dev_get_drvdata(dev);
237
238 return snprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)mtd->flags);
239
240}
241static DEVICE_ATTR(flags, S_IRUGO, mtd_flags_show, NULL);
242
243static ssize_t mtd_size_show(struct device *dev,
244 struct device_attribute *attr, char *buf)
245{
246 struct mtd_info *mtd = dev_get_drvdata(dev);
247
248 return snprintf(buf, PAGE_SIZE, "%llu\n",
249 (unsigned long long)mtd->size);
250
251}
252static DEVICE_ATTR(size, S_IRUGO, mtd_size_show, NULL);
253
254static ssize_t mtd_erasesize_show(struct device *dev,
255 struct device_attribute *attr, char *buf)
256{
257 struct mtd_info *mtd = dev_get_drvdata(dev);
258
259 return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->erasesize);
260
261}
262static DEVICE_ATTR(erasesize, S_IRUGO, mtd_erasesize_show, NULL);
263
264static ssize_t mtd_writesize_show(struct device *dev,
265 struct device_attribute *attr, char *buf)
266{
267 struct mtd_info *mtd = dev_get_drvdata(dev);
268
269 return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->writesize);
270
271}
272static DEVICE_ATTR(writesize, S_IRUGO, mtd_writesize_show, NULL);
273
274static ssize_t mtd_subpagesize_show(struct device *dev,
275 struct device_attribute *attr, char *buf)
276{
277 struct mtd_info *mtd = dev_get_drvdata(dev);
278 unsigned int subpagesize = mtd->writesize >> mtd->subpage_sft;
279
280 return snprintf(buf, PAGE_SIZE, "%u\n", subpagesize);
281
282}
283static DEVICE_ATTR(subpagesize, S_IRUGO, mtd_subpagesize_show, NULL);
284
285static ssize_t mtd_oobsize_show(struct device *dev,
286 struct device_attribute *attr, char *buf)
287{
288 struct mtd_info *mtd = dev_get_drvdata(dev);
289
290 return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->oobsize);
291
292}
293static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL);
294
295static ssize_t mtd_numeraseregions_show(struct device *dev,
296 struct device_attribute *attr, char *buf)
297{
298 struct mtd_info *mtd = dev_get_drvdata(dev);
299
300 return snprintf(buf, PAGE_SIZE, "%u\n", mtd->numeraseregions);
301
302}
303static DEVICE_ATTR(numeraseregions, S_IRUGO, mtd_numeraseregions_show,
304 NULL);
305
306static ssize_t mtd_name_show(struct device *dev,
307 struct device_attribute *attr, char *buf)
308{
309 struct mtd_info *mtd = dev_get_drvdata(dev);
310
311 return snprintf(buf, PAGE_SIZE, "%s\n", mtd->name);
312
313}
314static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
315
316static ssize_t mtd_ecc_strength_show(struct device *dev,
317 struct device_attribute *attr, char *buf)
318{
319 struct mtd_info *mtd = dev_get_drvdata(dev);
320
321 return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_strength);
322}
323static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL);
324
325static ssize_t mtd_bitflip_threshold_show(struct device *dev,
326 struct device_attribute *attr,
327 char *buf)
328{
329 struct mtd_info *mtd = dev_get_drvdata(dev);
330
331 return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold);
332}
333
334static ssize_t mtd_bitflip_threshold_store(struct device *dev,
335 struct device_attribute *attr,
336 const char *buf, size_t count)
337{
338 struct mtd_info *mtd = dev_get_drvdata(dev);
339 unsigned int bitflip_threshold;
340 int retval;
341
342 retval = kstrtouint(buf, 0, &bitflip_threshold);
343 if (retval)
344 return retval;
345
346 mtd->bitflip_threshold = bitflip_threshold;
347 return count;
348}
349static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
350 mtd_bitflip_threshold_show,
351 mtd_bitflip_threshold_store);
352
353static ssize_t mtd_ecc_step_size_show(struct device *dev,
354 struct device_attribute *attr, char *buf)
355{
356 struct mtd_info *mtd = dev_get_drvdata(dev);
357
358 return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_step_size);
359
360}
361static DEVICE_ATTR(ecc_step_size, S_IRUGO, mtd_ecc_step_size_show, NULL);
362
363static struct attribute *mtd_attrs[] = {
364 &dev_attr_type.attr,
365 &dev_attr_flags.attr,
366 &dev_attr_size.attr,
367 &dev_attr_erasesize.attr,
368 &dev_attr_writesize.attr,
369 &dev_attr_subpagesize.attr,
370 &dev_attr_oobsize.attr,
371 &dev_attr_numeraseregions.attr,
372 &dev_attr_name.attr,
373 &dev_attr_ecc_strength.attr,
374 &dev_attr_ecc_step_size.attr,
375 &dev_attr_bitflip_threshold.attr,
376 NULL,
377};
378ATTRIBUTE_GROUPS(mtd);
379
380static struct device_type mtd_devtype = {
381 .name = "mtd",
382 .groups = mtd_groups,
383 .release = mtd_release,
384};
385#endif
386
387
388
389
390
391
392
393
394
395
396
397int add_mtd_device(struct mtd_info *mtd)
398{
399#ifndef __UBOOT__
400 struct mtd_notifier *not;
401#endif
402 int i, error;
403
404#ifndef __UBOOT__
405 if (!mtd->backing_dev_info) {
406 switch (mtd->type) {
407 case MTD_RAM:
408 mtd->backing_dev_info = &mtd_bdi_rw_mappable;
409 break;
410 case MTD_ROM:
411 mtd->backing_dev_info = &mtd_bdi_ro_mappable;
412 break;
413 default:
414 mtd->backing_dev_info = &mtd_bdi_unmappable;
415 break;
416 }
417 }
418#endif
419
420 BUG_ON(mtd->writesize == 0);
421 mutex_lock(&mtd_table_mutex);
422
423 i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
424 if (i < 0)
425 goto fail_locked;
426
427 mtd->index = i;
428 mtd->usecount = 0;
429
430
431 if (mtd->bitflip_threshold == 0)
432 mtd->bitflip_threshold = mtd->ecc_strength;
433
434 if (is_power_of_2(mtd->erasesize))
435 mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
436 else
437 mtd->erasesize_shift = 0;
438
439 if (is_power_of_2(mtd->writesize))
440 mtd->writesize_shift = ffs(mtd->writesize) - 1;
441 else
442 mtd->writesize_shift = 0;
443
444 mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
445 mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
446
447
448 if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) {
449 error = mtd_unlock(mtd, 0, mtd->size);
450 if (error && error != -EOPNOTSUPP)
451 printk(KERN_WARNING
452 "%s: unlock failed, writes may not work\n",
453 mtd->name);
454 }
455
456#ifndef __UBOOT__
457
458
459
460 mtd->dev.type = &mtd_devtype;
461 mtd->dev.class = &mtd_class;
462 mtd->dev.devt = MTD_DEVT(i);
463 dev_set_name(&mtd->dev, "mtd%d", i);
464 dev_set_drvdata(&mtd->dev, mtd);
465 if (device_register(&mtd->dev) != 0)
466 goto fail_added;
467
468 if (MTD_DEVT(i))
469 device_create(&mtd_class, mtd->dev.parent,
470 MTD_DEVT(i) + 1,
471 NULL, "mtd%dro", i);
472
473 pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
474
475
476 list_for_each_entry(not, &mtd_notifiers, list)
477 not->add(mtd);
478#else
479 pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
480#endif
481
482 mutex_unlock(&mtd_table_mutex);
483
484
485
486
487 __module_get(THIS_MODULE);
488 return 0;
489
490#ifndef __UBOOT__
491fail_added:
492 idr_remove(&mtd_idr, i);
493#endif
494fail_locked:
495 mutex_unlock(&mtd_table_mutex);
496 return 1;
497}
498
499
500
501
502
503
504
505
506
507
508
509int del_mtd_device(struct mtd_info *mtd)
510{
511 int ret;
512#ifndef __UBOOT__
513 struct mtd_notifier *not;
514#endif
515
516 mutex_lock(&mtd_table_mutex);
517
518 if (idr_find(&mtd_idr, mtd->index) != mtd) {
519 ret = -ENODEV;
520 goto out_error;
521 }
522
523#ifndef __UBOOT__
524
525
526 list_for_each_entry(not, &mtd_notifiers, list)
527 not->remove(mtd);
528#endif
529
530 if (mtd->usecount) {
531 printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
532 mtd->index, mtd->name, mtd->usecount);
533 ret = -EBUSY;
534 } else {
535#ifndef __UBOOT__
536 device_unregister(&mtd->dev);
537#endif
538
539 idr_remove(&mtd_idr, mtd->index);
540
541 module_put(THIS_MODULE);
542 ret = 0;
543 }
544
545out_error:
546 mutex_unlock(&mtd_table_mutex);
547 return ret;
548}
549
550#ifndef __UBOOT__
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
580 struct mtd_part_parser_data *parser_data,
581 const struct mtd_partition *parts,
582 int nr_parts)
583{
584 int err;
585 struct mtd_partition *real_parts;
586
587 err = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
588 if (err <= 0 && nr_parts && parts) {
589 real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
590 GFP_KERNEL);
591 if (!real_parts)
592 err = -ENOMEM;
593 else
594 err = nr_parts;
595 }
596
597 if (err > 0) {
598 err = add_mtd_partitions(mtd, real_parts, err);
599 kfree(real_parts);
600 } else if (err == 0) {
601 err = add_mtd_device(mtd);
602 if (err == 1)
603 err = -ENODEV;
604 }
605
606 return err;
607}
608EXPORT_SYMBOL_GPL(mtd_device_parse_register);
609
610
611
612
613
614
615
616int mtd_device_unregister(struct mtd_info *master)
617{
618 int err;
619
620 err = del_mtd_partitions(master);
621 if (err)
622 return err;
623
624 if (!device_is_registered(&master->dev))
625 return 0;
626
627 return del_mtd_device(master);
628}
629EXPORT_SYMBOL_GPL(mtd_device_unregister);
630
631
632
633
634
635
636
637
638
639void register_mtd_user (struct mtd_notifier *new)
640{
641 struct mtd_info *mtd;
642
643 mutex_lock(&mtd_table_mutex);
644
645 list_add(&new->list, &mtd_notifiers);
646
647 __module_get(THIS_MODULE);
648
649 mtd_for_each_device(mtd)
650 new->add(mtd);
651
652 mutex_unlock(&mtd_table_mutex);
653}
654EXPORT_SYMBOL_GPL(register_mtd_user);
655
656
657
658
659
660
661
662
663
664
665int unregister_mtd_user (struct mtd_notifier *old)
666{
667 struct mtd_info *mtd;
668
669 mutex_lock(&mtd_table_mutex);
670
671 module_put(THIS_MODULE);
672
673 mtd_for_each_device(mtd)
674 old->remove(mtd);
675
676 list_del(&old->list);
677 mutex_unlock(&mtd_table_mutex);
678 return 0;
679}
680EXPORT_SYMBOL_GPL(unregister_mtd_user);
681#endif
682
683
684
685
686
687
688
689
690
691
692
693
694struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
695{
696 struct mtd_info *ret = NULL, *other;
697 int err = -ENODEV;
698
699 mutex_lock(&mtd_table_mutex);
700
701 if (num == -1) {
702 mtd_for_each_device(other) {
703 if (other == mtd) {
704 ret = mtd;
705 break;
706 }
707 }
708 } else if (num >= 0) {
709 ret = idr_find(&mtd_idr, num);
710 if (mtd && mtd != ret)
711 ret = NULL;
712 }
713
714 if (!ret) {
715 ret = ERR_PTR(err);
716 goto out;
717 }
718
719 err = __get_mtd_device(ret);
720 if (err)
721 ret = ERR_PTR(err);
722out:
723 mutex_unlock(&mtd_table_mutex);
724 return ret;
725}
726EXPORT_SYMBOL_GPL(get_mtd_device);
727
728
729int __get_mtd_device(struct mtd_info *mtd)
730{
731 int err;
732
733 if (!try_module_get(mtd->owner))
734 return -ENODEV;
735
736 if (mtd->_get_device) {
737 err = mtd->_get_device(mtd);
738
739 if (err) {
740 module_put(mtd->owner);
741 return err;
742 }
743 }
744 mtd->usecount++;
745 return 0;
746}
747EXPORT_SYMBOL_GPL(__get_mtd_device);
748
749
750
751
752
753
754
755
756
757struct mtd_info *get_mtd_device_nm(const char *name)
758{
759 int err = -ENODEV;
760 struct mtd_info *mtd = NULL, *other;
761
762 mutex_lock(&mtd_table_mutex);
763
764 mtd_for_each_device(other) {
765 if (!strcmp(name, other->name)) {
766 mtd = other;
767 break;
768 }
769 }
770
771 if (!mtd)
772 goto out_unlock;
773
774 err = __get_mtd_device(mtd);
775 if (err)
776 goto out_unlock;
777
778 mutex_unlock(&mtd_table_mutex);
779 return mtd;
780
781out_unlock:
782 mutex_unlock(&mtd_table_mutex);
783 return ERR_PTR(err);
784}
785EXPORT_SYMBOL_GPL(get_mtd_device_nm);
786
787#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
788
789
790
791
792
793
794
795
796
797
798
799void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
800 const uint64_t length, uint64_t *len_incl_bad,
801 int *truncated)
802{
803 *truncated = 0;
804 *len_incl_bad = 0;
805
806 if (!mtd->_block_isbad) {
807 *len_incl_bad = length;
808 return;
809 }
810
811 uint64_t len_excl_bad = 0;
812 uint64_t block_len;
813
814 while (len_excl_bad < length) {
815 if (offset >= mtd->size) {
816 *truncated = 1;
817 return;
818 }
819
820 block_len = mtd->erasesize - (offset & (mtd->erasesize - 1));
821
822 if (!mtd->_block_isbad(mtd, offset & ~(mtd->erasesize - 1)))
823 len_excl_bad += block_len;
824
825 *len_incl_bad += block_len;
826 offset += block_len;
827 }
828}
829#endif
830
831void put_mtd_device(struct mtd_info *mtd)
832{
833 mutex_lock(&mtd_table_mutex);
834 __put_mtd_device(mtd);
835 mutex_unlock(&mtd_table_mutex);
836
837}
838EXPORT_SYMBOL_GPL(put_mtd_device);
839
840void __put_mtd_device(struct mtd_info *mtd)
841{
842 --mtd->usecount;
843 BUG_ON(mtd->usecount < 0);
844
845 if (mtd->_put_device)
846 mtd->_put_device(mtd);
847
848 module_put(mtd->owner);
849}
850EXPORT_SYMBOL_GPL(__put_mtd_device);
851
852
853
854
855
856
857
858
859int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
860{
861 if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
862 return -EINVAL;
863 if (!(mtd->flags & MTD_WRITEABLE))
864 return -EROFS;
865 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
866 if (!instr->len) {
867 instr->state = MTD_ERASE_DONE;
868 mtd_erase_callback(instr);
869 return 0;
870 }
871 return mtd->_erase(mtd, instr);
872}
873EXPORT_SYMBOL_GPL(mtd_erase);
874
875#ifndef __UBOOT__
876
877
878
879int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
880 void **virt, resource_size_t *phys)
881{
882 *retlen = 0;
883 *virt = NULL;
884 if (phys)
885 *phys = 0;
886 if (!mtd->_point)
887 return -EOPNOTSUPP;
888 if (from < 0 || from > mtd->size || len > mtd->size - from)
889 return -EINVAL;
890 if (!len)
891 return 0;
892 return mtd->_point(mtd, from, len, retlen, virt, phys);
893}
894EXPORT_SYMBOL_GPL(mtd_point);
895
896
897int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
898{
899 if (!mtd->_point)
900 return -EOPNOTSUPP;
901 if (from < 0 || from > mtd->size || len > mtd->size - from)
902 return -EINVAL;
903 if (!len)
904 return 0;
905 return mtd->_unpoint(mtd, from, len);
906}
907EXPORT_SYMBOL_GPL(mtd_unpoint);
908#endif
909
910
911
912
913
914
915unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
916 unsigned long offset, unsigned long flags)
917{
918 if (!mtd->_get_unmapped_area)
919 return -EOPNOTSUPP;
920 if (offset > mtd->size || len > mtd->size - offset)
921 return -EINVAL;
922 return mtd->_get_unmapped_area(mtd, len, offset, flags);
923}
924EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
925
926int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
927 u_char *buf)
928{
929 int ret_code;
930 *retlen = 0;
931 if (from < 0 || from > mtd->size || len > mtd->size - from)
932 return -EINVAL;
933 if (!len)
934 return 0;
935
936
937
938
939
940
941 ret_code = mtd->_read(mtd, from, len, retlen, buf);
942 if (unlikely(ret_code < 0))
943 return ret_code;
944 if (mtd->ecc_strength == 0)
945 return 0;
946 return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
947}
948EXPORT_SYMBOL_GPL(mtd_read);
949
950int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
951 const u_char *buf)
952{
953 *retlen = 0;
954 if (to < 0 || to > mtd->size || len > mtd->size - to)
955 return -EINVAL;
956 if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
957 return -EROFS;
958 if (!len)
959 return 0;
960 return mtd->_write(mtd, to, len, retlen, buf);
961}
962EXPORT_SYMBOL_GPL(mtd_write);
963
964
965
966
967
968
969
970
971int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
972 const u_char *buf)
973{
974 *retlen = 0;
975 if (!mtd->_panic_write)
976 return -EOPNOTSUPP;
977 if (to < 0 || to > mtd->size || len > mtd->size - to)
978 return -EINVAL;
979 if (!(mtd->flags & MTD_WRITEABLE))
980 return -EROFS;
981 if (!len)
982 return 0;
983 return mtd->_panic_write(mtd, to, len, retlen, buf);
984}
985EXPORT_SYMBOL_GPL(mtd_panic_write);
986
987int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
988{
989 int ret_code;
990 ops->retlen = ops->oobretlen = 0;
991 if (!mtd->_read_oob)
992 return -EOPNOTSUPP;
993
994
995
996
997
998
999 ret_code = mtd->_read_oob(mtd, from, ops);
1000 if (unlikely(ret_code < 0))
1001 return ret_code;
1002 if (mtd->ecc_strength == 0)
1003 return 0;
1004 return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
1005}
1006EXPORT_SYMBOL_GPL(mtd_read_oob);
1007
1008
1009
1010
1011
1012
1013int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
1014 struct otp_info *buf)
1015{
1016 if (!mtd->_get_fact_prot_info)
1017 return -EOPNOTSUPP;
1018 if (!len)
1019 return 0;
1020 return mtd->_get_fact_prot_info(mtd, len, retlen, buf);
1021}
1022EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info);
1023
1024int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
1025 size_t *retlen, u_char *buf)
1026{
1027 *retlen = 0;
1028 if (!mtd->_read_fact_prot_reg)
1029 return -EOPNOTSUPP;
1030 if (!len)
1031 return 0;
1032 return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf);
1033}
1034EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg);
1035
1036int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
1037 struct otp_info *buf)
1038{
1039 if (!mtd->_get_user_prot_info)
1040 return -EOPNOTSUPP;
1041 if (!len)
1042 return 0;
1043 return mtd->_get_user_prot_info(mtd, len, retlen, buf);
1044}
1045EXPORT_SYMBOL_GPL(mtd_get_user_prot_info);
1046
1047int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
1048 size_t *retlen, u_char *buf)
1049{
1050 *retlen = 0;
1051 if (!mtd->_read_user_prot_reg)
1052 return -EOPNOTSUPP;
1053 if (!len)
1054 return 0;
1055 return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf);
1056}
1057EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
1058
1059int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
1060 size_t *retlen, u_char *buf)
1061{
1062 int ret;
1063
1064 *retlen = 0;
1065 if (!mtd->_write_user_prot_reg)
1066 return -EOPNOTSUPP;
1067 if (!len)
1068 return 0;
1069 ret = mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
1070 if (ret)
1071 return ret;
1072
1073
1074
1075
1076
1077 return (*retlen) ? 0 : -ENOSPC;
1078}
1079EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);
1080
1081int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
1082{
1083 if (!mtd->_lock_user_prot_reg)
1084 return -EOPNOTSUPP;
1085 if (!len)
1086 return 0;
1087 return mtd->_lock_user_prot_reg(mtd, from, len);
1088}
1089EXPORT_SYMBOL_GPL(mtd_lock_user_prot_reg);
1090
1091
1092int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1093{
1094 if (!mtd->_lock)
1095 return -EOPNOTSUPP;
1096 if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
1097 return -EINVAL;
1098 if (!len)
1099 return 0;
1100 return mtd->_lock(mtd, ofs, len);
1101}
1102EXPORT_SYMBOL_GPL(mtd_lock);
1103
1104int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1105{
1106 if (!mtd->_unlock)
1107 return -EOPNOTSUPP;
1108 if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
1109 return -EINVAL;
1110 if (!len)
1111 return 0;
1112 return mtd->_unlock(mtd, ofs, len);
1113}
1114EXPORT_SYMBOL_GPL(mtd_unlock);
1115
1116int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1117{
1118 if (!mtd->_is_locked)
1119 return -EOPNOTSUPP;
1120 if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
1121 return -EINVAL;
1122 if (!len)
1123 return 0;
1124 return mtd->_is_locked(mtd, ofs, len);
1125}
1126EXPORT_SYMBOL_GPL(mtd_is_locked);
1127
1128int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
1129{
1130 if (!mtd->_block_isbad)
1131 return 0;
1132 if (ofs < 0 || ofs > mtd->size)
1133 return -EINVAL;
1134 return mtd->_block_isbad(mtd, ofs);
1135}
1136EXPORT_SYMBOL_GPL(mtd_block_isbad);
1137
1138int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
1139{
1140 if (!mtd->_block_markbad)
1141 return -EOPNOTSUPP;
1142 if (ofs < 0 || ofs > mtd->size)
1143 return -EINVAL;
1144 if (!(mtd->flags & MTD_WRITEABLE))
1145 return -EROFS;
1146 return mtd->_block_markbad(mtd, ofs);
1147}
1148EXPORT_SYMBOL_GPL(mtd_block_markbad);
1149
1150#ifndef __UBOOT__
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162static int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
1163 unsigned long count, loff_t to, size_t *retlen)
1164{
1165 unsigned long i;
1166 size_t totlen = 0, thislen;
1167 int ret = 0;
1168
1169 for (i = 0; i < count; i++) {
1170 if (!vecs[i].iov_len)
1171 continue;
1172 ret = mtd_write(mtd, to, vecs[i].iov_len, &thislen,
1173 vecs[i].iov_base);
1174 totlen += thislen;
1175 if (ret || thislen != vecs[i].iov_len)
1176 break;
1177 to += vecs[i].iov_len;
1178 }
1179 *retlen = totlen;
1180 return ret;
1181}
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
1195 unsigned long count, loff_t to, size_t *retlen)
1196{
1197 *retlen = 0;
1198 if (!(mtd->flags & MTD_WRITEABLE))
1199 return -EROFS;
1200 if (!mtd->_writev)
1201 return default_mtd_writev(mtd, vecs, count, to, retlen);
1202 return mtd->_writev(mtd, vecs, count, to, retlen);
1203}
1204EXPORT_SYMBOL_GPL(mtd_writev);
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size)
1231{
1232 gfp_t flags = __GFP_NOWARN | __GFP_WAIT |
1233 __GFP_NORETRY | __GFP_NO_KSWAPD;
1234 size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE);
1235 void *kbuf;
1236
1237 *size = min_t(size_t, *size, KMALLOC_MAX_SIZE);
1238
1239 while (*size > min_alloc) {
1240 kbuf = kmalloc(*size, flags);
1241 if (kbuf)
1242 return kbuf;
1243
1244 *size >>= 1;
1245 *size = ALIGN(*size, mtd->writesize);
1246 }
1247
1248
1249
1250
1251
1252 return kmalloc(*size, GFP_KERNEL);
1253}
1254EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to);
1255#endif
1256
1257#ifdef CONFIG_PROC_FS
1258
1259
1260
1261
1262static int mtd_proc_show(struct seq_file *m, void *v)
1263{
1264 struct mtd_info *mtd;
1265
1266 seq_puts(m, "dev: size erasesize name\n");
1267 mutex_lock(&mtd_table_mutex);
1268 mtd_for_each_device(mtd) {
1269 seq_printf(m, "mtd%d: %8.8llx %8.8x \"%s\"\n",
1270 mtd->index, (unsigned long long)mtd->size,
1271 mtd->erasesize, mtd->name);
1272 }
1273 mutex_unlock(&mtd_table_mutex);
1274 return 0;
1275}
1276
1277static int mtd_proc_open(struct inode *inode, struct file *file)
1278{
1279 return single_open(file, mtd_proc_show, NULL);
1280}
1281
1282static const struct file_operations mtd_proc_ops = {
1283 .open = mtd_proc_open,
1284 .read = seq_read,
1285 .llseek = seq_lseek,
1286 .release = single_release,
1287};
1288#endif
1289
1290
1291
1292
1293#ifndef __UBOOT__
1294static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
1295{
1296 int ret;
1297
1298 ret = bdi_init(bdi);
1299 if (!ret)
1300 ret = bdi_register(bdi, NULL, "%s", name);
1301
1302 if (ret)
1303 bdi_destroy(bdi);
1304
1305 return ret;
1306}
1307
1308static struct proc_dir_entry *proc_mtd;
1309
1310static int __init init_mtd(void)
1311{
1312 int ret;
1313
1314 ret = class_register(&mtd_class);
1315 if (ret)
1316 goto err_reg;
1317
1318 ret = mtd_bdi_init(&mtd_bdi_unmappable, "mtd-unmap");
1319 if (ret)
1320 goto err_bdi1;
1321
1322 ret = mtd_bdi_init(&mtd_bdi_ro_mappable, "mtd-romap");
1323 if (ret)
1324 goto err_bdi2;
1325
1326 ret = mtd_bdi_init(&mtd_bdi_rw_mappable, "mtd-rwmap");
1327 if (ret)
1328 goto err_bdi3;
1329
1330 proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
1331
1332 ret = init_mtdchar();
1333 if (ret)
1334 goto out_procfs;
1335
1336 return 0;
1337
1338out_procfs:
1339 if (proc_mtd)
1340 remove_proc_entry("mtd", NULL);
1341err_bdi3:
1342 bdi_destroy(&mtd_bdi_ro_mappable);
1343err_bdi2:
1344 bdi_destroy(&mtd_bdi_unmappable);
1345err_bdi1:
1346 class_unregister(&mtd_class);
1347err_reg:
1348 pr_err("Error registering mtd class or bdi: %d\n", ret);
1349 return ret;
1350}
1351
1352static void __exit cleanup_mtd(void)
1353{
1354 cleanup_mtdchar();
1355 if (proc_mtd)
1356 remove_proc_entry("mtd", NULL);
1357 class_unregister(&mtd_class);
1358 bdi_destroy(&mtd_bdi_unmappable);
1359 bdi_destroy(&mtd_bdi_ro_mappable);
1360 bdi_destroy(&mtd_bdi_rw_mappable);
1361}
1362
1363module_init(init_mtd);
1364module_exit(cleanup_mtd);
1365#endif
1366
1367MODULE_LICENSE("GPL");
1368MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1369MODULE_DESCRIPTION("Core MTD registration and access routines");
1370