summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/blackmagic/bmp_port_cdc_acm.c18
-rw-r--r--platform/daplink/dap_main.c41
-rw-r--r--platform/fatfs/usbd_fatfs_mtp.c351
-rw-r--r--platform/fatfs/usbh_fatfs.c11
-rw-r--r--platform/fatfs/vfs_fatfs_port.c504
-rw-r--r--platform/idf/usbh_fatfs.c5
-rw-r--r--platform/rtthread/rt_usbd_adb_msh.c (renamed from platform/rtthread/rt_usbd_adb.c)87
-rw-r--r--platform/rtthread/rt_usbd_serial.c1
-rw-r--r--platform/rtthread/rt_usbh_msc.c11
-rw-r--r--platform/rtthread/rt_vfs_dfs.c310
-rw-r--r--platform/zephyr/usbh_msc_disk.c126
11 files changed, 1007 insertions, 458 deletions
diff --git a/platform/blackmagic/bmp_port_cdc_acm.c b/platform/blackmagic/bmp_port_cdc_acm.c
index ae4e5457..e1353d66 100644
--- a/platform/blackmagic/bmp_port_cdc_acm.c
+++ b/platform/blackmagic/bmp_port_cdc_acm.c
@@ -9,24 +9,16 @@
#include "usbd_cdc_acm.h"
#include "general.h"
#include "gdb_if.h"
-#include "hpm_l1c_drv.h"
+
+#define USBD_VID 0xffff
+#define USBD_PID 0xffff
+#define USBD_MAX_POWER 100
+#define USBD_LANGID_STRING 1033
#define CDC_IN_EP 0x81
#define CDC_OUT_EP 0x01
#define CDC_INT_EP 0x83
-#define CDC_MAX_PACKET_SIZE 512
-
-#ifdef CONFIG_USB_HS
-#if CDC_MAX_PACKET_SIZE != 512
-#error "CDC_MAX_PACKET_SIZE must be 512 in hs"
-#endif
-#else
-#if CDC_MAX_PACKET_SIZE != 64
-#error "CDC_MAX_PACKET_SIZE must be 64 in fs"
-#endif
-#endif
-
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
diff --git a/platform/daplink/dap_main.c b/platform/daplink/dap_main.c
index 27e0355b..b145c223 100644
--- a/platform/daplink/dap_main.c
+++ b/platform/daplink/dap_main.c
@@ -335,17 +335,16 @@ static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t USB_Request[DAP_PACKET_COU
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t USB_Response[DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // Response Buffer
static uint16_t USB_RespSize[DAP_PACKET_COUNT]; // Response Size
-volatile struct cdc_line_coding g_cdc_lincoding;
-volatile uint8_t config_uart = 0;
-volatile uint8_t config_uart_transfer = 0;
-
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t uartrx_ringbuffer[CONFIG_UARTRX_RINGBUF_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usbrx_ringbuffer[CONFIG_USBRX_RINGBUF_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_tmpbuffer[DAP_PACKET_SIZE];
+static volatile struct cdc_line_coding g_cdc_lincoding;
+static volatile uint8_t config_uart = 0;
+static volatile uint8_t config_uart_transfer = 0;
static volatile uint8_t usbrx_idle_flag = 0;
-static volatile uint8_t usbtx_idle_flag = 0;
-static volatile uint8_t uarttx_idle_flag = 0;
+static volatile uint8_t usbtx_idle_flag = 1;
+static volatile uint8_t uarttx_idle_flag = 1;
USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_uartrx;
USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_usbrx;
@@ -356,9 +355,6 @@ void usbd_event_handler(uint8_t busid, uint8_t event)
switch (event) {
case USBD_EVENT_RESET:
usbrx_idle_flag = 0;
- usbtx_idle_flag = 0;
- uarttx_idle_flag = 0;
- config_uart_transfer = 0;
break;
case USBD_EVENT_CONNECTED:
break;
@@ -437,20 +433,13 @@ void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void)busid;
- uint32_t size;
- uint8_t *buffer;
chry_ringbuffer_linear_read_done(&g_uartrx, nbytes);
if ((nbytes % DAP_PACKET_SIZE) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(0, CDC_IN_EP, NULL, 0);
} else {
- if (chry_ringbuffer_get_used(&g_uartrx)) {
- buffer = chry_ringbuffer_linear_read_setup(&g_uartrx, &size);
- usbd_ep_start_write(0, CDC_IN_EP, buffer, size);
- } else {
- usbtx_idle_flag = 1;
- }
+ usbtx_idle_flag = 1;
}
}
@@ -624,7 +613,8 @@ void chry_dap_handle(void)
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
{
(void)busid;
- if (memcmp(line_coding, (uint8_t *)&g_cdc_lincoding, sizeof(struct cdc_line_coding)) != 0) {
+
+ if (memcmp((uint8_t *)&g_cdc_lincoding, line_coding, sizeof(struct cdc_line_coding)) != 0 && line_coding->dwDTERate != 0) {
memcpy((uint8_t *)&g_cdc_lincoding, line_coding, sizeof(struct cdc_line_coding));
config_uart = 1;
config_uart_transfer = 0;
@@ -642,6 +632,10 @@ void chry_dap_usb2uart_handle(void)
uint32_t size;
uint8_t *buffer;
+ if (usb_device_is_configured(0) == 0) {
+ return;
+ }
+
if (config_uart) {
/* disable irq here */
config_uart = 0;
@@ -700,16 +694,9 @@ __WEAK void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_
/* called by user */
void chry_dap_usb2uart_uart_send_complete(uint32_t size)
{
- uint8_t *buffer;
-
chry_ringbuffer_linear_read_done(&g_usbrx, size);
- if (chry_ringbuffer_get_used(&g_usbrx)) {
- buffer = chry_ringbuffer_linear_read_setup(&g_usbrx, &size);
- chry_dap_usb2uart_uart_send_bydma(buffer, size);
- } else {
- uarttx_idle_flag = 1;
- }
+ uarttx_idle_flag = 1;
}
/* implment by user */
@@ -746,4 +733,4 @@ int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
memcpy(mass_block[sector].BlockSpace, buffer, length);
return 0;
}
-#endif
+#endif \ No newline at end of file
diff --git a/platform/fatfs/usbd_fatfs_mtp.c b/platform/fatfs/usbd_fatfs_mtp.c
deleted file mode 100644
index 8126e3d5..00000000
--- a/platform/fatfs/usbd_fatfs_mtp.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2025, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include "ff.h"
-#include "diskio.h"
-#include "usbd_core.h"
-#include "usb_osal.h"
-#include "usbd_mtp.h"
-
-FATFS s_sd_disk;
-FIL s_file;
-BYTE work[FF_MAX_SS];
-
-const TCHAR driver_num_buf[3] = { '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)
-{
- FRESULT result;
- DIR *dir;
-
- dir = usb_osal_malloc(sizeof(DIR));
- result = f_opendir(dir, name);
- if (result != FR_OK) {
- printf("f_opendir failed, cause: %s\n", show_error_string(result));
- usb_osal_free(dir);
- return NULL; // Failed to open directory
- }
- return (MTP_DIR *)dir;
-}
-
-int usbd_mtp_closedir(MTP_DIR *dir)
-{
- FRESULT result;
- result = f_closedir((DIR *)dir);
- if (result != FR_OK) {
- printf("f_closedir failed, cause: %s\n", show_error_string(result));
- return -1; // Failed to close directory
- }
- usb_osal_free(dir); // Free the directory structure
- return result;
-}
-
-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 mtp_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 = MTP_S_IFREG | MTP_S_IRUSR | MTP_S_IRGRP | MTP_S_IROTH |
- MTP_S_IWUSR | MTP_S_IWGRP | MTP_S_IWOTH;
- if (file_info.fattrib & AM_DIR) {
- buf->st_mode &= ~MTP_S_IFREG;
- buf->st_mode |= MTP_S_IFDIR | MTP_S_IXUSR | MTP_S_IXGRP | MTP_S_IXOTH;
- }
- if (file_info.fattrib & AM_RDO)
- buf->st_mode &= ~(MTP_S_IWUSR | MTP_S_IWGRP | MTP_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 == MTP_O_RDONLY) {
- flags = FA_READ | FA_OPEN_EXISTING;
- } else if (mode == MTP_O_WRONLY) {
- flags = FA_WRITE | FA_OPEN_ALWAYS;
- } else if (mode == MTP_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();
-}
diff --git a/platform/fatfs/usbh_fatfs.c b/platform/fatfs/usbh_fatfs.c
index abb7181b..9c799d62 100644
--- a/platform/fatfs/usbh_fatfs.c
+++ b/platform/fatfs/usbh_fatfs.c
@@ -14,12 +14,17 @@ int USB_disk_initialize(void)
{
active_msc_class = (struct usbh_msc *)usbh_find_class_instance("/dev/sda");
if (active_msc_class == NULL) {
- printf("do not find /dev/sda\r\n");
+ USB_LOG_ERR("do not find /dev/sda\r\n");
return RES_NOTRDY;
}
if (usbh_msc_scsi_init(active_msc_class) < 0) {
return RES_NOTRDY;
}
+
+ if ((active_msc_class->blocksize < FF_MIN_SS) || (active_msc_class->blocksize > FF_MAX_SS)) {
+ USB_LOG_ERR("unsupported block size %u\r\n", (unsigned int)active_msc_class->blocksize);
+ return RES_NOTRDY;
+ }
return RES_OK;
}
@@ -38,7 +43,7 @@ int USB_disk_read(BYTE *buff, LBA_t sector, UINT count)
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = (uint8_t *)aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
if (!align_buf) {
- printf("msc get align buf failed\r\n");
+ USB_LOG_ERR("msc get align buf failed\r\n");
return -USB_ERR_NOMEM;
}
}
@@ -68,7 +73,7 @@ int USB_disk_write(const BYTE *buff, LBA_t sector, UINT count)
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = (uint8_t *)aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
if (!align_buf) {
- printf("msc get align buf failed\r\n");
+ USB_LOG_ERR("msc get align buf failed\r\n");
return -USB_ERR_NOMEM;
}
usb_memcpy(align_buf, buff, count * active_msc_class->blocksize);
diff --git a/platform/fatfs/vfs_fatfs_port.c b/platform/fatfs/vfs_fatfs_port.c
new file mode 100644
index 00000000..efb14d33
--- /dev/null
+++ b/platform/fatfs/vfs_fatfs_port.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2024 ~ 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "ff.h"
+#include "diskio.h"
+#include "usbd_core.h"
+#include "usb_vfs.h"
+
+FATFS s_sd_disk;
+FIL s_file;
+BYTE work[FF_MAX_SS];
+
+const TCHAR driver_num_buf[4] = { DEV_SD + '0', ':', '/', '\0' };
+
+static 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));
+ }
+
+ fresult = f_chdrive(driver_num_buf);
+ 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, "readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
+ if (fresult != FR_OK) {
+ printf("Create new file failed, cause: %s\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;
+}
+
+static 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 *vfs_get_fs_root_path(void)
+{
+ return "/";
+}
+
+const char *vfs_get_fs_description(void)
+{
+ return "CherryUSB VFS FATFS";
+}
+
+/* -------------------------------------------------------------------------
+ * helpers
+ * ---------------------------------------------------------------------- */
+
+/** FatFs result -> VFS_ERR_*, so the host gets a readable reason. */
+static int adb_err(FRESULT fr)
+{
+ switch (fr) {
+ case FR_OK:
+ return 0;
+ case FR_NO_FILE:
+ case FR_NO_PATH:
+ return VFS_ERR_NOENT;
+ case FR_EXIST:
+ return VFS_ERR_EXIST;
+ case FR_INVALID_NAME:
+ return VFS_ERR_INVAL;
+ case FR_INVALID_PARAMETER:
+ return VFS_ERR_INVAL;
+ case FR_INVALID_OBJECT:
+ return VFS_ERR_INVAL;
+ case FR_WRITE_PROTECTED:
+ return VFS_ERR_ROFS;
+ case FR_DENIED:
+ /* "access denied", which FatFs also uses for a full directory */
+ return VFS_ERR_ROFS;
+ case FR_INVALID_DRIVE:
+ case FR_NOT_ENABLED:
+ case FR_NO_FILESYSTEM:
+ case FR_NOT_READY:
+ return VFS_ERR_NODEV;
+ case FR_TIMEOUT:
+ case FR_LOCKED:
+ return VFS_ERR_AGAIN;
+ case FR_NOT_ENOUGH_CORE:
+ case FR_TOO_MANY_OPEN_FILES:
+ return VFS_ERR_NOMEM;
+ case FR_DISK_ERR:
+ case FR_INT_ERR:
+ default:
+ return VFS_ERR_IO;
+ }
+}
+
+/**
+ * days since 1970-01-01, proleptic gregorian (Howard Hinnant's algorithm).
+ * Kept here rather than pulling in <time.h>, which an RTOS may not have.
+ */
+static int days_from_civil(int y, unsigned m, unsigned d)
+{
+ int era;
+ unsigned yoe, doy, doe;
+
+ y -= (m <= 2u) ? 1 : 0;
+ era = (y >= 0 ? y : y - 399) / 400;
+ yoe = (unsigned)(y - era * 400);
+ doy = (153u * (m + (m > 2u ? (unsigned)-3 : 9u)) + 2u) / 5u + d - 1u;
+ doe = yoe * 365u + yoe / 4u - yoe / 100u + doy;
+
+ return era * 146097 + (int)doe - 719468;
+}
+
+/**
+ * FatFs date/time -> unix seconds.
+ *
+ * adb sync carries the file time in STAT and DENT records, but FatFs keeps a
+ * packed DOS timestamp, so it has to be converted somewhere. Doing it here
+ * keeps the protocol layer free of file system specifics.
+ */
+static uint32_t fat_time_to_unix(uint16_t fdate, uint16_t ftime)
+{
+ unsigned year = 1980u + ((fdate >> 9) & 0x7Fu);
+ unsigned month = (fdate >> 5) & 0x0Fu;
+ unsigned day = fdate & 0x1Fu;
+ unsigned hour = ((unsigned)ftime >> 11) & 0x1Fu;
+ unsigned minute = ((unsigned)ftime >> 5) & 0x3Fu;
+ unsigned second = ((unsigned)ftime & 0x1Fu) * 2u;
+
+ if ((fdate == 0) || (month == 0) || (day == 0)) {
+ return 0; /* FatFs stores 0 when there is no valid timestamp */
+ }
+
+ return (uint32_t)(days_from_civil((int)year, month, day) * 86400 +
+ (int)(hour * 3600u + minute * 60u + second));
+}
+
+int vfs_mkdir(const char *path)
+{
+ FRESULT result;
+
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ result = f_mkdir(path);
+ /* adb push of a directory tree re-sends SEND for directories it has already
+ * created, so "it is already there" has to count as success */
+ if ((result != FR_OK) && (result != FR_EXIST)) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+int vfs_rmdir(const char *path)
+{
+ FRESULT result = f_rmdir(path);
+
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+VFS_DIR *vfs_opendir(const char *name)
+{
+ FRESULT result;
+ DIR *dir;
+
+ if (!name || !name[0]) {
+ return NULL;
+ }
+
+ dir = usb_osal_malloc(sizeof(DIR));
+ if (!dir) {
+ return NULL;
+ }
+
+ result = f_opendir(dir, name);
+ if (result != FR_OK) {
+ usb_osal_free(dir);
+ return NULL;
+ }
+
+ return (VFS_DIR *)dir;
+}
+
+int vfs_closedir(VFS_DIR *dir)
+{
+ FRESULT result;
+
+ if (!dir) {
+ return VFS_ERR_INVAL;
+ }
+
+ result = f_closedir((DIR *)dir);
+ usb_osal_free(dir); /* release it either way */
+
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+struct vfs_dirent *vfs_readdir(VFS_DIR *dir)
+{
+ static struct vfs_dirent dirent;
+ FILINFO fno;
+ FRESULT result;
+
+ if (!dir) {
+ return NULL;
+ }
+
+ result = f_readdir((DIR *)dir, &fno);
+ if ((result != FR_OK) || (fno.fname[0] == 0)) {
+ return NULL; /* end of directory, or a hard error */
+ }
+
+ memset(&dirent, 0, sizeof(dirent));
+ strncpy(dirent.d_name, fno.fname, sizeof(dirent.d_name) - 1);
+ dirent.d_name[sizeof(dirent.d_name) - 1] = '\0';
+ dirent.d_namlen = (uint8_t)strlen(dirent.d_name);
+ /* d_type is just the type field of a mode shifted down, see vfs_posix.h */
+ dirent.d_type = (uint8_t)(((fno.fattrib & AM_DIR) ? VFS_S_IFDIR
+ : VFS_S_IFREG) >>
+ 12);
+
+ 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 vfs_stat(const char *path, struct vfs_stat *buf)
+{
+ FILINFO file_info;
+ FRESULT result;
+ FATFS *f;
+
+ if (!path || !path[0] || !buf) {
+ return VFS_ERR_INVAL;
+ }
+
+ f = &s_sd_disk;
+
+ result = f_stat(path, &file_info);
+ if (result != FR_OK) {
+ /* Stay quiet on purpose: adb stats a path precisely to find out whether
+ * it exists, so "not found" is a normal answer and not an error. The
+ * service reports it to the host as "mode 0". */
+ return adb_err(result);
+ }
+
+ memset(buf, 0, sizeof(*buf));
+ buf->st_mode = VFS_S_IFREG | VFS_S_IRUSR | VFS_S_IRGRP | VFS_S_IROTH |
+ VFS_S_IWUSR | VFS_S_IWGRP | VFS_S_IWOTH;
+ if (file_info.fattrib & AM_DIR) {
+ buf->st_mode &= ~VFS_S_IFREG;
+ buf->st_mode |= VFS_S_IFDIR | VFS_S_IXUSR | VFS_S_IXGRP | VFS_S_IXOTH;
+ }
+ if (file_info.fattrib & AM_RDO) {
+ buf->st_mode &= ~(VFS_S_IWUSR | VFS_S_IWGRP | VFS_S_IWOTH);
+ }
+
+ buf->st_dev = 0;
+ buf->st_nlink = 1;
+ 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); /* st_blocks is in 512B units */
+ } else {
+ buf->st_blocks = f->csize;
+ }
+ buf->st_mtime = fat_time_to_unix(file_info.fdate, file_info.ftime);
+ return 0;
+}
+
+int vfs_statfs(const char *path, struct vfs_statfs *buf)
+{
+ FATFS *f;
+ FRESULT res;
+ DWORD fre_clust, fre_sect, tot_sect;
+
+ if (!path || !path[0] || !buf) {
+ return VFS_ERR_INVAL;
+ }
+
+ f = &s_sd_disk;
+
+ res = f_getfree(path, &fre_clust, &f);
+ if (res != FR_OK) {
+ return adb_err(res);
+ }
+ 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 vfs_open(const char *path, uint8_t mode)
+{
+ FRESULT result;
+ BYTE flags;
+
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (mode == VFS_O_RDONLY) {
+ flags = FA_READ | FA_OPEN_EXISTING;
+ } else if (mode == VFS_O_WRONLY) {
+ flags = FA_WRITE | FA_CREATE_ALWAYS;
+ } else if (mode == VFS_O_RDWR) {
+ flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
+ } else {
+ return VFS_ERR_INVAL;
+ }
+
+ result = f_open(&s_file, path, flags);
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+int vfs_close(int fd)
+{
+ FRESULT result;
+
+ (void)fd;
+
+ result = f_close(&s_file);
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+int vfs_read(int fd, void *buf, size_t len)
+{
+ UINT bytes_read;
+ FRESULT result;
+
+ (void)fd;
+
+ result = f_read(&s_file, buf, len, &bytes_read);
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return (int)bytes_read;
+}
+
+int vfs_write(int fd, const void *buf, size_t len)
+{
+ UINT bytes_written;
+ FRESULT result;
+
+ (void)fd;
+
+ result = f_write(&s_file, buf, len, &bytes_written);
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return (int)bytes_written;
+}
+
+int vfs_unlink(const char *path)
+{
+ FRESULT result = f_unlink(path);
+
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+void vfs_mount(void)
+{
+ //sd_mkfs();
+
+ sd_mount_fs();
+
+ sd_write_file();
+} \ No newline at end of file
diff --git a/platform/idf/usbh_fatfs.c b/platform/idf/usbh_fatfs.c
index fef0798f..ca2713ae 100644
--- a/platform/idf/usbh_fatfs.c
+++ b/platform/idf/usbh_fatfs.c
@@ -9,6 +9,7 @@
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
+#include "esp_idf_version.h"
#include "esp_log.h"
#include "esp_check.h"
#include "diskio_impl.h"
@@ -215,12 +216,16 @@ esp_err_t msc_host_vfs_register(struct usbh_msc *msc_class,
strcpy(vfs->base_path, base_path);
vfs->pdrv = pdrv;
+#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(6, 0, 0)
esp_vfs_fat_conf_t conf = {
.base_path = base_path,
.fat_drive = drive,
.max_files = mount_config->max_files,
};
ret = esp_vfs_fat_register(&conf, &fs);
+#else
+ ret = esp_vfs_fat_register(base_path, drive, mount_config->max_files, &fs);
+#endif
ESP_GOTO_ON_ERROR(ret, fail, TAG, "Failed to register filesystem, error=%s", esp_err_to_name(ret));
vfs->fs = fs;
diff --git a/platform/rtthread/rt_usbd_adb.c b/platform/rtthread/rt_usbd_adb_msh.c
index 4ab7f59a..d994894f 100644
--- a/platform/rtthread/rt_usbd_adb.c
+++ b/platform/rtthread/rt_usbd_adb_msh.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, sakumisu
+ * Copyright (c) 2024 ~ 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -9,33 +9,21 @@
#include "usbd_core.h"
#include "usbd_adb.h"
+#ifdef RT_USING_FINSH
+#include <shell.h>
+#include <finsh.h>
+#endif
+
#ifndef CONFIG_USBDEV_SHELL_RX_BUFSIZE
#define CONFIG_USBDEV_SHELL_RX_BUFSIZE (2048)
#endif
struct usbd_adb_shell {
struct rt_device parent;
- usb_osal_sem_t tx_done;
struct rt_ringbuffer rx_rb;
rt_uint8_t rx_rb_buffer[CONFIG_USBDEV_SHELL_RX_BUFSIZE];
} g_usbd_adb_shell;
-void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len)
-{
- rt_ringbuffer_put(&g_usbd_adb_shell.rx_rb, data, len);
-
- if (g_usbd_adb_shell.parent.rx_indicate) {
- g_usbd_adb_shell.parent.rx_indicate(&g_usbd_adb_shell.parent, len);
- }
-}
-
-void usbd_adb_notify_write_done(void)
-{
- if (g_usbd_adb_shell.tx_done) {
- usb_osal_sem_give(g_usbd_adb_shell.tx_done);
- }
-}
-
static rt_err_t usbd_adb_shell_open(struct rt_device *dev, rt_uint16_t oflag)
{
while (!usb_device_is_configured(0)) {
@@ -46,10 +34,6 @@ static rt_err_t usbd_adb_shell_open(struct rt_device *dev, rt_uint16_t oflag)
static rt_err_t usbd_adb_shell_close(struct rt_device *dev)
{
- if (g_usbd_adb_shell.tx_done) {
- usb_osal_sem_give(g_usbd_adb_shell.tx_done);
- }
-
return RT_EOK;
}
@@ -70,15 +54,7 @@ static rt_ssize_t usbd_adb_shell_write(struct rt_device *dev,
RT_ASSERT(dev != RT_NULL);
- if (!usb_device_is_configured(0)) {
- return size;
- }
-
- if (usbd_adb_can_write() && size) {
- usb_osal_sem_reset(g_usbd_adb_shell.tx_done);
- usbd_abd_write(ADB_SHELL_LOALID, buffer, size);
- usb_osal_sem_take(g_usbd_adb_shell.tx_done, 0xffffffff);
- }
+ usbd_adb_write(ADB_LOCALID_SHELL, buffer, size);
return size;
}
@@ -94,7 +70,7 @@ const static struct rt_device_ops usbd_adb_shell_ops = {
};
#endif
-void usbd_adb_shell_init(uint8_t in_ep, uint8_t out_ep)
+void rt_usbd_adb_shell_init(void)
{
rt_err_t ret;
struct rt_device *device;
@@ -125,31 +101,58 @@ void usbd_adb_shell_init(uint8_t in_ep, uint8_t out_ep)
device->fops = NULL;
#endif
- g_usbd_adb_shell.tx_done = usb_osal_sem_create(0);
rt_ringbuffer_init(&g_usbd_adb_shell.rx_rb, g_usbd_adb_shell.rx_rb_buffer, sizeof(g_usbd_adb_shell.rx_rb_buffer));
}
-static int adb_enter(int argc, char **argv)
+static void adb_shell_on_open(uint32_t remoteid)
{
- (void)argc;
- (void)argv;
-
+ USB_LOG_INFO("adb shell open, remoteid:%u\r\n", (unsigned)remoteid);
finsh_set_device("adb-sh");
rt_console_set_device("adb-sh");
+}
- return 0;
+static void adb_shell_on_close(uint32_t remoteid)
+{
+ USB_LOG_INFO("adb shell close, remoteid:%u\r\n", (unsigned)remoteid);
+}
+
+static void adb_shell_on_write(uint32_t remoteid, const uint8_t *data, uint32_t len)
+{
+ rt_size_t put;
+
+ put = rt_ringbuffer_put(&g_usbd_adb_shell.rx_rb, data, len);
+ if (g_usbd_adb_shell.parent.rx_indicate != RT_NULL) {
+ g_usbd_adb_shell.parent.rx_indicate(&g_usbd_adb_shell.parent, put);
+ }
+}
+
+static const struct adb_service adb_shell_service = {
+ .name = "shell:",
+ .localid = ADB_LOCALID_SHELL,
+ .on_open = adb_shell_on_open,
+ .on_close = adb_shell_on_close,
+ .on_write = adb_shell_on_write,
+};
+
+void usbd_adb_shell_init(void)
+{
+ if (usbd_adb_service_register(&adb_shell_service) != 0) {
+ USB_LOG_ERR("adb shell: register failed\r\n");
+ }
+ rt_usbd_adb_shell_init();
}
-MSH_CMD_EXPORT(adb_enter, adb_enter);
static int adb_exit(int argc, char **argv)
{
(void)argc;
(void)argv;
- usbd_adb_close(ADB_SHELL_LOALID);
+ usbd_adb_close(ADB_LOCALID_SHELL);
- finsh_set_device(RT_CONSOLE_DEVICE_NAME);
- rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
+ if (rt_console_get_device() != rt_device_find(RT_CONSOLE_DEVICE_NAME)) {
+ rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
+ finsh_set_device(RT_CONSOLE_DEVICE_NAME);
+ }
return 0;
}
diff --git a/platform/rtthread/rt_usbd_serial.c b/platform/rtthread/rt_usbd_serial.c
index 41fb01af..138f4cc8 100644
--- a/platform/rtthread/rt_usbd_serial.c
+++ b/platform/rtthread/rt_usbd_serial.c
@@ -258,6 +258,7 @@ void usbd_cdc_acm_serial_init(uint8_t busid, uint8_t in_ep, uint8_t out_ep)
serial->in_ep = in_ep;
serial->out_ep = out_ep;
serial->tx_done = usb_osal_sem_create(0);
+ USB_ASSERT(serial->tx_done != NULL);
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &serial->intf_ctrl));
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &serial->intf_data));
diff --git a/platform/rtthread/rt_usbh_msc.c b/platform/rtthread/rt_usbh_msc.c
index 77846665..aa2e4a8d 100644
--- a/platform/rtthread/rt_usbh_msc.c
+++ b/platform/rtthread/rt_usbh_msc.c
@@ -29,9 +29,13 @@ static rt_err_t rt_udisk_init(rt_device_t dev)
return RT_EOK;
}
-
+#if (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 0))
static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer,
rt_size_t size)
+#else
+static rt_size_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer,
+ rt_size_t size)
+#endif
{
struct usbh_msc *msc_class = (struct usbh_msc *)dev->user_data;
int ret;
@@ -62,8 +66,13 @@ static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer,
return size;
}
+#if (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 0))
static rt_ssize_t rt_udisk_write(rt_device_t dev, rt_off_t pos, const void *buffer,
rt_size_t size)
+#else
+static rt_size_t rt_udisk_write(rt_device_t dev, rt_off_t pos, const void *buffer,
+ rt_size_t size)
+#endif
{
struct usbh_msc *msc_class = (struct usbh_msc *)dev->user_data;
int ret;
diff --git a/platform/rtthread/rt_vfs_dfs.c b/platform/rtthread/rt_vfs_dfs.c
new file mode 100644
index 00000000..6bd2f20f
--- /dev/null
+++ b/platform/rtthread/rt_vfs_dfs.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include <string.h>
+#include <errno.h>
+
+#include <dfs_fs.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "usbd_core.h"
+#include "usb_vfs.h"
+
+#ifndef RT_USING_DFS
+#error "RT_USING_DFS must be enabled to use adb sync over the RT-Thread file system"
+#endif
+
+#ifndef CONFIG_USB_DFS_MOUNT_POINT
+#define CONFIG_USB_DFS_MOUNT_POINT "/"
+#endif
+
+/* -------------------------------------------------------------------------
+ * helpers
+ * ---------------------------------------------------------------------- */
+
+/**
+ * POSIX errno as a plain positive value.
+ *
+ * RT-Thread stores whatever code it was handed, and the DFS layer is not
+ * consistent about the sign, so it is normalised before being looked at.
+ */
+static int dfs_errno(void)
+{
+ int err = errno;
+
+ return (err < 0) ? -err : err;
+}
+
+/** errno -> VFS_ERR_*, so the host gets a readable reason. */
+static int dfs_errno_to_vfs(int err)
+{
+ switch (err) {
+ case ENOENT:
+ return VFS_ERR_NOENT;
+ case EEXIST:
+ return VFS_ERR_EXIST;
+ case EINVAL:
+ return VFS_ERR_INVAL;
+ case ENOTDIR:
+ return VFS_ERR_NOTDIR;
+ case EISDIR:
+ return VFS_ERR_ISDIR;
+ case ENOSPC:
+ return VFS_ERR_NOSPC;
+ case ENOMEM:
+ return VFS_ERR_NOMEM;
+ case EBUSY:
+ case EAGAIN:
+ return VFS_ERR_AGAIN;
+ case ENODEV:
+ return VFS_ERR_NODEV;
+ case EROFS:
+ case EACCES:
+ case EPERM:
+ return VFS_ERR_ROFS;
+ case EIO:
+ default:
+ return VFS_ERR_IO;
+ }
+}
+
+const char *vfs_get_fs_root_path(void)
+{
+ return CONFIG_USB_DFS_MOUNT_POINT;
+}
+
+const char *vfs_get_fs_description(void)
+{
+ return "CherryUSB VFS DFS";
+}
+
+int vfs_mkdir(const char *path)
+{
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (mkdir(path, 0777) < 0) {
+ /* adb push of a directory tree re-sends SEND for directories it has
+ * already created, so "it is already there" has to count as success */
+ int err = dfs_errno();
+
+ if (err != EEXIST) {
+ return dfs_errno_to_vfs(err);
+ }
+ }
+
+ return 0;
+}
+
+int vfs_rmdir(const char *path)
+{
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (rmdir(path) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return 0;
+}
+
+VFS_DIR *vfs_opendir(const char *name)
+{
+ DIR *dir;
+
+ if (!name || !name[0]) {
+ return NULL;
+ }
+
+ dir = opendir(name);
+ if (!dir) {
+ return NULL;
+ }
+
+ return (VFS_DIR *)dir;
+}
+
+int vfs_closedir(VFS_DIR *dir)
+{
+ if (!dir) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (closedir((DIR *)dir) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return 0;
+}
+
+struct vfs_dirent *vfs_readdir(VFS_DIR *dir)
+{
+ static struct vfs_dirent dirent;
+ struct dirent *entry;
+
+ if (!dir) {
+ return NULL;
+ }
+
+ entry = readdir((DIR *)dir);
+ if (!entry) {
+ return NULL; /* end of directory, or a hard error */
+ }
+
+ memset(&dirent, 0, sizeof(dirent));
+ strncpy(dirent.d_name, entry->d_name, sizeof(dirent.d_name) - 1);
+ dirent.d_name[sizeof(dirent.d_name) - 1] = '\0';
+ dirent.d_namlen = (uint8_t)strlen(dirent.d_name);
+ /* d_type is just the type field of a mode shifted down, see usb_vfs.h.
+ * RT-Thread hands back DT_*, so the two cases that matter are translated
+ * and anything else (including DT_UNKNOWN) falls back to a regular file. */
+ dirent.d_type = (entry->d_type == DT_DIR) ? (uint8_t)(VFS_S_IFDIR >> 12)
+ : (uint8_t)(VFS_S_IFREG >> 12);
+
+ return &dirent;
+}
+
+int vfs_stat(const char *path, struct vfs_stat *buf)
+{
+ struct stat st;
+
+ if (!path || !path[0] || !buf) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (stat(path, &st) < 0) {
+ /* Stay quiet on purpose: adb stats a path precisely to find out whether
+ * it exists, so "not found" is a normal answer and not an error. The
+ * service reports it to the host as "mode 0". */
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ memset(buf, 0, sizeof(*buf));
+ if (S_ISDIR(st.st_mode)) {
+ buf->st_mode = VFS_S_IFDIR | VFS_S_IRWXU | VFS_S_IRWXG | VFS_S_IRWXO;
+ } else {
+ buf->st_mode = VFS_S_IFREG | VFS_S_IRUSR | VFS_S_IRGRP | VFS_S_IROTH |
+ VFS_S_IWUSR | VFS_S_IWGRP | VFS_S_IWOTH;
+ }
+
+ buf->st_dev = 0;
+ buf->st_nlink = 1;
+ buf->st_size = st.st_size;
+ buf->st_mtime = st.st_mtime;
+ /* st_blksize/st_blocks are left at zero: RT-Thread's struct stat does not
+ * carry them consistently across DFS versions, and the adb STAT record
+ * only ever reports mode, size and mtime. */
+ return 0;
+}
+
+int vfs_statfs(const char *path, struct vfs_statfs *buf)
+{
+ struct statfs st;
+
+ if (!path || !path[0] || !buf) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (dfs_statfs(path, &st) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ buf->f_bsize = st.f_bsize;
+ buf->f_blocks = st.f_blocks;
+ buf->f_bfree = st.f_bfree;
+ return 0;
+}
+
+int vfs_open(const char *path, uint8_t mode)
+{
+ int flags;
+ int fd;
+
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (mode == VFS_O_RDONLY) {
+ flags = O_RDONLY; /* existing file only */
+ } else if (mode == VFS_O_WRONLY) {
+ flags = O_WRONLY | O_CREAT | O_TRUNC; /* create / truncate */
+ } else if (mode == VFS_O_RDWR) {
+ flags = O_RDWR | O_CREAT; /* create, no truncate */
+ } else {
+ return VFS_ERR_INVAL;
+ }
+
+ fd = open(path, flags, 0666);
+ if (fd < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return fd;
+}
+
+int vfs_close(int fd)
+{
+ if (fd < 0) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (close(fd) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return 0;
+}
+
+int vfs_read(int fd, void *buf, size_t len)
+{
+ int ret;
+
+ if (fd < 0) {
+ return VFS_ERR_INVAL;
+ }
+
+ ret = (int)read(fd, buf, len);
+ if (ret < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return ret;
+}
+
+int vfs_write(int fd, const void *buf, size_t len)
+{
+ int ret;
+
+ if (fd < 0) {
+ return VFS_ERR_INVAL;
+ }
+
+ ret = (int)write(fd, buf, len);
+ if (ret < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return ret;
+}
+
+int vfs_unlink(const char *path)
+{
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (unlink(path) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return 0;
+}
diff --git a/platform/zephyr/usbh_msc_disk.c b/platform/zephyr/usbh_msc_disk.c
index 6890f985..129cbfe4 100644
--- a/platform/zephyr/usbh_msc_disk.c
+++ b/platform/zephyr/usbh_msc_disk.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, sakumisu
+ * Copyright (c) 2025-2026 sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,16 +13,37 @@
#endif
#endif
-struct usbh_msc *active_msc_class;
+struct usbh_msc_disk_context {
+ struct usbh_msc *msc_class;
+ struct disk_info disk;
+ char name[CONFIG_USBHOST_DEV_NAMELEN];
+ char devname[CONFIG_USBHOST_DEV_NAMELEN];
+};
+
+static struct usbh_msc_disk_context
+ msc_disk_context[CONFIG_USBHOST_MAX_MSC_CLASS];
+
+static struct usbh_msc_disk_context *disk_msc_context(struct disk_info *disk)
+{
+ return CONTAINER_OF(disk, struct usbh_msc_disk_context, disk);
+}
+
+static bool disk_msc_connected(const struct usbh_msc *msc_class)
+{
+ return msc_class != NULL && msc_class->hport != NULL &&
+ msc_class->hport->connected;
+}
static int disk_msc_access_init(struct disk_info *disk)
{
- active_msc_class = (struct usbh_msc *)usbh_find_class_instance("/dev/sda");
- if (active_msc_class == NULL) {
- printf("do not find /dev/sda\r\n");
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
+ ctx->msc_class = (struct usbh_msc *)usbh_find_class_instance(ctx->devname);
+ if (ctx->msc_class == NULL) {
+ printf("do not find %s\r\n", ctx->devname);
return -ENODEV;
}
- if (usbh_msc_scsi_init(active_msc_class) < 0) {
+ if (usbh_msc_scsi_init(ctx->msc_class) < 0) {
return -EIO;
}
return 0;
@@ -30,6 +51,12 @@ static int disk_msc_access_init(struct disk_info *disk)
static int disk_msc_access_status(struct disk_info *disk)
{
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return DISK_STATUS_NOMEDIA;
+ }
+
return DISK_STATUS_OK;
}
@@ -38,25 +65,30 @@ static int disk_msc_access_read(struct disk_info *disk, uint8_t *buff,
{
int ret;
uint8_t *align_buf;
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return -ENODEV;
+ }
align_buf = (uint8_t *)buff;
#ifdef CONFIG_DCACHE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
- align_buf = (uint8_t *)k_aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
+ align_buf = (uint8_t *)k_aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * ctx->msc_class->blocksize);
if (!align_buf) {
printf("msc get align buf failed\r\n");
return -ENOMEM;
}
}
#endif
- if (usbh_msc_scsi_read10(active_msc_class, sector, align_buf, count) < 0) {
+ if (usbh_msc_scsi_read10(ctx->msc_class, sector, align_buf, count) < 0) {
ret = -EIO;
} else {
ret = 0;
}
#ifdef CONFIG_DCACHE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
- usb_memcpy(buff, align_buf, count * active_msc_class->blocksize);
+ usb_memcpy(buff, align_buf, count * ctx->msc_class->blocksize);
k_free(align_buf);
}
#endif
@@ -68,19 +100,24 @@ static int disk_msc_access_write(struct disk_info *disk, const uint8_t *buff,
{
int ret;
uint8_t *align_buf;
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return -ENODEV;
+ }
align_buf = (uint8_t *)buff;
#ifdef CONFIG_DCACHE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
- align_buf = (uint8_t *)k_aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
+ align_buf = (uint8_t *)k_aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * ctx->msc_class->blocksize);
if (!align_buf) {
printf("msc get align buf failed\r\n");
return -ENOMEM;
}
- usb_memcpy(align_buf, buff, count * active_msc_class->blocksize);
+ usb_memcpy(align_buf, buff, count * ctx->msc_class->blocksize);
}
#endif
- if (usbh_msc_scsi_write10(active_msc_class, sector, align_buf, count) < 0) {
+ if (usbh_msc_scsi_write10(ctx->msc_class, sector, align_buf, count) < 0) {
ret = -EIO;
} else {
ret = 0;
@@ -95,14 +132,22 @@ static int disk_msc_access_write(struct disk_info *disk, const uint8_t *buff,
static int disk_msc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buff)
{
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
switch (cmd) {
case DISK_IOCTL_CTRL_SYNC:
break;
case DISK_IOCTL_GET_SECTOR_COUNT:
- *(uint32_t *)buff = active_msc_class->blocknum;
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return -ENODEV;
+ }
+ *(uint32_t *)buff = ctx->msc_class->blocknum;
break;
case DISK_IOCTL_GET_SECTOR_SIZE:
- *(uint32_t *)buff = active_msc_class->blocksize;
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return -ENODEV;
+ }
+ *(uint32_t *)buff = ctx->msc_class->blocksize;
break;
case DISK_IOCTL_GET_ERASE_BLOCK_SZ:
*(uint32_t *)buff = 1U;
@@ -126,17 +171,56 @@ static const struct disk_operations msc_disk_ops = {
.ioctl = disk_msc_access_ioctl,
};
-static struct disk_info usbh_msc_disk = {
- .name = "USB",
- .ops = &msc_disk_ops,
-};
+__WEAK void usbh_msc_app_run(struct usbh_msc *msc_class)
+{
+ (void)msc_class;
+}
+
+__WEAK void usbh_msc_app_stop(struct usbh_msc *msc_class)
+{
+ (void)msc_class;
+}
void usbh_msc_run(struct usbh_msc *msc_class)
{
- disk_access_register(&usbh_msc_disk);
+ uint8_t index;
+ struct usbh_msc_disk_context *ctx;
+
+ if (msc_class == NULL || msc_class->sdchar < 'a' ||
+ msc_class->sdchar >= 'a' + CONFIG_USBHOST_MAX_MSC_CLASS) {
+ return;
+ }
+
+ index = msc_class->sdchar - 'a';
+ ctx = &msc_disk_context[index];
+ memset(ctx, 0, sizeof(*ctx));
+ snprintf(ctx->name, sizeof(ctx->name), "USB%u", index);
+ snprintf(ctx->devname, sizeof(ctx->devname), "/dev/sd%c", msc_class->sdchar);
+ ctx->msc_class = msc_class;
+ ctx->disk.name = ctx->name;
+ ctx->disk.ops = &msc_disk_ops;
+
+ if (disk_access_register(&ctx->disk) < 0) {
+ return;
+ }
+
+ usbh_msc_app_run(msc_class);
}
void usbh_msc_stop(struct usbh_msc *msc_class)
{
- disk_access_unregister(&usbh_msc_disk);
-} \ No newline at end of file
+ uint8_t index;
+ struct usbh_msc_disk_context *ctx;
+
+ usbh_msc_app_stop(msc_class);
+
+ if (msc_class == NULL || msc_class->sdchar < 'a' ||
+ msc_class->sdchar >= 'a' + CONFIG_USBHOST_MAX_MSC_CLASS) {
+ return;
+ }
+
+ index = msc_class->sdchar - 'a';
+ ctx = &msc_disk_context[index];
+ disk_access_unregister(&ctx->disk);
+ ctx->msc_class = NULL;
+}