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 HID 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_hid.h"
28 #include "ux_device_stack.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _ux_device_class_hid_initialize                     PORTABLE C      */
36 /*                                                           6.2.0        */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function initializes the USB HID device.                       */
44 /*    This function is called by the class register function. It is only  */
45 /*    done once.                                                          */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    command                              Pointer to hid command         */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    Completion Status                                                   */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    _ux_utility_memory_allocate           Allocate memory               */
58 /*    _ux_utility_memory_free               Free memory                   */
59 /*    _ux_device_thread_create              Create thread                 */
60 /*    _ux_device_thread_delete              Delete thread                 */
61 /*    _ux_utility_event_flags_create        Create event flags group      */
62 /*                                                                        */
63 /*  CALLED BY                                                             */
64 /*                                                                        */
65 /*    USBX Source Code                                                    */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
72 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
73 /*                                            used UX prefix to refer to  */
74 /*                                            TX symbols instead of using */
75 /*                                            them directly,              */
76 /*                                            resulting in version 6.1    */
77 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            added standalone support,   */
79 /*                                            added interrupt OUT support,*/
80 /*                                            resulting in version 6.1.10 */
81 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            resulting in version 6.1.11 */
83 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
84 /*                                            added standalone receiver,  */
85 /*                                            fixed parameter/variable    */
86 /*                                            names conflict C++ keyword, */
87 /*                                            resulting in version 6.1.12 */
88 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            fixed compile warnings,     */
90 /*                                            resulting in version 6.2.0  */
91 /*                                                                        */
92 /**************************************************************************/
_ux_device_class_hid_initialize(UX_SLAVE_CLASS_COMMAND * command)93 UINT  _ux_device_class_hid_initialize(UX_SLAVE_CLASS_COMMAND *command)
94 {
95 
96 UX_SLAVE_CLASS_HID                      *hid;
97 UX_SLAVE_CLASS_HID_PARAMETER            *hid_parameter;
98 UX_SLAVE_CLASS                          *class_ptr;
99 UINT                                    status = UX_SUCCESS;
100 
101 
102     /* Get the class container.  */
103     class_ptr =  command -> ux_slave_class_command_class_ptr;
104 
105     /* Create an instance of the device hid class.  */
106     hid =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_HID));
107 
108     /* Check for successful allocation.  */
109     if (hid == UX_NULL)
110         return(UX_MEMORY_INSUFFICIENT);
111 
112     /* Save the address of the HID instance inside the HID container.  */
113     class_ptr -> ux_slave_class_instance = (VOID *) hid;
114 
115 #if !defined(UX_DEVICE_STANDALONE)
116 
117     /* Allocate some memory for the thread stack. */
118     class_ptr -> ux_slave_class_thread_stack =
119             _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_DEVICE_CLASS_HID_THREAD_STACK_SIZE);
120 
121     /* Check for successful allocation.  */
122     if (class_ptr -> ux_slave_class_thread_stack == UX_NULL)
123         status = UX_MEMORY_INSUFFICIENT;
124 
125     /* This instance needs to be running in a different thread. So start
126        a new thread. We pass a pointer to the class to the new thread.  This thread
127        does not start until we have a instance of the class. */
128     if (status == UX_SUCCESS)
129         status =  _ux_device_thread_create(&class_ptr -> ux_slave_class_thread, "ux_slave_hid_thread",
130                     _ux_device_class_hid_interrupt_thread,
131                     (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) class_ptr -> ux_slave_class_thread_stack,
132                     UX_DEVICE_CLASS_HID_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
133                     UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
134 #else
135 
136     /* Set task function.  */
137     class_ptr -> ux_slave_class_task_function = _ux_device_class_hid_tasks_run;
138 #endif
139 
140     /* Check the creation of this thread.  */
141     if (status == UX_SUCCESS)
142     {
143 
144 #if !defined(UX_DEVICE_STANDALONE)
145         UX_THREAD_EXTENSION_PTR_SET(&(class_ptr -> ux_slave_class_thread), class_ptr)
146 #endif
147 
148         /* Get the pointer to the application parameters for the hid class.  */
149         hid_parameter =  command -> ux_slave_class_command_parameter;
150 
151         /* Store all the application parameter information about the report.  */
152         hid -> ux_device_class_hid_report_address             = hid_parameter -> ux_device_class_hid_parameter_report_address;
153         hid -> ux_device_class_hid_report_length              = hid_parameter -> ux_device_class_hid_parameter_report_length;
154         hid -> ux_device_class_hid_report_id                  = hid_parameter -> ux_device_class_hid_parameter_report_id;
155 
156         /* Store the callback function.  */
157         hid -> ux_device_class_hid_callback                   = hid_parameter -> ux_device_class_hid_parameter_callback;
158         hid -> ux_device_class_hid_get_callback               = hid_parameter -> ux_device_class_hid_parameter_get_callback;
159 
160         /* Create the event array.  */
161         hid -> ux_device_class_hid_event_array =  _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_HID_EVENT), UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE);
162 
163         /* Check for successful allocation.  */
164         if (hid -> ux_device_class_hid_event_array != UX_NULL)
165         {
166 
167             /* Initialize the head and tail of the notification round robin buffers.
168                At first, the head and tail are pointing to the beginning of the array.  */
169             hid -> ux_device_class_hid_event_array_head =  hid -> ux_device_class_hid_event_array;
170             hid -> ux_device_class_hid_event_array_tail =  hid -> ux_device_class_hid_event_array;
171             hid -> ux_device_class_hid_event_array_end  =  hid -> ux_device_class_hid_event_array + UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE;
172 
173             /* Store the start and stop signals if needed by the application.  */
174             hid -> ux_slave_class_hid_instance_activate = hid_parameter -> ux_slave_class_hid_instance_activate;
175             hid -> ux_slave_class_hid_instance_deactivate = hid_parameter -> ux_slave_class_hid_instance_deactivate;
176 
177             /* By default no event wait timeout.  */
178             hid -> ux_device_class_hid_event_wait_timeout = UX_WAIT_FOREVER;
179 
180 #if !defined(UX_DEVICE_STANDALONE)
181 
182             /* Create a event flag group for the hid class to synchronize with the event interrupt thread.  */
183             status =  _ux_utility_event_flags_create(&hid -> ux_device_class_hid_event_flags_group, "ux_device_class_hid_event_flag");
184 
185             /* Check status.  */
186             if (status != UX_SUCCESS)
187                 status = UX_EVENT_ERROR;
188             else
189 #endif
190             {
191 #if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT)
192 
193 #if !defined(UX_DEVICE_STANDALONE)
194 
195                 /* Create a mutex for reading reentry check.  */
196                 status = _ux_utility_mutex_create(&hid -> ux_device_class_hid_read_mutex,
197                                                   "ux_device_class_hid_read_mutex");
198                 if (status == UX_SUCCESS)
199                 {
200 #endif
201 
202                     /* If receiver is enabled by parameter, initialize it.  */
203                     if (hid_parameter -> ux_device_class_hid_parameter_receiver_initialize)
204                     {
205 
206                         /* Allocate buffer for receiver and receiver events.  */
207                         status = hid_parameter ->
208                                 ux_device_class_hid_parameter_receiver_initialize(hid,
209                                                 hid_parameter,
210                                                 &hid -> ux_device_class_hid_receiver);
211                     }
212 
213                     /* Done success, return.  */
214                     if (status == UX_SUCCESS)
215                         return(status);
216 
217 #if !defined(UX_DEVICE_STANDALONE)
218 
219                     /* There is error, delete mutex.  */
220                     _ux_device_mutex_delete(&hid -> ux_device_class_hid_read_mutex);
221                 }
222                 else
223                     status = UX_MUTEX_ERROR;
224 
225                 /* There is error, delete event flags.  */
226                 _ux_utility_event_flags_delete(&hid -> ux_device_class_hid_event_flags_group);
227 #endif
228 #else
229                 return(status);
230 #endif
231 
232             }
233 
234 #if !defined(UX_DEVICE_STANDALONE) || defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT)
235 
236             /* There is still initialization activities after array creation,
237              * and some error occurs in this stage.  */
238             /* Free allocated event array memory.  */
239             _ux_utility_memory_free(hid -> ux_device_class_hid_event_array);
240 #endif
241 
242         }
243         else
244             status =  UX_MEMORY_INSUFFICIENT;
245 
246 #if !defined(UX_DEVICE_STANDALONE)
247 
248         /* Delete thread.  */
249         _ux_device_thread_delete(&class_ptr -> ux_slave_class_thread);
250 #endif
251     }
252     else
253         status = (UX_THREAD_ERROR);
254 
255 #if !defined(UX_DEVICE_STANDALONE)
256 
257     /* Free stack. */
258     if (class_ptr -> ux_slave_class_thread_stack)
259         _ux_utility_memory_free(class_ptr -> ux_slave_class_thread_stack);
260 #endif
261 
262     /* Unmount instance. */
263     class_ptr -> ux_slave_class_instance =  UX_NULL;
264 
265     /* Free HID instance. */
266     _ux_utility_memory_free(hid);
267 
268     /* Return completion status.  */
269     return(status);
270 }
271 
272