diff --git a/components/fatfs/diskio/diskio.c b/components/fatfs/diskio/diskio.c index 7d39835fb7..5804e905c4 100644 --- a/components/fatfs/diskio/diskio.c +++ b/components/fatfs/diskio/diskio.c @@ -13,6 +13,7 @@ #include #include #include "diskio_impl.h" +#include "private_include/diskio_private.h" #include "ffconf.h" #include "ff.h" @@ -117,3 +118,16 @@ DWORD get_fattime(void) | (WORD)(tmr.tm_min << 5) | (WORD)(tmr.tm_sec >> 1); } + +bool ff_diskio_is_registered(BYTE ldrv) +{ + if (ldrv < FF_VOLUMES && s_impls[ldrv]) { + return true; + } + return false; +} + +inline DRESULT ff_diskio_get_sector_size(BYTE ldrv, UINT* out_bytes_per_sector) +{ + return ff_disk_ioctl(ldrv, GET_SECTOR_SIZE, (void*) out_bytes_per_sector); +} diff --git a/components/fatfs/diskio/diskio_sdmmc.c b/components/fatfs/diskio/diskio_sdmmc.c index 689a07bc62..4c76510544 100644 --- a/components/fatfs/diskio/diskio_sdmmc.c +++ b/components/fatfs/diskio/diskio_sdmmc.c @@ -5,6 +5,7 @@ */ #include "diskio_impl.h" +#include "private_include/diskio_sdmmc_private.h" #include "ffconf.h" #include "ff.h" #include "sdmmc_cmd.h" @@ -143,3 +144,14 @@ BYTE ff_diskio_get_pdrv_card(const sdmmc_card_t* card) } return 0xff; } + +BYTE ff_diskio_get_pdrv_cnt_card(const sdmmc_card_t* card) +{ + BYTE num = 0; + for (int i = 0; i < FF_VOLUMES; i++) { + if (card == s_cards[i]) { + num += 1; + } + } + return num; +} diff --git a/components/fatfs/diskio/diskio_sdmmc.h b/components/fatfs/diskio/diskio_sdmmc.h index d6c881ae58..85c85b2964 100644 --- a/components/fatfs/diskio/diskio_sdmmc.h +++ b/components/fatfs/diskio/diskio_sdmmc.h @@ -1,13 +1,12 @@ /* - * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include "sdmmc_cmd.h" -#include "sd_protocol_defs.h" +#include "sd_protocol_types.h" #ifdef __cplusplus extern "C" { @@ -30,9 +29,9 @@ void ff_sdmmc_set_disk_status_check(BYTE pdrv, bool enable); void ff_diskio_register_sdmmc(unsigned char pdrv, sdmmc_card_t* card); /** - * @brief Get the driver number corresponding to a card + * @brief Get the first registered drive number corresponding to a card * - * @param card The card to get its driver + * @param card The card to get its drive number * @return Driver number to the card */ BYTE ff_diskio_get_pdrv_card(const sdmmc_card_t* card); diff --git a/components/fatfs/diskio/private_include/diskio_private.h b/components/fatfs/diskio/private_include/diskio_private.h new file mode 100644 index 0000000000..220edf0e7a --- /dev/null +++ b/components/fatfs/diskio/private_include/diskio_private.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "diskio.h" + +/** + * @brief Check if a drive number is registered + * + * @param ldrv logical or physical drive number + * + * @return true if the drive number is registered, false otherwise + */ +bool ff_diskio_is_registered(BYTE ldrv); + +/** + * @brief Get sector size of a drive + * + * @param ldrv logical or physical drive number + * @param out_bytes_per_sector output parameter to receive the sector size in bytes + * + * @return DRESULT indicating success or failure + */ +DRESULT ff_diskio_get_sector_size(BYTE ldrv, UINT* out_bytes_per_sector); + +#ifdef __cplusplus +} +#endif diff --git a/components/fatfs/diskio/private_include/diskio_sdmmc_private.h b/components/fatfs/diskio/private_include/diskio_sdmmc_private.h new file mode 100644 index 0000000000..3ed8e8142a --- /dev/null +++ b/components/fatfs/diskio/private_include/diskio_sdmmc_private.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sd_protocol_types.h" + +typedef unsigned char BYTE; + +/** + * @brief Get count of all registered drives corresponding to a card + * + * @param card The card to get its drive number + * @return Number of registered drives to the card + */ +BYTE ff_diskio_get_pdrv_cnt_card(const sdmmc_card_t* card); + +#ifdef __cplusplus +} +#endif diff --git a/components/fatfs/vfs/esp_vfs_fat.h b/components/fatfs/vfs/esp_vfs_fat.h index e8e4aec145..332a131c80 100644 --- a/components/fatfs/vfs/esp_vfs_fat.h +++ b/components/fatfs/vfs/esp_vfs_fat.h @@ -16,6 +16,26 @@ extern "C" { #endif +typedef enum { + FORMATTED_DURING_LAST_MOUNT = 1 << 0, // The FATFS partition was formatted during the last mount +} vfs_fat_x_ctx_flags_t; + +typedef PARTITION esp_vfs_fat_pdrv_part_t; + +/** + * @note When the value of item is less than or equal to 100, it specifies the partition size in percentage of the entire drive space. + * When it is larger than 100, it specifies number of sectors. The partition map table is terminated by a zero, + * 4th partition in MBR format or no remaining space for next allocation. If the specified size is larger than remaining space on the drive, + * the partition is truncated at end of the drive. + * + * For example: + * + * `{100, 0, 0, 0}` will create a single partition with 100% of the drive space. + * `{50, 50, 0, 0}` will create two partitions, first with 50% of the drive space and second with the remaining 50%. + * `{0x10000000, 0x10000000, 0x10000000, 0}` will create three partitions, each with a size of 256 MiB, leaving remaining space non-allocated. + */ +typedef LBA_t esp_vfs_fat_drive_divide_arr_t[4]; + /** * @brief Configuration structure for esp_vfs_fat_register */ @@ -152,9 +172,10 @@ typedef esp_vfs_fat_mount_config_t esp_vfs_fat_sdmmc_mount_config_t; * For SDMMC peripheral, pass a pointer to sdmmc_slot_config_t * structure initialized using SDMMC_SLOT_CONFIG_DEFAULT. * @param mount_config pointer to structure with extra parameters for mounting FATFS - * @param[out] out_card if not NULL, pointer to the card information structure will be returned via this argument + * @param[out] out_card pointer to the card information structure will be returned via this argument * @return * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if any of the arguments is NULL * - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called * - ESP_ERR_NO_MEM if memory can not be allocated * - ESP_FAIL if partition can not be mounted @@ -192,12 +213,13 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, * For SPI peripheral, pass a pointer to sdspi_device_config_t * structure initialized using SDSPI_DEVICE_CONFIG_DEFAULT(). * @param mount_config pointer to structure with extra parameters for mounting FATFS - * @param[out] out_card If not NULL, pointer to the card information structure will be returned via + * @param[out] out_card Pointer to the card information structure will be returned via * this argument. It is suggested to hold this handle and use it to unmount the card later if * needed. Otherwise it's not suggested to use more than one card at the same time and unmount one * of them in your application. * @return * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if any of the arguments is NULL * - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called * - ESP_ERR_NO_MEM if memory can not be allocated * - ESP_FAIL if partition can not be mounted diff --git a/components/fatfs/vfs/vfs_fat.c b/components/fatfs/vfs/vfs_fat.c index a2c865b4c5..aeab037f57 100644 --- a/components/fatfs/vfs/vfs_fat.c +++ b/components/fatfs/vfs/vfs_fat.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,10 +14,12 @@ #include #include #include "esp_vfs_fat.h" +#include "vfs_fat_internal.h" #include "esp_vfs.h" #include "esp_log.h" #include "ff.h" #include "diskio_impl.h" +#include "private_include/diskio_private.h" #define F_WRITE_MALLOC_ZEROING_BUF_SIZE_LIMIT 512 @@ -1530,3 +1532,63 @@ fail: errno = fresult_to_errno(res); return -1; } + +esp_err_t esp_vfs_fat_format_drive(uint8_t ldrv, const esp_vfs_fat_mount_config_t* mount_config) +{ + if (mount_config == NULL || !ff_diskio_is_registered(ldrv)) { + return ESP_ERR_INVALID_ARG; + } + + FRESULT res = FR_OK; + esp_err_t err = ESP_OK; + const size_t workbuf_size = 4096; + void* workbuf = NULL; + + workbuf = ff_memalloc(workbuf_size); + if (workbuf == NULL) { + return ESP_ERR_NO_MEM; + } + + size_t sector_size = 512; // default value + ff_diskio_get_sector_size(ldrv, §or_size); + size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(sector_size, mount_config->allocation_unit_size); + ESP_LOGW(TAG, "formatting drive, allocation unit size=%d", alloc_unit_size); + const MKFS_PARM opt = {(BYTE)FM_ANY, (mount_config->use_one_fat ? 1 : 2), 0, 0, alloc_unit_size}; + char drv[3] = {(char)('0' + ldrv), ':', 0}; + res = f_mkfs(drv, &opt, workbuf, workbuf_size); + if (res != FR_OK) { + err = ESP_FAIL; + ESP_LOGE(TAG, "f_mkfs failed (%d)", res); + } + + free(workbuf); + return err; +} + +esp_err_t esp_vfs_fat_partition_drive(uint8_t pdrv, const esp_vfs_fat_drive_divide_arr_t drive_divide) +{ + if (!ff_diskio_is_registered(pdrv)) { + return ESP_ERR_INVALID_ARG; + } + + FRESULT res = FR_OK; + esp_err_t err = ESP_OK; + const size_t workbuf_size = 4096; + void* workbuf = NULL; + ESP_LOGD(TAG, "partitioning drive"); + + workbuf = ff_memalloc(workbuf_size); + if (workbuf == NULL) { + return ESP_ERR_NO_MEM; + } + + LBA_t ptbl[4] = {drive_divide[0], drive_divide[1], drive_divide[2], drive_divide[3]}; + res = f_fdisk(pdrv, ptbl, workbuf); + if (res != FR_OK) { + err = ESP_FAIL; + ESP_LOGE(TAG, "f_fdisk failed (%d)", res); + } + + free(workbuf); + return err; +} diff --git a/components/fatfs/vfs/vfs_fat_internal.h b/components/fatfs/vfs/vfs_fat_internal.h index 5b8946044d..d20f64c438 100644 --- a/components/fatfs/vfs/vfs_fat_internal.h +++ b/components/fatfs/vfs/vfs_fat_internal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,10 +13,6 @@ #include #include -typedef enum { - FORMATTED_DURING_LAST_MOUNT = 1 << 0, // The FATFS partition was formatted during the last mount -} vfs_fat_x_ctx_flags_t; - typedef struct vfs_fat_spiflash_ctx_t { const esp_partition_t *partition; //The partition where the FAT is located bool by_label; //If the partition is mounted by label or not @@ -49,3 +45,88 @@ static inline size_t esp_vfs_fat_get_allocation_unit_size( vfs_fat_spiflash_ctx_t* get_vfs_fat_spiflash_ctx(wl_handle_t wlhandle); vfs_fat_sd_ctx_t* get_vfs_fat_get_sd_ctx(const sdmmc_card_t *card); + +/** + * @brief Helper function to initialize SD card using SDMMC peripheral + * + * @param host_config pointer to structure describing SDMMC host + * @param slot_config pointer to structure with slot configuration + * @param card pointer to structure with card information + * @param[out] out_host_inited if not NULL, pointer to boolean variable will be set to true if host was initialized + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if any of the arguments other than `out_host_inited` is NULL + * - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers + */ +esp_err_t esp_vfs_fat_sdmmc_sdcard_init(const sdmmc_host_t* host_config, const void* slot_config, sdmmc_card_t* card, bool* out_host_inited); + +/** + * @brief Helper function to initialize SD card using SDSPI peripheral + * + * @param host_config pointer to structure describing SDSPI host + * @param slot_config pointer to structure with slot configuration + * @param card pointer to structure with card information + * @param[out] out_host_inited if not NULL, pointer to boolean variable will be set to true if host was initialized + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if any of the arguments other than `out_host_inited` is NULL + * - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers + */ +esp_err_t esp_vfs_fat_sdspi_sdcard_init(const sdmmc_host_t* host_config, const void* slot_config, sdmmc_card_t* card, bool* out_host_inited); + +/** + * @brief Convenience function to get FAT filesystem registered and mounted in VFS with an initialized card handle + * + * @note This function is intended to be used when the card is already initialized and the user wants to mount the FAT filesystem on it. + * Can be used to mount multiple partitions on a single card. + * + * @param card pointer to the card handle, which should be initialised by calling `esp_vfs_fat_sdmmc_sdcard_init` or `esp_vfs_fat_sdspi_sdcard_init` first + * @param base_path path where partition should be registered (e.g. "/sdcard" or "/part1", etc.) + * @param mount_config pointer to structure with extra parameters for mounting FATFS + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if any of the arguments is NULL + * - ESP_ERR_NO_MEM if memory can not be allocated + * - ESP_FAIL if partition can not be mounted + * - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers + */ +esp_err_t esp_vfs_fat_mount_initialized(sdmmc_card_t* card, + const char* base_path, + const esp_vfs_fat_mount_config_t* mount_config); + +/** + * @brief Format FATFS partition on a drive to FAT filesystem + * + * @param ldrv logical or physical drive number + * @param mount_config pointer to structure with extra parameters for mounting FATFS + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if mount_config is NULL or ldrv is not valid + * - ESP_ERR_NO_MEM if memory allocation failed + * - ESP_FAIL if f_mkfs failed + */ +esp_err_t esp_vfs_fat_format_drive(uint8_t ldrv, const esp_vfs_fat_mount_config_t* mount_config); + +/** + * @brief Partition the drive to multiple FATFS partitions + * + * @param pdrv physical drive number + * @param drive_divide array of 4 LBA_t values, specifying the size of each partition + * + * @note `esp_vfs_fat_drive_divide_arr_t drive_divide` + * - When the value of item is less than or equal to 100, it specifies the partition size in percentage of the entire drive space. + * When it is larger than 100, it specifies number of sectors. The partition map table is terminated by a zero, + * 4th partition in MBR format or no remaining space for next allocation. If the specified size is larger than remaining space on the drive, + * the partition is truncated at end of the drive. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if pdrv is not valid + * - ESP_ERR_NO_MEM if memory allocation failed + * - ESP_FAIL if f_fdisk failed + */ +esp_err_t esp_vfs_fat_partition_drive(uint8_t pdrv, const esp_vfs_fat_drive_divide_arr_t drive_divide); diff --git a/components/fatfs/vfs/vfs_fat_sdmmc.c b/components/fatfs/vfs/vfs_fat_sdmmc.c index 160c5c0101..b559c0cd3f 100644 --- a/components/fatfs/vfs/vfs_fat_sdmmc.c +++ b/components/fatfs/vfs/vfs_fat_sdmmc.c @@ -17,6 +17,7 @@ #include "diskio_sdmmc.h" #include "soc/soc_caps.h" #include "sd_protocol_defs.h" +#include "private_include/diskio_sdmmc_private.h" #if SOC_SDMMC_HOST_SUPPORTED #include "driver/sdmmc_host.h" @@ -34,8 +35,7 @@ static const char* TAG = "vfs_fat_sdmmc"; static vfs_fat_sd_ctx_t *s_ctx[FF_VOLUMES] = {}; static void call_host_deinit(const sdmmc_host_t *host_config); -static esp_err_t partition_card(const esp_vfs_fat_mount_config_t *mount_config, - const char *drv, sdmmc_card_t *card, BYTE pdrv); +static esp_err_t partition_card(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, BYTE pdrv); static bool s_get_context_id_by_card(const sdmmc_card_t *card, uint32_t *out_id) { @@ -73,12 +73,10 @@ vfs_fat_sd_ctx_t* get_vfs_fat_get_sd_ctx(const sdmmc_card_t *card) static esp_err_t mount_prepare_mem(const char *base_path, BYTE *out_pdrv, - char **out_dup_path, - sdmmc_card_t** out_card) + char **out_dup_path) { esp_err_t err = ESP_OK; char* dup_path = NULL; - sdmmc_card_t* card = NULL; // connect SDMMC driver to FATFS BYTE pdrv = FF_DRV_NOT_USED; @@ -87,14 +85,6 @@ static esp_err_t mount_prepare_mem(const char *base_path, return ESP_ERR_NO_MEM; } - // not using ff_memalloc here, as allocation in internal RAM is preferred - card = (sdmmc_card_t*)malloc(sizeof(sdmmc_card_t)); - if (card == NULL) { - ESP_LOGD(TAG, "could not locate new sdmmc_card_t"); - err = ESP_ERR_NO_MEM; - goto cleanup; - } - dup_path = strdup(base_path); if(!dup_path){ ESP_LOGD(TAG, "could not copy base_path"); @@ -102,18 +92,17 @@ static esp_err_t mount_prepare_mem(const char *base_path, goto cleanup; } - *out_card = card; *out_pdrv = pdrv; *out_dup_path = dup_path; return ESP_OK; cleanup: - free(card); free(dup_path); return err; } -static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config, vfs_fat_x_ctx_flags_t *out_flags) +static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config, vfs_fat_x_ctx_flags_t *out_flags) { + char drv[3] = {(char)('0' + pdrv), ':', 0}; esp_err_t err = ESP_OK; FRESULT res = f_mount(fs, drv, 1); if (res != FR_OK) { @@ -125,7 +114,7 @@ static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8 return ESP_FAIL; } - err = partition_card(mount_config, drv, card, pdrv); + err = partition_card(mount_config, card, pdrv); if (err != ESP_OK) { return err; } @@ -150,7 +139,7 @@ static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8 return ESP_OK; } -static esp_err_t mount_to_vfs_fat(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, uint8_t pdrv, +static esp_err_t esp_vfs_fat_mount_internal(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, uint8_t pdrv, const char *base_path, FATFS **out_fs, vfs_fat_x_ctx_flags_t *out_flags) { FATFS *fs = NULL; @@ -176,7 +165,7 @@ static esp_err_t mount_to_vfs_fat(const esp_vfs_fat_mount_config_t *mount_config } // Try to mount partition - err = s_f_mount(card, fs, drv, pdrv, mount_config, out_flags); + err = s_f_mount(card, fs, pdrv, mount_config, out_flags); if (err != ESP_OK) { goto fail; } @@ -191,44 +180,44 @@ fail: return err; } -static esp_err_t partition_card(const esp_vfs_fat_mount_config_t *mount_config, - const char *drv, sdmmc_card_t *card, BYTE pdrv) +static esp_err_t partition_card(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, BYTE pdrv) { - FRESULT res = FR_OK; - esp_err_t err; - const size_t workbuf_size = 4096; - void* workbuf = NULL; - ESP_LOGW(TAG, "partitioning card"); + esp_err_t err = ESP_OK; + esp_vfs_fat_drive_divide_arr_t partitions = {100, 0, 0, 0}; + err = esp_vfs_fat_partition_drive(pdrv, partitions); + if (err != ESP_OK) { + return err; + } + err = esp_vfs_fat_format_drive(pdrv, mount_config); + return err; +} - workbuf = ff_memalloc(workbuf_size); - if (workbuf == NULL) { +static esp_err_t esp_vfs_fat_save_ctx(uint8_t drv_num, + const esp_vfs_fat_mount_config_t* mount_config, + sdmmc_card_t* card, + char* base_path, + FATFS* fs, + vfs_fat_x_ctx_flags_t flags) +{ + vfs_fat_sd_ctx_t *ctx = NULL; + uint32_t ctx_id = FF_VOLUMES; + + ctx = calloc(1, sizeof(vfs_fat_sd_ctx_t)); + if (!ctx) { + ESP_LOGE(TAG, "mount_prepare failed"); return ESP_ERR_NO_MEM; } + ctx->pdrv = drv_num; + memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t)); + ctx->card = card; + ctx->base_path = base_path; + ctx->fs = fs; + ctx->flags = flags; + ctx_id = s_get_unused_context_id(); + assert(ctx_id != FF_VOLUMES); + s_ctx[ctx_id] = ctx; - LBA_t plist[] = {100, 0, 0, 0}; - res = f_fdisk(pdrv, plist, workbuf); - if (res != FR_OK) { - err = ESP_FAIL; - ESP_LOGD(TAG, "f_fdisk failed (%d)", res); - goto fail; - } - size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size( - card->csd.sector_size, - mount_config->allocation_unit_size); - ESP_LOGW(TAG, "formatting card, allocation unit size=%d", alloc_unit_size); - const MKFS_PARM opt = {(BYTE)FM_ANY, (mount_config->use_one_fat ? 1 : 2), 0, 0, alloc_unit_size}; - res = f_mkfs(drv, &opt, workbuf, workbuf_size); - if (res != FR_OK) { - err = ESP_FAIL; - ESP_LOGD(TAG, "f_mkfs failed (%d)", res); - goto fail; - } - - free(workbuf); return ESP_OK; -fail: - free(workbuf); - return err; } #if SOC_SDMMC_HOST_SUPPORTED @@ -238,29 +227,19 @@ static esp_err_t init_sdmmc_host(int slot, const void *slot_config, int *out_slo return sdmmc_host_init_slot(slot, (const sdmmc_slot_config_t*) slot_config); } - -esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, - const sdmmc_host_t* host_config, - const void* slot_config, - const esp_vfs_fat_mount_config_t* mount_config, - sdmmc_card_t** out_card) +esp_err_t esp_vfs_fat_sdmmc_sdcard_init(const sdmmc_host_t* host_config, + const void* slot_config, + sdmmc_card_t* card, + bool* out_host_inited) { - esp_err_t err; - vfs_fat_sd_ctx_t *ctx = NULL; - uint32_t ctx_id = FF_VOLUMES; - FATFS *fs = NULL; - int card_handle = -1; //uninitialized - sdmmc_card_t* card = NULL; - BYTE pdrv = FF_DRV_NOT_USED; - char* dup_path = NULL; - bool host_inited = false; - - err = mount_prepare_mem(base_path, &pdrv, &dup_path, &card); - if (err != ESP_OK) { - ESP_LOGE(TAG, "mount_prepare failed"); - return err; + if (host_config == NULL || slot_config == NULL || card == NULL) { + return ESP_ERR_INVALID_ARG; } + esp_err_t err; + int card_handle = -1; //uninitialized + bool host_inited = false; + err = (*host_config->init)(); CHECK_EXECUTE_RESULT(err, "host init failed"); //deinit() needs to be called to revert the init @@ -274,36 +253,53 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, err = sdmmc_card_init(host_config, card); CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed"); - vfs_fat_x_ctx_flags_t flags = 0; - - err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs, &flags); - CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed"); - - if (out_card != NULL) { - *out_card = card; + if (out_host_inited != NULL) { + *out_host_inited = host_inited; } - ctx = calloc(1, sizeof(vfs_fat_sd_ctx_t)); - if (!ctx) { - CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem"); - } - ctx->pdrv = pdrv; - memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t)); - ctx->card = card; - ctx->base_path = dup_path; - ctx->fs = fs; - ctx->flags = flags; - ctx_id = s_get_unused_context_id(); - assert(ctx_id != FF_VOLUMES); - s_ctx[ctx_id] = ctx; - + return ESP_OK; +cleanup: + if (host_inited) { + call_host_deinit(host_config); + } + return err; +} + +esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, + const sdmmc_host_t* host_config, + const void* slot_config, + const esp_vfs_fat_mount_config_t* mount_config, + sdmmc_card_t** out_card) +{ + if (base_path == NULL || host_config == NULL || slot_config == NULL || mount_config == NULL || out_card == NULL) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err; + sdmmc_card_t* card = NULL; + bool host_inited = false; + + // not using ff_memalloc here, as allocation in internal RAM is preferred + card = (sdmmc_card_t*) malloc(sizeof(sdmmc_card_t)); + if (card == NULL) { + ESP_LOGD(TAG, "could not locate new sdmmc_card_t"); + err = ESP_ERR_NO_MEM; + goto cleanup; + } + + err = esp_vfs_fat_sdmmc_sdcard_init(host_config, slot_config, card, &host_inited); + CHECK_EXECUTE_RESULT(err, "esp_vfs_fat_sdmmc_sdcard_init failed"); + + err = esp_vfs_fat_mount_initialized(card, base_path, mount_config); + CHECK_EXECUTE_RESULT(err, "esp_vfs_fat_mount_initialized failed"); + + *out_card = card; return ESP_OK; cleanup: if (host_inited) { call_host_deinit(host_config); } free(card); - free(dup_path); return err; } #endif @@ -320,34 +316,25 @@ bus first and check the device parameters." return err; } -esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path, - const sdmmc_host_t* host_config_input, - const sdspi_device_config_t* slot_config, - const esp_vfs_fat_mount_config_t* mount_config, - sdmmc_card_t** out_card) +esp_err_t esp_vfs_fat_sdspi_sdcard_init(const sdmmc_host_t* host_config, + const void* slot_config, + sdmmc_card_t* card, + bool* out_host_inited) { - const sdmmc_host_t* host_config = host_config_input; - esp_err_t err; - vfs_fat_sd_ctx_t *ctx = NULL; - uint32_t ctx_id = FF_VOLUMES; - FATFS *fs = NULL; - int card_handle = -1; //uninitialized - bool host_inited = false; - BYTE pdrv = FF_DRV_NOT_USED; - sdmmc_card_t* card = NULL; - char* dup_path = NULL; - - err = mount_prepare_mem(base_path, &pdrv, &dup_path, &card); - if (err != ESP_OK) { - ESP_LOGE(TAG, "mount_prepare failed"); - return err; + if (host_config == NULL || slot_config == NULL || card == NULL) { + return ESP_ERR_INVALID_ARG; } + const sdmmc_host_t* host = host_config; + esp_err_t err; + int card_handle = -1; //uninitialized + bool host_inited = false; + //the init() function is usually empty, doesn't require any deinit to revert it - err = (*host_config->init)(); + err = (*host->init)(); CHECK_EXECUTE_RESULT(err, "host init failed"); - err = init_sdspi_host(host_config->slot, slot_config, &card_handle); + err = init_sdspi_host(host->slot, slot_config, &card_handle); CHECK_EXECUTE_RESULT(err, "slot init failed"); //Set `host_inited` to true to indicate that host_config->deinit() needs //to be called to revert `init_sdspi_host` @@ -358,39 +345,59 @@ esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path, * above. But the input pointer is const, so create a new variable. */ sdmmc_host_t new_config; - if (card_handle != host_config->slot) { - new_config = *host_config_input; - host_config = &new_config; + if (card_handle != host->slot) { + new_config = *host_config; + host = &new_config; new_config.slot = card_handle; } // probe and initialize card - err = sdmmc_card_init(host_config, card); + err = sdmmc_card_init(host, card); CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed"); - vfs_fat_x_ctx_flags_t flags = 0; - - err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs, &flags); - CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed"); - - if (out_card != NULL) { - *out_card = card; + if (out_host_inited != NULL) { + *out_host_inited = host_inited; } - ctx = calloc(1, sizeof(vfs_fat_sd_ctx_t)); - if (!ctx) { - CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem"); + return ESP_OK; +cleanup: + if (host_inited) { + call_host_deinit(host); } - ctx->pdrv = pdrv; - memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t)); - ctx->card = card; - ctx->base_path = dup_path; - ctx->fs = fs; - ctx->flags = flags; - ctx_id = s_get_unused_context_id(); - assert(ctx_id != FF_VOLUMES); - s_ctx[ctx_id] = ctx; + return err; +} +esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path, + const sdmmc_host_t* host_config_input, + const sdspi_device_config_t* slot_config, + const esp_vfs_fat_mount_config_t* mount_config, + sdmmc_card_t** out_card) +{ + + if (base_path == NULL || host_config_input == NULL || slot_config == NULL || mount_config == NULL || out_card == NULL) { + return ESP_ERR_INVALID_ARG; + } + + const sdmmc_host_t* host_config = host_config_input; + esp_err_t err; + bool host_inited = false; + sdmmc_card_t* card = NULL; + + // not using ff_memalloc here, as allocation in internal RAM is preferred + card = (sdmmc_card_t*) malloc(sizeof(sdmmc_card_t)); + if (card == NULL) { + ESP_LOGD(TAG, "could not locate new sdmmc_card_t"); + err = ESP_ERR_NO_MEM; + goto cleanup; + } + + err = esp_vfs_fat_sdspi_sdcard_init(host_config_input, slot_config, card, &host_inited); + CHECK_EXECUTE_RESULT(err, "esp_vfs_fat_sdspi_sdcard_init failed"); + + err = esp_vfs_fat_mount_initialized(card, base_path, mount_config); + CHECK_EXECUTE_RESULT(err, "esp_vfs_fat_mount_initialized failed"); + + *out_card = card; return ESP_OK; cleanup: @@ -398,6 +405,39 @@ cleanup: call_host_deinit(host_config); } free(card); + return err; +} + +esp_err_t esp_vfs_fat_mount_initialized(sdmmc_card_t* card, + const char* base_path, + const esp_vfs_fat_mount_config_t* mount_config) +{ + if (card == NULL || base_path == NULL || mount_config == NULL) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err; + + FATFS *fs = NULL; + BYTE ldrv = FF_DRV_NOT_USED; + char* dup_path = NULL; + + err = mount_prepare_mem(base_path, &ldrv, &dup_path); + if (err != ESP_OK) { + ESP_LOGE(TAG, "mount_prepare failed"); + return err; + } + + vfs_fat_x_ctx_flags_t flags = 0; + + err = esp_vfs_fat_mount_internal(mount_config, card, ldrv, dup_path, &fs, &flags); + CHECK_EXECUTE_RESULT(err, "esp_vfs_fat_mount_internal failed"); + + err = esp_vfs_fat_save_ctx(ldrv, mount_config, card, dup_path, fs, flags); + CHECK_EXECUTE_RESULT(err, "esp_vfs_fat_save_ctx failed"); + + return ESP_OK; +cleanup: free(dup_path); return err; } @@ -413,10 +453,11 @@ static void call_host_deinit(const sdmmc_host_t *host_config) static esp_err_t unmount_card_core(const char *base_path, sdmmc_card_t *card) { - BYTE pdrv = ff_diskio_get_pdrv_card(card); - if (pdrv == 0xff) { + BYTE pdrv_num = ff_diskio_get_pdrv_cnt_card(card); + if (pdrv_num == 0) { return ESP_ERR_INVALID_ARG; } + BYTE pdrv = ff_diskio_get_pdrv_card(card); // unmount char drv[3] = {(char)('0' + pdrv), ':', 0}; @@ -424,8 +465,10 @@ static esp_err_t unmount_card_core(const char *base_path, sdmmc_card_t *card) // release SD driver ff_diskio_unregister(pdrv); - call_host_deinit(&card->host); - free(card); + if (pdrv_num == 1) { + call_host_deinit(&card->host); + free(card); + } esp_err_t err = esp_vfs_fat_unregister_path(base_path); return err; @@ -470,12 +513,6 @@ esp_err_t esp_vfs_fat_sdcard_format_cfg(const char *base_path, sdmmc_card_t *car return ESP_FAIL; } - const size_t workbuf_size = 4096; - void *workbuf = ff_memalloc(workbuf_size); - if (workbuf == NULL) { - return ESP_ERR_NO_MEM; - } - //format uint32_t id = FF_VOLUMES; @@ -489,20 +526,14 @@ esp_err_t esp_vfs_fat_sdcard_format_cfg(const char *base_path, sdmmc_card_t *car s_ctx[id]->mount_config = *cfg; } - size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size( - card->csd.sector_size, - s_ctx[id]->mount_config.allocation_unit_size); - ESP_LOGI(TAG, "Formatting card, allocation unit size=%d", alloc_unit_size); - const MKFS_PARM opt = {(BYTE)FM_ANY, (s_ctx[id]->mount_config.use_one_fat ? 1 : 2), 0, 0, alloc_unit_size}; - res = f_mkfs(drv, &opt, workbuf, workbuf_size); - free(workbuf); - if (res != FR_OK) { - ret = ESP_FAIL; - ESP_LOGD(TAG, "f_mkfs failed (%d)", res); + ret = esp_vfs_fat_format_drive(pdrv, &s_ctx[id]->mount_config); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_vfs_fat_format_drive failed"); + return ret; } //mount back - esp_err_t err = s_f_mount(card, s_ctx[id]->fs, drv, pdrv, &s_ctx[id]->mount_config, NULL); + esp_err_t err = s_f_mount(card, s_ctx[id]->fs, pdrv, &s_ctx[id]->mount_config, NULL); if (err != ESP_OK) { unmount_card_core(base_path, card); ESP_LOGE(TAG, "failed to format, resources recycled, please mount again"); diff --git a/examples/network/simple_sniffer/main/simple_sniffer_example_main.c b/examples/network/simple_sniffer/main/simple_sniffer_example_main.c index 7eab272f59..1c74842479 100644 --- a/examples/network/simple_sniffer/main/simple_sniffer_example_main.c +++ b/examples/network/simple_sniffer/main/simple_sniffer_example_main.c @@ -148,6 +148,8 @@ static struct { struct arg_end *end; } mount_args; +static sdmmc_card_t *card = NULL; + /** 'mount' command */ static int mount(int argc, char **argv) { @@ -168,8 +170,6 @@ static int mount(int argc, char **argv) }; // initialize SD card and mount FAT filesystem. - sdmmc_card_t *card; - #if CONFIG_SNIFFER_SD_SPI_MODE ESP_LOGI(TAG, "Using SPI peripheral"); sdmmc_host_t host = SDSPI_HOST_DEFAULT(); @@ -249,10 +249,11 @@ static int unmount(int argc, char **argv) } /* unmount sd card */ if (!strncmp(mount_args.device->sval[0], "sd", 2)) { - if (esp_vfs_fat_sdmmc_unmount() != ESP_OK) { + if (esp_vfs_fat_sdcard_unmount(CONFIG_SNIFFER_MOUNT_POINT, card) != ESP_OK) { ESP_LOGE(TAG, "Card unmount failed"); return -1; } + card = NULL; ESP_LOGI(TAG, "Card unmounted"); } return 0;