diff options
-rw-r--r-- | drivers/mtd/mtdcore.c | 148 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 129 |
2 files changed, 165 insertions, 112 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 5ea22cf357fb..8d5e103695f9 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
@@ -683,6 +683,154 @@ void __put_mtd_device(struct mtd_info *mtd) | |||
683 | EXPORT_SYMBOL_GPL(__put_mtd_device); | 683 | EXPORT_SYMBOL_GPL(__put_mtd_device); |
684 | 684 | ||
685 | /* | 685 | /* |
686 | * Erase is an asynchronous operation. Device drivers are supposed | ||
687 | * to call instr->callback() whenever the operation completes, even | ||
688 | * if it completes with a failure. | ||
689 | * Callers are supposed to pass a callback function and wait for it | ||
690 | * to be called before writing to the block. | ||
691 | */ | ||
692 | int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) | ||
693 | { | ||
694 | if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr) | ||
695 | return -EINVAL; | ||
696 | return mtd->_erase(mtd, instr); | ||
697 | } | ||
698 | EXPORT_SYMBOL_GPL(mtd_erase); | ||
699 | |||
700 | /* | ||
701 | * This stuff for eXecute-In-Place. phys is optional and may be set to NULL. | ||
702 | */ | ||
703 | int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, | ||
704 | void **virt, resource_size_t *phys) | ||
705 | { | ||
706 | *retlen = 0; | ||
707 | if (!mtd->_point) | ||
708 | return -EOPNOTSUPP; | ||
709 | if (from < 0 || from > mtd->size || len > mtd->size - from) | ||
710 | return -EINVAL; | ||
711 | return mtd->_point(mtd, from, len, retlen, virt, phys); | ||
712 | } | ||
713 | EXPORT_SYMBOL_GPL(mtd_point); | ||
714 | |||
715 | /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ | ||
716 | int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len) | ||
717 | { | ||
718 | if (!mtd->_point) | ||
719 | return -EOPNOTSUPP; | ||
720 | if (from < 0 || from > mtd->size || len > mtd->size - from) | ||
721 | return -EINVAL; | ||
722 | return mtd->_unpoint(mtd, from, len); | ||
723 | } | ||
724 | EXPORT_SYMBOL_GPL(mtd_unpoint); | ||
725 | |||
726 | /* | ||
727 | * Allow NOMMU mmap() to directly map the device (if not NULL) | ||
728 | * - return the address to which the offset maps | ||
729 | * - return -ENOSYS to indicate refusal to do the mapping | ||
730 | */ | ||
731 | unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len, | ||
732 | unsigned long offset, unsigned long flags) | ||
733 | { | ||
734 | if (!mtd->_get_unmapped_area) | ||
735 | return -EOPNOTSUPP; | ||
736 | if (offset > mtd->size || len > mtd->size - offset) | ||
737 | return -EINVAL; | ||
738 | return mtd->_get_unmapped_area(mtd, len, offset, flags); | ||
739 | } | ||
740 | EXPORT_SYMBOL_GPL(mtd_get_unmapped_area); | ||
741 | |||
742 | int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, | ||
743 | u_char *buf) | ||
744 | { | ||
745 | if (from < 0 || from > mtd->size || len > mtd->size - from) | ||
746 | return -EINVAL; | ||
747 | return mtd->_read(mtd, from, len, retlen, buf); | ||
748 | } | ||
749 | EXPORT_SYMBOL_GPL(mtd_read); | ||
750 | |||
751 | int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, | ||
752 | const u_char *buf) | ||
753 | { | ||
754 | *retlen = 0; | ||
755 | if (!mtd->_write) | ||
756 | return -EROFS; | ||
757 | if (to < 0 || to > mtd->size || len > mtd->size - to) | ||
758 | return -EINVAL; | ||
759 | return mtd->_write(mtd, to, len, retlen, buf); | ||
760 | } | ||
761 | EXPORT_SYMBOL_GPL(mtd_write); | ||
762 | |||
763 | /* | ||
764 | * In blackbox flight recorder like scenarios we want to make successful writes | ||
765 | * in interrupt context. panic_write() is only intended to be called when its | ||
766 | * known the kernel is about to panic and we need the write to succeed. Since | ||
767 | * the kernel is not going to be running for much longer, this function can | ||
768 | * break locks and delay to ensure the write succeeds (but not sleep). | ||
769 | */ | ||
770 | int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, | ||
771 | const u_char *buf) | ||
772 | { | ||
773 | *retlen = 0; | ||
774 | if (!mtd->_panic_write) | ||
775 | return -EOPNOTSUPP; | ||
776 | if (to < 0 || to > mtd->size || len > mtd->size - to) | ||
777 | return -EINVAL; | ||
778 | return mtd->_panic_write(mtd, to, len, retlen, buf); | ||
779 | } | ||
780 | EXPORT_SYMBOL_GPL(mtd_panic_write); | ||
781 | |||
782 | /* Chip-supported device locking */ | ||
783 | int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
784 | { | ||
785 | if (!mtd->_lock) | ||
786 | return -EOPNOTSUPP; | ||
787 | if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) | ||
788 | return -EINVAL; | ||
789 | return mtd->_lock(mtd, ofs, len); | ||
790 | } | ||
791 | EXPORT_SYMBOL_GPL(mtd_lock); | ||
792 | |||
793 | int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
794 | { | ||
795 | if (!mtd->_unlock) | ||
796 | return -EOPNOTSUPP; | ||
797 | if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) | ||
798 | return -EINVAL; | ||
799 | return mtd->_unlock(mtd, ofs, len); | ||
800 | } | ||
801 | EXPORT_SYMBOL_GPL(mtd_unlock); | ||
802 | |||
803 | int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
804 | { | ||
805 | if (!mtd->_is_locked) | ||
806 | return -EOPNOTSUPP; | ||
807 | if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) | ||
808 | return -EINVAL; | ||
809 | return mtd->_is_locked(mtd, ofs, len); | ||
810 | } | ||
811 | EXPORT_SYMBOL_GPL(mtd_is_locked); | ||
812 | |||
813 | int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) | ||
814 | { | ||
815 | if (!mtd->_block_isbad) | ||
816 | return 0; | ||
817 | if (ofs < 0 || ofs > mtd->size) | ||
818 | return -EINVAL; | ||
819 | return mtd->_block_isbad(mtd, ofs); | ||
820 | } | ||
821 | EXPORT_SYMBOL_GPL(mtd_block_isbad); | ||
822 | |||
823 | int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||
824 | { | ||
825 | if (!mtd->_block_markbad) | ||
826 | return -EOPNOTSUPP; | ||
827 | if (ofs < 0 || ofs > mtd->size) | ||
828 | return -EINVAL; | ||
829 | return mtd->_block_markbad(mtd, ofs); | ||
830 | } | ||
831 | EXPORT_SYMBOL_GPL(mtd_block_markbad); | ||
832 | |||
833 | /* | ||
686 | * default_mtd_writev - the default writev method | 834 | * default_mtd_writev - the default writev method |
687 | * @mtd: mtd device description object pointer | 835 | * @mtd: mtd device description object pointer |
688 | * @vecs: the vectors to write | 836 | * @vecs: the vectors to write |
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 8c243117c087..317a80c4d54c 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -240,83 +240,18 @@ struct mtd_info { | |||
240 | int usecount; | 240 | int usecount; |
241 | }; | 241 | }; |
242 | 242 | ||
243 | /* | 243 | int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); |
244 | * Erase is an asynchronous operation. Device drivers are supposed | 244 | int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, |
245 | * to call instr->callback() whenever the operation completes, even | 245 | void **virt, resource_size_t *phys); |
246 | * if it completes with a failure. | 246 | int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len); |
247 | * Callers are supposed to pass a callback function and wait for it | 247 | unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len, |
248 | * to be called before writing to the block. | 248 | unsigned long offset, unsigned long flags); |
249 | */ | 249 | int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, |
250 | static inline int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) | 250 | u_char *buf); |
251 | { | 251 | int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, |
252 | return mtd->_erase(mtd, instr); | 252 | const u_char *buf); |
253 | } | 253 | int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, |
254 | 254 | const u_char *buf); | |
255 | /* | ||
256 | * This stuff for eXecute-In-Place. phys is optional and may be set to NULL. | ||
257 | */ | ||
258 | static inline int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, | ||
259 | size_t *retlen, void **virt, resource_size_t *phys) | ||
260 | { | ||
261 | *retlen = 0; | ||
262 | if (!mtd->_point) | ||
263 | return -EOPNOTSUPP; | ||
264 | return mtd->_point(mtd, from, len, retlen, virt, phys); | ||
265 | } | ||
266 | |||
267 | /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ | ||
268 | static inline int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len) | ||
269 | { | ||
270 | if (!mtd->_point) | ||
271 | return -EOPNOTSUPP; | ||
272 | return mtd->_unpoint(mtd, from, len); | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Allow NOMMU mmap() to directly map the device (if not NULL) | ||
277 | * - return the address to which the offset maps | ||
278 | * - return -ENOSYS to indicate refusal to do the mapping | ||
279 | */ | ||
280 | static inline unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, | ||
281 | unsigned long len, | ||
282 | unsigned long offset, | ||
283 | unsigned long flags) | ||
284 | { | ||
285 | if (!mtd->_get_unmapped_area) | ||
286 | return -EOPNOTSUPP; | ||
287 | return mtd->_get_unmapped_area(mtd, len, offset, flags); | ||
288 | } | ||
289 | |||
290 | static inline int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
291 | size_t *retlen, u_char *buf) | ||
292 | { | ||
293 | return mtd->_read(mtd, from, len, retlen, buf); | ||
294 | } | ||
295 | |||
296 | static inline int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
297 | size_t *retlen, const u_char *buf) | ||
298 | { | ||
299 | *retlen = 0; | ||
300 | if (!mtd->_write) | ||
301 | return -EROFS; | ||
302 | return mtd->_write(mtd, to, len, retlen, buf); | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * In blackbox flight recorder like scenarios we want to make successful writes | ||
307 | * in interrupt context. panic_write() is only intended to be called when its | ||
308 | * known the kernel is about to panic and we need the write to succeed. Since | ||
309 | * the kernel is not going to be running for much longer, this function can | ||
310 | * break locks and delay to ensure the write succeeds (but not sleep). | ||
311 | */ | ||
312 | static inline int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
313 | size_t *retlen, const u_char *buf) | ||
314 | { | ||
315 | *retlen = 0; | ||
316 | if (!mtd->_panic_write) | ||
317 | return -EOPNOTSUPP; | ||
318 | return mtd->_panic_write(mtd, to, len, retlen, buf); | ||
319 | } | ||
320 | 255 | ||
321 | static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from, | 256 | static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from, |
322 | struct mtd_oob_ops *ops) | 257 | struct mtd_oob_ops *ops) |
@@ -405,27 +340,11 @@ static inline void mtd_sync(struct mtd_info *mtd) | |||
405 | mtd->_sync(mtd); | 340 | mtd->_sync(mtd); |
406 | } | 341 | } |
407 | 342 | ||
408 | /* Chip-supported device locking */ | 343 | int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); |
409 | static inline int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | 344 | int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); |
410 | { | 345 | int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len); |
411 | if (!mtd->_lock) | 346 | int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs); |
412 | return -EOPNOTSUPP; | 347 | int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs); |
413 | return mtd->_lock(mtd, ofs, len); | ||
414 | } | ||
415 | |||
416 | static inline int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
417 | { | ||
418 | if (!mtd->_unlock) | ||
419 | return -EOPNOTSUPP; | ||
420 | return mtd->_unlock(mtd, ofs, len); | ||
421 | } | ||
422 | |||
423 | static inline int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
424 | { | ||
425 | if (!mtd->_is_locked) | ||
426 | return -EOPNOTSUPP; | ||
427 | return mtd->_is_locked(mtd, ofs, len); | ||
428 | } | ||
429 | 348 | ||
430 | static inline int mtd_suspend(struct mtd_info *mtd) | 349 | static inline int mtd_suspend(struct mtd_info *mtd) |
431 | { | 350 | { |
@@ -438,20 +357,6 @@ static inline void mtd_resume(struct mtd_info *mtd) | |||
438 | mtd->_resume(mtd); | 357 | mtd->_resume(mtd); |
439 | } | 358 | } |
440 | 359 | ||
441 | static inline int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) | ||
442 | { | ||
443 | if (!mtd->_block_isbad) | ||
444 | return 0; | ||
445 | return mtd->_block_isbad(mtd, ofs); | ||
446 | } | ||
447 | |||
448 | static inline int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||
449 | { | ||
450 | if (!mtd->_block_markbad) | ||
451 | return -EOPNOTSUPP; | ||
452 | return mtd->_block_markbad(mtd, ofs); | ||
453 | } | ||
454 | |||
455 | static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd) | 360 | static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd) |
456 | { | 361 | { |
457 | if (mtd->erasesize_shift) | 362 | if (mtd->erasesize_shift) |