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