vfs_fat_diskio.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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 "py/binary.h"
  36. #include "py/objarray.h"
  37. #include "lib/oofatfs/ff.h"
  38. #include "lib/oofatfs/diskio.h"
  39. #include "extmod/vfs_fat.h"
  40. #if _MAX_SS == _MIN_SS
  41. #define SECSIZE(fs) (_MIN_SS)
  42. #else
  43. #define SECSIZE(fs) ((fs)->ssize)
  44. #endif
  45. typedef void *bdev_t;
  46. STATIC fs_user_mount_t *disk_get_device(void *bdev) {
  47. return (fs_user_mount_t*)bdev;
  48. }
  49. /*-----------------------------------------------------------------------*/
  50. /* Read Sector(s) */
  51. /*-----------------------------------------------------------------------*/
  52. DRESULT disk_read (
  53. bdev_t pdrv, /* Physical drive nmuber (0..) */
  54. BYTE *buff, /* Data buffer to store read data */
  55. DWORD sector, /* Sector address (LBA) */
  56. UINT count /* Number of sectors to read (1..128) */
  57. )
  58. {
  59. fs_user_mount_t *vfs = disk_get_device(pdrv);
  60. if (vfs == NULL) {
  61. return RES_PARERR;
  62. }
  63. if (vfs->flags & FSUSER_NATIVE) {
  64. mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->readblocks[2];
  65. if (f(buff, sector, count) != 0) {
  66. return RES_ERROR;
  67. }
  68. } else {
  69. mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff};
  70. vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
  71. vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar);
  72. mp_call_method_n_kw(2, 0, vfs->readblocks);
  73. // TODO handle error return
  74. }
  75. return RES_OK;
  76. }
  77. /*-----------------------------------------------------------------------*/
  78. /* Write Sector(s) */
  79. /*-----------------------------------------------------------------------*/
  80. DRESULT disk_write (
  81. bdev_t pdrv, /* Physical drive nmuber (0..) */
  82. const BYTE *buff, /* Data to be written */
  83. DWORD sector, /* Sector address (LBA) */
  84. UINT count /* Number of sectors to write (1..128) */
  85. )
  86. {
  87. fs_user_mount_t *vfs = disk_get_device(pdrv);
  88. if (vfs == NULL) {
  89. return RES_PARERR;
  90. }
  91. if (vfs->writeblocks[0] == MP_OBJ_NULL) {
  92. // read-only block device
  93. return RES_WRPRT;
  94. }
  95. if (vfs->flags & FSUSER_NATIVE) {
  96. mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->writeblocks[2];
  97. if (f(buff, sector, count) != 0) {
  98. return RES_ERROR;
  99. }
  100. } else {
  101. mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff};
  102. vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
  103. vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar);
  104. mp_call_method_n_kw(2, 0, vfs->writeblocks);
  105. // TODO handle error return
  106. }
  107. return RES_OK;
  108. }
  109. /*-----------------------------------------------------------------------*/
  110. /* Miscellaneous Functions */
  111. /*-----------------------------------------------------------------------*/
  112. DRESULT disk_ioctl (
  113. bdev_t pdrv, /* Physical drive nmuber (0..) */
  114. BYTE cmd, /* Control code */
  115. void *buff /* Buffer to send/receive control data */
  116. )
  117. {
  118. fs_user_mount_t *vfs = disk_get_device(pdrv);
  119. if (vfs == NULL) {
  120. return RES_PARERR;
  121. }
  122. // First part: call the relevant method of the underlying block device
  123. mp_obj_t ret = mp_const_none;
  124. if (vfs->flags & FSUSER_HAVE_IOCTL) {
  125. // new protocol with ioctl
  126. static const uint8_t op_map[8] = {
  127. [CTRL_SYNC] = BP_IOCTL_SYNC,
  128. [GET_SECTOR_COUNT] = BP_IOCTL_SEC_COUNT,
  129. [GET_SECTOR_SIZE] = BP_IOCTL_SEC_SIZE,
  130. [IOCTL_INIT] = BP_IOCTL_INIT,
  131. };
  132. uint8_t bp_op = op_map[cmd & 7];
  133. if (bp_op != 0) {
  134. vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op);
  135. vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
  136. ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
  137. }
  138. } else {
  139. // old protocol with sync and count
  140. switch (cmd) {
  141. case CTRL_SYNC:
  142. if (vfs->u.old.sync[0] != MP_OBJ_NULL) {
  143. mp_call_method_n_kw(0, 0, vfs->u.old.sync);
  144. }
  145. break;
  146. case GET_SECTOR_COUNT:
  147. ret = mp_call_method_n_kw(0, 0, vfs->u.old.count);
  148. break;
  149. case GET_SECTOR_SIZE:
  150. // old protocol has fixed sector size of 512 bytes
  151. break;
  152. case IOCTL_INIT:
  153. // old protocol doesn't have init
  154. break;
  155. }
  156. }
  157. // Second part: convert the result for return
  158. switch (cmd) {
  159. case CTRL_SYNC:
  160. return RES_OK;
  161. case GET_SECTOR_COUNT: {
  162. *((DWORD*)buff) = mp_obj_get_int(ret);
  163. return RES_OK;
  164. }
  165. case GET_SECTOR_SIZE: {
  166. if (ret == mp_const_none) {
  167. // Default sector size
  168. *((WORD*)buff) = 512;
  169. } else {
  170. *((WORD*)buff) = mp_obj_get_int(ret);
  171. }
  172. #if _MAX_SS != _MIN_SS
  173. // need to store ssize because we use it in disk_read/disk_write
  174. vfs->fatfs.ssize = *((WORD*)buff);
  175. #endif
  176. return RES_OK;
  177. }
  178. case GET_BLOCK_SIZE:
  179. *((DWORD*)buff) = 1; // erase block size in units of sector size
  180. return RES_OK;
  181. case IOCTL_INIT:
  182. case IOCTL_STATUS: {
  183. DSTATUS stat;
  184. if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) {
  185. // error initialising
  186. stat = STA_NOINIT;
  187. } else if (vfs->writeblocks[0] == MP_OBJ_NULL) {
  188. stat = STA_PROTECT;
  189. } else {
  190. stat = 0;
  191. }
  192. *((DSTATUS*)buff) = stat;
  193. return RES_OK;
  194. }
  195. default:
  196. return RES_PARERR;
  197. }
  198. }
  199. #endif // MICROPY_VFS && MICROPY_VFS_FAT