user_diskio.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #include "user_diskio.h"
  2. #include <furi_hal.h>
  3. #include "sector_cache.h"
  4. static DSTATUS driver_check_status(BYTE lun) {
  5. UNUSED(lun);
  6. DSTATUS status = 0;
  7. if(sd_get_card_state() != SdSpiStatusOK) {
  8. status = STA_NOINIT;
  9. }
  10. return status;
  11. }
  12. static DSTATUS driver_initialize(BYTE pdrv);
  13. static DSTATUS driver_status(BYTE pdrv);
  14. static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
  15. static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
  16. static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff);
  17. Diskio_drvTypeDef sd_fatfs_driver = {
  18. driver_initialize,
  19. driver_status,
  20. driver_read,
  21. driver_write,
  22. driver_ioctl,
  23. };
  24. static inline bool sd_cache_get(uint32_t address, uint32_t* data) {
  25. uint8_t* cached_data = sector_cache_get(address);
  26. if(cached_data) {
  27. memcpy(data, cached_data, SD_BLOCK_SIZE);
  28. return true;
  29. }
  30. return false;
  31. }
  32. static inline void sd_cache_put(uint32_t address, uint32_t* data) {
  33. sector_cache_put(address, (uint8_t*)data);
  34. }
  35. static inline void sd_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) {
  36. sector_cache_invalidate_range(start_sector, end_sector);
  37. }
  38. static inline void sd_cache_invalidate_all() {
  39. sector_cache_init();
  40. }
  41. static bool sd_device_read(uint32_t* buff, uint32_t sector, uint32_t count) {
  42. bool result = false;
  43. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
  44. furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
  45. if(sd_read_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) {
  46. FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
  47. /* wait until the read operation is finished */
  48. result = true;
  49. while(sd_get_card_state() != SdSpiStatusOK) {
  50. if(furi_hal_cortex_timer_is_expired(timer)) {
  51. result = false;
  52. break;
  53. }
  54. }
  55. }
  56. furi_hal_sd_spi_handle = NULL;
  57. furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
  58. return result;
  59. }
  60. static bool sd_device_write(uint32_t* buff, uint32_t sector, uint32_t count) {
  61. bool result = false;
  62. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
  63. furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
  64. if(sd_write_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) {
  65. FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
  66. /* wait until the Write operation is finished */
  67. result = true;
  68. while(sd_get_card_state() != SdSpiStatusOK) {
  69. if(furi_hal_cortex_timer_is_expired(timer)) {
  70. sd_cache_invalidate_all();
  71. result = false;
  72. break;
  73. }
  74. }
  75. }
  76. furi_hal_sd_spi_handle = NULL;
  77. furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
  78. return result;
  79. }
  80. /**
  81. * @brief Initializes a Drive
  82. * @param pdrv: Physical drive number (0..)
  83. * @retval DSTATUS: Operation status
  84. */
  85. static DSTATUS driver_initialize(BYTE pdrv) {
  86. UNUSED(pdrv);
  87. return RES_OK;
  88. }
  89. /**
  90. * @brief Gets Disk Status
  91. * @param pdrv: Physical drive number (0..)
  92. * @retval DSTATUS: Operation status
  93. */
  94. static DSTATUS driver_status(BYTE pdrv) {
  95. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
  96. furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
  97. DSTATUS status = driver_check_status(pdrv);
  98. furi_hal_sd_spi_handle = NULL;
  99. furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
  100. return status;
  101. }
  102. /**
  103. * @brief Reads Sector(s)
  104. * @param pdrv: Physical drive number (0..)
  105. * @param *buff: Data buffer to store read data
  106. * @param sector: Sector address (LBA)
  107. * @param count: Number of sectors to read (1..128)
  108. * @retval DRESULT: Operation result
  109. */
  110. static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
  111. UNUSED(pdrv);
  112. bool result;
  113. bool single_sector = count == 1;
  114. if(single_sector) {
  115. if(sd_cache_get(sector, (uint32_t*)buff)) {
  116. return RES_OK;
  117. }
  118. }
  119. result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count);
  120. if(!result) {
  121. uint8_t counter = sd_max_mount_retry_count();
  122. while(result == false && counter > 0 && hal_sd_detect()) {
  123. SdSpiStatus status;
  124. if((counter % 2) == 0) {
  125. // power reset sd card
  126. status = sd_init(true);
  127. } else {
  128. status = sd_init(false);
  129. }
  130. if(status == SdSpiStatusOK) {
  131. result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count);
  132. }
  133. counter--;
  134. }
  135. }
  136. if(single_sector && result == true) {
  137. sd_cache_put(sector, (uint32_t*)buff);
  138. }
  139. return result ? RES_OK : RES_ERROR;
  140. }
  141. /**
  142. * @brief Writes Sector(s)
  143. * @param pdrv: Physical drive number (0..)
  144. * @param *buff: Data to be written
  145. * @param sector: Sector address (LBA)
  146. * @param count: Number of sectors to write (1..128)
  147. * @retval DRESULT: Operation result
  148. */
  149. static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
  150. UNUSED(pdrv);
  151. bool result;
  152. sd_cache_invalidate_range(sector, sector + count);
  153. result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count);
  154. if(!result) {
  155. uint8_t counter = sd_max_mount_retry_count();
  156. while(result == false && counter > 0 && hal_sd_detect()) {
  157. SdSpiStatus status;
  158. if((counter % 2) == 0) {
  159. // power reset sd card
  160. status = sd_init(true);
  161. } else {
  162. status = sd_init(false);
  163. }
  164. if(status == SdSpiStatusOK) {
  165. result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count);
  166. }
  167. counter--;
  168. }
  169. }
  170. return result ? RES_OK : RES_ERROR;
  171. }
  172. /**
  173. * @brief I/O control operation
  174. * @param pdrv: Physical drive number (0..)
  175. * @param cmd: Control code
  176. * @param *buff: Buffer to send/receive control data
  177. * @retval DRESULT: Operation result
  178. */
  179. static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
  180. DRESULT res = RES_ERROR;
  181. SD_CardInfo CardInfo;
  182. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
  183. furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
  184. DSTATUS status = driver_check_status(pdrv);
  185. if(status & STA_NOINIT) return RES_NOTRDY;
  186. switch(cmd) {
  187. /* Make sure that no pending write process */
  188. case CTRL_SYNC:
  189. res = RES_OK;
  190. break;
  191. /* Get number of sectors on the disk (DWORD) */
  192. case GET_SECTOR_COUNT:
  193. sd_get_card_info(&CardInfo);
  194. *(DWORD*)buff = CardInfo.LogBlockNbr;
  195. res = RES_OK;
  196. break;
  197. /* Get R/W sector size (WORD) */
  198. case GET_SECTOR_SIZE:
  199. sd_get_card_info(&CardInfo);
  200. *(WORD*)buff = CardInfo.LogBlockSize;
  201. res = RES_OK;
  202. break;
  203. /* Get erase block size in unit of sector (DWORD) */
  204. case GET_BLOCK_SIZE:
  205. sd_get_card_info(&CardInfo);
  206. *(DWORD*)buff = CardInfo.LogBlockSize;
  207. res = RES_OK;
  208. break;
  209. default:
  210. res = RES_PARERR;
  211. }
  212. furi_hal_sd_spi_handle = NULL;
  213. furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
  214. return res;
  215. }