From 4d3af7ddb25add756ea61176c66c96e503e8d9c5 Mon Sep 17 00:00:00 2001 From: MAY Date: Sun, 18 Jan 2026 15:14:28 +0100 Subject: [PATCH] Device MSC: add START STOP (load/eject) request support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add mass-storage “removable media” support by tracking per-LUN prevent/allow medium removal and loaded/ejected status. - Introduce an optional per-LUN callback to handle SCSI START STOP UNIT (including load/eject and power-condition fields). - Extend storage constants (media types, sense keys/codes, power conditions, prevent flags) to support the new behavior and improve readability (explicit hex values). - Initialize new per-LUN state on activation (default: medium removal allowed, medium loaded) and wire the new callback through storage initialization. - Includes minor formatting/comment cleanups and version banner updates to 6.4.6. SCSI Block Commands – 4 (SBC-4) --- .../inc/ux_device_class_storage.h | 220 ++++--- .../src/ux_device_class_storage_activate.c | 93 +-- .../src/ux_device_class_storage_initialize.c | 6 +- ...lass_storage_prevent_allow_media_removal.c | 96 +-- .../src/ux_device_class_storage_read.c | 147 +++-- .../ux_device_class_storage_read_capacity.c | 118 ++-- ...evice_class_storage_read_format_capacity.c | 103 +-- .../src/ux_device_class_storage_start_stop.c | 134 ++-- .../src/ux_device_class_storage_test_ready.c | 104 +-- .../src/ux_device_class_storage_write.c | 138 ++-- test/cmake/usbx/regression/CMakeLists.txt | 1 + ...vice_class_storage_media_start_stop_test.c | 600 ++++++++++++++++++ test/regression/usbxtestcontrol.c | 2 + 13 files changed, 1285 insertions(+), 477 deletions(-) create mode 100644 test/regression/usbx_ux_device_class_storage_media_start_stop_test.c diff --git a/common/usbx_device_classes/inc/ux_device_class_storage.h b/common/usbx_device_classes/inc/ux_device_class_storage.h index 8151695e..341ac3f4 100644 --- a/common/usbx_device_classes/inc/ux_device_class_storage.h +++ b/common/usbx_device_classes/inc/ux_device_class_storage.h @@ -1,10 +1,10 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 **************************************************************************/ @@ -25,7 +25,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_device_class_storage.h PORTABLE C */ -/* 6.3.0 */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -61,21 +61,24 @@ /* endpoint buffer in classes, */ /* added error checks support, */ /* resulting in version 6.3.0 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ #ifndef UX_DEVICE_CLASS_STORAGE_H #define UX_DEVICE_CLASS_STORAGE_H -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ -#ifdef __cplusplus +#ifdef __cplusplus -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { -#endif +#endif /* Internal option: enable the basic USBX error checking. This define is typically used @@ -107,12 +110,15 @@ extern "C" { #define UX_SLAVE_CLASS_STORAGE_PROTOCOL_BO 0x50 /* Define Storage Class USB MEDIA types. */ -#define UX_SLAVE_CLASS_STORAGE_MEDIA_FAT_DISK 0 -#define UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM 5 -#define UX_SLAVE_CLASS_STORAGE_MEDIA_OPTICAL_DISK 7 +#define UX_SLAVE_CLASS_STORAGE_MEDIA_FAT_DISK 0x00 +#define UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM 0x05 +#define UX_SLAVE_CLASS_STORAGE_MEDIA_OPTICAL_DISK 0x07 #define UX_SLAVE_CLASS_STORAGE_MEDIA_IOMEGA_CLICK 0x55 +/* Define Storage Class USB medium removable type. */ +#define UX_SLAVE_CLASS_STORAGE_MEDIA_IS_NOT_REMOVABLE 0x00 +#define UX_SLAVE_CLASS_STORAGE_MEDIA_IS_REMOVABLE (1u<<8) /* Define Storage Class SCSI command constants. */ @@ -308,23 +314,27 @@ extern "C" { /* Define Storage Class SCSI sense key definition constants. */ -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE 0x0 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_RECOVERED_ERROR 0x1 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NOT_READY 0x2 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_MEDIUM_ERROR 0x3 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_HARDWARE_ERROR 0x4 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ILLEGAL_REQUEST 0x5 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION 0x6 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_DATA_PROTECT 0x7 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_BLANK_CHECK 0x8 -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ABORTED_COMMAND 0x0b -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_VOLUME_OVERFLOW 0x0d -#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_MISCOMPARE 0x0e - +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE 0x00 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_RECOVERED_ERROR 0x01 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NOT_READY 0x02 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_MEDIUM_ERROR 0x03 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_HARDWARE_ERROR 0x04 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ILLEGAL_REQUEST 0x05 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION 0x06 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_DATA_PROTECT 0x07 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_BLANK_CHECK 0x08 +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ABORTED_COMMAND 0x0B +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_VOLUME_OVERFLOW 0x0D +#define UX_SLAVE_CLASS_STORAGE_SENSE_KEY_MISCOMPARE 0x0E + +#define UX_SLAVE_CLASS_STORAGE_SENSE_CODE_NOT_READY 0x04 +#define UX_SLAVE_CLASS_STORAGE_SENSE_CODE_WRITE_PROTECTED 0x27 +#define UX_SLAVE_CLASS_STORAGE_SENSE_CODE_NOT_READY_TO_READY 0x28 +#define UX_SLAVE_CLASS_STORAGE_SENSE_CODE_NOT_PRESENT 0x3A /* Define Storage Class SCSI sense key definition constants. */ -#define UX_SLAVE_CLASS_STORAGE_REQUEST_CODE_MEDIA_PROTECTED 0x27 +#define UX_SLAVE_CLASS_STORAGE_REQUEST_CODE_MEDIA_PROTECTED 0x27 /* Define Storage Class SCSI GET CONFIGURATION command constants. */ @@ -335,13 +345,13 @@ extern "C" { #define UX_SLAVE_CLASS_STORAGE_GET_CONFIGURATION_COMMAND_LENGTH_SBC 9 /* Define Storage Class SCSI ASC return codes. */ -#define UX_SLAVE_CLASS_STORAGE_ASC_KEY_INVALID_COMMAND 0x20 +#define UX_SLAVE_CLASS_STORAGE_ASC_KEY_INVALID_COMMAND 0x20 /* Define Storage Class CSW status. */ -#define UX_SLAVE_CLASS_STORAGE_CSW_PASSED 0 -#define UX_SLAVE_CLASS_STORAGE_CSW_FAILED 1 -#define UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR 2 +#define UX_SLAVE_CLASS_STORAGE_CSW_PASSED 0x00 +#define UX_SLAVE_CLASS_STORAGE_CSW_FAILED 0x01 +#define UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR 0x02 /* Define generic SCSI values. */ @@ -351,15 +361,32 @@ extern "C" { #define UX_SLAVE_CLASS_STORAGE_INQUIRY_PERIPHERAL_TYPE 0x00 #define UX_SLAVE_CLASS_STORAGE_RESET 0xff #define UX_SLAVE_CLASS_STORAGE_GET_MAX_LUN 0xfe -#define UX_SLAVE_CLASS_STORAGE_MAX_LUN 0 -#define UX_SLAVE_CLASS_STORAGE_RESPONSE_LENGTH 64 +#define UX_SLAVE_CLASS_STORAGE_MAX_LUN 0x00 +#define UX_SLAVE_CLASS_STORAGE_RESPONSE_LENGTH 0x40 /* Define Storage Class SCSI read disk information command constants. */ -#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_OPERATION 0 -#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_STATUS 2 -#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_ALLOCATION_LENGTH 7 -#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_LENGTH 10 +#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_OPERATION 0x00 +#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_STATUS 0x02 +#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_ALLOCATION_LENGTH 0x07 +#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_LENGTH 0x0A + +/* Define Storage Class (SBC-4) POWER CONDITION constants. */ + +#define UX_SLAVE_CLASS_STORAGE_POWER_CONDITION_START_VALID 0x00 +#define UX_SLAVE_CLASS_STORAGE_POWER_CONDITION_ACTIVE 0x01 +#define UX_SLAVE_CLASS_STORAGE_POWER_CONDITION_IDLE 0x02 +#define UX_SLAVE_CLASS_STORAGE_POWER_CONDITION_STANDBY 0x03 +#define UX_SLAVE_CLASS_STORAGE_POWER_CONDITION_LU_CONTROL 0x07 +#define UX_SLAVE_CLASS_STORAGE_POWER_CONDITION_FORCE_IDLE_0 0x0A +#define UX_SLAVE_CLASS_STORAGE_POWER_CONDITION_FORCE_STANDBY_0 0x0B + +/* Define Storage Class (SBC-4) PREVENT constants. */ + +#define UX_SLAVE_CLASS_STORAGE_MEDIUM_REMOVAL_IS_ALLOWED 0x00 +#define UX_SLAVE_CLASS_STORAGE_MEDIUM_REMOVAL_SHALL_BE_PREVENTED 0x01 +#define UX_SLAVE_CLASS_STORAGE_MEDIUM_PREVENT_OBSOLETE_2 0x02 +#define UX_SLAVE_CLASS_STORAGE_MEDIUM_PREVENT_OBSOLETE_3 0x03 /* Define Storage Class Feature Descriptor generic format. */ @@ -504,12 +531,17 @@ typedef struct UX_SLAVE_CLASS_STORAGE_LUN_STRUCT ULONG ux_slave_class_storage_request_sense_status; ULONG ux_slave_class_storage_disk_status; ULONG ux_slave_class_storage_last_session_state; + ULONG ux_slave_class_storage_prevent_medium_removal; + ULONG ux_slave_class_storage_medium_loaded_status; UINT (*ux_slave_class_storage_media_read)(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); UINT (*ux_slave_class_storage_media_write)(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); UINT (*ux_slave_class_storage_media_flush)(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); UINT (*ux_slave_class_storage_media_status)(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); UINT (*ux_slave_class_storage_media_notification)(VOID *storage, ULONG lun, ULONG media_id, ULONG notification_class, UCHAR **media_notification, ULONG *media_notification_length); + + /* Optional callback invoked when load/eject media is requested. */ + UINT (*ux_slave_class_storage_media_start_stop)(VOID *storage, ULONG lun, ULONG power_condition, ULONG start, ULONG load_eject); } UX_SLAVE_CLASS_STORAGE_LUN; /* Sense status value (key at bit0-7, code at bit8-15 and qualifier at bit16-23). */ @@ -605,64 +637,76 @@ UINT _ux_device_class_storage_initialize(UX_SLAVE_CLASS_COMMAND *command); UINT _ux_device_class_storage_uninitialize(UX_SLAVE_CLASS_COMMAND *command); UINT _ux_device_class_storage_activate(UX_SLAVE_CLASS_COMMAND *command); UINT _ux_device_class_storage_control_request(UX_SLAVE_CLASS_COMMAND *command); -UINT _ux_device_class_storage_csw_send(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, UCHAR csw_status); +UINT _ux_device_class_storage_csw_send(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, UCHAR csw_status); UINT _ux_device_class_storage_deactivate(UX_SLAVE_CLASS_COMMAND *command); UINT _ux_device_class_storage_entry(UX_SLAVE_CLASS_COMMAND *command); -UINT _ux_device_class_storage_format(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_inquiry(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_mode_select(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_mode_sense(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_format(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_inquiry(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_mode_select(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_mode_sense(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); UINT _ux_device_class_storage_prevent_allow_media_removal(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb); -UINT _ux_device_class_storage_read(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command); -UINT _ux_device_class_storage_read_capacity(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_read_format_capacity(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_read_toc(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb); -UINT _ux_device_class_storage_request_sense(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_start_stop(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_test_ready(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -VOID _ux_device_class_storage_thread(ULONG storage_instance); -UINT _ux_device_class_storage_verify(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_write(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command); -UINT _ux_device_class_storage_synchronize_cache(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command); -UINT _ux_device_class_storage_read_disk_information(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_read(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command); +UINT _ux_device_class_storage_read_capacity(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_read_format_capacity(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_read_toc(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb); +UINT _ux_device_class_storage_request_sense(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_start_stop(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); - -UINT _ux_device_class_storage_get_configuration(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, +UINT _ux_device_class_storage_test_ready(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +VOID _ux_device_class_storage_thread(ULONG storage_instance); +UINT _ux_device_class_storage_verify(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_write(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command); +UINT _ux_device_class_storage_synchronize_cache(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command); +UINT _ux_device_class_storage_read_disk_information(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); + +UINT _ux_device_class_storage_get_configuration(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); UINT _ux_device_class_storage_get_status_notification(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); +UINT _ux_device_class_storage_report_key(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); -UINT _ux_device_class_storage_report_key(UX_SLAVE_CLASS_STORAGE *storage, - ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, - UCHAR *cbwcb); - -UINT _ux_device_class_storage_get_performance(UX_SLAVE_CLASS_STORAGE *storage, - ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, - UCHAR *cbwcb); + +UINT _ux_device_class_storage_get_performance(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); UINT _ux_device_class_storage_read_dvd_structure(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb); UINT _ux_device_class_storage_tasks_run(VOID *instance); @@ -674,10 +718,10 @@ UINT _uxe_device_class_storage_initialize(UX_SLAVE_CLASS_COMMAND *command); #define ux_device_class_storage_entry _ux_device_class_storage_entry -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ #ifdef __cplusplus -} -#endif +} +#endif #endif diff --git a/common/usbx_device_classes/src/ux_device_class_storage_activate.c b/common/usbx_device_classes/src/ux_device_class_storage_activate.c index b868c497..0df0a5d2 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_activate.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_activate.c @@ -1,18 +1,18 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 */ +/** */ +/** USBX Component */ /** */ /** Device Storage Class */ /** */ @@ -29,40 +29,40 @@ #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_storage_activate PORTABLE C */ -/* 6.3.0 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_storage_activate PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function activates the USB storage device. */ -/* */ -/* INPUT */ -/* */ -/* command Pointer to storage command */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* _ux_device_thread_resume Resume thread */ -/* */ -/* CALLED BY */ -/* */ -/* Device Storage Class */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* */ +/* This function activates the USB storage device. */ +/* */ +/* INPUT */ +/* */ +/* command Pointer to storage command */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_thread_resume Resume thread */ +/* */ +/* CALLED BY */ +/* */ +/* Device Storage Class */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* resulting in version 6.1 */ @@ -77,15 +77,19 @@ /* added a new mode to manage */ /* endpoint buffer in classes, */ /* resulting in version 6.3.0 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ UINT _ux_device_class_storage_activate(UX_SLAVE_CLASS_COMMAND *command) { - + UINT status = UX_SUCCESS; UX_SLAVE_INTERFACE *interface_ptr; UX_SLAVE_CLASS *class_ptr; UX_SLAVE_CLASS_STORAGE *storage; +ULONG lun_index; #if defined(UX_DEVICE_STANDALONE) UX_SLAVE_ENDPOINT *endpoint; #endif @@ -99,17 +103,17 @@ UX_SLAVE_ENDPOINT *endpoint; /* Get the interface that owns this instance. */ interface_ptr = (UX_SLAVE_INTERFACE *) command -> ux_slave_class_command_interface; - + /* Store the class instance into the interface. */ interface_ptr -> ux_slave_interface_class_instance = (VOID *)storage; - + /* Now the opposite, store the interface in the class instance. */ storage -> ux_slave_class_storage_interface = interface_ptr; #if !defined(UX_DEVICE_STANDALONE) /* Resume thread. */ - _ux_device_thread_resume(&class_ptr -> ux_slave_class_thread); + _ux_device_thread_resume(&class_ptr -> ux_slave_class_thread); #else @@ -130,7 +134,7 @@ UX_SLAVE_ENDPOINT *endpoint; /* We found the IN endpoint first. */ storage -> ux_device_class_storage_ep_in = endpoint; - + /* So the next endpoint has to be the OUT endpoint. */ storage -> ux_device_class_storage_ep_out = endpoint -> ux_slave_endpoint_next_endpoint; } @@ -162,13 +166,20 @@ UX_SLAVE_ENDPOINT *endpoint; status = UX_SUCCESS; #endif + /* Default when activating storage device: media removal is allowed (not prevented) and loaded. */ + for (lun_index = 0; lun_index < storage -> ux_slave_class_storage_number_lun; lun_index++) + { + storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_prevent_medium_removal = 0; + storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_medium_loaded_status = 1; + } + /* If there is a activate function call it. */ if (storage -> ux_slave_class_storage_instance_activate != UX_NULL) - { + { /* Invoke the application. */ storage -> ux_slave_class_storage_instance_activate(storage); } - + /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_ACTIVATE, storage, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) diff --git a/common/usbx_device_classes/src/ux_device_class_storage_initialize.c b/common/usbx_device_classes/src/ux_device_class_storage_initialize.c index c6f393e0..ec201245 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_initialize.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_initialize.c @@ -40,7 +40,7 @@ UCHAR _ux_system_slave_class_storage_product_serial[] = "123 /* FUNCTION RELEASE */ /* */ /* _ux_device_class_storage_initialize PORTABLE C */ -/* 6.3.0 */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -85,6 +85,9 @@ UCHAR _ux_system_slave_class_storage_product_serial[] = "123 /* added a new mode to manage */ /* endpoint buffer in classes, */ /* resulting in version 6.3.0 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ UINT _ux_device_class_storage_initialize(UX_SLAVE_CLASS_COMMAND *command) @@ -184,6 +187,7 @@ ULONG lun_index; storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_write = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_write; storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_status = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_status; storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_notification = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_notification; + storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_start_stop = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_start_stop; } /* If it's OK, complete it. */ diff --git a/common/usbx_device_classes/src/ux_device_class_storage_prevent_allow_media_removal.c b/common/usbx_device_classes/src/ux_device_class_storage_prevent_allow_media_removal.c index 3a831ee4..b7b1fafb 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_prevent_allow_media_removal.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_prevent_allow_media_removal.c @@ -1,18 +1,18 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 */ +/** */ +/** USBX Component */ /** */ /** Device Storage Class */ /** */ @@ -29,68 +29,82 @@ #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ /* _ux_device_class_storage_prevent_allow_media_removal */ -/* PORTABLE C */ -/* 6.1 */ +/* PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function allows or prevents the removal of the media. We don't */ -/* do anything here, just the CSW is returned with a SUCCESS code. */ -/* */ -/* INPUT */ -/* */ -/* storage Pointer to storage class */ +/* */ +/* This function allows or prevents the removal of the media. */ +/* The PREVENT ALLOW MEDIUM REMOVAL command allows an application */ +/* client to restrict the demounting of the removable */ +/* medium. */ +/* */ +/* INPUT */ +/* */ +/* storage Pointer to storage class */ +/* lun Logical unit number */ /* endpoint_in Pointer to IN endpoint */ /* endpoint_out Pointer to OUT endpoint */ -/* cbwcb Pointer to CBWCB */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* _ux_device_class_storage_csw_send Send CSW */ -/* */ -/* CALLED BY */ -/* */ +/* cbwcb Pointer to CBWCB */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ /* Device Storage Class */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* optimized command logic, */ /* resulting in version 6.1 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ -UINT _ux_device_class_storage_prevent_allow_media_removal(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb) +UINT _ux_device_class_storage_prevent_allow_media_removal(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb) { - UX_PARAMETER_NOT_USED(lun); +ULONG prevent_flag; + UX_PARAMETER_NOT_USED(endpoint_in); UX_PARAMETER_NOT_USED(endpoint_out); - UX_PARAMETER_NOT_USED(cbwcb); /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_PREVENT_ALLOW_MEDIA_REMOVAL, storage, lun, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + /* Parse the PREVENT/ALLOW MEDIA REMOVAL command: byte 4 bit 0 is the prevent flag. */ + prevent_flag = (ULONG)(cbwcb[4] & 0x01); + + /* Update internal flag to track prevent/allow state for this LUN. */ + if (prevent_flag == UX_SLAVE_CLASS_STORAGE_MEDIUM_REMOVAL_IS_ALLOWED) + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_prevent_medium_removal = 0; + else + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_prevent_medium_removal = 1; + /* We set the CSW with success. */ storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED; /* Return successful completion. */ return(UX_SUCCESS); } - diff --git a/common/usbx_device_classes/src/ux_device_class_storage_read.c b/common/usbx_device_classes/src/ux_device_class_storage_read.c index 91e48d4a..a0925003 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_read.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_read.c @@ -1,18 +1,18 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 */ +/** */ +/** USBX Component */ /** */ /** Device Storage Class */ /** */ @@ -29,50 +29,50 @@ #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_storage_read PORTABLE C */ -/* 6.1.10 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_storage_read PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function performs a READ command in 32 or 16 bits. */ -/* */ -/* INPUT */ -/* */ -/* storage Pointer to storage class */ +/* */ +/* This function performs a READ command in 32 or 16 bits. */ +/* */ +/* INPUT */ +/* */ +/* storage Pointer to storage class */ +/* lun Logical unit number */ /* endpoint_in Pointer to IN endpoint */ /* endpoint_out Pointer to OUT endpoint */ -/* cbwcb Pointer to CBWCB */ -/* scsi_command SCSI command */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* (ux_slave_class_storage_media_read) Read from media */ -/* (ux_slave_class_storage_media_status) Get media status */ -/* _ux_device_stack_endpoint_stall Stall endpoint */ -/* _ux_device_stack_transfer_request Transfer request */ -/* _ux_utility_long_get_big_endian Get 32-bit big endian */ -/* _ux_utility_short_get_big_endian Get 16-bit big endian */ -/* _ux_device_class_storage_csw_send Send CSW */ -/* */ -/* CALLED BY */ -/* */ -/* Device Storage Class */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* cbwcb Pointer to CBWCB */ +/* scsi_command SCSI command */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* (ux_slave_class_storage_media_read) Read from media */ +/* (ux_slave_class_storage_media_status) Get media status */ +/* _ux_device_stack_endpoint_stall Stall endpoint */ +/* _ux_device_stack_transfer_request Transfer request */ +/* _ux_utility_long_get_big_endian Get 32-bit big endian */ +/* _ux_utility_short_get_big_endian Get 16-bit big endian */ +/* */ +/* CALLED BY */ +/* */ +/* Device Storage Class */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* optimized command logic, */ @@ -83,22 +83,25 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* added standalone support, */ /* resulting in version 6.1.10 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ -UINT _ux_device_class_storage_read(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb, UCHAR scsi_command) +UINT _ux_device_class_storage_read(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command) { UINT status; ULONG lba; UX_SLAVE_TRANSFER *transfer_request; -ULONG total_number_blocks; +ULONG total_number_blocks; ULONG media_status; ULONG total_length; #if !defined(UX_DEVICE_STANDALONE) -ULONG number_blocks; +ULONG number_blocks; ULONG transfer_length; ULONG done_length; #endif @@ -106,6 +109,20 @@ ULONG done_length; UX_PARAMETER_NOT_USED(endpoint_out); + if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_medium_loaded_status == 0) + { + /* Media not loaded. Set NOT READY sense code. */ + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = + UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NOT_READY, + UX_SLAVE_CLASS_STORAGE_SENSE_CODE_NOT_PRESENT, 0x00); + + /* Return CSW with failure. */ + storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED; + + /* Return completion status. */ + return(UX_SUCCESS); + } + /* Get the LBA from the CBWCB. */ lba = _ux_utility_long_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_READ_LBA); @@ -116,7 +133,7 @@ ULONG done_length; /* Get the number of blocks from the CBWCB in 16 bits. */ total_number_blocks = _ux_utility_short_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_READ_TRANSFER_LENGTH_16); - else + else /* Get the number of blocks from the CBWCB in 32 bits. */ total_number_blocks = _ux_utility_long_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_READ_TRANSFER_LENGTH_32); @@ -133,7 +150,7 @@ ULONG done_length; #if defined(UX_DEVICE_STANDALONE) /* Obtain the status of the device. */ - status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, + status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_id, &media_status); /* Update the request sense. */ @@ -196,23 +213,23 @@ ULONG done_length; { /* Obtain the status of the device. */ - status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, + status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_id, &media_status); - + /* Update the request sense. */ storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status; - + /* If there is a problem, return a failed command. */ if (status != UX_SUCCESS) { - + /* We have a problem, media status error. Return a bad completion and wait for the REQUEST_SENSE command. */ _ux_device_stack_endpoint_stall(endpoint_in); /* Update residue. */ storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length - done_length; - + /* Return an error. */ return(UX_ERROR); } @@ -222,7 +239,7 @@ ULONG done_length; /* Compute the transfer length based on the maximum allowed. */ transfer_length = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE; - + else /* Compute the transfer length based on what is left to transfer. */ @@ -232,27 +249,27 @@ ULONG done_length; number_blocks = transfer_length / storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_block_length; /* If trace is enabled, insert this event into the trace buffer. */ - UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_READ, storage, lun, transfer_request -> ux_slave_transfer_request_data_pointer, + UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_READ, storage, lun, transfer_request -> ux_slave_transfer_request_data_pointer, number_blocks, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) /* Execute the read command from the local media. */ - status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_read(storage, lun, - transfer_request -> ux_slave_transfer_request_data_pointer, number_blocks, lba, &media_status); + status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_read(storage, lun, + transfer_request -> ux_slave_transfer_request_data_pointer, number_blocks, lba, &media_status); /* If there is a problem, return a failed command. */ if (status != UX_SUCCESS) { - + /* We have a problem, request error. Return a bad completion and wait for the REQUEST_SENSE command. */ _ux_device_stack_endpoint_stall(endpoint_in); - + /* Update residue. */ storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length - done_length; /* And update the REQUEST_SENSE codes. */ storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status; - + /* Return an error. */ return(UX_ERROR); } @@ -267,7 +284,7 @@ ULONG done_length; /* We have a problem, request error. Return a bad completion and wait for the REQUEST_SENSE command. */ _ux_device_stack_endpoint_stall(endpoint_in); - + /* Update residue. */ storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length - done_length; @@ -282,11 +299,11 @@ ULONG done_length; /* Update the LBA address. */ lba += number_blocks; - + /* Update the length to remain. */ - total_length -= transfer_length; + total_length -= transfer_length; done_length += transfer_length; - + /* Update the number of blocks to read. */ total_number_blocks -= number_blocks; } diff --git a/common/usbx_device_classes/src/ux_device_class_storage_read_capacity.c b/common/usbx_device_classes/src/ux_device_class_storage_read_capacity.c index c3825e7a..7a549630 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_read_capacity.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_read_capacity.c @@ -1,18 +1,18 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 */ +/** */ +/** USBX Component */ /** */ /** Device Storage Class */ /** */ @@ -34,48 +34,47 @@ /* Build option checked runtime by UX_ASSERT */ #endif -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_storage_read_capacity PORTABLE C */ -/* 6.3.0 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_storage_read_capacity PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function performs a READ_CAPACITY command. */ -/* */ -/* INPUT */ -/* */ -/* storage Pointer to storage class */ +/* */ +/* This function performs a READ_CAPACITY command. */ +/* */ +/* INPUT */ +/* */ +/* storage Pointer to storage class */ +/* lun Logical unit number */ /* endpoint_in Pointer to IN endpoint */ /* endpoint_out Pointer to OUT endpoint */ -/* cbwcb Pointer to CBWCB */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* _ux_device_class_storage_csw_send Send CSW */ -/* _ux_device_stack_transfer_request Transfer request */ +/* cbwcb Pointer to CBWCB */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_request Transfer request */ /* _ux_device_stack_endpoint_stall Stall endpoint */ -/* _ux_utility_long_put_big_endian Put 32-bit big endian */ -/* _ux_utility_memory_copy Copy memory */ -/* _ux_utility_memory_set Set memory */ -/* */ -/* CALLED BY */ -/* */ -/* Device Storage Class */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* _ux_utility_long_put_big_endian Put 32-bit big endian */ +/* _ux_utility_memory_set Set memory */ +/* */ +/* CALLED BY */ +/* */ +/* Device Storage Class */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* optimized command logic, */ @@ -89,11 +88,14 @@ /* checked compiling options */ /* by runtime UX_ASSERT, */ /* resulting in version 6.3.0 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ UINT _ux_device_class_storage_read_capacity(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb) + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb) { UINT status; @@ -110,8 +112,25 @@ UCHAR *read_capacity_buffer; /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_READ_CAPACITY, storage, lun, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_medium_loaded_status == 0) + { + /* Media not loaded. Set NOT READY sense code. */ + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = + UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NOT_READY, + UX_SLAVE_CLASS_STORAGE_SENSE_CODE_NOT_PRESENT, 0x00); + + /* Return CSW with failure. */ + storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED; + + /* We need to STALL the IN endpoint. The endpoint will be reset by the host. */ + _ux_device_stack_endpoint_stall(endpoint_in); + + /* Return error. */ + return(UX_SUCCESS); + } + /* Obtain the status of the device. */ - status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, + status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_id, &media_status); /* Update the request sense. */ @@ -133,24 +152,24 @@ UCHAR *read_capacity_buffer; } else { - + /* Obtain the pointer to the transfer request. */ transfer_request = &endpoint_in -> ux_slave_endpoint_transfer_request; /* Obtain read capacity response buffer. */ read_capacity_buffer = transfer_request -> ux_slave_transfer_request_data_pointer; - + /* Ensure it is cleaned. */ _ux_utility_memory_set(read_capacity_buffer, 0, UX_SLAVE_CLASS_STORAGE_READ_CAPACITY_RESPONSE_LENGTH); /* Use case of memcpy is verified. */ - + /* Insert the last LBA address in the response. */ _ux_utility_long_put_big_endian(&read_capacity_buffer[UX_SLAVE_CLASS_STORAGE_READ_CAPACITY_RESPONSE_LAST_LBA], storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_last_lba); - + /* Insert the block length in the response. */ _ux_utility_long_put_big_endian(&read_capacity_buffer[UX_SLAVE_CLASS_STORAGE_READ_CAPACITY_RESPONSE_BLOCK_SIZE], storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_block_length); - + #if defined(UX_DEVICE_STANDALONE) /* Next: Transfer (DATA). */ @@ -168,7 +187,7 @@ UCHAR *read_capacity_buffer; #else /* Send a data payload with the read_capacity response buffer. */ - _ux_device_stack_transfer_request(transfer_request, + _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_STORAGE_READ_CAPACITY_RESPONSE_LENGTH, UX_SLAVE_CLASS_STORAGE_READ_CAPACITY_RESPONSE_LENGTH); #endif @@ -177,8 +196,7 @@ UCHAR *read_capacity_buffer; storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED; status = UX_SUCCESS; } - + /* Return completion status. */ return(status); } - diff --git a/common/usbx_device_classes/src/ux_device_class_storage_read_format_capacity.c b/common/usbx_device_classes/src/ux_device_class_storage_read_format_capacity.c index e84e424c..4e82bb8a 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_read_format_capacity.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_read_format_capacity.c @@ -1,18 +1,18 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 */ +/** */ +/** USBX Component */ /** */ /** Device Storage Class */ /** */ @@ -34,47 +34,46 @@ /* Build option checked runtime by UX_ASSERT */ #endif -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_storage_read_format_capacity PORTABLE C */ -/* 6.3.0 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_storage_read_format_capacity PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function performs a READ_FORMAT_CAPACITY command. */ -/* */ -/* INPUT */ -/* */ -/* storage Pointer to storage class */ +/* */ +/* This function performs a READ_FORMAT_CAPACITY command. */ +/* */ +/* INPUT */ +/* */ +/* storage Pointer to storage class */ +/* lun Logical unit number */ /* endpoint_in Pointer to IN endpoint */ /* endpoint_out Pointer to OUT endpoint */ -/* cbwcb Pointer to CBWCB */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* _ux_device_class_storage_csw_send Send CSW */ -/* _ux_device_stack_transfer_request Transfer request */ +/* cbwcb Pointer to CBWCB */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_request Transfer request */ /* _ux_utility_memory_set Set memory */ /* _ux_utility_long_put_big_endian Put 32-bit big endian */ -/* _ux_utility_memory_copy Copy memory */ -/* */ -/* CALLED BY */ -/* */ -/* Device Storage Class */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* */ +/* CALLED BY */ +/* */ +/* Device Storage Class */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* optimized command logic, */ @@ -88,11 +87,14 @@ /* checked compiling options */ /* by runtime UX_ASSERT, */ /* resulting in version 6.3.0 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ UINT _ux_device_class_storage_read_format_capacity(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb) + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb) { UINT status; @@ -108,6 +110,20 @@ UCHAR *read_format_capacity_buffer; /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_READ_FORMAT_CAPACITY, storage, lun, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_medium_loaded_status == 0) + { + /* Media not loaded. Set NOT READY sense code. */ + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = + UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NOT_READY, + UX_SLAVE_CLASS_STORAGE_SENSE_CODE_NOT_PRESENT, 0x00); + + /* Return CSW with failure. */ + storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED; + + /* Return completion status. */ + return(UX_SUCCESS); + } + /* Obtain the pointer to the transfer request. */ transfer_request = &endpoint_in -> ux_slave_endpoint_transfer_request; @@ -129,7 +145,7 @@ UCHAR *read_format_capacity_buffer; storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_block_length); /* Insert the response code : always 2. */ - read_format_capacity_buffer[UX_SLAVE_CLASS_STORAGE_READ_FORMAT_CAPACITY_RESPONSE_DESC_CODE] = 2; + read_format_capacity_buffer[UX_SLAVE_CLASS_STORAGE_READ_FORMAT_CAPACITY_RESPONSE_DESC_CODE] = 2; #if defined(UX_DEVICE_STANDALONE) @@ -148,9 +164,9 @@ UCHAR *read_format_capacity_buffer; #else /* Send a data payload with the read_capacity response buffer. */ - _ux_device_stack_transfer_request(transfer_request, - UX_SLAVE_CLASS_STORAGE_READ_FORMAT_CAPACITY_RESPONSE_LENGTH, - UX_SLAVE_CLASS_STORAGE_READ_FORMAT_CAPACITY_RESPONSE_LENGTH); + _ux_device_stack_transfer_request(transfer_request, + UX_SLAVE_CLASS_STORAGE_READ_FORMAT_CAPACITY_RESPONSE_LENGTH, + UX_SLAVE_CLASS_STORAGE_READ_FORMAT_CAPACITY_RESPONSE_LENGTH); #endif /* Now we set the CSW with success. */ @@ -160,4 +176,3 @@ UCHAR *read_format_capacity_buffer; /* Return completion status. */ return(status); } - diff --git a/common/usbx_device_classes/src/ux_device_class_storage_start_stop.c b/common/usbx_device_classes/src/ux_device_class_storage_start_stop.c index f3b7a989..f167aa12 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_start_stop.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_start_stop.c @@ -1,18 +1,18 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 */ +/** */ +/** USBX Component */ /** */ /** Device Storage Class */ /** */ @@ -29,67 +29,119 @@ #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_storage_start_stop PORTABLE C */ -/* 6.1 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_storage_start_stop PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function starts or stops the media. This command will not do */ -/* anything here, just the CSW is returned with a SUCCESS code. */ -/* */ -/* INPUT */ -/* */ -/* storage Pointer to storage class */ +/* */ +/* This function starts or stops the media. The device load or eject */ +/* the medium. */ +/* */ +/* INPUT */ +/* */ +/* storage Pointer to storage class */ +/* lun Logical unit number */ /* endpoint_in Pointer to IN endpoint */ /* endpoint_out Pointer to OUT endpoint */ -/* cbwcb Pointer to CBWCB */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* _ux_device_class_storage_csw_send Send CSW */ -/* */ -/* CALLED BY */ -/* */ +/* cbwcb Pointer to CBWCB */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ /* Device Storage Class */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* optimized command logic, */ /* resulting in version 6.1 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ -UINT _ux_device_class_storage_start_stop(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb) +UINT _ux_device_class_storage_start_stop(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb) { - UX_PARAMETER_NOT_USED(lun); +ULONG power_condition; +ULONG start; +ULONG load_eject; + UX_PARAMETER_NOT_USED(endpoint_in); UX_PARAMETER_NOT_USED(endpoint_out); - UX_PARAMETER_NOT_USED(cbwcb); /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_START_STOP, storage, lun, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + /* Parse START/STOP (SBC-2 0x1B): byte 4 has LOEJ (bit1) and START (bit0). */ + power_condition = (ULONG)((cbwcb[4] & 0xF0) >> 0x04); + start = (ULONG)(cbwcb[4] & 0x01); + load_eject = (ULONG)((cbwcb[4] & 0x02) >> 0x01); + + if ((load_eject == 1) && + (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_prevent_medium_removal == 1) && + (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_removable_flag == UX_SLAVE_CLASS_STORAGE_MEDIA_IS_NOT_REMOVABLE)) + { + /* Update the REQUEST SENSE codes. */ + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = + UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ILLEGAL_REQUEST, + UX_SLAVE_CLASS_STORAGE_ASC_KEY_INVALID_COMMAND, 0x00); + + /* Set the CSW with failure. */ + storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED; + + /* Return error. */ + return(UX_ERROR); + } + + /* power_condition = 0, load_eject = 0 : no action regarding loading or ejecting the medium. + power_condition = 0, load_eject = 1, start = 0 : unload the medium. + power_condition = 0, load_eject = 1, start = 1 : load the medium. + */ + if (power_condition == UX_SLAVE_CLASS_STORAGE_POWER_CONDITION_START_VALID) + { + if (load_eject != 0) + { + if (start == 0) + { + /* Eject media: mark as empty. */ + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_medium_loaded_status = 0; + } + else + { + /* Load media: mark as present/complete. */ + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_medium_loaded_status = 1; + } + } + } + + /* Call the media start/stop function if available. */ + if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_start_stop != UX_NULL) + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_start_stop( + storage, lun, power_condition, start, load_eject); + /* We set the CSW with success. */ storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED; /* Return successful completion. */ return(UX_SUCCESS); } - diff --git a/common/usbx_device_classes/src/ux_device_class_storage_test_ready.c b/common/usbx_device_classes/src/ux_device_class_storage_test_ready.c index 3a74fc0b..bc6719aa 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_test_ready.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_test_ready.c @@ -1,18 +1,18 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 */ +/** */ +/** USBX Component */ /** */ /** Device Storage Class */ /** */ @@ -29,47 +29,47 @@ #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_storage_test_ready PORTABLE C */ -/* 6.1.10 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_storage_test_ready PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function tests if the SCSI slave device is ready. */ -/* The status function of the storage devices is called. If there is */ -/* an error, the request sense parameters are set for the host to */ -/* investigate. */ -/* */ -/* INPUT */ -/* */ -/* storage Pointer to storage class */ +/* */ +/* This function tests if the SCSI slave device is ready. */ +/* The status function of the storage devices is called. If there is */ +/* an error, the request sense parameters are set for the host to */ +/* investigate. */ +/* */ +/* INPUT */ +/* */ +/* storage Pointer to storage class */ +/* lun Logical unit number */ /* endpoint_in Pointer to IN endpoint */ /* endpoint_out Pointer to OUT endpoint */ -/* cbwcb Pointer to CBWCB */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* (ux_slave_class_storage_media_status) Get media status */ -/* _ux_device_class_storage_csw_send Send CSW */ -/* */ -/* CALLED BY */ -/* */ -/* Device Storage Class */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* cbwcb Pointer to CBWCB */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* (ux_slave_class_storage_media_status) Get media status */ +/* */ +/* CALLED BY */ +/* */ +/* Device Storage Class */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* optimized command logic, */ @@ -80,16 +80,19 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* added standalone support, */ /* resulting in version 6.1.10 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ -UINT _ux_device_class_storage_test_ready(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb) +UINT _ux_device_class_storage_test_ready(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb) { UINT status; ULONG media_status; - UX_PARAMETER_NOT_USED(lun); UX_PARAMETER_NOT_USED(endpoint_in); UX_PARAMETER_NOT_USED(endpoint_out); UX_PARAMETER_NOT_USED(cbwcb); @@ -97,8 +100,22 @@ ULONG media_status; /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_TEST_READY, storage, lun, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_medium_loaded_status == 0) + { + /* Media not loaded. Set NOT READY sense code. */ + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = + UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NOT_READY, + UX_SLAVE_CLASS_STORAGE_SENSE_CODE_NOT_PRESENT, 0x00); + + /* Return CSW with failure. */ + storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED; + + /* Return completion status. */ + return(UX_SUCCESS); + } + /* Obtain the status of the device. */ - status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, + status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_id, &media_status); /* Set the sense/code/qualifier codes for the REQUEST_SENSE command. */ @@ -122,4 +139,3 @@ ULONG media_status; /* Return completion status. */ return(status); } - diff --git a/common/usbx_device_classes/src/ux_device_class_storage_write.c b/common/usbx_device_classes/src/ux_device_class_storage_write.c index 5f865121..679d303c 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_write.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_write.c @@ -1,18 +1,18 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * 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 */ +/** */ +/** USBX Component */ /** */ /** Device Storage Class */ /** */ @@ -28,53 +28,50 @@ #include "ux_device_class_storage.h" #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_storage_write PORTABLE C */ -/* 6.1.10 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_storage_write PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function performs a WRITE command in 32 or 16 bits. */ -/* */ -/* INPUT */ -/* */ -/* storage Pointer to storage class */ +/* */ +/* This function performs a WRITE command in 32 or 16 bits. */ +/* */ +/* INPUT */ +/* */ +/* storage Pointer to storage class */ +/* lun Logical unit number */ /* endpoint_in Pointer to IN endpoint */ /* endpoint_out Pointer to OUT endpoint */ -/* cbwcb Pointer to the CBWCB */ -/* scsi_command SCSI command */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* (ux_slave_class_storage_media_status) Get media status */ -/* (ux_slave_class_storage_media_write) Write to media */ -/* _ux_device_class_storage_csw_send Send CSW */ -/* _ux_device_stack_endpoint_stall Stall endpoint */ -/* _ux_device_stack_transfer_request Transfer request */ -/* _ux_utility_long_get_big_endian Get 32-bit big endian */ -/* _ux_utility_memory_allocate Allocate memory */ -/* _ux_utility_memory_free Release memory */ +/* cbwcb Pointer to the CBWCB */ +/* scsi_command SCSI command */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* (ux_slave_class_storage_media_status) Get media status */ +/* (ux_slave_class_storage_media_write) Write to media */ +/* _ux_device_stack_endpoint_stall Stall endpoint */ +/* _ux_device_stack_transfer_request Transfer request */ /* _ux_utility_long_get_big_endian Get 32-bit big endian */ -/* _ux_utility_short_get_big_endian Get 16-bit big endian */ -/* */ -/* CALLED BY */ -/* */ -/* Device Storage Class */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* _ux_utility_short_get_big_endian Get 16-bit big endian */ +/* */ +/* CALLED BY */ +/* */ +/* Device Storage Class */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* optimized command logic, */ @@ -85,22 +82,25 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* added standalone support, */ /* resulting in version 6.1.10 */ +/* 01-20-2026 Mohamed AYED Modified comment(s), */ +/* support load eject media */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ -UINT _ux_device_class_storage_write(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, - UX_SLAVE_ENDPOINT *endpoint_in, - UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb, UCHAR scsi_command) +UINT _ux_device_class_storage_write(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, + UX_SLAVE_ENDPOINT *endpoint_in, + UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command) { UINT status; UX_SLAVE_TRANSFER *transfer_request; ULONG lba; -ULONG total_number_blocks; +ULONG total_number_blocks; ULONG media_status; ULONG total_length; #if !defined(UX_DEVICE_STANDALONE) -ULONG number_blocks; +ULONG number_blocks; ULONG transfer_length; ULONG done_length; #endif @@ -108,9 +108,23 @@ ULONG done_length; UX_PARAMETER_NOT_USED(endpoint_in); + if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_medium_loaded_status == 0) + { + /* Media not loaded. Set NOT READY sense code. */ + storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = + UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NOT_READY, + UX_SLAVE_CLASS_STORAGE_SENSE_CODE_NOT_PRESENT, 0x00); + + /* Return CSW with failure. */ + storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED; + + /* Return completion status. */ + return(UX_SUCCESS); + } + /* Get the LBA from the CBWCB. */ lba = _ux_utility_long_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_WRITE_LBA); - + /* The type of commands will tell us the width of the field containing the number of sectors to read. */ if (scsi_command == UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16) @@ -118,7 +132,7 @@ ULONG done_length; /* Get the number of blocks from the CBWCB in 16 bits. */ total_number_blocks = _ux_utility_short_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_WRITE_TRANSFER_LENGTH_16); - else + else /* Get the number of blocks from the CBWCB in 32 bits. */ total_number_blocks = _ux_utility_long_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_WRITE_TRANSFER_LENGTH_32); @@ -130,9 +144,9 @@ ULONG done_length; transfer_request = &endpoint_out -> ux_slave_endpoint_transfer_request; /* Obtain the status of the device. */ - status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, + status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun, storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_id, &media_status); - + /* Update the request sense. */ storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status; @@ -227,10 +241,10 @@ ULONG done_length; transfer_length = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE; else transfer_length = total_length; - + /* Get the data payload from the host. */ status = _ux_device_stack_transfer_request(transfer_request, transfer_length, transfer_length); - + /* Check the status. */ if (status != UX_SUCCESS) { @@ -245,38 +259,38 @@ ULONG done_length; /* And update the REQUEST_SENSE codes. */ storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); - + /* Return an error. */ return(UX_ERROR); } /* Compute the number of blocks to transfer. */ number_blocks = transfer_length / storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_block_length; - + /* Execute the write command to the local media. */ status = storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_write(storage, lun, transfer_request -> ux_slave_transfer_request_data_pointer, number_blocks, lba, &media_status); - + /* If there is a problem, return a failed command. */ if (status != UX_SUCCESS) { - + /* We have a problem, request error. Return a bad completion and wait for the REQUEST_SENSE command. */ _ux_device_stack_endpoint_stall(endpoint_out); - + /* Update residue. */ storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length - done_length; /* And update the REQUEST_SENSE codes. */ storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status; - + /* Return an error. */ return(UX_ERROR); } /* Update the lba. */ lba += number_blocks; - + /* Update the length to remain. */ total_length -= transfer_length; done_length += transfer_length; diff --git a/test/cmake/usbx/regression/CMakeLists.txt b/test/cmake/usbx/regression/CMakeLists.txt index 8d29d436..29927655 100644 --- a/test/cmake/usbx/regression/CMakeLists.txt +++ b/test/cmake/usbx/regression/CMakeLists.txt @@ -347,6 +347,7 @@ set(ux_class_storage_test_cases ${SOURCE_DIR}/usbx_ux_device_class_storage_read_test.c ${SOURCE_DIR}/usbx_ux_device_class_storage_request_sense_test.c ${SOURCE_DIR}/usbx_ux_device_class_storage_start_stop_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_media_start_stop_test.c ${SOURCE_DIR}/usbx_ux_device_class_storage_synchronize_cache_test.c ${SOURCE_DIR}/usbx_ux_device_class_storage_test_ready_test.c ${SOURCE_DIR}/usbx_ux_device_class_storage_thread_test.c diff --git a/test/regression/usbx_ux_device_class_storage_media_start_stop_test.c b/test/regression/usbx_ux_device_class_storage_media_start_stop_test.c new file mode 100644 index 00000000..4dc96211 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_media_start_stop_test.c @@ -0,0 +1,600 @@ +/* This test is designed to cover ux_slave_class_storage_media_start_stop callback handling. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static TX_THREAD tx_demo_thread_host_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_start_stop(VOID *storage, ULONG lun, ULONG power_condition, ULONG start, ULONG load_eject); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; + +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static volatile ULONG start_stop_call_count; +static volatile VOID *start_stop_last_storage; +static volatile ULONG start_stop_last_lun; +static volatile ULONG start_stop_last_power_condition; +static volatile ULONG start_stop_last_start; +static volatile ULONG start_stop_last_load_eject; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + +#define STRING_FRAMEWORK_LENGTH 38 +static UCHAR string_framework[] = { + + /* Manufacturer string descriptor : Index 1 */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 */ + 0x09, 0x04, 0x02, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 + }; + + +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + error_callback_counter ++; + + if (!error_callback_ignore) + { + /* Failed test. */ + printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +static UINT host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_media_start_stop_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_media_start_stop Test.............. "); + stepinfo("\n"); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2); + + /* Initialize USBX. Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disk memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Format the ram drive. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* Initialize the device portion of USBX. */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL); + if(status!=UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_start_stop = demo_thread_media_start_stop; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(UX_NULL); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the USB host controllers available in this system */ + status = ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_START_STOP(UCHAR byte4) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_START_STOP; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 4) = byte4; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + start_stop_call_count = 0; + start_stop_last_storage = UX_NULL; + start_stop_last_lun = 0; + start_stop_last_power_condition = 0; + start_stop_last_start = 0; + start_stop_last_load_eject = 0; + + /* START STOP UNIT: POWER CONDITION=0, LOEJ=1, START=0 (eject). */ + _test_init_cbw_START_STOP(0x02); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* START STOP UNIT: POWER CONDITION=0, LOEJ=1, START=1 (load). */ + _test_init_cbw_START_STOP(0x03); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + if (start_stop_call_count != 2 || + start_stop_last_storage == UX_NULL || + start_stop_last_lun != 0 || + start_stop_last_power_condition != 0 || + start_stop_last_start != 1 || + start_stop_last_load_eject != 1) + { + printf("ERROR #%d: media_start_stop args: cnt=%lu storage=%p lun=%lu pc=%lu start=%lu loej=%lu\n", + __LINE__, (ULONG)start_stop_call_count, (VOID *)start_stop_last_storage, + (ULONG)start_stop_last_lun, (ULONG)start_stop_last_power_condition, + (ULONG)start_stop_last_start, (ULONG)start_stop_last_load_eject); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)lun; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)lun; + (void)media_status; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory1[lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)lun; + (void)media_status; + + ux_utility_memory_copy(&ram_disk_memory1[lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_start_stop(VOID *storage, ULONG lun, ULONG power_condition, ULONG start, ULONG load_eject) +{ + + start_stop_call_count++; + start_stop_last_storage = storage; + start_stop_last_lun = lun; + start_stop_last_power_condition = power_condition; + start_stop_last_start = start; + start_stop_last_load_eject = load_eject; + + return(UX_SUCCESS); +} diff --git a/test/regression/usbxtestcontrol.c b/test/regression/usbxtestcontrol.c index 5ffc6871..0738f29e 100644 --- a/test/regression/usbxtestcontrol.c +++ b/test/regression/usbxtestcontrol.c @@ -285,6 +285,7 @@ void usbx_ux_device_class_storage_mode_select_test_application_define(void *) void usbx_ux_device_class_storage_mode_sense_test_application_define(void *); void usbx_ux_device_class_storage_request_sense_test_application_define(void *); void usbx_ux_device_class_storage_start_stop_test_application_define(void *); +void usbx_ux_device_class_storage_media_start_stop_test_application_define(void *); void usbx_ux_device_class_storage_prevent_allow_media_removal_test_application_define(void *); void usbx_ux_device_class_storage_verify_test_application_define(void *); void usbx_ux_device_class_storage_uninitialize_test_application_define(void *); @@ -521,6 +522,7 @@ TEST_ENTRY test_control_tests[] = usbx_ux_device_class_storage_mode_sense_test_application_define, usbx_ux_device_class_storage_request_sense_test_application_define, usbx_ux_device_class_storage_start_stop_test_application_define, + usbx_ux_device_class_storage_media_start_stop_test_application_define, usbx_ux_device_class_storage_prevent_allow_media_removal_test_application_define, usbx_ux_device_class_storage_verify_test_application_define, usbx_ux_device_class_storage_uninitialize_test_application_define,