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 /** */
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_event_set PORTABLE C */
36 /* 6.3.0 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function sends an event to the hid class. It is processed */
44 /* asynchronously by the interrupt thread. */
45 /* */
46 /* INPUT */
47 /* */
48 /* hid Address of hid class */
49 /* event Pointer of the event */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* status UX_SUCCESS if there is an */
54 /* event */
55 /* CALLS */
56 /* */
57 /* _ux_utility_memory_copy Copy memory */
58 /* _ux_device_event_flags_set Set event flags */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* ThreadX */
63 /* */
64 /* RELEASE HISTORY */
65 /* */
66 /* DATE NAME DESCRIPTION */
67 /* */
68 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
69 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
70 /* added standalone support, */
71 /* verified memset and memcpy */
72 /* cases, used UX prefix to */
73 /* refer to TX symbols instead */
74 /* of using them directly, */
75 /* resulting in version 6.1 */
76 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
77 /* added standalone support, */
78 /* resulting in version 6.1.10 */
79 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
80 /* resulting in version 6.1.11 */
81 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
82 /* added zero copy support, */
83 /* resulting in version 6.3.0 */
84 /* */
85 /**************************************************************************/
_ux_device_class_hid_event_set(UX_SLAVE_CLASS_HID * hid,UX_SLAVE_CLASS_HID_EVENT * hid_event)86 UINT _ux_device_class_hid_event_set(UX_SLAVE_CLASS_HID *hid,
87 UX_SLAVE_CLASS_HID_EVENT *hid_event)
88 {
89
90 UX_DEVICE_CLASS_HID_EVENT *current_hid_event;
91 UX_DEVICE_CLASS_HID_EVENT *next_hid_event;
92 UCHAR *next_position;
93
94 /* If trace is enabled, insert this event into the trace buffer. */
95 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_HID_EVENT_SET, hid, hid_event, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
96
97 /* Current position of the head. */
98 current_hid_event = hid -> ux_device_class_hid_event_array_head;
99
100 /* If the pointer is NULL, the round robin buffer has not been activated. */
101 if (current_hid_event == UX_NULL)
102 return (UX_ERROR);
103
104 /* Calculate the next position. */
105 next_position = (UCHAR *)current_hid_event + UX_DEVICE_CLASS_HID_EVENT_QUEUE_ITEM_SIZE(hid);
106 if (next_position >= (UCHAR *)hid -> ux_device_class_hid_event_array_end)
107 next_position = (UCHAR *)hid -> ux_device_class_hid_event_array;
108 next_hid_event = (UX_DEVICE_CLASS_HID_EVENT *)next_position;
109
110 /* Any place left for this event ? */
111 if (next_hid_event == hid -> ux_device_class_hid_event_array_tail)
112 return (UX_ERROR);
113
114 /* There is an event to report, get the current pointer to the event. */
115 current_hid_event = hid -> ux_device_class_hid_event_array_head;
116
117 /* Update the head. */
118 hid -> ux_device_class_hid_event_array_head = next_hid_event;
119
120 /* Check if this event has a report ID. */
121 if (hid -> ux_device_class_hid_report_id == UX_TRUE)
122 {
123
124 /* Yes, there's a report ID. Check to see if our event buffer can also
125 fit the extra byte. */
126 if (hid_event -> ux_device_class_hid_event_length + 1 > UX_DEVICE_CLASS_HID_EVENT_MAX_LENGTH(hid))
127 {
128
129 /* Error trap. */
130 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
131
132 /* If trace is enabled, insert this event into the trace buffer. */
133 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
134
135 /* Return overflow error. */
136 return(UX_MEMORY_INSUFFICIENT);
137 }
138
139 /* Store the report ID. */
140 *UX_DEVICE_CLASS_HID_EVENT_BUFFER(current_hid_event) = (UCHAR)(hid_event -> ux_device_class_hid_event_report_id);
141
142 /* Store the data itself. */
143 _ux_utility_memory_copy(UX_DEVICE_CLASS_HID_EVENT_BUFFER(current_hid_event) + 1,
144 hid_event -> ux_device_class_hid_event_buffer,
145 hid_event -> ux_device_class_hid_event_length); /* Use case of memcpy is verified. */
146
147 /* fill in the event structure from the user. */
148 current_hid_event -> ux_device_class_hid_event_length = hid_event -> ux_device_class_hid_event_length + 1;
149 }
150 else
151 {
152
153 /* No report ID to consider. */
154
155 /* Store copy of data so application can free event there (easier use). */
156 _ux_utility_memory_copy(UX_DEVICE_CLASS_HID_EVENT_BUFFER(current_hid_event),
157 hid_event -> ux_device_class_hid_event_buffer,
158 hid_event -> ux_device_class_hid_event_length); /* Use case of memcpy is verified. */
159
160 /* fill in the event structure from the user. */
161 current_hid_event -> ux_device_class_hid_event_length = hid_event -> ux_device_class_hid_event_length;
162 }
163
164 #if defined(UX_DEVICE_STANDALONE)
165
166 /* Set state machine to start sending if no transfer on going. */
167 if (hid -> ux_device_class_hid_event_state != UX_STATE_WAIT &&
168 hid -> ux_device_class_hid_event_state != UX_STATE_EXIT)
169 hid -> ux_device_class_hid_event_state = UX_STATE_RESET;
170 #else
171
172 /* Set an event to wake up the interrupt thread. */
173 _ux_device_event_flags_set(&hid -> ux_device_class_hid_event_flags_group, UX_DEVICE_CLASS_HID_NEW_EVENT, UX_OR);
174 #endif
175
176 /* Return event status to the user. */
177 return(UX_SUCCESS);
178 }
179
180
181 /**************************************************************************/
182 /* */
183 /* FUNCTION RELEASE */
184 /* */
185 /* _uxe_device_class_hid_event_set PORTABLE C */
186 /* 6.3.0 */
187 /* AUTHOR */
188 /* */
189 /* Chaoqiong Xiao, Microsoft Corporation */
190 /* */
191 /* DESCRIPTION */
192 /* */
193 /* This function checks errors in HID event set function call. */
194 /* */
195 /* INPUT */
196 /* */
197 /* hid Pointer to hid instance */
198 /* hid_event Pointer to hid event */
199 /* */
200 /* OUTPUT */
201 /* */
202 /* None */
203 /* */
204 /* CALLS */
205 /* */
206 /* _ux_device_class_hid_event_set Set an HID event */
207 /* */
208 /* CALLED BY */
209 /* */
210 /* Application */
211 /* */
212 /* RELEASE HISTORY */
213 /* */
214 /* DATE NAME DESCRIPTION */
215 /* */
216 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
217 /* */
218 /**************************************************************************/
_uxe_device_class_hid_event_set(UX_SLAVE_CLASS_HID * hid,UX_SLAVE_CLASS_HID_EVENT * hid_event)219 UINT _uxe_device_class_hid_event_set(UX_SLAVE_CLASS_HID *hid,
220 UX_SLAVE_CLASS_HID_EVENT *hid_event)
221 {
222
223 /* Sanity checks. */
224 if ((hid == UX_NULL) || (hid_event == UX_NULL))
225 return(UX_INVALID_PARAMETER);
226
227 /* Invoke function to get event. */
228 return(_ux_device_class_hid_event_set(hid, hid_event));
229 }
230