vfs_fat_diskio.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * Original template for this file comes from:
  5. * Low level disk I/O module skeleton for FatFs, (C)ChaN, 2013
  6. *
  7. * The MIT License (MIT)
  8. *
  9. * Copyright (c) 2013, 2014 Damien P. George
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. */
  29. #include "py/mpconfig.h"
  30. #if MICROPY_VFS && MICROPY_VFS_FAT
  31. #include <stdint.h>
  32. #include <stdio.h>
  33. #include "py/mphal.h"
  34. #include "py/runtime.h"
  35. #include "lib/oofatfs/ff.h"
  36. #include "lib/oofatfs/diskio.h"
  37. #include "extmod/vfs_fat.h"
  38. #if _MAX_SS == _MIN_SS
  39. #define SECSIZE(fs) (_MIN_SS)
  40. #else
  41. #define SECSIZE(fs) ((fs)->ssize)
  42. #endif
  43. typedef void *bdev_t;
  44. STATIC fs_user_mount_t *disk_get_device(void *bdev) {
  45. return (fs_user_mount_t*)bdev;
  46. }
  47. /*-----------------------------------------------------------------------*/
  48. /* Initialize a Drive */
  49. /*-----------------------------------------------------------------------*/
  50. STATIC
  51. DSTATUS disk_initialize (
  52. bdev_t pdrv /* Physical drive nmuber (0..) */
  53. )
  54. {
  55. fs_user_mount_t *vfs = disk_get_device(pdrv);
  56. if (vfs == NULL) {
  57. return STA_NOINIT;
  58. }
  59. if (vfs->flags & FSUSER_HAVE_IOCTL) {
  60. // new protocol with ioctl; call ioctl(INIT, 0)
  61. vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_INIT);
  62. vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
  63. mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
  64. if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) {
  65. // error initialising
  66. return STA_NOINIT;
  67. }
  68. }
  69. if (vfs->writeblocks[0] == MP_OBJ_NULL) {
  70. return STA_PROTECT;
  71. } else {
  72. return 0;
  73. }
  74. }
  75. /*-----------------------------------------------------------------------*/
  76. /* Get Disk Status */
  77. /*-----------------------------------------------------------------------*/
  78. STATIC
  79. DSTATUS disk_status (
  80. bdev_t pdrv /* Physical drive nmuber (0..) */
  81. )
  82. {
  83. fs_user_mount_t *vfs = disk_get_device(pdrv);
  84. if (vfs == NULL) {
  85. return STA_NOINIT;
  86. }
  87. if (vfs->writeblocks[0] == MP_OBJ_NULL) {
  88. return STA_PROTECT;
  89. } else {
  90. return 0;
  91. }
  92. }
  93. /*-----------------------------------------------------------------------*/
  94. /* Read Sector(s) */
  95. /*-----------------------------------------------------------------------*/
  96. DRESULT disk_read (
  97. bdev_t pdrv, /* Physical drive nmuber (0..) */
  98. BYTE *buff, /* Data buffer to store read data */
  99. DWORD sector, /* Sector address (LBA) */
  100. UINT count /* Number of sectors to read (1..128) */
  101. )
  102. {
  103. fs_user_mount_t *vfs = disk_get_device(pdrv);
  104. if (vfs == NULL) {
  105. return RES_PARERR;
  106. }
  107. if (vfs->flags & FSUSER_NATIVE) {
  108. mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->readblocks[2];
  109. if (f(buff, sector, count) != 0) {
  110. return RES_ERROR;
  111. }
  112. } else {
  113. vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
  114. vfs->readblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), buff);
  115. mp_call_method_n_kw(2, 0, vfs->readblocks);
  116. // TODO handle error return
  117. }
  118. return RES_OK;
  119. }
  120. /*-----------------------------------------------------------------------*/
  121. /* Write Sector(s) */
  122. /*-----------------------------------------------------------------------*/
  123. DRESULT disk_write (
  124. bdev_t pdrv, /* Physical drive nmuber (0..) */
  125. const BYTE *buff, /* Data to be written */
  126. DWORD sector, /* Sector address (LBA) */
  127. UINT count /* Number of sectors to write (1..128) */
  128. )
  129. {
  130. fs_user_mount_t *vfs = disk_get_device(pdrv);
  131. if (vfs == NULL) {
  132. return RES_PARERR;
  133. }
  134. if (vfs->writeblocks[0] == MP_OBJ_NULL) {
  135. // read-only block device
  136. return RES_WRPRT;
  137. }
  138. if (vfs->flags & FSUSER_NATIVE) {
  139. mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->writeblocks[2];
  140. if (f(buff, sector, count) != 0) {
  141. return RES_ERROR;
  142. }
  143. } else {
  144. vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
  145. vfs->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), (void*)buff);
  146. mp_call_method_n_kw(2, 0, vfs->writeblocks);
  147. // TODO handle error return
  148. }
  149. return RES_OK;
  150. }
  151. /*-----------------------------------------------------------------------*/
  152. /* Miscellaneous Functions */
  153. /*-----------------------------------------------------------------------*/
  154. DRESULT disk_ioctl (
  155. bdev_t pdrv, /* Physical drive nmuber (0..) */
  156. BYTE cmd, /* Control code */
  157. void *buff /* Buffer to send/receive control data */
  158. )
  159. {
  160. fs_user_mount_t *vfs = disk_get_device(pdrv);
  161. if (vfs == NULL) {
  162. return RES_PARERR;
  163. }
  164. if (vfs->flags & FSUSER_HAVE_IOCTL) {
  165. // new protocol with ioctl
  166. switch (cmd) {
  167. case CTRL_SYNC:
  168. vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SYNC);
  169. vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
  170. mp_call_method_n_kw(2, 0, vfs->u.ioctl);
  171. return RES_OK;
  172. case GET_SECTOR_COUNT: {
  173. vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_COUNT);
  174. vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
  175. mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
  176. *((DWORD*)buff) = mp_obj_get_int(ret);
  177. return RES_OK;
  178. }
  179. case GET_SECTOR_SIZE: {
  180. vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_SIZE);
  181. vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
  182. mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
  183. if (ret == mp_const_none) {
  184. // Default sector size
  185. *((WORD*)buff) = 512;
  186. } else {
  187. *((WORD*)buff) = mp_obj_get_int(ret);
  188. }
  189. #if _MAX_SS != _MIN_SS
  190. // need to store ssize because we use it in disk_read/disk_write
  191. vfs->fatfs.ssize = *((WORD*)buff);
  192. #endif
  193. return RES_OK;
  194. }
  195. case GET_BLOCK_SIZE:
  196. *((DWORD*)buff) = 1; // erase block size in units of sector size
  197. return RES_OK;
  198. case IOCTL_INIT:
  199. *((DSTATUS*)buff) = disk_initialize(pdrv);
  200. return RES_OK;
  201. case IOCTL_STATUS:
  202. *((DSTATUS*)buff) = disk_status(pdrv);
  203. return RES_OK;
  204. default:
  205. return RES_PARERR;
  206. }
  207. } else {
  208. // old protocol with sync and count
  209. switch (cmd) {
  210. case CTRL_SYNC:
  211. if (vfs->u.old.sync[0] != MP_OBJ_NULL) {
  212. mp_call_method_n_kw(0, 0, vfs->u.old.sync);
  213. }
  214. return RES_OK;
  215. case GET_SECTOR_COUNT: {
  216. mp_obj_t ret = mp_call_method_n_kw(0, 0, vfs->u.old.count);
  217. *((DWORD*)buff) = mp_obj_get_int(ret);
  218. return RES_OK;
  219. }
  220. case GET_SECTOR_SIZE:
  221. *((WORD*)buff) = 512; // old protocol had fixed sector size
  222. #if _MAX_SS != _MIN_SS
  223. // need to store ssize because we use it in disk_read/disk_write
  224. vfs->fatfs.ssize = 512;
  225. #endif
  226. return RES_OK;
  227. case GET_BLOCK_SIZE:
  228. *((DWORD*)buff) = 1; // erase block size in units of sector size
  229. return RES_OK;
  230. case IOCTL_INIT:
  231. *((DSTATUS*)buff) = disk_initialize(pdrv);
  232. return RES_OK;
  233. case IOCTL_STATUS:
  234. *((DSTATUS*)buff) = disk_status(pdrv);
  235. return RES_OK;
  236. default:
  237. return RES_PARERR;
  238. }
  239. }
  240. }
  241. #endif // MICROPY_VFS && MICROPY_VFS_FAT