1313#include "diskio_wl.h"
1414#include "wear_levelling.h"
1515#include "esp_partition.h"
16+ #include "esp_memory_utils.h"
17+ #include "sdkconfig.h"
1618#include "vfs_fat_internal.h"
1719#include "tinyusb.h"
20+ #include "device/usbd_pvt.h"
1821#include "class/msc/msc_device.h"
1922#include "tusb_msc_storage.h"
20- #include "esp_vfs_fat.h"
2123#if SOC_SDMMC_HOST_SUPPORTED
2224#include "diskio_sdmmc.h"
2325#endif
2426
2527static const char * TAG = "tinyusb_msc_storage" ;
2628
29+ #define MSC_STORAGE_MEM_ALIGN 4
30+ #define MSC_STORAGE_BUFFER_SIZE CONFIG_TINYUSB_MSC_BUFSIZE /*!< Size of the buffer, configured via menuconfig (MSC FIFO size) */
31+
32+ #if ((MSC_STORAGE_BUFFER_SIZE ) % MSC_STORAGE_MEM_ALIGN != 0 )
33+ #error "CONFIG_TINYUSB_MSC_BUFSIZE must be divisible by MSC_STORAGE_MEM_ALIGN. Adjust your configuration (MSC FIFO size) in menuconfig."
34+ #endif
35+
2736// CONFIG_TINYUSB_MSC_BUFSIZE must be bigger, or equal to the CONFIG_WL_SECTOR_SIZE
2837#if (CONFIG_TINYUSB_MSC_BUFSIZE < CONFIG_WL_SECTOR_SIZE )
2938#error "CONFIG_TINYUSB_MSC_BUFSIZE must be at least at the size of CONFIG_WL_SECTOR_SIZE"
3039#endif
3140
41+ /**
42+ * @brief Structure representing a single write buffer for MSC operations.
43+ */
3244typedef struct {
33- bool is_fat_mounted ;
34- const char * base_path ;
45+ uint8_t data_buffer [MSC_STORAGE_BUFFER_SIZE ]; /*!< Buffer to store write data. The size is defined by MSC_STORAGE_BUFFER_SIZE. */
46+ uint32_t lba ; /*!< Logical Block Address for the current WRITE10 operation. */
47+ uint32_t offset ; /*!< Offset within the specified LBA for the current write operation. */
48+ uint32_t bufsize ; /*!< Number of bytes to be written in this operation. */
49+ } msc_storage_buffer_t ;
50+
51+ /**
52+ * @brief Handle for TinyUSB MSC storage interface.
53+ *
54+ * This structure holds metadata and function pointers required to
55+ * manage the underlying storage medium (SPI flash, SDMMC).
56+ */
57+ typedef struct {
58+ msc_storage_buffer_t storage_buffer ;
59+ bool is_fat_mounted ; /*!< Indicates if the FAT filesystem is currently mounted. */
60+ const char * base_path ; /*!< Base path where the filesystem is mounted. */
3561 union {
36- wl_handle_t wl_handle ;
62+ wl_handle_t wl_handle ; /*!< Handle for wear leveling on SPI flash. */
3763#if SOC_SDMMC_HOST_SUPPORTED
38- sdmmc_card_t * card ;
64+ sdmmc_card_t * card ; /*!< Handle for SDMMC card. */
3965#endif
4066 };
41- esp_err_t (* mount )(BYTE pdrv );
42- esp_err_t (* unmount )(void );
43- uint32_t (* sector_count )(void );
44- uint32_t (* sector_size )(void );
45- esp_err_t (* read )(size_t sector_size , uint32_t lba , uint32_t offset , size_t size , void * dest );
46- esp_err_t (* write )(size_t sector_size , size_t addr , uint32_t lba , uint32_t offset , size_t size , const void * src );
47- tusb_msc_callback_t callback_mount_changed ;
48- tusb_msc_callback_t callback_premount_changed ;
49- int max_files ;
50- } tinyusb_msc_storage_handle_s ; /*!< MSC object */
67+ esp_err_t (* mount )(BYTE pdrv ); /*!< Pointer to the mount function. */
68+ esp_err_t (* unmount )(void ); /*!< Pointer to the unmount function. */
69+ uint32_t sector_count ; /*!< Total number of sectors in the storage medium. */
70+ uint32_t sector_size ; /*!< Size of a single sector in bytes. */
71+ esp_err_t (* read )(size_t sector_size , /*!< Function pointer for reading data. */
72+ uint32_t lba , uint32_t offset , size_t size , void * dest );
73+ esp_err_t (* write )(size_t sector_size , /*!< Function pointer for writing data. */
74+ size_t addr , uint32_t lba , uint32_t offset , size_t size , const void * src );
75+ tusb_msc_callback_t callback_mount_changed ; /*!< Callback for mount state change. */
76+ tusb_msc_callback_t callback_premount_changed ; /*!< Callback for pre-mount state change. */
77+ int max_files ; /*!< Maximum number of files that can be open simultaneously. */
78+ } tinyusb_msc_storage_handle_s ;
5179
5280/* handle of tinyusb driver connected to application */
5381static tinyusb_msc_storage_handle_s * s_storage_handle ;
@@ -175,7 +203,7 @@ static esp_err_t _write_sector_sdmmc(size_t sector_size,
175203}
176204#endif
177205
178- static esp_err_t msc_storage_read_sector (uint32_t lba ,
206+ static esp_err_t _msc_storage_read_sector (uint32_t lba ,
179207 uint32_t offset ,
180208 size_t size ,
181209 void * dest )
@@ -185,7 +213,7 @@ static esp_err_t msc_storage_read_sector(uint32_t lba,
185213 return (s_storage_handle -> read )(sector_size , lba , offset , size , dest );
186214}
187215
188- static esp_err_t msc_storage_write_sector (uint32_t lba ,
216+ static esp_err_t _msc_storage_write_sector (uint32_t lba ,
189217 uint32_t offset ,
190218 size_t size ,
191219 const void * src )
@@ -254,6 +282,29 @@ static esp_err_t _mount(char *drv, FATFS *fs)
254282 return ret ;
255283}
256284
285+ /**
286+ * @brief Handles deferred USB MSC write operations.
287+ *
288+ * This function is invoked via TinyUSB's deferred execution mechanism to perform
289+ * write operations to the underlying storage. It writes data from the
290+ * `storage_buffer` stored within the `s_storage_handle`.
291+ *
292+ * @param param Unused. Present for compatibility with deferred function signature.
293+ */
294+ static void _write_func (void * param )
295+ {
296+ // Process the data in storage_buffer
297+ esp_err_t err = _msc_storage_write_sector (
298+ s_storage_handle -> storage_buffer .lba ,
299+ s_storage_handle -> storage_buffer .offset ,
300+ s_storage_handle -> storage_buffer .bufsize ,
301+ (const void * )s_storage_handle -> storage_buffer .data_buffer
302+ );
303+ if (err != ESP_OK ) {
304+ ESP_LOGE (TAG , "Write failed, error=0x%x" , err );
305+ }
306+ }
307+
257308esp_err_t tinyusb_msc_storage_mount (const char * base_path )
258309{
259310 esp_err_t ret = ESP_OK ;
@@ -369,29 +420,29 @@ esp_err_t tinyusb_msc_storage_unmount(void)
369420uint32_t tinyusb_msc_storage_get_sector_count (void )
370421{
371422 assert (s_storage_handle );
372- return (s_storage_handle -> sector_count )() ;
423+ return (s_storage_handle -> sector_count );
373424}
374425
375426uint32_t tinyusb_msc_storage_get_sector_size (void )
376427{
377428 assert (s_storage_handle );
378- return (s_storage_handle -> sector_size )() ;
429+ return (s_storage_handle -> sector_size );
379430}
380431
381432esp_err_t tinyusb_msc_storage_init_spiflash (const tinyusb_msc_spiflash_config_t * config )
382433{
383434 assert (!s_storage_handle );
384- s_storage_handle = (tinyusb_msc_storage_handle_s * )malloc ( sizeof (tinyusb_msc_storage_handle_s ));
385- ESP_RETURN_ON_FALSE (s_storage_handle , ESP_ERR_NO_MEM , TAG , "could not allocate new handle for storage" );
435+ s_storage_handle = (tinyusb_msc_storage_handle_s * )heap_caps_aligned_alloc ( MSC_STORAGE_MEM_ALIGN , sizeof (tinyusb_msc_storage_handle_s ), MALLOC_CAP_DMA );
436+ ESP_RETURN_ON_FALSE (s_storage_handle , ESP_ERR_NO_MEM , TAG , "Failed to allocate memory for storage handle " );
386437 s_storage_handle -> mount = & _mount_spiflash ;
387438 s_storage_handle -> unmount = & _unmount_spiflash ;
388- s_storage_handle -> sector_count = & _get_sector_count_spiflash ;
389- s_storage_handle -> sector_size = & _get_sector_size_spiflash ;
439+ s_storage_handle -> wl_handle = config -> wl_handle ;
440+ s_storage_handle -> sector_count = _get_sector_count_spiflash ();
441+ s_storage_handle -> sector_size = _get_sector_size_spiflash ();
390442 s_storage_handle -> read = & _read_sector_spiflash ;
391443 s_storage_handle -> write = & _write_sector_spiflash ;
392444 s_storage_handle -> is_fat_mounted = false;
393445 s_storage_handle -> base_path = NULL ;
394- s_storage_handle -> wl_handle = config -> wl_handle ;
395446 // In case the user does not set mount_config.max_files
396447 // and for backward compatibility with versions <1.4.2
397448 // max_files is set to 2
@@ -410,24 +461,28 @@ esp_err_t tinyusb_msc_storage_init_spiflash(const tinyusb_msc_spiflash_config_t
410461 tinyusb_msc_unregister_callback (TINYUSB_MSC_EVENT_PREMOUNT_CHANGED );
411462 }
412463
464+ if (!esp_ptr_dma_capable ((const void * )s_storage_handle -> storage_buffer .data_buffer )) {
465+ ESP_LOGW (TAG , "storage buffer is not DMA capable" );
466+ }
467+
413468 return ESP_OK ;
414469}
415470
416471#if SOC_SDMMC_HOST_SUPPORTED
417472esp_err_t tinyusb_msc_storage_init_sdmmc (const tinyusb_msc_sdmmc_config_t * config )
418473{
419474 assert (!s_storage_handle );
420- s_storage_handle = (tinyusb_msc_storage_handle_s * )malloc ( sizeof (tinyusb_msc_storage_handle_s ));
421- ESP_RETURN_ON_FALSE (s_storage_handle , ESP_ERR_NO_MEM , TAG , "could not allocate new handle for storage" );
475+ s_storage_handle = (tinyusb_msc_storage_handle_s * )heap_caps_aligned_alloc ( MSC_STORAGE_MEM_ALIGN , sizeof (tinyusb_msc_storage_handle_s ), MALLOC_CAP_DMA );
476+ ESP_RETURN_ON_FALSE (s_storage_handle , ESP_ERR_NO_MEM , TAG , "Failed to allocate memory for storage handle " );
422477 s_storage_handle -> mount = & _mount_sdmmc ;
423478 s_storage_handle -> unmount = & _unmount_sdmmc ;
424- s_storage_handle -> sector_count = & _get_sector_count_sdmmc ;
425- s_storage_handle -> sector_size = & _get_sector_size_sdmmc ;
479+ s_storage_handle -> card = config -> card ;
480+ s_storage_handle -> sector_count = _get_sector_count_sdmmc ();
481+ s_storage_handle -> sector_size = _get_sector_size_sdmmc ();
426482 s_storage_handle -> read = & _read_sector_sdmmc ;
427483 s_storage_handle -> write = & _write_sector_sdmmc ;
428484 s_storage_handle -> is_fat_mounted = false;
429485 s_storage_handle -> base_path = NULL ;
430- s_storage_handle -> card = config -> card ;
431486 // In case the user does not set mount_config.max_files
432487 // and for backward compatibility with versions <1.4.2
433488 // max_files is set to 2
@@ -446,15 +501,20 @@ esp_err_t tinyusb_msc_storage_init_sdmmc(const tinyusb_msc_sdmmc_config_t *confi
446501 tinyusb_msc_unregister_callback (TINYUSB_MSC_EVENT_PREMOUNT_CHANGED );
447502 }
448503
504+ if (!esp_ptr_dma_capable ((const void * )s_storage_handle -> storage_buffer .data_buffer )) {
505+ ESP_LOGW (TAG , "storage buffer is not DMA capable" );
506+ }
507+
449508 return ESP_OK ;
450509}
451510#endif
452511
453512void tinyusb_msc_storage_deinit (void )
454513{
455- assert (s_storage_handle );
456- free (s_storage_handle );
457- s_storage_handle = NULL ;
514+ if (s_storage_handle ) {
515+ heap_caps_free (s_storage_handle );
516+ s_storage_handle = NULL ;
517+ }
458518}
459519
460520esp_err_t tinyusb_msc_register_callback (tinyusb_msc_event_type_t event_type ,
@@ -513,7 +573,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16
513573 (void ) lun ;
514574 const char vid [] = "TinyUSB" ;
515575 const char pid [] = "Flash Storage" ;
516- const char rev [] = "0.1 " ;
576+ const char rev [] = "0.2 " ;
517577
518578 memcpy (vendor_id , vid , strlen (vid ));
519579 memcpy (product_id , pid , strlen (pid ));
@@ -572,7 +632,7 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo
572632// - Application fill the buffer (up to bufsize) with address contents and return number of read byte.
573633int32_t tud_msc_read10_cb (uint8_t lun , uint32_t lba , uint32_t offset , void * buffer , uint32_t bufsize )
574634{
575- esp_err_t err = msc_storage_read_sector (lba , offset , bufsize , buffer );
635+ esp_err_t err = _msc_storage_read_sector (lba , offset , bufsize , buffer );
576636 if (err != ESP_OK ) {
577637 ESP_LOGE (TAG , "msc_storage_read_sector failed: 0x%x" , err );
578638 return 0 ;
@@ -585,11 +645,17 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff
585645// - Application write data from buffer to address contents (up to bufsize) and return number of written byte.
586646int32_t tud_msc_write10_cb (uint8_t lun , uint32_t lba , uint32_t offset , uint8_t * buffer , uint32_t bufsize )
587647{
588- esp_err_t err = msc_storage_write_sector (lba , offset , bufsize , buffer );
589- if (err != ESP_OK ) {
590- ESP_LOGE (TAG , "msc_storage_write_sector failed: 0x%x" , err );
591- return 0 ;
592- }
648+ assert (bufsize <= MSC_STORAGE_BUFFER_SIZE );
649+ // Copy data to the buffer
650+ memcpy ((void * )s_storage_handle -> storage_buffer .data_buffer , buffer , bufsize );
651+ s_storage_handle -> storage_buffer .lba = lba ;
652+ s_storage_handle -> storage_buffer .offset = offset ;
653+ s_storage_handle -> storage_buffer .bufsize = bufsize ;
654+
655+ // Defer execution of the write to the TinyUSB task
656+ usbd_defer_func (_write_func , NULL , false);
657+
658+ // Return the number of bytes accepted
593659 return bufsize ;
594660}
595661
0 commit comments