diff --git a/components/esp_blockdev/include/esp_blockdev.h b/components/esp_blockdev/include/esp_blockdev.h index f4becdddbd..96c9532f64 100644 --- a/components/esp_blockdev/include/esp_blockdev.h +++ b/components/esp_blockdev/include/esp_blockdev.h @@ -16,54 +16,129 @@ extern "C" { #endif -/* +/** * @file esp_blockdev.h * @brief Block Device Layer interface definition. * * This header defines public parts of the Block Device Layer interface (BDL). - * It can be extended but existing definitions are guaranteed to stay unchanged (Open-Closed Principle). + * It can be extended, but existing definitions are guaranteed to remain unchanged (open-closed principle). * See the in-code comments and README.md for more details. */ /** - * @brief Block device I/O control commands + * @defgroup esp_blockdev_ioctl_cmds Block device ioctl commands * - * The commands are grouped into two categories: system and user. - * The system commands are used for internal device management and are not expected to be used by the user (values 0-127). - * The user commands are used for user-specific operations and are expected to be defined by the user (values 128-255). + * Commands fall into two ranges: system (internal device management, not for typical application use; values 0-127) + * and user (application-defined; values 128-255). + * + * @{ */ -#define ESP_BLOCKDEV_CMD_SYSTEM_BASE 0x00 /*!< System commands base value */ -#define ESP_BLOCKDEV_CMD_USER_BASE 0x80 /*!< User commands base value */ +#define ESP_BLOCKDEV_CMD_SYSTEM_BASE 0x00 /*!< System commands base value */ +#define ESP_BLOCKDEV_CMD_USER_BASE 0x80 /*!< User commands base value */ -// Command name Code Description Argument type -#define ESP_BLOCKDEV_CMD_MARK_DELETED ESP_BLOCKDEV_CMD_SYSTEM_BASE /*!< mark given range as invalid, data to be deleted/overwritten eventually [ esp_blockdev_cmd_arg_erase_t* ]*/ -#define ESP_BLOCKDEV_CMD_ERASE_CONTENTS (ESP_BLOCKDEV_CMD_SYSTEM_BASE + 1) /*!< erase required range and set the contents to the device's default bit values [ esp_blockdev_cmd_arg_erase_t* ]*/ +/** + * @brief Mark a range as deleted or invalid (TRIM / discard) + * + * Tells the device or FTL that the range is no longer needed. Data may remain readable until the + * space is reclaimed; behavior is analogous to TRIM on SSDs or discard on eMMC. Use + * @ref ESP_BLOCKDEV_CMD_ERASE_CONTENTS when the caller requires the range to read as the device's + * post-erase default value. + * + * Argument: a pointer to @ref esp_blockdev_cmd_arg_erase_t. + * + * @code{c} + * esp_blockdev_cmd_arg_erase_t arg = { + * .start_addr = aligned_start, + * .erase_len = aligned_len, + * }; + * esp_err_t ret = bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_MARK_DELETED, &arg); + * @endcode + */ +#define ESP_BLOCKDEV_CMD_MARK_DELETED (ESP_BLOCKDEV_CMD_SYSTEM_BASE + 0) -typedef struct esp_blockdev_cmd_arg_erase_t { - uint64_t start_addr; /*!< IN - starting address of the disk space to erase/trim/discard/sanitize (in bytes), must be a multiple of erase block size */ - size_t erase_len; /*!< IN - size of the area to erase/trim/discard/sanitize (in bytes), must be a multiple of erase block size */ +/** + * @brief Erase a range and set contents to the default erased value + * + * Performs an erase (or equivalent) so that reads in the range return the device's default value + * after erase (see the @c default_val_after_erase field in @ref esp_blockdev_flags_t). This is stronger than + * @ref ESP_BLOCKDEV_CMD_MARK_DELETED, which only invalidates data from the perspective of the translation layer. + * + * Argument: a pointer to @ref esp_blockdev_cmd_arg_erase_t. + * + * @code{c} + * esp_blockdev_cmd_arg_erase_t arg = { + * .start_addr = aligned_start, + * .erase_len = aligned_len, + * }; + * esp_err_t ret = bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_ERASE_CONTENTS, &arg); + * @endcode + */ +#define ESP_BLOCKDEV_CMD_ERASE_CONTENTS (ESP_BLOCKDEV_CMD_SYSTEM_BASE + 1) + +/** @} */ + +/** + * @brief Input arguments for erase-related block-device ioctl commands + * + * Pass a pointer to this structure as the @c args argument to @ref esp_blockdev_ops_t::ioctl + * when using @ref ESP_BLOCKDEV_CMD_MARK_DELETED or @ref ESP_BLOCKDEV_CMD_ERASE_CONTENTS. + * Both @c start_addr and @c erase_len must be aligned to @ref esp_blockdev_geometry_t::erase_size + * for the target device. + */ +typedef struct { + /** + * @brief Byte offset of the range from the start of the device + * + * Must be a multiple of @ref esp_blockdev_geometry_t::erase_size. + */ + uint64_t start_addr; + + /** + * @brief Length of the range in bytes + * + * Must be a multiple of @ref esp_blockdev_geometry_t::erase_size. + */ + size_t erase_len; } esp_blockdev_cmd_arg_erase_t; /** - * @brief Block device property flags + * @brief Block device property flags (@c esp_blockdev_flags_t) * - * Various properties and characteristics of given BDL device. + * Various properties and characteristics of a BDL device. + * Represented as a @c struct when @c __DOXYGEN__ is defined (for documentation only) and as a @c union in normal builds. * - * @note Convenience macros ESP_BLOCKDEV_FLAGS__CONFIG_DEFAULT() provide the most common setup of usual ESP-IDF component equipped with BDL interface. They can be used as a starting point for own initializers. + * @note The macros @c ESP_BLOCKDEV_FLAGS_CONFIG_DEFAULT and @c ESP_BLOCKDEV_FLAGS_INST_CONFIG_DEFAULT provide a typical configuration for ESP-IDF components that expose a BDL interface. Use them as a starting point for custom initializers. */ -typedef union { +#if defined(__DOXYGEN__) +typedef struct { + bool read_only; /*!< no erase/write operations allowed */ + bool encrypted; /*!< the device data is encrypted */ + bool erase_before_write; /*!< erasing required before any write operation */ + bool and_type_write; /*!< 0-bits cannot be changed to 1-bits (NAND/NOR flash behavior) */ + bool default_val_after_erase; /*!< default bit value after erasing (0 or 1) */ + bool reserved[27]; /*!< Reserved for future blockdev flags */ + uint32_t val; /*!< Raw bitfield view for bulk initialization */ +} esp_blockdev_flags_t; +#else +typedef union esp_blockdev_flags { struct { uint32_t read_only: 1; /*!< no erase/write operations allowed */ uint32_t encrypted: 1; /*!< the device data is encrypted */ uint32_t erase_before_write: 1; /*!< erasing required before any write operation */ - uint32_t and_type_write: 1; /*!< 0-bits can't be changed to 1-bits - NAND/NOR flash behavior */ + uint32_t and_type_write: 1; /*!< 0-bits cannot be changed to 1-bits (NAND/NOR flash behavior) */ uint32_t default_val_after_erase: 1; /*!< default bit value after erasing (0 or 1) */ - uint32_t reserved: 27; + uint32_t reserved: 27; /*!< Reserved for future blockdev flags */ }; - uint32_t val; + uint32_t val; /*!< Raw bitfield view for bulk initialization */ } esp_blockdev_flags_t; +#endif +/** + * @brief Brace-enclosed initializer for @c esp_blockdev_flags_t with typical ESP-IDF defaults + * + * @see ESP_BLOCKDEV_FLAGS_INST_CONFIG_DEFAULT + */ #define ESP_BLOCKDEV_FLAGS_CONFIG_DEFAULT() { \ { \ .read_only = 0, \ @@ -75,6 +150,13 @@ typedef union { } \ } +/** + * @brief Assign typical ESP-IDF default values to an existing @c esp_blockdev_flags_t + * + * @param flags Flags instance to initialize (statement form, not an expression) + * + * @see ESP_BLOCKDEV_FLAGS_CONFIG_DEFAULT + */ #define ESP_BLOCKDEV_FLAGS_INST_CONFIG_DEFAULT(flags) { \ flags.read_only = 0; \ flags.encrypted = 0; \ @@ -87,142 +169,212 @@ typedef union { /** * @brief Block device geometry * - * Various block size parameters needed for proper R/W/E processing on given device. + * Granularity and capacity parameters for read, write, and erase operations on the device. */ -typedef struct esp_blockdev_geometry_t { - - /** Size of the device disk space (in bytes). - * Mandatory parameter. - * */ +typedef struct { + /** + * @brief Total addressable size of the device in bytes + * + * Mandatory for every block device. + */ uint64_t disk_size; - /** Minimum block size (in bytes) for disk-read operations on given device. - * Mandatory parameter. - * */ + /** + * @brief Minimum read transaction size in bytes + * + * Mandatory. All read lengths and offsets must respect this granularity where required by the driver. + */ size_t read_size; - /** Minimum block size (in bytes) for disk-write operations on given device. - * Mandatory parameter for all R/W devices, 0 for R/O. - * */ + /** + * @brief Minimum write transaction size in bytes + * + * Mandatory for read/write devices; set to @c 0 for read-only devices. + */ size_t write_size; - /** Minimum block size (in bytes) for erase operations on given device. - * Mandatory parameter for all R/W devices, 0 for R/O. - * @note Typically used as a sector size in file system meaning. - * */ + /** + * @brief Minimum erase granularity in bytes + * + * Mandatory for read/write devices; set to @c 0 for read-only devices. + * + * @note Often corresponds to the logical sector size used by file systems. + */ size_t erase_size; - /** Default write block size (in bytes) of given device. Recommended for optimal performance. - * 0 means not used. - * */ + /** + * @brief Suggested write chunk size in bytes for best performance + * + * Set to @c 0 if not used. Optional hint for upper layers. + */ size_t recommended_write_size; - /** Default read block size (in bytes) of given device. Recommended for optimal performance. - * 0 means not used. - * */ + /** + * @brief Suggested read chunk size in bytes for best performance + * + * Set to @c 0 if not used. Optional hint for upper layers. + */ size_t recommended_read_size; - /** Default erase block size (in bytes) of given device. Recommended for optimal performance. - * 0 means not used. - * @note Typically used as target hardware erase block size. - * */ + /** + * @brief Suggested erase chunk size in bytes for best performance + * + * Set to @c 0 if not used. Optional hint for upper layers. + * + * @note Often matches the physical erase block of the underlying flash or similar media. + */ size_t recommended_erase_size; } esp_blockdev_geometry_t; -/** Standard BDL access handle, the only public BDL instance identifier. - * Allocated and initialized by the device's class factory, optionally closed by the device release handler. +/** Forward declaration; see @ref esp_blockdev */ +typedef struct esp_blockdev esp_blockdev_t; + +/** + * @brief Opaque handle to a block device instance + * + * Pointer to @ref esp_blockdev. This is the only public identifier for a BDL instance: it is returned + * from the device factory and must be released through @ref esp_blockdev_ops_t::release when no longer needed. + */ +typedef esp_blockdev_t* esp_blockdev_handle_t; + +/** + * @brief Sentinel for an invalid block device handle + * + * Compare handles to @c NULL; this macro expands to @c NULL for readability. */ -typedef struct esp_blockdev_t* esp_blockdev_handle_t; #define ESP_BLOCKDEV_HANDLE_INVALID NULL /** + * @struct esp_blockdev_ops_t * @brief Block device operations * - * Various block operations needed for proper R/W/E processing on given device. + * Function table for read, write, erase, sync, ioctl, and release on a block device instance. */ -typedef struct esp_blockdev_ops_t { +typedef struct { - /** READ operation: - * Read required number of bytes from the device at given offset, store the data into the output buffer. + /** + * @brief Read data from the device * - * @param dev_handle Target device handle - * @param dst_buf Output buffer to receive the data read - * @param dst_buf_size Size of the destination buffer (in bytes) - * @param src_addr Data read source address (offset in given device address space) - * @param data_read_len Data read length (in bytes) - * */ + * Reads the requested number of bytes from the device at the given offset into the output buffer. + * + * @par Parameters + * - @a dev_handle Target device handle + * - @a dst_buf Output buffer to receive the data read + * - @a dst_buf_size Size of the destination buffer (in bytes) + * - @a src_addr Source address for the read (offset in the device's address space) + * - @a data_read_len Data read length (in bytes) + * + * @par Return value + * - ESP_OK on success + * - Another @c esp_err_t error code on failure + */ esp_err_t (*read)(esp_blockdev_handle_t dev_handle, uint8_t* dst_buf, size_t dst_buf_size, uint64_t src_addr, size_t data_read_len); - /** WRITE operation: - * Write required number of bytes taken from the input memory buffer to the device at given offset. + /** + * @brief Write data to the device * - * @param dev_handle Target device handle - * @param src_buf Input buffer providing the data to write - * @param dst_addr Data destination address (offset in given device address space) - * @param data_write_len Length of the data to be written (in bytes) - * */ + * Writes the requested number of bytes from the input buffer to the device at the given offset. + * + * @par Parameters + * - @a dev_handle Target device handle + * - @a src_buf Input buffer providing the data to write + * - @a dst_addr Destination address for the write (offset in the device's address space) + * - @a data_write_len Length of the data to be written (in bytes) + * + * @par Return value + * - ESP_OK on success + * - Another @c esp_err_t error code on failure + */ esp_err_t (*write)(esp_blockdev_handle_t dev_handle, const uint8_t* src_buf, uint64_t dst_addr, size_t data_write_len); - /** ERASE operation: - * Erase given address range . - * Both erase_len and start_addr must be aligned to multiples of the erase block size (in bytes) given by 'erase_size' member. - * The erasing process can be secured by one or more operations, depending on given BDL device nature. - * The only expected result is safely wiped data within the required range. + /** + * @brief Erase an address range on the device * - * @param dev_handle Target device handle - * @param start_addr Start address for the erase operation - * @param erase_len Length of the address space chunk to be erased (in bytes) - * */ + * Erases the address range @c [start_addr, start_addr + erase_len). + * Both @c erase_len and @c start_addr must be aligned to multiples of the erase block size in bytes (@c erase_size in @ref esp_blockdev_geometry_t). + * The implementation may use one or more internal operations, depending on the device. + * The result must be that data in the range is no longer readable as previously written content. + * + * @par Parameters + * - @a dev_handle Target device handle + * - @a start_addr Start address for the erase operation + * - @a erase_len Length of the address range to erase (in bytes) + * + * @par Return value + * - ESP_OK on success + * - Another @c esp_err_t error code on failure + */ esp_err_t (*erase)(esp_blockdev_handle_t dev_handle, uint64_t start_addr, size_t erase_len); - /** SYNC operation: - * Commit all the pending write operations and block until all are finished. - * Does nothing if the device doesn't support write operations caching + /** + * @brief Commit pending writes to the device * - * @param dev_handle Target device handle - * */ + * Commits all pending writes and blocks until they complete. + * Does nothing if the device does not cache writes. + * + * @par Parameters + * - @a dev_handle Target device handle + * + * @par Return value + * - ESP_OK on success + * - Another @c esp_err_t error code on failure + */ esp_err_t (*sync)(esp_blockdev_handle_t dev_handle); - /** IOCTL operation: - * I/O control commands. Each command has corresponding in/out parameters which are to be verified - * within given ioctl handler. The commands can be extended by the device implementation within the following ranges: - * - 0x00-0x7F: IDF device commands (system) - * - 0x80-0xFF: user-defined commands - * See ESP_BLOCKDEV_CMD* macros. + /** + * @brief Device-specific I/O control * - * @param dev_handle Target device handle - * @param cmd Command ID - * @param args Command specific arguments - * */ + * Each command has parameters that the handler must validate. + * Implementations may extend commands within these ranges: + * - 0x00-0x7F: IDF device commands (system) + * - 0x80-0xFF: user-defined commands + * + * Refer to the @c ESP_BLOCKDEV_CMD_ macros in this header. + * + * @par Parameters + * - @a dev_handle Target device handle + * - @a cmd Command ID + * - @a args Command-specific arguments + * + * @par Return value + * - ESP_OK on success + * - Another @c esp_err_t error code on failure + */ esp_err_t (*ioctl)(esp_blockdev_handle_t dev_handle, const uint8_t cmd, void* args); - /** Instance destructor: - * Cleanup code for the specific device handle - * @param dev_handle Target device handle - * */ + /** + * @brief Release resources for this device handle + * + * @par Parameters + * - @a dev_handle Target device handle + * + * @par Return value + * - ESP_OK on success + * - Another @c esp_err_t error code on failure + */ esp_err_t (*release)(esp_blockdev_handle_t dev_handle); } esp_blockdev_ops_t; /** - * @brief IDF generic Block device interface structure - * This structure defines an interface for a generic block-device capable of common disk operations and providing properties important - * for the device's deployment into the target component stack. + * @struct esp_blockdev + * @brief Generic IDF block device interface * - * @note The device context pointer is used to store the device-specific context. It is not used by the BDL layer and is intended to be used by the device implementation. - * @note The ops pointer holds the address of the device operations structure which can be shared by multiple device instances of the same type (driver). + * Describes a block device that supports common disk operations and exposes parameters needed to integrate it into a component stack. + * + * @note The context pointer @c ctx holds driver-private data; the BDL layer does not interpret it. + * @note The @c ops table may be shared by multiple instances of the same driver type. */ -typedef struct esp_blockdev_t { +struct esp_blockdev { - /* Device context pointer */ - void* ctx; + void* ctx; /*!< Owner-provided context; not interpreted by the BDL layer */ - esp_blockdev_flags_t device_flags; - esp_blockdev_geometry_t geometry; - const esp_blockdev_ops_t* ops; + esp_blockdev_flags_t device_flags; /*!< Capabilities and requirements */ + esp_blockdev_geometry_t geometry; /*!< Operation granularity and capacity */ + const esp_blockdev_ops_t* ops; /*!< Function table implementing the device */ -} esp_blockdev_t; +}; #ifdef __cplusplus } // extern "C"