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