summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usbx_device_classes/inc/ux_device_class_storage.h55
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_activate.c88
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_initialize.c1
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_prevent_allow_media_removal.c87
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_read.c138
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_read_capacity.c109
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_read_format_capacity.c90
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_start_stop.c125
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_test_ready.c94
-rw-r--r--common/usbx_device_classes/src/ux_device_class_storage_write.c129
-rw-r--r--test/cmake/usbx/regression/CMakeLists.txt1
-rw-r--r--test/regression/usbx_ux_device_class_storage_media_start_stop_test.c600
-rw-r--r--test/regression/usbxtestcontrol.c2
13 files changed, 1142 insertions, 377 deletions
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 8151695..32f8e56 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
**************************************************************************/
@@ -67,15 +67,15 @@
#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
@@ -112,7 +112,10 @@ extern "C" {
#define UX_SLAVE_CLASS_STORAGE_MEDIA_OPTICAL_DISK 7
#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. */
@@ -321,6 +324,10 @@ extern "C" {
#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. */
@@ -361,6 +368,23 @@ extern "C" {
#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_ALLOCATION_LENGTH 7
#define UX_SLAVE_CLASS_STORAGE_READ_DISK_INFORMATION_LENGTH 10
+/* 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. */
#define USBX_DEVICE_CLASS_STORAGE_FEATURE_DESCRIPTOR_FEATURE_CODE 0
@@ -504,12 +528,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). */
@@ -674,10 +703,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 b868c49..5894af1 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 */
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_device_class_storage_activate PORTABLE C */
/* 6.3.0 */
/* 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 */
@@ -81,11 +81,12 @@
/**************************************************************************/
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 +100,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 +131,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 +163,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 c6f393e..3f7b7ab 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
@@ -184,6 +184,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 3a831ee..f844495 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,79 @@
#include "ux_device_stack.h"
-/**************************************************************************/
-/* */
-/* FUNCTION RELEASE */
-/* */
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
/* _ux_device_class_storage_prevent_allow_media_removal */
-/* PORTABLE C */
+/* PORTABLE C */
/* 6.1 */
/* 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 */
/* */
/**************************************************************************/
-UINT _ux_device_class_storage_prevent_allow_media_removal(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun,
+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 91e48d4..e4c4607 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 */
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_device_class_storage_read PORTABLE C */
/* 6.1.10 */
/* 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, */
@@ -85,7 +85,7 @@
/* resulting in version 6.1.10 */
/* */
/**************************************************************************/
-UINT _ux_device_class_storage_read(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun,
+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)
{
@@ -93,12 +93,12 @@ UINT _ux_device_class_storage_read(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun,
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 +106,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 +130,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 +147,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 +210,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 +236,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 +246,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 +281,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 +296,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 c3825e7..8b59ff1 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 */
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_device_class_storage_read_capacity PORTABLE C */
/* 6.3.0 */
/* 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, */
@@ -110,8 +109,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 +149,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 +184,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 +193,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 e84e424..f3abb91 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 */
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_device_class_storage_read_format_capacity PORTABLE C */
/* 6.3.0 */
/* 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, */
@@ -108,6 +107,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 +142,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,7 +161,7 @@ UCHAR *read_format_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_FORMAT_CAPACITY_RESPONSE_LENGTH,
UX_SLAVE_CLASS_STORAGE_READ_FORMAT_CAPACITY_RESPONSE_LENGTH);
#endif
@@ -160,4 +173,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 f3b7a98..f93b481 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,116 @@
#include "ux_device_stack.h"
-/**************************************************************************/
-/* */
-/* FUNCTION RELEASE */
-/* */
-/* _ux_device_class_storage_start_stop PORTABLE C */
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_device_class_storage_start_stop PORTABLE C */
/* 6.1 */
/* 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 */
/* */
/**************************************************************************/
-UINT _ux_device_class_storage_start_stop(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun,
+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 3a74fc0..1b11096 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 */
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_device_class_storage_test_ready PORTABLE C */
/* 6.1.10 */
/* 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, */
@@ -89,7 +89,6 @@ UINT _ux_device_class_storage_test_ready(UX_SLAVE_CLASS_STORAGE *storage, ULONG
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 +96,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 +135,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 5f86512..08946c6 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 */
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_device_class_storage_write PORTABLE C */
/* 6.1.10 */
/* 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, */
@@ -87,7 +84,7 @@
/* resulting in version 6.1.10 */
/* */
/**************************************************************************/
-UINT _ux_device_class_storage_write(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun,
+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)
{
@@ -95,12 +92,12 @@ UINT _ux_device_class_storage_write(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun,
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 +105,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 +129,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 +141,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 +238,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 +256,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 8d29d43..2992765 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 0000000..4dc9621
--- /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 <stdio.h>
+#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 5ffc687..0738f29 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,