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: 2024-12-12 17:16:36 Branches: 18 18 100.0 %

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

11
    if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_flush != UX_NULL &&
222
6
        (page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE ||
223
        page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_ALL))
224
    {
225
4
        page_length = USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CACHE_LENGTH;
226
227
        /* Store page code.  */
228
4
        *(page_pointer) = UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE;
229
230
        /* Store the length of the page data.  */
231
4
        *(page_pointer + UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_LENGTH) =
232
                            UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_PAGE_LENGTH;
233
234
        /* Set the Write Cache Enabled (WCE) bit.  */
235
4
        *(page_pointer + UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_FLAGS) |=
236
                            UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_FLAG_WCE;
237
238
4
        mode_data_length += page_length;
239
4
        page_pointer += page_length;
240
    }
241
242
    /* Informational Exceptions Control mode page.  */
243

11
    if (page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC ||
244
        page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_ALL)
245
    {
246
6
        page_length = USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_IEC_LENGTH;
247
248
        /* Store page code.  */
249
6
        *(page_pointer) = UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC;
250
251
        /* Store the length of the page data.  */
252
6
        *(page_pointer + 1) = UX_SLAVE_CLASS_STORAGE_IEC_MODE_PAGE_PAGE_LENGTH;
253
254
6
        mode_data_length += page_length;
255
    }
256
257
    /* Put the payload length in the header.  */
258
11
    if (mode_sense_command == UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT)
259
6
        * transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR)(mode_data_length);
260
    else
261
5
        _ux_utility_short_put_big_endian(transfer_request -> ux_slave_transfer_request_data_pointer, (USHORT)mode_data_length);
262
263
    /* Store the write protection flag.  */
264
11
    *(transfer_request -> ux_slave_transfer_request_data_pointer + flags_index) = read_only_flag;
265
266
#if defined(UX_DEVICE_STANDALONE)
267
268
    /* Next: Transfer (DATA).  */
269
    storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
270
    storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_READ;
271
272
    storage -> ux_device_class_storage_transfer = transfer_request;
273
    storage -> ux_device_class_storage_device_length = mode_data_length;
274
    storage -> ux_device_class_storage_data_length = mode_data_length;
275
    storage -> ux_device_class_storage_data_count = 0;
276
277
#else
278
279
    /* Send a payload with the response buffer.  */
280
11
    _ux_device_stack_transfer_request(transfer_request, mode_sense_reply_length, mode_sense_reply_length);
281
#endif
282
283
    /* Now we set the CSW with success.  */
284
11
    storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED;
285
11
    status = UX_SUCCESS;
286
287
    /* Return completion status.  */
288
11
    return(status);
289
}
290