usbd_fatfs_mtp.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * Copyright (c) 2025, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "ff.h"
  7. #include "diskio.h"
  8. #include "usbd_core.h"
  9. #include "usb_osal.h"
  10. #include "usbd_mtp.h"
  11. FATFS s_sd_disk;
  12. FIL s_file;
  13. BYTE work[FF_MAX_SS];
  14. const TCHAR driver_num_buf[3] = { '0', ':', '\0' };
  15. const char *show_error_string(FRESULT fresult);
  16. static FRESULT sd_mount_fs(void)
  17. {
  18. FRESULT fresult = f_mount(&s_sd_disk, driver_num_buf, 1);
  19. if (fresult == FR_OK) {
  20. printf("SD card has been mounted successfully\n");
  21. } else {
  22. printf("Failed to mount SD card, cause: %s\n", show_error_string(fresult));
  23. }
  24. return fresult;
  25. }
  26. #if 0
  27. static FRESULT sd_mkfs(void)
  28. {
  29. printf("Formatting the SD card, depending on the SD card capacity, the formatting process may take a long time\n");
  30. FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
  31. if (fresult != FR_OK) {
  32. printf("Making File system failed, cause: %s\n", show_error_string(fresult));
  33. } else {
  34. printf("Making file system is successful\n");
  35. }
  36. return fresult;
  37. }
  38. #endif
  39. static FRESULT sd_write_file(void)
  40. {
  41. FRESULT fresult = f_open(&s_file, "0:/readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
  42. if (fresult != FR_OK) {
  43. printf("Create new file failed, cause: %d\n", show_error_string(fresult));
  44. } else {
  45. printf("Create new file successfully, status=%d\n", fresult);
  46. }
  47. char hello_str[] = "Hello, this is SD card FATFS demo\n";
  48. UINT byte_written;
  49. fresult = f_write(&s_file, hello_str, sizeof(hello_str), &byte_written);
  50. if (fresult != FR_OK) {
  51. printf("Write file failed, cause: %s\n", show_error_string(fresult));
  52. } else {
  53. printf("Write file operation is successfully\n");
  54. }
  55. f_close(&s_file);
  56. return fresult;
  57. }
  58. const char *show_error_string(FRESULT fresult)
  59. {
  60. const char *result_str;
  61. switch (fresult) {
  62. case FR_OK:
  63. result_str = "succeeded";
  64. break;
  65. case FR_DISK_ERR:
  66. result_str = "A hard error occurred in the low level disk I/O level";
  67. break;
  68. case FR_INT_ERR:
  69. result_str = "Assertion failed";
  70. break;
  71. case FR_NOT_READY:
  72. result_str = "The physical drive cannot work";
  73. break;
  74. case FR_NO_FILE:
  75. result_str = "Could not find the file";
  76. break;
  77. case FR_NO_PATH:
  78. result_str = "Could not find the path";
  79. break;
  80. case FR_INVALID_NAME:
  81. result_str = "Tha path name format is invalid";
  82. break;
  83. case FR_DENIED:
  84. result_str = "Access denied due to prohibited access or directory full";
  85. break;
  86. case FR_EXIST:
  87. result_str = "Access denied due to prohibited access";
  88. break;
  89. case FR_INVALID_OBJECT:
  90. result_str = "The file/directory object is invalid";
  91. break;
  92. case FR_WRITE_PROTECTED:
  93. result_str = "The physical drive is write protected";
  94. break;
  95. case FR_INVALID_DRIVE:
  96. result_str = "The logical driver number is invalid";
  97. break;
  98. case FR_NOT_ENABLED:
  99. result_str = "The volume has no work area";
  100. break;
  101. case FR_NO_FILESYSTEM:
  102. result_str = "There is no valid FAT volume";
  103. break;
  104. case FR_MKFS_ABORTED:
  105. result_str = "THe f_mkfs() aborted due to any problem";
  106. break;
  107. case FR_TIMEOUT:
  108. result_str = "Could not get a grant to access the volume within defined period";
  109. break;
  110. case FR_LOCKED:
  111. result_str = "The operation is rejected according to the file sharing policy";
  112. break;
  113. case FR_NOT_ENOUGH_CORE:
  114. result_str = "LFN working buffer could not be allocated";
  115. break;
  116. case FR_TOO_MANY_OPEN_FILES:
  117. result_str = "Number of open files > FF_FS_LOCK";
  118. break;
  119. case FR_INVALID_PARAMETER:
  120. result_str = "Given parameter is invalid";
  121. break;
  122. default:
  123. result_str = "Unknown error";
  124. break;
  125. }
  126. return result_str;
  127. }
  128. const char *usbd_mtp_fs_root_path(void)
  129. {
  130. return driver_num_buf;
  131. }
  132. const char *usbd_mtp_fs_description(void)
  133. {
  134. return "CherryUSB MTP";
  135. }
  136. int usbd_mtp_mkdir(const char *path)
  137. {
  138. FRESULT result = f_mkdir(path);
  139. if (result != FR_OK) {
  140. printf("f_mkdir failed, cause: %s\n", show_error_string(result));
  141. return -1;
  142. }
  143. return 0; // Directory created successfully
  144. }
  145. int usbd_mtp_rmdir(const char *path)
  146. {
  147. FRESULT result = f_rmdir(path);
  148. if (result != FR_OK) {
  149. printf("f_mkdir failed, cause: %s\n", show_error_string(result));
  150. return -1;
  151. }
  152. return 0; // Directory created successfully
  153. }
  154. MTP_DIR *usbd_mtp_opendir(const char *name)
  155. {
  156. FRESULT result;
  157. DIR *dir;
  158. dir = usb_osal_malloc(sizeof(DIR));
  159. result = f_opendir(dir, name);
  160. if (result != FR_OK) {
  161. printf("f_opendir failed, cause: %s\n", show_error_string(result));
  162. usb_osal_free(dir);
  163. return NULL; // Failed to open directory
  164. }
  165. return (MTP_DIR *)dir;
  166. }
  167. int usbd_mtp_closedir(MTP_DIR *dir)
  168. {
  169. FRESULT result;
  170. result = f_closedir((DIR *)dir);
  171. if (result != FR_OK) {
  172. printf("f_closedir failed, cause: %s\n", show_error_string(result));
  173. return -1; // Failed to close directory
  174. }
  175. usb_osal_free(dir); // Free the directory structure
  176. return result;
  177. }
  178. struct mtp_dirent *usbd_mtp_readdir(MTP_DIR *dir)
  179. {
  180. FILINFO fno;
  181. FRESULT result;
  182. result = f_readdir((DIR *)dir, &fno);
  183. if (result != FR_OK || fno.fname[0] == 0)
  184. return NULL;
  185. static struct mtp_dirent dirent;
  186. memset(&dirent, 0, sizeof(struct mtp_dirent));
  187. strncpy(dirent.d_name, fno.fname, sizeof(dirent.d_name) - 1);
  188. dirent.d_name[sizeof(dirent.d_name) - 1] = '\0';
  189. dirent.d_namlen = strlen(dirent.d_name);
  190. return &dirent;
  191. }
  192. #undef SS
  193. #if FF_MAX_SS == FF_MIN_SS
  194. #define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */
  195. #else
  196. #define SS(fs) ((fs)->ssize) /* Variable sector size */
  197. #endif
  198. int usbd_mtp_stat(const char *path, struct stat *buf)
  199. {
  200. FILINFO file_info;
  201. FRESULT result;
  202. FATFS *f;
  203. f = &s_sd_disk;
  204. result = f_stat(path, &file_info);
  205. if (result != FR_OK) {
  206. printf("f_stat failed, cause: %s\n", show_error_string(result));
  207. return -1;
  208. }
  209. buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
  210. S_IWUSR | S_IWGRP | S_IWOTH;
  211. if (file_info.fattrib & AM_DIR) {
  212. buf->st_mode &= ~S_IFREG;
  213. buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
  214. }
  215. if (file_info.fattrib & AM_RDO)
  216. buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
  217. buf->st_size = file_info.fsize;
  218. buf->st_blksize = f->csize * SS(f);
  219. if (file_info.fattrib & AM_ARC) {
  220. buf->st_blocks = file_info.fsize ? ((file_info.fsize - 1) / SS(f) / f->csize + 1) : 0;
  221. buf->st_blocks *= (buf->st_blksize / 512); // man say st_blocks is number of 512B blocks allocated
  222. } else {
  223. buf->st_blocks = f->csize;
  224. }
  225. return 0;
  226. }
  227. int usbd_mtp_statfs(const char *path, struct mtp_statfs *buf)
  228. {
  229. FATFS *f;
  230. FRESULT res;
  231. DWORD fre_clust, fre_sect, tot_sect;
  232. f = &s_sd_disk;
  233. res = f_getfree(path, &fre_clust, &f);
  234. if (res != FR_OK) {
  235. printf("f_getfree failed, cause: %s\n", show_error_string(res));
  236. return -1;
  237. }
  238. tot_sect = (f->n_fatent - 2) * f->csize;
  239. fre_sect = fre_clust * f->csize;
  240. buf->f_blocks = tot_sect;
  241. buf->f_bfree = fre_sect;
  242. #if FF_MAX_SS != FF_MIN_SS
  243. buf->f_bsize = f->ssize;
  244. #else
  245. buf->f_bsize = FF_MIN_SS;
  246. #endif
  247. return 0;
  248. }
  249. int usbd_mtp_open(const char *path, uint8_t mode)
  250. {
  251. BYTE flags;
  252. if (mode == O_RDONLY) {
  253. flags = FA_READ | FA_OPEN_EXISTING;
  254. } else if (mode == O_WRONLY) {
  255. flags = FA_WRITE | FA_OPEN_ALWAYS;
  256. } else if (mode == O_RDWR) {
  257. flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
  258. } else {
  259. return -1; // Invalid mode
  260. }
  261. FRESULT result = f_open(&s_file, path, flags);
  262. if (result != FR_OK) {
  263. printf("f_open failed, cause: %s\n", show_error_string(result));
  264. return -1;
  265. }
  266. return 0;
  267. }
  268. int usbd_mtp_close(int fd)
  269. {
  270. FRESULT result = f_close(&s_file);
  271. if (result != FR_OK) {
  272. printf("f_close failed, cause: %s\n", show_error_string(result));
  273. return -1;
  274. }
  275. return 0;
  276. }
  277. int usbd_mtp_read(int fd, void *buf, size_t len)
  278. {
  279. UINT bytes_read;
  280. FRESULT result = f_read(&s_file, buf, len, &bytes_read);
  281. if (result != FR_OK) {
  282. printf("f_read failed, cause: %s\n", show_error_string(result));
  283. return -1;
  284. }
  285. return bytes_read; // Return number of bytes read
  286. }
  287. int usbd_mtp_write(int fd, const void *buf, size_t len)
  288. {
  289. UINT bytes_written;
  290. FRESULT result = f_write(&s_file, buf, len, &bytes_written);
  291. if (result != FR_OK) {
  292. printf("f_write failed, cause: %s\n", show_error_string(result));
  293. return -1;
  294. }
  295. return bytes_written; // Return number of bytes written
  296. }
  297. int usbd_mtp_unlink(const char *path)
  298. {
  299. FRESULT result = f_unlink(path);
  300. if (result != FR_OK) {
  301. printf("f_unlink failed, cause: %s\n", show_error_string(result));
  302. return -1;
  303. }
  304. return 0; // File deleted successfully
  305. }
  306. void usbd_mtp_mount()
  307. {
  308. sd_mount_fs();
  309. // write a file to test the SD card
  310. sd_write_file();
  311. }