mtd.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. * File : mtd.c
  8. *
  9. * Change Logs:
  10. * Date Author Notes
  11. 2018-09-10 heyuanjie87 first version
  12. */
  13. #include <drivers/mtd.h>
  14. static rt_mtd_t* mtd_part_alloc(rt_mtd_t *master, const struct mtd_part *part)
  15. {
  16. rt_mtd_t *slave;
  17. slave = rt_malloc(sizeof(rt_mtd_t));
  18. if (slave == RT_NULL)
  19. goto out;
  20. slave->master = master;
  21. *slave = *master;
  22. slave->size = part->size;
  23. slave->offset = part->offset;
  24. out:
  25. return slave;
  26. }
  27. rt_mtd_t* rt_mtd_get(const char *name)
  28. {
  29. rt_mtd_t *mtd;
  30. mtd = (rt_mtd_t *)rt_device_find(name);
  31. if (mtd == RT_NULL)
  32. return RT_NULL;
  33. if (mtd->parent.type != RT_Device_Class_MTD)
  34. return RT_NULL;
  35. return mtd;
  36. }
  37. /*
  38. * Register MTD driver
  39. *
  40. * @parts partion description
  41. * @np number of partitions
  42. * @return number of unregistered partitions
  43. *
  44. */
  45. int rt_mtd_register(rt_mtd_t *master, const struct mtd_part *parts, int np)
  46. {
  47. int ret;
  48. rt_mtd_t *slave;
  49. master->master = master;
  50. master->parent.type = RT_Device_Class_MTD;
  51. if (np > 0)
  52. {
  53. master->offset = parts->offset;
  54. master->size = parts->size;
  55. ret = rt_device_register((rt_device_t)master, parts->name, 0);
  56. if (ret != 0)
  57. goto _out;
  58. np --;
  59. parts ++;
  60. }
  61. while (np > 0)
  62. {
  63. slave = mtd_part_alloc(master, parts);
  64. if (!slave)
  65. break;
  66. ret = rt_device_register((rt_device_t)slave, parts->name, 0);
  67. if (ret)
  68. break;
  69. parts ++;
  70. np --;
  71. }
  72. _out:
  73. return np;
  74. }
  75. int rt_mtd_block_erase(rt_mtd_t *mtd, uint32_t block)
  76. {
  77. uint32_t total_blks;
  78. loff_t addr;
  79. total_blks = mtd->size/mtd->block_size;
  80. if (block >= total_blks)
  81. return -EINVAL;
  82. addr = mtd->offset + mtd->block_size * block;
  83. return mtd->ops->erase(mtd->master, addr, mtd->block_size);
  84. }
  85. int rt_mtd_block_isbad(rt_mtd_t *mtd, uint32_t block)
  86. {
  87. uint32_t total_blks, offset_blk;
  88. if (!mtd->ops->isbad)
  89. return 0;
  90. total_blks = mtd->size / mtd->block_size;
  91. if (block >= total_blks)
  92. return -EINVAL;
  93. offset_blk = mtd->offset / mtd->block_size;
  94. return mtd->ops->isbad(mtd->master, block + offset_blk);
  95. }
  96. int rt_mtd_block_markbad(rt_mtd_t *mtd, uint32_t block)
  97. {
  98. uint32_t total_blks, offset_blk;
  99. if (!mtd->ops->markbad)
  100. return -EOPNOTSUPP;
  101. total_blks = mtd->size / mtd->block_size;
  102. if (block >= total_blks)
  103. return -EINVAL;
  104. offset_blk = mtd->offset / mtd->block_size;
  105. return mtd->ops->markbad(mtd->master, block + offset_blk);
  106. }
  107. int rt_mtd_erase(rt_mtd_t *mtd, loff_t addr, size_t size)
  108. {
  109. if (addr > mtd->size || (addr + size) > mtd->size)
  110. return -EINVAL;
  111. addr += mtd->offset;
  112. return mtd->ops->erase(mtd->master, addr, size);
  113. }
  114. /*
  115. * Read data only
  116. *
  117. * @from offset to read from
  118. * @return success size or error code
  119. */
  120. int rt_mtd_read(rt_mtd_t *mtd, loff_t from, uint8_t *buf, size_t len)
  121. {
  122. int ret;
  123. struct mtd_io_desc desc = {0};
  124. if (from < 0 || from >= (loff_t)mtd->size || len > mtd->size - from)
  125. return -EINVAL;
  126. if (!len)
  127. return 0;
  128. desc.datbuf = buf;
  129. desc.datlen = len;
  130. ret = mtd->ops->read(mtd->master, from + mtd->offset, &desc);
  131. if (ret)
  132. return ret;
  133. return desc.datretlen;
  134. }
  135. /**
  136. * Write data only
  137. *
  138. * @to offset to write from
  139. * @return success size or error code
  140. */
  141. int rt_mtd_write(rt_mtd_t *mtd, loff_t to, const uint8_t *buf, size_t len)
  142. {
  143. int ret;
  144. struct mtd_io_desc desc = {0};
  145. if (to < 0 || to >= (loff_t)mtd->size || len > mtd->size - to)
  146. return -EINVAL;
  147. if (!mtd->ops->write)
  148. return -EROFS;
  149. if (!len)
  150. return 0;
  151. desc.datbuf = (uint8_t*)buf;
  152. desc.datlen = len;
  153. ret = mtd->ops->write(mtd->master, to + mtd->offset, &desc);
  154. if (ret)
  155. return ret;
  156. return desc.datretlen;
  157. }
  158. /**
  159. * Read data and/or out-of-band
  160. *
  161. * @from offset to read from
  162. * @desc sector operation description structure
  163. * @return error code, 0 success
  164. */
  165. int rt_mtd_read_oob(rt_mtd_t *mtd, loff_t from, struct mtd_io_desc *desc)
  166. {
  167. desc->datretlen = 0;
  168. desc->oobretlen = 0;
  169. if (from < 0 || from >= (loff_t)mtd->size)
  170. return -EINVAL;
  171. if (desc->datbuf && (desc->datlen > (mtd->size - from)))
  172. return -EINVAL;
  173. return mtd->ops->read(mtd->master, from + mtd->offset, desc);
  174. }
  175. /**
  176. * Write data and/or out-of-band
  177. *
  178. * @to offset to read from
  179. * @desc sector operation description structure
  180. * @return error code, 0 success
  181. */
  182. int rt_mtd_write_oob(rt_mtd_t *mtd, loff_t to, struct mtd_io_desc *desc)
  183. {
  184. desc->datretlen = 0;
  185. desc->oobretlen = 0;
  186. if (to < 0 || to >= (loff_t)mtd->size)
  187. return -EINVAL;
  188. if (desc->datbuf && (desc->datlen >(mtd->size - to)))
  189. return -EINVAL;
  190. return mtd->ops->write(mtd->master, to + mtd->offset, desc);
  191. }