summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorsakumisu <[email protected]>2025-05-26 21:54:32 +0800
committersakumisu <[email protected]>2025-05-26 21:54:32 +0800
commitfe24f8d4ba7d73be47a5e78a9d87689294099eac (patch)
tree06ca27bcdb7b4289d98a87fa71afb3e7604404f1 /platform
parent5fed8b7d0539e37100d91381a8b46847364ecd4d (diff)
feat(class/mtp): support mtp device
Signed-off-by: sakumisu <[email protected]>
Diffstat (limited to 'platform')
-rw-r--r--platform/README.md3
-rw-r--r--platform/fatfs/usbd_fatfs_mtp.c337
2 files changed, 339 insertions, 1 deletions
diff --git a/platform/README.md b/platform/README.md
index 639b9efe..79cea2f9 100644
--- a/platform/README.md
+++ b/platform/README.md
@@ -5,7 +5,8 @@ This is a platform support for other opensource projects.
## Fatfs
-Fatfs support with usb host msc.
+- Fatfs support with usb host msc.
+- Fatfs support with usb device mtp.
## lwip
diff --git a/platform/fatfs/usbd_fatfs_mtp.c b/platform/fatfs/usbd_fatfs_mtp.c
new file mode 100644
index 00000000..3298560c
--- /dev/null
+++ b/platform/fatfs/usbd_fatfs_mtp.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2025 sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+#include "ff.h"
+#include "diskio.h"
+#include "usbd_core.h"
+#include "usbd_mtp.h"
+
+FATFS s_sd_disk;
+FIL s_file;
+DIR s_dir;
+BYTE work[FF_MAX_SS];
+
+const TCHAR driver_num_buf[4] = { '0', ':', '/', '\0' };
+
+const char *show_error_string(FRESULT fresult);
+
+static FRESULT sd_mount_fs(void)
+{
+ FRESULT fresult = f_mount(&s_sd_disk, driver_num_buf, 1);
+ if (fresult == FR_OK) {
+ printf("SD card has been mounted successfully\n");
+ } else {
+ printf("Failed to mount SD card, cause: %s\n", show_error_string(fresult));
+ }
+
+ return fresult;
+}
+
+#if 0
+static FRESULT sd_mkfs(void)
+{
+ printf("Formatting the SD card, depending on the SD card capacity, the formatting process may take a long time\n");
+ FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
+ if (fresult != FR_OK) {
+ printf("Making File system failed, cause: %s\n", show_error_string(fresult));
+ } else {
+ printf("Making file system is successful\n");
+ }
+
+ return fresult;
+}
+#endif
+
+static FRESULT sd_write_file(void)
+{
+ FRESULT fresult = f_open(&s_file, "0:/readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
+ if (fresult != FR_OK) {
+ printf("Create new file failed, cause: %d\n", show_error_string(fresult));
+ } else {
+ printf("Create new file successfully, status=%d\n", fresult);
+ }
+ char hello_str[] = "Hello, this is SD card FATFS demo\n";
+ UINT byte_written;
+ fresult = f_write(&s_file, hello_str, sizeof(hello_str), &byte_written);
+ if (fresult != FR_OK) {
+ printf("Write file failed, cause: %s\n", show_error_string(fresult));
+ } else {
+ printf("Write file operation is successfully\n");
+ }
+
+ f_close(&s_file);
+
+ return fresult;
+}
+
+const char *show_error_string(FRESULT fresult)
+{
+ const char *result_str;
+
+ switch (fresult) {
+ case FR_OK:
+ result_str = "succeeded";
+ break;
+ case FR_DISK_ERR:
+ result_str = "A hard error occurred in the low level disk I/O level";
+ break;
+ case FR_INT_ERR:
+ result_str = "Assertion failed";
+ break;
+ case FR_NOT_READY:
+ result_str = "The physical drive cannot work";
+ break;
+ case FR_NO_FILE:
+ result_str = "Could not find the file";
+ break;
+ case FR_NO_PATH:
+ result_str = "Could not find the path";
+ break;
+ case FR_INVALID_NAME:
+ result_str = "Tha path name format is invalid";
+ break;
+ case FR_DENIED:
+ result_str = "Access denied due to prohibited access or directory full";
+ break;
+ case FR_EXIST:
+ result_str = "Access denied due to prohibited access";
+ break;
+ case FR_INVALID_OBJECT:
+ result_str = "The file/directory object is invalid";
+ break;
+ case FR_WRITE_PROTECTED:
+ result_str = "The physical drive is write protected";
+ break;
+ case FR_INVALID_DRIVE:
+ result_str = "The logical driver number is invalid";
+ break;
+ case FR_NOT_ENABLED:
+ result_str = "The volume has no work area";
+ break;
+ case FR_NO_FILESYSTEM:
+ result_str = "There is no valid FAT volume";
+ break;
+ case FR_MKFS_ABORTED:
+ result_str = "THe f_mkfs() aborted due to any problem";
+ break;
+ case FR_TIMEOUT:
+ result_str = "Could not get a grant to access the volume within defined period";
+ break;
+ case FR_LOCKED:
+ result_str = "The operation is rejected according to the file sharing policy";
+ break;
+ case FR_NOT_ENOUGH_CORE:
+ result_str = "LFN working buffer could not be allocated";
+ break;
+ case FR_TOO_MANY_OPEN_FILES:
+ result_str = "Number of open files > FF_FS_LOCK";
+ break;
+ case FR_INVALID_PARAMETER:
+ result_str = "Given parameter is invalid";
+ break;
+ default:
+ result_str = "Unknown error";
+ break;
+ }
+ return result_str;
+}
+
+const char *usbd_mtp_fs_root_path(void)
+{
+ return driver_num_buf;
+}
+
+const char *usbd_mtp_fs_description(void)
+{
+ return "CherryUSB MTP";
+}
+
+int usbd_mtp_mkdir(const char *path)
+{
+ FRESULT result = f_mkdir(path);
+ if (result != FR_OK) {
+ printf("f_mkdir failed, cause: %s\n", show_error_string(result));
+ return -1;
+ }
+ return 0; // Directory created successfully
+}
+
+int usbd_mtp_rmdir(const char *path)
+{
+ FRESULT result = f_rmdir(path);
+ if (result != FR_OK) {
+ printf("f_mkdir failed, cause: %s\n", show_error_string(result));
+ return -1;
+ }
+ return 0; // Directory created successfully
+}
+
+MTP_DIR *usbd_mtp_opendir(const char *name)
+{
+ f_opendir(&s_dir, name);
+ return (MTP_DIR *)&s_dir;
+}
+
+int usbd_mtp_closedir(MTP_DIR *dir)
+{
+ return f_closedir((DIR *)dir);
+}
+
+struct mtp_dirent *usbd_mtp_readdir(MTP_DIR *dir)
+{
+ FILINFO fno;
+ FRESULT result;
+
+ result = f_readdir((DIR *)dir, &fno);
+ if (result != FR_OK || fno.fname[0] == 0)
+ return NULL;
+
+ static struct mtp_dirent dirent;
+ memset(&dirent, 0, sizeof(struct mtp_dirent));
+ strncpy(dirent.d_name, fno.fname, sizeof(dirent.d_name) - 1);
+ dirent.d_name[sizeof(dirent.d_name) - 1] = '\0';
+ dirent.d_namlen = strlen(dirent.d_name);
+
+ return &dirent;
+}
+
+#undef SS
+#if FF_MAX_SS == FF_MIN_SS
+#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */
+#else
+#define SS(fs) ((fs)->ssize) /* Variable sector size */
+#endif
+
+int usbd_mtp_stat(const char *path, struct stat *buf)
+{
+ FILINFO file_info;
+ FRESULT result;
+ FATFS *f;
+ f = &s_sd_disk;
+
+ result = f_stat(path, &file_info);
+ if (result != FR_OK) {
+ printf("f_stat failed, cause: %s\n", show_error_string(result));
+ return -1;
+ }
+ buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ if (file_info.fattrib & AM_DIR) {
+ buf->st_mode &= ~S_IFREG;
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ }
+ if (file_info.fattrib & AM_RDO)
+ buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+
+ buf->st_size = file_info.fsize;
+ buf->st_blksize = f->csize * SS(f);
+ if (file_info.fattrib & AM_ARC) {
+ buf->st_blocks = file_info.fsize ? ((file_info.fsize - 1) / SS(f) / f->csize + 1) : 0;
+ buf->st_blocks *= (buf->st_blksize / 512); // man say st_blocks is number of 512B blocks allocated
+ } else {
+ buf->st_blocks = f->csize;
+ }
+ return 0;
+}
+
+int usbd_mtp_statfs(const char *path, struct mtp_statfs *buf)
+{
+ FATFS *f;
+ FRESULT res;
+ DWORD fre_clust, fre_sect, tot_sect;
+
+ f = &s_sd_disk;
+
+ res = f_getfree(path, &fre_clust, &f);
+ if (res != FR_OK) {
+ printf("f_getfree failed, cause: %s\n", show_error_string(res));
+ return -1;
+ }
+ tot_sect = (f->n_fatent - 2) * f->csize;
+ fre_sect = fre_clust * f->csize;
+
+ buf->f_blocks = tot_sect;
+ buf->f_bfree = fre_sect;
+#if FF_MAX_SS != FF_MIN_SS
+ buf->f_bsize = f->ssize;
+#else
+ buf->f_bsize = FF_MIN_SS;
+#endif
+ return 0;
+}
+
+int usbd_mtp_open(const char *path, uint8_t mode)
+{
+ BYTE flags;
+
+ if (mode == O_RDONLY) {
+ flags = FA_READ | FA_OPEN_EXISTING;
+ } else if (mode == O_WRONLY) {
+ flags = FA_WRITE | FA_OPEN_ALWAYS;
+ } else if (mode == O_RDWR) {
+ flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
+ } else {
+ return -1; // Invalid mode
+ }
+
+ FRESULT result = f_open(&s_file, path, flags);
+ if (result != FR_OK) {
+ printf("f_open failed, cause: %s\n", show_error_string(result));
+ return -1;
+ }
+ return 0;
+}
+
+int usbd_mtp_close(int fd)
+{
+ FRESULT result = f_close(&s_file);
+ if (result != FR_OK) {
+ printf("f_close failed, cause: %s\n", show_error_string(result));
+ return -1;
+ }
+ return 0;
+}
+
+int usbd_mtp_read(int fd, void *buf, size_t len)
+{
+ UINT bytes_read;
+ FRESULT result = f_read(&s_file, buf, len, &bytes_read);
+ if (result != FR_OK) {
+ printf("f_read failed, cause: %s\n", show_error_string(result));
+ return -1;
+ }
+ return bytes_read; // Return number of bytes read
+}
+
+int usbd_mtp_write(int fd, const void *buf, size_t len)
+{
+ UINT bytes_written;
+ FRESULT result = f_write(&s_file, buf, len, &bytes_written);
+ if (result != FR_OK) {
+ printf("f_write failed, cause: %s\n", show_error_string(result));
+ return -1;
+ }
+ return bytes_written; // Return number of bytes written
+}
+
+int usbd_mtp_unlink(const char *path)
+{
+ FRESULT result = f_unlink(path);
+ if (result != FR_OK) {
+ printf("f_unlink failed, cause: %s\n", show_error_string(result));
+ return -1;
+ }
+ return 0; // File deleted successfully
+}
+
+void usbd_mtp_mount()
+{
+ sd_mount_fs();
+
+ // write a file to test the SD card
+ sd_write_file();
+}