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