GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_device_classes/src/ux_device_class_storage_mode_sense.c Lines: 40 40 100.0 %
Date: 2026-03-06 18:57:10 Branches: 18 18 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** USBX Component                                                        */
17
/**                                                                       */
18
/**   Device Storage Class                                                */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define UX_SOURCE_CODE
24
25
26
/* Include necessary system files.  */
27
28
#include "ux_api.h"
29
#include "ux_device_class_storage.h"
30
#include "ux_device_stack.h"
31
32
#ifdef UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC
33
#define USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CDROM_LENGTH (0x42 + 2)
34
UCHAR usbx_device_class_storage_mode_sense_page_cdrom[USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CDROM_LENGTH] = {
35
36
    0x2A, 0x42, 0x3F, 0x37, 0xF1, 0x77, 0x29, 0x23,
37
    0x10, 0x89, 0x01, 0x00, 0x02, 0x00, 0x05, 0x84,
38
    0x00, 0x10, 0x10, 0x89, 0x00, 0x00, 0x00, 0x01,
39
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44
    0x00, 0x00, 0x00, 0x00
45
46
};
47
#else
48
#define USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CDROM_LENGTH (0)
49
#endif
50
#define USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CACHE_LENGTH (UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_PAGE_LENGTH + 2)
51
#define USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_IEC_LENGTH   (UX_SLAVE_CLASS_STORAGE_IEC_MODE_PAGE_PAGE_LENGTH + 2)
52
53
/* Ensure sense pages can fit in the bulk in endpoint's transfer buffer.  */
54
#define USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_ALL_RESPONSE_LENGTH (    \
55
    UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_HEADER_LENGTH_10 +         \
56
    USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CDROM_LENGTH +               \
57
    USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CACHE_LENGTH +               \
58
    USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_IEC_LENGTH)
59
#if USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_ALL_RESPONSE_LENGTH > UX_SLAVE_REQUEST_DATA_MAX_LENGTH
60
/* #error "The maximum-sized MODE_SENSE response cannot fit inside the bulk in endpoint's data buffer."  */
61
/* Build option checked runtime by UX_ASSERT  */
62
#endif
63
64
/**************************************************************************/
65
/*                                                                        */
66
/*  FUNCTION                                               RELEASE        */
67
/*                                                                        */
68
/*    _ux_device_class_storage_mode_sense                 PORTABLE C      */
69
/*                                                           6.3.0        */
70
/*  AUTHOR                                                                */
71
/*                                                                        */
72
/*    Chaoqiong Xiao, Microsoft Corporation                               */
73
/*                                                                        */
74
/*  DESCRIPTION                                                           */
75
/*                                                                        */
76
/*    This function performs a MODE_SENSE SCSI command. It supports       */
77
/*    the standard page for the CD-ROM.                                   */
78
/*                                                                        */
79
/*  INPUT                                                                 */
80
/*                                                                        */
81
/*    storage                               Pointer to storage class      */
82
/*    endpoint_in                           Pointer to IN endpoint        */
83
/*    endpoint_out                          Pointer to OUT endpoint       */
84
/*    cbwcb                                 Pointer to CBWCB              */
85
/*                                                                        */
86
/*  OUTPUT                                                                */
87
/*                                                                        */
88
/*    Completion Status                                                   */
89
/*                                                                        */
90
/*  CALLS                                                                 */
91
/*                                                                        */
92
/*    _ux_device_stack_transfer_request     Transfer request              */
93
/*    _ux_device_class_storage_csw_send     Send CSW                      */
94
/*    _ux_utility_short_get_big_endian      Get 16-bit big endian         */
95
/*    _ux_utility_short_put_big_endian      Put 16-bit big endian         */
96
/*    _ux_utility_memory_set                Set memory                    */
97
/*    _ux_utility_memory_copy               Copy memory                   */
98
/*                                                                        */
99
/*  CALLED BY                                                             */
100
/*                                                                        */
101
/*    Device Storage Class                                                */
102
/*                                                                        */
103
/**************************************************************************/
104
11
UINT  _ux_device_class_storage_mode_sense(UX_SLAVE_CLASS_STORAGE *storage,
105
                      ULONG               lun,
106
                      UX_SLAVE_ENDPOINT   *endpoint_in,
107
                      UX_SLAVE_ENDPOINT   *endpoint_out,
108
                      UCHAR               *cbwcb)
