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 /** Storage Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_storage.h"
29 #include "ux_host_stack.h"
30
UX_OVERFLOW_CHECK_MULC_ULONG(sizeof (UX_HOST_CLASS_STORAGE_MEDIA),UX_HOST_CLASS_STORAGE_MAX_MEDIA)31 UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_MULC_ULONG(sizeof(UX_HOST_CLASS_STORAGE_MEDIA), UX_HOST_CLASS_STORAGE_MAX_MEDIA), UX_HOST_CLASS_STORAGE_MAX_MEDIA_mul_ovf)
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_storage_entry PORTABLE C */
38 /* 6.1.10 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function is the entry point of the storage class. It will be */
46 /* called by the USBX stack enumeration module when there is a new */
47 /* USB disk on the bus or when the USB disk is removed. */
48 /* */
49 /* Version 2.0 of the storage class only supports USB FAT media and */
50 /* not CD-ROM. */
51 /* */
52 /* INPUT */
53 /* */
54 /* command Pointer to class command */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* Completion Status */
59 /* */
60 /* CALLS */
61 /* */
62 /* _ux_host_class_storage_activate Activate storage class */
63 /* _ux_host_class_storage_deactivate Deactivate storage class */
64 /* _ux_utility_memory_allocate Allocate memory block */
65 /* _ux_utility_memory_free Free memory block */
66 /* _ux_utility_thread_create Create storage class thread */
67 /* _ux_utility_thread_delete Delete storage class thread */
68 /* */
69 /* CALLED BY */
70 /* */
71 /* Host Stack */
72 /* */
73 /* RELEASE HISTORY */
74 /* */
75 /* DATE NAME DESCRIPTION */
76 /* */
77 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
78 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
79 /* added destroy command, */
80 /* used host class extension */
81 /* pointer for class specific */
82 /* structured data, */
83 /* used UX prefix to refer to */
84 /* TX symbols instead of using */
85 /* them directly, */
86 /* resulting in version 6.1 */
87 /* 11-09-2020 Chaoqiong Xiao Modified comment(s), */
88 /* fixed class ext access, */
89 /* resulting in version 6.1.2 */
90 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
91 /* added standalone support, */
92 /* resulting in version 6.1.10 */
93 /* */
94 /**************************************************************************/
95 UINT _ux_host_class_storage_entry(UX_HOST_CLASS_COMMAND *command)
96 {
97
98 UINT status;
99 UX_HOST_CLASS *class_inst;
100 #if !defined(UX_HOST_STANDALONE)
101 UX_HOST_CLASS_STORAGE_EXT *class_ext;
102 #endif
103
104
105 /* The command request will tell us we need to do here, either a enumeration
106 query, an activation or a deactivation. */
107 switch (command -> ux_host_class_command_request)
108 {
109
110 case UX_HOST_CLASS_COMMAND_QUERY:
111
112 /* The query command is used to let the stack enumeration process know if we want to own
113 this device or not. */
114 if ((command -> ux_host_class_command_usage == UX_HOST_CLASS_COMMAND_USAGE_CSP) &&
115 (command -> ux_host_class_command_class == UX_HOST_CLASS_STORAGE_CLASS))
116 return(UX_SUCCESS);
117 else
118 return(UX_NO_CLASS_MATCH);
119
120 case UX_HOST_CLASS_COMMAND_ACTIVATE:
121
122 /* We are assuming the device will mount. If this is the first activation of
123 the storage class, we have to fire up one thread for the media insertion
124 and acquire some memory for the media array. */
125
126 /* Get class. */
127 class_inst = command -> ux_host_class_command_class_ptr;
128
129 #if !defined(UX_HOST_STANDALONE)
130
131 /* Allocate UX_HOST_CLASS_STORAGE_EXT. */
132 if (class_inst -> ux_host_class_ext == UX_NULL)
133 {
134
135 /* Need memory for extension fields. */
136 class_ext = _ux_utility_memory_allocate(UX_NO_ALIGN,
137 UX_REGULAR_MEMORY,
138 sizeof(UX_HOST_CLASS_STORAGE_EXT));
139
140 /* Check completion status. */
141 if (class_ext == UX_NULL)
142 return(UX_MEMORY_INSUFFICIENT);
143
144 /* Create the storage class thread. */
145 status = _ux_host_thread_create(&class_ext -> ux_host_class_thread,
146 "ux_host_storage_thread",
147 _ux_host_class_storage_thread_entry,
148 (ULONG) (ALIGN_TYPE) class_inst,
149 class_ext -> ux_host_class_thread_stack,
150 UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE,
151 UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS,
152 UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS,
153 UX_NO_TIME_SLICE, UX_DONT_START);
154
155 /* Check the completion status. */
156 if (status != UX_SUCCESS)
157 {
158 _ux_utility_memory_free(class_ext);
159 class_inst -> ux_host_class_ext = UX_NULL;
160 return(UX_THREAD_ERROR);
161 }
162
163 /* Set thead ext ptr. */
164 UX_THREAD_EXTENSION_PTR_SET(&(class_ext -> ux_host_class_thread), class_inst);
165
166 /* Save extension. */
167 class_inst -> ux_host_class_ext = (VOID *)class_ext;
168 }
169 else
170 {
171
172 /* Get storage class extension. */
173 class_ext = (UX_HOST_CLASS_STORAGE_EXT *)class_inst -> ux_host_class_ext;
174 }
175 #endif
176
177 /* Allocate some memory for the media structures used by UX_MEDIA (default FileX). */
178 if (class_inst -> ux_host_class_media == UX_NULL)
179 {
180
181 /* UX_HOST_CLASS_STORAGE_MAX_MEDIA*sizeof(UX_HOST_CLASS_STORAGE_MEDIA) overflow
182 * is checked outside of function.
183 */
184 class_inst -> ux_host_class_media =
185 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,
186 UX_HOST_CLASS_STORAGE_MAX_MEDIA*sizeof(UX_HOST_CLASS_STORAGE_MEDIA));
187
188 /* Check the completion status. */
189 if (class_inst -> ux_host_class_media == UX_NULL)
190 return(UX_MEMORY_INSUFFICIENT);
191 }
192
193 /* Now that the extension pointer has been set, resume the thread. */
194 _ux_host_thread_resume(&class_ext -> ux_host_class_thread);
195
196 /* The activate command is used when the device inserted has found a parent and
197 is ready to complete the enumeration. */
198 status = _ux_host_class_storage_activate(command);
199
200 /* Return the completion status. */
201 return(status);
202
203 case UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT:
204 return(UX_STATE_NEXT);
205
206 case UX_HOST_CLASS_COMMAND_DEACTIVATE:
207
208 /* The deactivate command is used when the device has been extracted either
209 directly or when its parents has been extracted. */
210 status = _ux_host_class_storage_deactivate(command);
211
212 /* Return the completion status. */
213 return(status);
214
215 case UX_HOST_CLASS_COMMAND_DESTROY:
216
217 /* The destroy command is used when the class is unregistered. */
218
219 /* Get class. */
220 class_inst = command -> ux_host_class_command_class_ptr;
221
222 /* Free allocated media structures. */
223 if (class_inst -> ux_host_class_media)
224 {
225 _ux_utility_memory_free(class_inst -> ux_host_class_media);
226 class_inst -> ux_host_class_media = UX_NULL;
227 }
228
229 #if !defined(UX_HOST_STANDALONE)
230
231 /* Free class extension resources. */
232 if (class_inst -> ux_host_class_ext)
233 {
234
235 /* Get storage class extension. */
236 class_ext = (UX_HOST_CLASS_STORAGE_EXT *)class_inst -> ux_host_class_ext;
237
238 /* Delete storage thread. */
239 _ux_host_thread_delete(&class_ext -> ux_host_class_thread);
240
241 /* Free class extension memory. */
242 _ux_utility_memory_free(class_ext);
243
244 /* Set extension pointer to NULL. */
245 class_inst -> ux_host_class_ext = UX_NULL;
246 }
247 #endif
248
249 /* Return success. */
250 return(UX_SUCCESS);
251
252 default:
253
254 /* Error trap. */
255 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
256
257 /* If trace is enabled, insert this event into the trace buffer. */
258 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
259
260 /* Return an error. */
261 return(UX_FUNCTION_NOT_SUPPORTED);
262 }
263 }
264
265