/*************************************************************************** * Copyright (c) 2024 Microsoft Corporation * Copyright (c) 2026-present Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * SPDX-License-Identifier: MIT **************************************************************************/ /**************************************************************************/ /**************************************************************************/ /** */ /** USBX Component */ /** */ /** Device Storage Class */ /** */ /**************************************************************************/ /**************************************************************************/ #define UX_SOURCE_CODE /* Include necessary system files. */ #include "ux_api.h" #include "ux_device_class_storage.h" #include "ux_device_stack.h" #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_PROFILE_LENGTH 228 #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_HEADER_LENGTH 8 #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_DESCRIPTOR_LENGTH 32 #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_HEADER_LENGTH 4 #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_LENGTH (USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_PROFILE_LENGTH - USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_DESCRIPTOR_LENGTH - USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_HEADER_LENGTH) UCHAR usbx_device_class_storage_configuration_profile[] = { /* Feature Header */ 0x00, 0x00, /* Entire length of profile filled by firmware */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Current profile */ /* Feature Descriptor */ 0x00, 0x00, /* Feature Code : profile list */ 0x00, /* Persistent/current */ 0x1c, /* Additional Length */ 0x00, 0x12, 0x00, 0x00, /* DVD-RAM */ 0x00, 0x11, 0x00, 0x00, /* DVD-R */ 0x00, 0x10, 0x00, 0x00, /* DVD-ROM */ 0x00, 0x0A, 0x00, 0x00, /* CD-RW */ 0x00, 0x09, 0x00, 0x00, /* CD-R */ 0x00, 0x08, 0x00, 0x00, /* CD-ROM */ 0x00, 0x02, 0x00, 0x00, /* Writable capable with removable media. */ /* Feature Descriptor */ 0x00, 0x01, /* Feature Code : core feature */ 0x0b, /* Persistent/current */ 0x08, /* Additional Length */ 0x00, 0x00, 0x00, 0x07, /* Physical Interface Standard */ 0x01, 0x00, 0x00, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x02, /* Feature Code : morphing (Ability to notify initiator about operational changes and accept initiator requests to prevent operational changes) */ 0x07, /* Persistent/current */ 0x04, /* Additional Length */ 0x02, 0x00, 0x00, 0x00, /* Physical Interface Standard */ /* Feature Descriptor */ 0x00, 0x03, /* Feature Code : Removable Medium (The medium may be removed from the device ) */ 0x0b, /* Persistent/current */ 0x04, /* Additional Length */ 0x2b, 0x00, 0x00, 0x00, /* Physical Interface Standard */ /* Feature Descriptor */ 0x00, 0x10, /* Feature Code : Random Readable (Read ability for storage devices with random addressing) */ 0x00, /* Persistent/current */ 0x08, /* Additional Length */ 0x00, 0x00, 0x08, 0x00, /* */ 0x00, 0x01, 0x01, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x1d, /* Feature Code : MultiRead (The logical unit can read all CD media types) */ 0x00, /* Persistent/current */ 0x00, /* Additional Length */ /* Feature Descriptor */ 0x00, 0x1e, /* Feature Code : CD Read (The ability to read CD specific structures) */ 0x08, /* Persistent/current */ 0x04, /* Additional Length */ 0x03, 0x00, 0x00, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x1f, /* Feature Code : DVD Read (The ability to read DVD specific structures) */ 0x08, /* Persistent/current */ 0x04, /* Additional Length */ 0x01, 0x00, 0x01, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x20, /* Feature Code : Random Writable (Write support for randomly addressed writes) */ 0x04, /* Persistent/current */ 0x0c, /* Additional Length */ 0x00, 0x00, 0x00, 0x00, /* */ 0x00, 0x00, 0x08, 0x00, /* */ 0x00, 0x00, 0x01, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x21, /* Feature Code : Incremental Streaming Writable (Write support for sequential recording) */ 0x0C, /* Persistent/current */ 0x08, /* Additional Length */ 0x00, 0x00, 0x00, 0x00, /* */ 0x00, 0x00, 0x00, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x23, /* Feature Code : Formattable (Support for formatting of media.) */ 0x08, /* Persistent/current */ 0x08, /* Additional Length */ 0x00, 0x00, 0x00, 0x00, /* */ 0x00, 0x00, 0x00, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x24, /* Feature Code : Defect Management (Ability of the drive/media system to provide an apparently defect-free space.) */ 0x04, /* Persistent/current */ 0x04, /* Additional Length */ 0x80, 0x00, 0x00, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x26, /* Feature Code : Restricted Overwrite (Write support for media that must be written in multiples of logical blocks.) */ 0x00, /* Persistent/current */ 0x00, /* Additional Length */ /* Feature Descriptor */ 0x00, 0x2d, /* Feature Code : CD Track at Once (Ability to write CD with Track at Once recording) */ 0x08, /* Persistent/current */ 0x04, /* Additional Length */ 0x46, 0x00, 0x3f, 0x0f, /* */ /* Feature Descriptor */ 0x00, 0x2e, /* Feature Code : CD Mastering (The ability to write CD with Session at Once or Raw write methods.) */ 0x04, /* Persistent/current */ 0x04, /* Additional Length */ 0x7f, 0x00, 0x0d, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x2f, /* Feature Code : DVD-R Write (The ability to write DVD specific structures) */ 0x08, /* Persistent/current */ 0x04, /* Additional Length */ 0x4e, 0x00, 0x00, 0x00, /* */ 0x01, 0x00, /* Feature Code : Power Management (Initiator and device directed power management) */ 0x07, /* Persistent/current */ 0x04, /* Additional Length */ 0x00, 0x00, 0x00, 0x00, /* */ 0x01, 0x01, /* Feature Code : S.M.A.R.T. (Self Monitoring Analysis and Reporting Technology (Failure prediction)) */ 0x00, /* Persistent/current */ 0x04, /* Additional Length */ 0x00, 0x00, 0x00, 0x00, /* */ 0x01, 0x08, /* Feature Code : Logical Unit serial number (Logical unit has a unique identifier) */ 0x03, /* Persistent/current */ 0x10, /* Additional Length */ 0x53, 0x31, 0x33, 0x36, /* Serial Number */ 0x36, 0x59, 0x42, 0x46, 0x37, 0x30, 0x30, 0x39, 0x45, 0x48, 0x20, 0x20, 0x01, 0x0a, /* Feature Code : Not sure : says FDC STC TOC */ 0x00, /* Persistent/current */ 0x0c, /* Additional Length */ 0x46, 0x44, 0x43, 0x00, 0x53, 0x54, 0x43, 0x00, 0x54, 0x4F, 0x43, 0x00, }; #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_PROFILE_LENGTH 112 #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_HEADER_LENGTH 8 #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_FEATURE_DESCRIPTOR_LENGTH 32 #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_FEATURE_HEADER_LENGTH 4 #define USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_FEATURE_LENGTH (USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_PROFILE_LENGTH - USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_FEATURE_DESCRIPTOR_LENGTH - USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_HEADER_LENGTH) UCHAR usbx_device_class_storage_configuration_active_profile[] = { /* Feature Header */ 0x00, 0x00, /* Entire length of profile filled by firmware */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, /* Current profile is CD-ROM*/ /* Feature Descriptor */ 0x00, 0x00, /* Feature Code : profile list */ 0x00, /* Persistent/current */ 0x1c, /* Additional Length */ 0x00, 0x12, 0x00, 0x00, /* DVD-RAM */ 0x00, 0x11, 0x00, 0x00, /* DVD-R */ 0x00, 0x10, 0x00, 0x00, /* DVD-ROM */ 0x00, 0x0A, 0x00, 0x00, /* CD-RW */ 0x00, 0x09, 0x00, 0x00, /* CD-R */ 0x00, 0x08, 0x01, 0x00, /* CD-ROM : active profile */ 0x00, 0x02, 0x00, 0x00, /* Writable capable with removable media. */ /* Feature Descriptor */ 0x00, 0x01, /* Feature Code : core feature */ 0x0b, /* Persistent/current */ 0x08, /* Additional Length */ 0x00, 0x00, 0x00, 0x07, /* Physical Interface Standard */ 0x01, 0x00, 0x00, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x02, /* Feature Code : morphing (Ability to notify initiator about operational changes and accept initiator requests to prevent operational changes) */ 0x07, /* Persistent/current */ 0x04, /* Additional Length */ 0x02, 0x00, 0x00, 0x00, /* Physical Interface Standard */ /* Feature Descriptor */ 0x00, 0x03, /* Feature Code : Removable Medium (The medium may be removed from the device ) */ 0x0b, /* Persistent/current */ 0x04, /* Additional Length */ 0x2b, 0x00, 0x00, 0x00, /* Physical Interface Standard */ /* Feature Descriptor */ 0x00, 0x10, /* Feature Code : Random Readable (Read ability for storage devices with random addressing) */ 0x01, /* Persistent/current */ 0x08, /* Additional Length */ 0x00, 0x00, 0x08, 0x00, /* */ 0x00, 0x01, 0x01, 0x00, /* */ /* Feature Descriptor */ 0x00, 0x1d, /* Feature Code : MultiRead (The logical unit can read all CD media types) */ 0x01, /* Persistent/current */ 0x00, /* Additional Length */ /* Feature Descriptor */ 0x00, 0x1e, /* Feature Code : CD Read (The ability to read CD specific structures) */ 0x09, /* Persistent/current */ 0x04, /* Additional Length */ 0x03, 0x00, 0x00, 0x00, /* */ 0x01, 0x08, /* Feature Code : Logical Unit serial number (Logical unit has a unique identifier) */ 0x03, /* Persistent/current */ 0x10, /* Additional Length */ 0x53, 0x31, 0x33, 0x36, /* Serial Number */ 0x36, 0x59, 0x42, 0x46, 0x37, 0x30, 0x30, 0x39, 0x45, 0x48, 0x20, 0x20, }; #if (UX_SLAVE_REQUEST_DATA_MAX_LENGTH < USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_PROFILE_LENGTH) ||\ (UX_SLAVE_REQUEST_DATA_MAX_LENGTH < USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_PROFILE_LENGTH) /* #error UX_SLAVE_REQUEST_DATA_MAX_LENGTH too small, please check */ /* Build option checked runtime by UX_ASSERT */ #endif /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_storage_get_configuration PORTABLE C */ /* 6.3.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function performs a GET_CONFIGURATION command. */ /* */ /* INPUT */ /* */ /* storage Pointer to storage class */ /* 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 */ /* _ux_device_stack_endpoint_stall Stall endpoint */ /* _ux_utility_short_get_big_endian Get 16-bit big endian */ /* _ux_utility_long_put_big_endian Put 32-bit big endian */ /* _ux_utility_memory_copy Copy memory */ /* */ /* CALLED BY */ /* */ /* Device Storage Class */ /* */ /**************************************************************************/ 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 status = 0; UX_SLAVE_TRANSFER *transfer_request; ULONG starting_feature; ULONG allocation_length; ULONG additional_length; ULONG profile_counter; UCHAR *profile_pointer; ULONG feature; UX_PARAMETER_NOT_USED(endpoint_out); /* Build option check. */ UX_ASSERT((UX_SLAVE_REQUEST_DATA_MAX_LENGTH >= USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_PROFILE_LENGTH) && (UX_SLAVE_REQUEST_DATA_MAX_LENGTH >= USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_PROFILE_LENGTH)); /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_GET_CONFIGURATION, storage, lun, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) /* Initialize the length of the configuration profile. */ _ux_utility_long_put_big_endian(usbx_device_class_storage_configuration_profile, (USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_PROFILE_LENGTH - 4)); /* Initialize the length of the active configuration profile. */ _ux_utility_long_put_big_endian(usbx_device_class_storage_configuration_active_profile, (USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_PROFILE_LENGTH - 4)); /* Obtain the pointer to the transfer request. */ transfer_request = &endpoint_in -> ux_slave_endpoint_transfer_request; /* Get the Starting Feature. */ starting_feature = _ux_utility_short_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_GET_CONFIGURATION_STARTING_FEATURE); /* Get the allocation length. */ allocation_length = _ux_utility_short_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_GET_CONFIGURATION_ALLOCATION_LENGTH); /* Default CSW to success. */ storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED; /* Is the request demanding all the features ? */ if (starting_feature == 0) { /* Is the requester demanding the active profile ? */ if ((*(cbwcb + UX_SLAVE_CLASS_STORAGE_GET_CONFIGURATION_RT) & 3) == 1) { /* We get the active profile. */ /* Can we send all the activeconfiguration profile ? If not, the host may demand the first part of the configuration to get the entire length. In this case, return the length demanded by the host. */ if (allocation_length >= USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_PROFILE_LENGTH) /* Adjust allocation length to maximum allowed. */ allocation_length = USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_ACTIVE_PROFILE_LENGTH; /* Copy the CSW into the transfer request memory. */ _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, usbx_device_class_storage_configuration_active_profile, allocation_length); /* Use case of memcpy is verified. */ } else { /* We get the whole profile. */ /* Can we send all the configuration profile ? If not, the host may demand the first part of the configuration to get the entire length. In this case, return the length demanded by the host. */ if (allocation_length >= USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_PROFILE_LENGTH) /* Adjust allocation length to maximum allowed. */ allocation_length = USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_PROFILE_LENGTH; /* Copy the CSW into the transfer request memory. */ _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, usbx_device_class_storage_configuration_profile, allocation_length); /* Use case of memcpy is verified. */ } /* Now success. */ status = UX_SUCCESS; } else { /* The caller has demanded a specific feature. Scan our configuration profile. Jump over the beginning sections. */ profile_pointer = usbx_device_class_storage_configuration_profile + USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_HEADER_LENGTH + USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_DESCRIPTOR_LENGTH; profile_counter = USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_LENGTH; /* Scan our configuration profile. */ while (profile_counter != 0) { /* Extract the feature from the configuration profile. */ feature = _ux_utility_short_get_big_endian(profile_pointer + USBX_DEVICE_CLASS_STORAGE_FEATURE_DESCRIPTOR_FEATURE_CODE); /* Extract the feature length from the configuration profile. */ additional_length = (ULONG ) *(profile_pointer + USBX_DEVICE_CLASS_STORAGE_FEATURE_DESCRIPTOR_FEATURE_ADD_LENGTH); /* Compare the Feature extracted with the one demanded. */ if (feature == starting_feature) { /* We found the feature, we check if the requester has enough space for us to return it. */ if (allocation_length >= (additional_length + USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_HEADER_LENGTH + USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_HEADER_LENGTH)) /* Need to adjust the allocation length. */ allocation_length = additional_length + USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_HEADER_LENGTH + USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_HEADER_LENGTH; /* Copy the CSW into the transfer request memory. */ _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, profile_pointer, allocation_length); /* Use case of memcpy is verified. */ /* Now success. */ status = UX_SUCCESS; /* Get out of the loop. */ break; } else { /* We have not yet found the feature, keep parsing. */ if (profile_counter - additional_length - USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_HEADER_LENGTH <= 0) { /* We are either at the end of the profile or the profile is corrupted. */ /* 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(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ILLEGAL_REQUEST,0x26,0x02); /* Now we set the CSW with failure. */ storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED; /* Set status to error. */ status = UX_ERROR; /* Get out of the loop. */ break; } else { /* Update the profile pointer. */ profile_pointer += additional_length + USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_HEADER_LENGTH; /* Update the length remaining to parse in profile. */ profile_counter -= additional_length + USBX_DEVICE_CLASS_STORAGE_CONFIGURATION_FEATURE_HEADER_LENGTH; } } } } /* Success, send data. */ if (status == UX_SUCCESS) { #if defined(UX_DEVICE_STANDALONE) /* Next: Transfer (DATA). */ storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START; storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_READ; storage -> ux_device_class_storage_transfer = transfer_request; storage -> ux_device_class_storage_device_length = allocation_length; storage -> ux_device_class_storage_data_length = allocation_length; storage -> ux_device_class_storage_data_count = 0; UX_SLAVE_TRANSFER_STATE_RESET(storage -> ux_device_class_storage_transfer); #else /* Send a data payload with the read_capacity response buffer. */ _ux_device_stack_transfer_request(transfer_request, allocation_length, allocation_length); #endif } else { /* Error, stall. */ #if !defined(UX_DEVICE_STANDALONE) _ux_device_stack_endpoint_stall(endpoint_in); #endif } /* Return completion status. */ return(status); }