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 /** USBX Component */
14 /** */
15 /** Device DFU Class */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19
20 #define UX_SOURCE_CODE
21
22
23 /* Include necessary system files. */
24
25 #include "ux_api.h"
26 #include "ux_device_class_dfu.h"
27 #include "ux_device_stack.h"
28
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _ux_device_class_dfu_initialize PORTABLE C */
35 /* 6.1.12 */
36 /* AUTHOR */
37 /* */
38 /* Chaoqiong Xiao, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function initializes the USB DFU device. */
43 /* */
44 /* INPUT */
45 /* */
46 /* command Pointer to dfu command */
47 /* */
48 /* OUTPUT */
49 /* */
50 /* Completion Status */
51 /* */
52 /* CALLS */
53 /* */
54 /* _ux_utility_memory_allocate Allocate memory */
55 /* _ux_utility_memory_free Free memory */
56 /* _ux_utility_descriptor_parse Parse a descriptor */
57 /* _ux_utility_event_flags_create Create event flags */
58 /* _ux_utility_event_flags_delete Delete event flags */
59 /* _ux_device_thread_create Create thread */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* USBX Source Code */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
70 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
71 /* used UX prefix to refer to */
72 /* TX symbols instead of using */
73 /* them directly, */
74 /* resulting in version 6.1 */
75 /* 04-02-2021 Chaoqiong Xiao Modified comment(s), */
76 /* fixed max transfer size, */
77 /* added max size limit check, */
78 /* resulting in version 6.1.6 */
79 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
80 /* added standalone support, */
81 /* resulting in version 6.1.10 */
82 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
83 /* internal clean up, */
84 /* resulting in version 6.1.11 */
85 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
86 /* fixed parameter/variable */
87 /* names conflict C++ keyword, */
88 /* resulting in version 6.1.12 */
89 /* */
90 /**************************************************************************/
_ux_device_class_dfu_initialize(UX_SLAVE_CLASS_COMMAND * command)91 UINT _ux_device_class_dfu_initialize(UX_SLAVE_CLASS_COMMAND *command)
92 {
93
94 UX_SLAVE_CLASS_DFU *dfu;
95 UX_SLAVE_CLASS_DFU_PARAMETER *dfu_parameter;
96 UX_SLAVE_CLASS *class_ptr;
97 UINT status = UX_DESCRIPTOR_CORRUPTED;
98 UX_DFU_FUNCTIONAL_DESCRIPTOR dfu_functional_descriptor;
99 UCHAR *dfu_framework;
100 ULONG dfu_framework_length;
101 UCHAR descriptor_type;
102 ULONG descriptor_length;
103
104 /* Get the class container. */
105 class_ptr = command -> ux_slave_class_command_class_ptr;
106
107 /* Create an instance of the device dfu class. */
108 dfu = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_DFU));
109
110 /* Check for successful allocation. */
111 if (dfu == UX_NULL)
112 return(UX_MEMORY_INSUFFICIENT);
113
114 /* Save the address of the DFU instance inside the DFU container. */
115 class_ptr -> ux_slave_class_instance = (VOID *) dfu;
116
117 /* Get the pointer to the application parameters for the dfu class. */
118 dfu_parameter = command -> ux_slave_class_command_parameter;
119
120 /* Save the calling parameters in the class instance. */
121 dfu -> ux_slave_class_dfu_instance_activate = dfu_parameter -> ux_slave_class_dfu_parameter_instance_activate;
122 dfu -> ux_slave_class_dfu_instance_deactivate = dfu_parameter -> ux_slave_class_dfu_parameter_instance_deactivate;
123 dfu -> ux_slave_class_dfu_read = dfu_parameter -> ux_slave_class_dfu_parameter_read;
124 dfu -> ux_slave_class_dfu_write = dfu_parameter -> ux_slave_class_dfu_parameter_write;
125 dfu -> ux_slave_class_dfu_get_status = dfu_parameter -> ux_slave_class_dfu_parameter_get_status;
126 dfu -> ux_slave_class_dfu_notify = dfu_parameter -> ux_slave_class_dfu_parameter_notify;
127 #ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE
128 dfu -> ux_device_class_dfu_custom_request = dfu_parameter -> ux_device_class_dfu_parameter_custom_request;
129 #endif
130
131 /* Store the device dfu in the project structure. */
132 _ux_system_slave -> ux_system_slave_dfu_framework = dfu_parameter -> ux_slave_class_dfu_parameter_framework;
133 _ux_system_slave -> ux_system_slave_dfu_framework_length = dfu_parameter -> ux_slave_class_dfu_parameter_framework_length;
134
135 /* There is a DFU descriptor. It has a device descriptor, a configuration descriptor,
136 an interface descriptor and finally a functional descriptor. */
137 dfu_framework = _ux_system_slave -> ux_system_slave_dfu_framework;
138 dfu_framework_length = _ux_system_slave -> ux_system_slave_dfu_framework_length;
139
140 /* Parse the device framework and locate interfaces and endpoint descriptor(s). */
141 while (dfu_framework_length != 0)
142 {
143
144 /* Get the length of this descriptor. */
145 descriptor_length = (ULONG) *dfu_framework;
146
147 /* Length validation. */
148 if (descriptor_length < 2 ||
149 descriptor_length > dfu_framework_length)
150 break;
151
152 /* And its type. */
153 descriptor_type = *(dfu_framework + 1);
154
155 /* Is this the Functional descriptor ? */
156 if (descriptor_type == UX_DFU_FUNCTIONAL_DESCRIPTOR_ITEM)
157 {
158
159 /* Parse the DFU descriptor in something more readable. */
160 _ux_utility_descriptor_parse(dfu_framework,
161 _ux_system_dfu_functional_descriptor_structure,
162 UX_DFU_FUNCTIONAL_DESCRIPTOR_ENTRIES,
163 (UCHAR *) &dfu_functional_descriptor);
164
165 /* Control transfer limit validation. */
166 if (dfu_functional_descriptor.wTransferSize > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
167 break;
168
169 /* Retrieve the DFU capabilities and store them in the system. */
170 _ux_system_slave -> ux_system_slave_device_dfu_capabilities = dfu_functional_descriptor.bmAttributes;
171
172 /* Retrieve the DFU timeout value. */
173 _ux_system_slave -> ux_system_slave_device_dfu_detach_timeout = dfu_functional_descriptor.wDetachTimeOut;
174
175 /* Retrieve the DFU transfer size value. */
176 _ux_system_slave -> ux_system_slave_device_dfu_transfer_size = dfu_functional_descriptor.wTransferSize;
177
178 /* In the system, state the DFU state machine. */
179 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_APP_IDLE;
180
181 /* DFU descriptor parsed, done. */
182 status = UX_SUCCESS;
183 break;
184 }
185
186 /* Adjust what is left of the device framework. */
187 dfu_framework_length -= descriptor_length;
188
189 /* Point to the next descriptor. */
190 dfu_framework += descriptor_length;
191
192 }
193
194 #if !defined(UX_DEVICE_STANDALONE)
195
196 /* Create a event flag group for the dfu class to synchronize with the event interrupt thread. */
197 status = _ux_utility_event_flags_create(&dfu -> ux_slave_class_dfu_event_flags_group, "ux_device_class_dfu_event_flag");
198
199 /* Check status. */
200 if (status != UX_SUCCESS)
201 status = UX_EVENT_ERROR;
202
203 /* Allocate some memory for the dfu thread stack. */
204 if (status == UX_SUCCESS)
205 {
206 dfu -> ux_slave_class_dfu_thread_stack =
207 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
208
209 /* Check for successful allocation. */
210 if (dfu -> ux_slave_class_dfu_thread_stack == UX_NULL)
211 status = UX_MEMORY_INSUFFICIENT;
212 }
213
214 /* dfu needs a thread to watch for disconnect and timer event for the DFU_DETACH sequence. */
215 if (status == UX_SUCCESS)
216 {
217 status = _ux_device_thread_create(&dfu -> ux_slave_class_dfu_thread , "ux_slave_class_dfu_thread",
218 _ux_device_class_dfu_thread,
219 (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) dfu -> ux_slave_class_dfu_thread_stack,
220 UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
221 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_AUTO_START);
222
223 /* Check the creation of this thread. */
224 if (status != UX_SUCCESS)
225 status = UX_THREAD_ERROR;
226 }
227
228 UX_THREAD_EXTENSION_PTR_SET(&(dfu -> ux_slave_class_dfu_thread), class_ptr)
229 #else
230
231 /* Set task function. */
232 class_ptr -> ux_slave_class_task_function = _ux_device_class_dfu_tasks_run;
233 #endif
234
235 /* Return completion status. */
236 if (status == UX_SUCCESS)
237 return(UX_SUCCESS);
238
239 /* There is error, free resources. */
240
241 #if !defined(UX_DEVICE_STANDALONE)
242
243 /* The last resource, thread is not created or created error, no need to free. */
244 if (dfu -> ux_slave_class_dfu_thread_stack)
245 _ux_utility_memory_free(dfu -> ux_slave_class_dfu_thread_stack);
246 if (dfu -> ux_slave_class_dfu_event_flags_group.tx_event_flags_group_id != 0)
247 _ux_utility_event_flags_delete(&dfu -> ux_slave_class_dfu_event_flags_group);
248 #endif
249
250 /* Detach from container and free instance memory. */
251 class_ptr -> ux_slave_class_instance = UX_NULL;
252 _ux_utility_memory_free(dfu);
253
254 return(status);
255 }
256
257 /**************************************************************************/
258 /* */
259 /* FUNCTION RELEASE */
260 /* */
261 /* _uxe_device_class_dfu_initialize PORTABLE C */
262 /* 6.3.0 */
263 /* AUTHOR */
264 /* */
265 /* Yajun Xia, Microsoft Corporation */
266 /* */
267 /* DESCRIPTION */
268 /* */
269 /* This function checks errors in DFU device class initialize */
270 /* function. */
271 /* */
272 /* INPUT */
273 /* */
274 /* command Pointer to dfu command */
275 /* */
276 /* OUTPUT */
277 /* */
278 /* Completion Status */
279 /* */
280 /* CALLS */
281 /* */
282 /* _ux_device_class_dfu_initialize DFU device class initialize */
283 /* function. */
284 /* */
285 /* CALLED BY */
286 /* */
287 /* USBX Source Code */
288 /* */
289 /* RELEASE HISTORY */
290 /* */
291 /* DATE NAME DESCRIPTION */
292 /* */
293 /* 10-31-2023 Yajun Xia Initial Version 6.3.0 */
294 /* */
295 /**************************************************************************/
_uxe_device_class_dfu_initialize(UX_SLAVE_CLASS_COMMAND * command)296 UINT _uxe_device_class_dfu_initialize(UX_SLAVE_CLASS_COMMAND *command)
297 {
298
299 UX_SLAVE_CLASS_DFU_PARAMETER *dfu_parameter;
300
301 /* Static Check */
302 if (command -> ux_slave_class_command_parameter == UX_NULL)
303 return(UX_INVALID_PARAMETER);
304
305 dfu_parameter = (UX_SLAVE_CLASS_DFU_PARAMETER *) command -> ux_slave_class_command_parameter;
306
307 if ((dfu_parameter -> ux_slave_class_dfu_parameter_framework == UX_NULL) &&
308 (dfu_parameter -> ux_slave_class_dfu_parameter_framework_length > 0))
309 return(UX_INVALID_PARAMETER);
310
311 return _ux_device_class_dfu_initialize(command);
312 }
313