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 /* Define the Slave Storage Class Inquiry data : DO NOT CHANGE THE LENGTH OF THESE ITEMS */
32
33 UCHAR _ux_system_slave_class_storage_vendor_id[] = "AzureRTO";
34 UCHAR _ux_system_slave_class_storage_product_id[] = "USBX storage dev";
35 UCHAR _ux_system_slave_class_storage_product_rev[] = "2000";
36 UCHAR _ux_system_slave_class_storage_product_serial[] = "12345678901234567890";
37
38 /**************************************************************************/
39 /* */
40 /* FUNCTION RELEASE */
41 /* */
42 /* _ux_device_class_storage_initialize PORTABLE C */
43 /* 6.3.0 */
44 /* AUTHOR */
45 /* */
46 /* Chaoqiong Xiao, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function initializes the USB storage device. */
51 /* */
52 /* INPUT */
53 /* */
54 /* command Pointer to storage command */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* Completion Status */
59 /* */
60 /* CALLS */
61 /* */
62 /* _ux_utility_memory_allocate Allocate memory */
63 /* _ux_utility_memory_free Free memory */
64 /* _ux_device_thread_create Create thread */
65 /* _ux_device_thread_delete Delete thread */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* Device Storage Class */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
76 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
77 /* used UX prefix to refer to */
78 /* TX symbols instead of using */
79 /* them directly, */
80 /* resulting in version 6.1 */
81 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
82 /* added standalone support, */
83 /* resulting in version 6.1.10 */
84 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
85 /* added a new mode to manage */
86 /* endpoint buffer in classes, */
87 /* resulting in version 6.3.0 */
88 /* */
89 /**************************************************************************/
_ux_device_class_storage_initialize(UX_SLAVE_CLASS_COMMAND * command)90 UINT _ux_device_class_storage_initialize(UX_SLAVE_CLASS_COMMAND *command)
91 {
92
93 UINT status = UX_SUCCESS;
94 UX_SLAVE_CLASS_STORAGE *storage;
95 UX_SLAVE_CLASS_STORAGE_PARAMETER *storage_parameter;
96 UX_SLAVE_CLASS *class_inst;
97 ULONG lun_index;
98
99
100 /* Get the pointer to the application parameters for the storage class. */
101 storage_parameter = command -> ux_slave_class_command_parameter;
102
103 /* Ensure the number of LUN declared by the caller does not exceed the
104 max number allowed for LUN storage. */
105 if (storage_parameter -> ux_slave_class_storage_parameter_number_lun > UX_MAX_SLAVE_LUN)
106 return UX_ERROR;
107
108 /* Get the class container. */
109 class_inst = command -> ux_slave_class_command_class_ptr;
110
111 /* Create an instance of the device storage class. */
112 storage = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_STORAGE));
113
114 /* Check for successful allocation. */
115 if (storage == UX_NULL)
116 return(UX_MEMORY_INSUFFICIENT);
117
118 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
119
120 /* Allocate bulk endpoint buffer. */
121 UX_ASSERT(!UX_DEVICE_CLASS_STORAGE_ENDPOINT_BUFFER_SIZE_CALC_OVERFLOW);
122 storage -> ux_device_class_storage_endpoint_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN,
123 UX_CACHE_SAFE_MEMORY, UX_DEVICE_CLASS_STORAGE_ENDPOINT_BUFFER_SIZE);
124 #else
125 status = UX_SUCCESS;
126 #endif
127
128 #if !defined(UX_DEVICE_STANDALONE)
129
130 /* Allocate some memory for the thread stack. */
131 if (status == UX_SUCCESS)
132 {
133 class_inst -> ux_slave_class_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
134
135 /* If it's OK, create thread. */
136 if (class_inst -> ux_slave_class_thread_stack != UX_NULL)
137
138 /* This instance needs to be running in a different thread. So start
139 a new thread. We pass a pointer to the class to the new thread. This thread
140 does not start until we have a instance of the class. */
141 status = _ux_device_thread_create(&class_inst -> ux_slave_class_thread, "ux_slave_storage_thread",
142 _ux_device_class_storage_thread,
143 (ULONG) (ALIGN_TYPE) class_inst, (VOID *) class_inst -> ux_slave_class_thread_stack,
144 UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
145 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
146 else
147 status = UX_MEMORY_INSUFFICIENT;
148 }
149 #else
150
151 /* Save tasks run entry. */
152 class_inst -> ux_slave_class_task_function = _ux_device_class_storage_tasks_run;
153 #endif
154
155 /* If thread resources allocated, go on. */
156 if (status == UX_SUCCESS)
157 {
158
159 UX_THREAD_EXTENSION_PTR_SET(&(class_inst -> ux_slave_class_thread), class_inst)
160
161 /* Store the number of LUN declared. */
162 storage -> ux_slave_class_storage_number_lun = storage_parameter -> ux_slave_class_storage_parameter_number_lun;
163
164 /* Copy each individual LUN parameters. */
165 for (lun_index = 0; lun_index < storage -> ux_slave_class_storage_number_lun; lun_index++)
166 {
167
168 /* Check block length size. */
169 if (storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_block_length > UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE)
170 {
171 /* Cannot proceed. */
172 status = (UX_MEMORY_INSUFFICIENT);
173 break;
174 }
175
176 /* Store all the application parameter information about the media. */
177 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_last_lba = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_last_lba;
178 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_block_length = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_block_length;
179 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_type = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_type;
180 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_removable_flag = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_removable_flag;
181 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_read_only_flag = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_read_only_flag;
182 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_read = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_read;
183 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_flush = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_flush;
184 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_write = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_write;
185 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_status = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_status;
186 storage -> ux_slave_class_storage_lun[lun_index].ux_slave_class_storage_media_notification = storage_parameter -> ux_slave_class_storage_parameter_lun[lun_index].ux_slave_class_storage_media_notification;
187 }
188
189 /* If it's OK, complete it. */
190 if (status == UX_SUCCESS)
191 {
192
193 /* Store the start and stop signals if needed by the application. */
194 storage -> ux_slave_class_storage_instance_activate = storage_parameter -> ux_slave_class_storage_instance_activate;
195 storage -> ux_slave_class_storage_instance_deactivate = storage_parameter -> ux_slave_class_storage_instance_deactivate;
196
197 /* Store the vendor id, product id, product revision and product serial. */
198 if (storage_parameter -> ux_slave_class_storage_parameter_vendor_id)
199 storage -> ux_slave_class_storage_vendor_id = storage_parameter -> ux_slave_class_storage_parameter_vendor_id;
200 else
201 storage -> ux_slave_class_storage_vendor_id = _ux_system_slave_class_storage_vendor_id;
202
203 if (storage_parameter -> ux_slave_class_storage_parameter_product_id)
204 storage -> ux_slave_class_storage_product_id = storage_parameter -> ux_slave_class_storage_parameter_product_id;
205 else
206 storage -> ux_slave_class_storage_product_id = _ux_system_slave_class_storage_product_id;
207
208 if (storage_parameter -> ux_slave_class_storage_parameter_product_rev)
209 storage -> ux_slave_class_storage_product_rev = storage_parameter -> ux_slave_class_storage_parameter_product_rev;
210 else
211 storage -> ux_slave_class_storage_product_rev = _ux_system_slave_class_storage_product_rev;
212
213 if (storage_parameter -> ux_slave_class_storage_parameter_product_serial)
214 storage -> ux_slave_class_storage_product_serial = storage_parameter -> ux_slave_class_storage_parameter_product_serial;
215 else
216 storage -> ux_slave_class_storage_product_serial = _ux_system_slave_class_storage_product_serial;
217
218 /* Save the address of the STORAGE instance inside the STORAGE container. */
219 class_inst -> ux_slave_class_instance = (VOID *) storage;
220
221 return(UX_SUCCESS);
222 }
223
224 /* Free thread resources. */
225 _ux_device_thread_delete(&class_inst -> ux_slave_class_thread);
226 }
227
228 #if !defined(UX_DEVICE_STANDALONE)
229 if (class_inst -> ux_slave_class_thread_stack != UX_NULL)
230 _ux_utility_memory_free(&class_inst -> ux_slave_class_thread_stack);
231 #endif
232
233 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
234 if (storage -> ux_device_class_storage_endpoint_buffer != UX_NULL)
235 _ux_utility_memory_free(storage -> ux_device_class_storage_endpoint_buffer);
236 #endif
237
238 /* Free instance. */
239 _ux_utility_memory_free(storage);
240
241 /* Return completion status. */
242 return(status);
243 }
244
245
246 /**************************************************************************/
247 /* */
248 /* FUNCTION RELEASE */
249 /* */
250 /* _uxe_device_class_storage_initialize PORTABLE C */
251 /* 6.3.0 */
252 /* AUTHOR */
253 /* */
254 /* Chaoqiong Xiao, Microsoft Corporation */
255 /* */
256 /* DESCRIPTION */
257 /* */
258 /* This function checks errors in storage initialization function call.*/
259 /* */
260 /* INPUT */
261 /* */
262 /* command Pointer to storage command */
263 /* */
264 /* OUTPUT */
265 /* */
266 /* Completion Status */
267 /* */
268 /* CALLS */
269 /* */
270 /* _ux_device_class_storage_initialize Initialize storage instance */
271 /* */
272 /* CALLED BY */
273 /* */
274 /* Application */
275 /* */
276 /* RELEASE HISTORY */
277 /* */
278 /* DATE NAME DESCRIPTION */
279 /* */
280 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
281 /* */
282 /**************************************************************************/
_uxe_device_class_storage_initialize(UX_SLAVE_CLASS_COMMAND * command)283 UINT _uxe_device_class_storage_initialize(UX_SLAVE_CLASS_COMMAND *command)
284 {
285
286 UX_SLAVE_CLASS_STORAGE_PARAMETER *storage_parameter;
287 UINT i;
288
289 /* Get the pointer to the application parameters for the storage class. */
290 storage_parameter = command -> ux_slave_class_command_parameter;
291
292 /* Sanity checks. */
293 if (storage_parameter -> ux_slave_class_storage_parameter_number_lun > UX_MAX_SLAVE_LUN)
294 return(UX_INVALID_PARAMETER);
295 for (i = 0; i < storage_parameter -> ux_slave_class_storage_parameter_number_lun; i ++)
296 {
297 if ((storage_parameter -> ux_slave_class_storage_parameter_lun[i].
298 ux_slave_class_storage_media_read == UX_NULL) ||
299 (storage_parameter -> ux_slave_class_storage_parameter_lun[i].
300 ux_slave_class_storage_media_write == UX_NULL) ||
301 (storage_parameter -> ux_slave_class_storage_parameter_lun[i].
302 ux_slave_class_storage_media_status == UX_NULL)
303 #if defined(UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC)
304 || (storage_parameter -> ux_slave_class_storage_parameter_lun[i].
305 ux_slave_class_storage_media_notification == UX_NULL)
306 #endif
307 )
308 {
309 return(UX_INVALID_PARAMETER);
310 }
311 }
312
313 /* Invoke storage initialize function. */
314 return(_ux_device_class_storage_initialize(command));
315 }
316