/*************************************************************************** * Copyright (c) 2024 Microsoft Corporation * Copyright (c) 2026-present Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * SPDX-License-Identifier: MIT **************************************************************************/ /**************************************************************************/ /**************************************************************************/ /** */ /** USBX Component */ /** */ /** Storage Class */ /** */ /**************************************************************************/ /**************************************************************************/ /* Include necessary system files. */ #define UX_SOURCE_CODE #include "ux_api.h" #include "ux_host_class_storage.h" #include "ux_host_stack.h" /* Defined if FileX is not integrated in USBX and it's used as external module for file system. */ /* #define UX_HOST_CLASS_STORAGE_EXT_FILEX */ #if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) #ifdef FX_API_H /* For test, confirm FX is not included before. */ #error fx_api.h should not be included in this mode #endif /* FX not integrated in UX, but used as external module. */ #if defined(UX_HOST_CLASS_STORAGE_EXT_FILEX) /* FX related things needs define here. */ #include "fx_api.h" #define UX_MEDIA FX_MEDIA VOID _ux_host_class_storage_driver_entry(UX_MEDIA *media); /* FX driver is available to support FX as external module. */ #ifndef UX_HOST_CLASS_STORAGE_DRIVER_ENTRY_ENABLE #define UX_HOST_CLASS_STORAGE_DRIVER_ENTRY_ENABLE #endif #endif #else /* FX driver is used for RTOS mode by default. */ #ifndef UX_HOST_CLASS_STORAGE_DRIVER_ENTRY_ENABLE #define UX_HOST_CLASS_STORAGE_DRIVER_ENTRY_ENABLE #endif #endif #if defined(UX_HOST_CLASS_STORAGE_DRIVER_ENTRY_ENABLE) /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_storage_driver_entry PORTABLE C */ /* 6.1.12 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function is the entry point for the FileX file system. All */ /* FileX driver I/O calls are are multiplexed here and rerouted to */ /* the proper USB storage class functions. */ /* */ /* When the entry is for storage with FX support (not in standalone */ /* mode, and with FileX), the FX media is openned in storage mount */ /* flow, and can be directly used in application after mounted. */ /* */ /* When the entry is for no FX mode (FX in external module, and USBX */ /* is compiled without FileX integration), it is an example with */ /* disk partition support. In this case the FX media does not operate */ /* inside the storage flow. Actions are taken when application mounts */ /* media to FX_MEDIA and then have access to media APIs. */ /* */ /* In no FX mode demo, it assumes media is managed with partition */ /* start from sector address of FX_MEDIA::fx_media_reserved_for_user. */ /* */ /* The following links are not initialized in no FX mode, they must be */ /* initialized before using the entry in no FX mode: */ /* - FX_MEDIA::fx_media_reserved_for_user */ /* Partition start sector inside */ /* the whole storage media, must */ /* set before media open */ /* - FX_MEDIA::fx_media_driver_info Pointer to storage media, */ /* assigned while calling media */ /* open (fx_media_open) */ /* */ /* INPUT */ /* */ /* media FileX media pointer */ /* */ /* OUTPUT */ /* */ /* None */ /* */ /* CALLS */ /* */ /* _ux_host_class_storage_sense_code_translate */ /* Translate error status codes */ /* _ux_host_class_storage_media_read Read sector(s) */ /* _ux_host_class_storage_media_write Write sector(s) */ /* _ux_host_semaphore_get Get protection semaphore */ /* _ux_host_semaphore_put Release protection semaphore */ /* */ /* CALLED BY */ /* */ /* FileX */ /* */ /**************************************************************************/ VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media) { UINT status; UX_HOST_CLASS_STORAGE *storage; UX_HOST_CLASS_STORAGE_MEDIA *storage_media; ULONG partition_start; /* Get the pointers to the instances and partition start. */ #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) storage = (UX_HOST_CLASS_STORAGE *) media -> fx_media_driver_info; storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) media -> fx_media_reserved_for_user; partition_start = storage_media -> ux_host_class_storage_media_partition_start; #else storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) media -> fx_media_driver_info; storage = storage_media -> ux_host_class_storage_media_storage; partition_start = (ULONG) media -> fx_media_reserved_for_user; #endif /* Ensure the instance is valid. */ if ((storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE) && (storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_MOUNTING)) { /* Class instance is invalid. Return an error! */ media -> fx_media_driver_status = FX_PTR_ERROR; return; } #if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) /* Ensure the media is valid. */ if ((storage_media -> ux_host_class_storage_media_storage != storage) || (storage_media -> ux_host_class_storage_media_status != UX_USED)) { /* Media instance is invalid. */ media -> fx_media_driver_status = FX_PTR_ERROR; return; } #endif /* Protect Thread reentry to this instance. */ status = _ux_host_class_storage_lock(storage, UX_WAIT_FOREVER); if (status != UX_SUCCESS) { /* Unable to lock, return an error. */ media -> fx_media_driver_status = FX_INVALID_STATE; return; } /* Restore the LUN number from the media instance. */ storage -> ux_host_class_storage_lun = storage_media -> ux_host_class_storage_media_lun; /* And the sector size. */ storage -> ux_host_class_storage_sector_size = storage_media -> ux_host_class_storage_media_sector_size; #if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) /* Restore current used last sector number. */ storage -> ux_host_class_storage_last_sector_number = storage_media -> ux_host_class_storage_media_number_sectors - 1; #endif /* Look at the request specified by the FileX caller. */ switch (media -> fx_media_driver_request) { case FX_DRIVER_READ: /* Read one or more sectors. */ status = _ux_host_class_storage_media_read(storage, media -> fx_media_driver_logical_sector + partition_start, media -> fx_media_driver_sectors, media -> fx_media_driver_buffer); /* Check completion status. */ if (status == UX_SUCCESS) media -> fx_media_driver_status = FX_SUCCESS; else { #if defined(UX_HOST_STANDALONE) /* Poll status. */ _ux_host_class_storage_media_check(storage); #endif media -> fx_media_driver_status = _ux_host_class_storage_sense_code_translate(storage, status); } break; case FX_DRIVER_WRITE: /* Write one or more sectors. */ status = _ux_host_class_storage_media_write(storage, media -> fx_media_driver_logical_sector + partition_start, media -> fx_media_driver_sectors, media -> fx_media_driver_buffer); /* Check completion status. */ if (status == UX_SUCCESS) media -> fx_media_driver_status = FX_SUCCESS; else { #if defined(UX_HOST_STANDALONE) /* Poll status. */ _ux_host_class_storage_media_check(storage); #endif media -> fx_media_driver_status = _ux_host_class_storage_sense_code_translate(storage,status); } break; case FX_DRIVER_FLUSH: /* Nothing to do. Just return a good status! */ media -> fx_media_driver_status = FX_SUCCESS; break; case FX_DRIVER_ABORT: /* Nothing to do. Just return a good status! */ media -> fx_media_driver_status = FX_SUCCESS; break; case FX_DRIVER_INIT: #if defined(UX_HOST_STANDALONE) /* Poll status. */ _ux_host_class_storage_media_check(storage); #endif /* Check for media protection. We must do this operation here because FileX clears all the media fields before init. */ if (storage -> ux_host_class_storage_write_protected_media == UX_TRUE) /* The media is Write Protected. We tell FileX. */ media -> fx_media_driver_write_protect = UX_TRUE; /* This function always succeeds. */ media -> fx_media_driver_status = FX_SUCCESS; break; case FX_DRIVER_UNINIT: /* Nothing to do. Just return a good status! */ media -> fx_media_driver_status = FX_SUCCESS; break; case FX_DRIVER_BOOT_READ: /* Read the media boot sector. */ status = _ux_host_class_storage_media_read(storage, partition_start, 1, media -> fx_media_driver_buffer); /* Check completion status. */ if (status == UX_SUCCESS) media -> fx_media_driver_status = FX_SUCCESS; else { #if defined(UX_HOST_STANDALONE) /* Poll status. */ _ux_host_class_storage_media_check(storage); #endif media -> fx_media_driver_status = _ux_host_class_storage_sense_code_translate(storage,status); } break; case FX_DRIVER_BOOT_WRITE: /* Write the boot sector. */ status = _ux_host_class_storage_media_write(storage, partition_start, 1, media -> fx_media_driver_buffer); /* Check completion status. */ if (status == UX_SUCCESS) media -> fx_media_driver_status = FX_SUCCESS; else { #if defined(UX_HOST_STANDALONE) /* Poll status. */ _ux_host_class_storage_media_check(storage); #endif media -> fx_media_driver_status = _ux_host_class_storage_sense_code_translate(storage,status); } break; default: /* Invalid request from FileX */ media -> fx_media_driver_status = FX_IO_ERROR; break; } /* Unprotect thread reentry to this instance. */ _ux_host_class_storage_unlock(storage); } #endif