109
{
110
111
UINT                    status;
112
UX_SLAVE_TRANSFER       *transfer_request;
113
ULONG                   mode_sense_reply_length;
114
ULONG                   page_code;
115
ULONG                   mode_sense_command;
116
UCHAR                   read_only_flag;
117
ULONG                   response_header_length;
118
ULONG                   flags_index;
119
ULONG                   mode_data_length;
120
UCHAR                   *page_pointer;
121
ULONG                   page_length;
122
123
124
    UX_PARAMETER_NOT_USED(endpoint_out);
125
126
    /* Build option check.  */
127
    UX_ASSERT(USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_ALL_RESPONSE_LENGTH <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
128
129
    /* If trace is enabled, insert this event into the trace buffer.  */
130
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_MODE_SENSE, storage, lun, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
131
132
    /* Obtain the pointer to the transfer request.  */
133
11
    transfer_request =  &endpoint_in -> ux_slave_endpoint_transfer_request;
134
135
    /* Get the command format : we have 1a and 5a.  */
136
11
    mode_sense_command =  (ULONG) *(cbwcb + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_OPERATION);
137
138
    /* Extract the notification from the cbwcb.  */
139
11
    page_code =  (ULONG) *(cbwcb + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE);
140
141
    /* Check the command.  */
142
11
    if (mode_sense_command == UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT)
143
    {
144
145
        /* Extract the length to be returned by the cbwcb.  */
146
6
        mode_sense_reply_length =  (ULONG) *(cbwcb + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_ALLOCATION_LENGTH_6);
147
6
        flags_index = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_FLAGS_6;
148
6
        response_header_length = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_HEADER_LENGTH_6;
149
    }
150
151
    else
152
    {
153
154
        /* Extract the length to be returned by the cbwcb.  */
155
5
        mode_sense_reply_length =  _ux_utility_short_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_ALLOCATION_LENGTH_10);
156
5
        flags_index = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_FLAGS_10;
157
5
        response_header_length = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_HEADER_LENGTH_10;
158
    }
159
160
    /* Ensure reply not exceed storage buffer.  */
161
11
    if (mode_sense_reply_length > UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE)
162
1
        mode_sense_reply_length = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE;
163
164
    /* Ensure memory buffer cleaned.  */
165
11
    _ux_utility_memory_set(transfer_request -> ux_slave_transfer_request_data_pointer, 0, mode_sense_reply_length); /* Use case of memset is verified. */
166
167
    /* Establish READ ONLY flag.  */
168
11
    if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_read_only_flag == UX_TRUE)
169
170
        /* This device is Read Only.  */
171
7
        read_only_flag = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_FLAG_WP;
172
173
    else
174
175
        /* This device can be written to.  */
176
4
        read_only_flag = 0;
177
178
    /* Build response based on expected page codes.  */
179
180
    /* Initialize length and page pointer.  */
181
11
    mode_data_length = response_header_length;
182
11
    page_pointer = transfer_request -> ux_slave_transfer_request_data_pointer + response_header_length;
183
184
#ifdef UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC
185
    /* CD Capabilities and Mechanical Status mode page.  */
186
    if(page_code == UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM ||
187
        page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_ALL)
188
    {
189
        page_length = USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CDROM_LENGTH;
190
191
        /* Copy page data.  */
192
        _ux_utility_memory_copy(page_pointer, usbx_device_class_storage_mode_sense_page_cdrom, page_length); /* Use case of memcpy is verified. */
193
194
        /* Update pointer and length.  */
195
        mode_data_length += page_length;
196
        page_pointer += page_length;
197
    }
198
#endif
199
200
    /* Caching mode page is returned if cache flush callback implemented.  */
201

11
    if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_flush != UX_NULL &&
202
6
        (page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE ||
203
        page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_ALL))
204
    {
205
4
        page_length = USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CACHE_LENGTH;
206
207
        /* Store page code.  */
208
4
        *(page_pointer) = UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE;
209
210
        /* Store the length of the page data.  */
211
4
        *(page_pointer + UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_LENGTH) =
212
                            UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_PAGE_LENGTH;
213
214
        /* Set the Write Cache Enabled (WCE) bit.  */
215
4
        *(page_pointer + UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_FLAGS) |=
216
                            UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_FLAG_WCE;
217
218
4
        mode_data_length += page_length;
219
4
        page_pointer += page_length;
220
    }
221
222
    /* Informational Exceptions Control mode page.  */
223

11
    if (page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC ||
224
        page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_ALL)
225
    {
226
6
        page_length = USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_IEC_LENGTH;
227
228
        /* Store page code.  */
229
6
        *(page_pointer) = UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC;
230
231
        /* Store the length of the page data.  */
232
6
        *(page_pointer + 1) = UX_SLAVE_CLASS_STORAGE_IEC_MODE_PAGE_PAGE_LENGTH;
233
234
6
        mode_data_length += page_length;
235
    }
236
237
    /* Put the payload length in the header.  */
238
11
    if (mode_sense_command == UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT)
239
6
        * transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR)(mode_data_length);
240
    else
241
5
        _ux_utility_short_put_big_endian(transfer_request -> ux_slave_transfer_request_data_pointer, (USHORT)mode_data_length);
242
243
    /* Store the write protection flag.  */
244
11
    *(transfer_request -> ux_slave_transfer_request_data_pointer + flags_index) = read_only_flag;
245
246
#if defined(UX_DEVICE_STANDALONE)
247
248
    /* Next: Transfer (DATA).  */
249
    storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
250
    storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_READ;
251
252
    storage -> ux_device_class_storage_transfer = transfer_request;
253
    storage -> ux_device_class_storage_device_length = mode_data_length;
254
    storage -> ux_device_class_storage_data_length = mode_data_length;
255
    storage -> ux_device_class_storage_data_count = 0;
256
257
#else
258
259
    /* Send a payload with the response buffer.  */
260
11
    _ux_device_stack_transfer_request(transfer_request, mode_sense_reply_length, mode_sense_reply_length);
261
#endif
262
263
    /* Now we set the CSW with success.  */
264
11
    storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED;
265
11
    status = UX_SUCCESS;
266
267
    /* Return completion status.  */
268
11
    return(status);
269
}
270