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