1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
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 #endif
62
63 /**************************************************************************/
64 /* */
65 /* FUNCTION RELEASE */
66 /* */
67 /* _ux_device_class_storage_mode_sense PORTABLE C */
68 /* 6.1.11 */
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 /* */
119 /**************************************************************************/
_ux_device_class_storage_mode_sense(UX_SLAVE_CLASS_STORAGE * storage,ULONG lun,UX_SLAVE_ENDPOINT * endpoint_in,UX_SLAVE_ENDPOINT * endpoint_out,UCHAR * cbwcb)120 UINT _ux_device_class_storage_mode_sense(UX_SLAVE_CLASS_STORAGE *storage,
121 ULONG lun,
122 UX_SLAVE_ENDPOINT *endpoint_in,
123 UX_SLAVE_ENDPOINT *endpoint_out,
124 UCHAR *cbwcb)
125 {
126
127 UINT status;
128 UX_SLAVE_TRANSFER *transfer_request;
129 ULONG mode_sense_reply_length;
130 ULONG page_code;
131 ULONG mode_sense_command;
132 UCHAR read_only_flag;
133 ULONG response_header_length;
134 ULONG flags_index;
135 ULONG mode_data_length;
136 UCHAR *page_pointer;
137 ULONG page_length;
138
139
140 UX_PARAMETER_NOT_USED(endpoint_out);
141
142 /* If trace is enabled, insert this event into the trace buffer. */
143 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_MODE_SENSE, storage, lun, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
144
145 /* Obtain the pointer to the transfer request. */
146 transfer_request = &endpoint_in -> ux_slave_endpoint_transfer_request;
147
148 /* Get the command format : we have 1a and 5a. */
149 mode_sense_command = (ULONG) *(cbwcb + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_OPERATION);
150
151 /* Extract the notification from the cbwcb. */
152 page_code = (ULONG) *(cbwcb + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE);
153
154 /* Check the command. */
155 if (mode_sense_command == UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT)
156 {
157
158 /* Extract the length to be returned by the cbwcb. */
159 mode_sense_reply_length = (ULONG) *(cbwcb + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_ALLOCATION_LENGTH_6);
160 flags_index = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_FLAGS_6;
161 response_header_length = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_HEADER_LENGTH_6;
162 }
163
164 else
165 {
166
167 /* Extract the length to be returned by the cbwcb. */
168 mode_sense_reply_length = _ux_utility_short_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_ALLOCATION_LENGTH_10);
169 flags_index = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_FLAGS_10;
170 response_header_length = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_HEADER_LENGTH_10;
171 }
172
173 /* Ensure reply not exceed storage buffer. */
174 if (mode_sense_reply_length > UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE)
175 mode_sense_reply_length = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE;
176
177 /* Ensure memory buffer cleaned. */
178 _ux_utility_memory_set(transfer_request -> ux_slave_transfer_request_data_pointer, 0, mode_sense_reply_length); /* Use case of memset is verified. */
179
180 /* Establish READ ONLY flag. */
181 if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_read_only_flag == UX_TRUE)
182
183 /* This device is Read Only. */
184 read_only_flag = UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_FLAG_WP;
185
186 else
187
188 /* This device can be written to. */
189 read_only_flag = 0;
190
191 /* Build response based on expected page codes. */
192
193 /* Initialize length and page pointer. */
194 mode_data_length = response_header_length;
195 page_pointer = transfer_request -> ux_slave_transfer_request_data_pointer + response_header_length;
196
197 #ifdef UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC
198 /* CD Capabilities and Mechanical Status mode page. */
199 if(page_code == UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM ||
200 page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_ALL)
201 {
202 page_length = USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CDROM_LENGTH;
203
204 /* Copy page data. */
205 _ux_utility_memory_copy(page_pointer, usbx_device_class_storage_mode_sense_page_cdrom, page_length); /* Use case of memcpy is verified. */
206
207 /* Update pointer and length. */
208 mode_data_length += page_length;
209 page_pointer += page_length;
210 }
211 #endif
212
213 /* Caching mode page is returned if cache flush callback implemented. */
214 if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_flush != UX_NULL &&
215 (page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE ||
216 page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_ALL))
217 {
218 page_length = USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_CACHE_LENGTH;
219
220 /* Store page code. */
221 *(page_pointer) = UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE;
222
223 /* Store the length of the page data. */
224 *(page_pointer + UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_LENGTH) =
225 UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_PAGE_LENGTH;
226
227 /* Set the Write Cache Enabled (WCE) bit. */
228 *(page_pointer + UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_FLAGS) |=
229 UX_SLAVE_CLASS_STORAGE_CACHING_MODE_PAGE_FLAG_WCE;
230
231 mode_data_length += page_length;
232 page_pointer += page_length;
233 }
234
235 /* Informational Exceptions Control mode page. */
236 if (page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC ||
237 page_code == UX_SLAVE_CLASS_STORAGE_PAGE_CODE_ALL)
238 {
239 page_length = USBX_DEVICE_CLASS_STORAGE_MODE_SENSE_PAGE_IEC_LENGTH;
240
241 /* Store page code. */
242 *(page_pointer) = UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC;
243
244 /* Store the length of the page data. */
245 *(page_pointer + 1) = UX_SLAVE_CLASS_STORAGE_IEC_MODE_PAGE_PAGE_LENGTH;
246
247 mode_data_length += page_length;
248 }
249
250 /* Put the payload length in the header. */
251 if (mode_sense_command == UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT)
252 * transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR)(mode_data_length);
253 else
254 _ux_utility_short_put_big_endian(transfer_request -> ux_slave_transfer_request_data_pointer, (USHORT)mode_data_length);
255
256 /* Store the write protection flag. */
257 *(transfer_request -> ux_slave_transfer_request_data_pointer + flags_index) = read_only_flag;
258
259 #if defined(UX_DEVICE_STANDALONE)
260
261 /* Next: Transfer (DATA). */
262 storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
263 storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_READ;
264
265 storage -> ux_device_class_storage_transfer = transfer_request;
266 storage -> ux_device_class_storage_device_length = mode_data_length;
267 storage -> ux_device_class_storage_data_length = mode_data_length;
268 storage -> ux_device_class_storage_data_count = 0;
269
270 #else
271
272 /* Send a payload with the response buffer. */
273 _ux_device_stack_transfer_request(transfer_request, mode_sense_reply_length, mode_sense_reply_length);
274 #endif
275
276 /* Now we set the CSW with success. */
277 storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED;
278 status = UX_SUCCESS;
279
280 /* Return completion status. */
281 return(status);
282 }
283
284