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 /** */
15 /** USBX Component */
16 /** */
17 /** HID Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_hid.h"
29 #include "ux_host_stack.h"
30
UX_OVERFLOW_CHECK_MULC_ULONG(UX_HOST_CLASS_HID_MAX_CLIENTS,sizeof (UX_HOST_CLASS_HID_CLIENT))31 UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_MULC_ULONG(UX_HOST_CLASS_HID_MAX_CLIENTS, sizeof(UX_HOST_CLASS_HID_CLIENT)), UX_HOST_CLASS_HID_MAX_CLIENTS_mem_alloc_ovf)
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_hid_client_register PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function registers a USB HID client to the HID class. The */
46 /* mechanism is similar to the USB stack class registration. The Class */
47 /* must specify an entry point for the USB stack to send commands */
48 /* such as: */
49 /* */
50 /* UX_HOST_CLASS_COMMAND_QUERY */
51 /* UX_HOST_CLASS_COMMAND_ACTIVATE */
52 /* UX_HOST_CLASS_COMMAND_DESTROY */
53 /* */
54 /* Note: The C string of hid_client_name must be NULL-terminated and */
55 /* the length of it (without the NULL-terminator itself) must be no */
56 /* larger than UX_HOST_CLASS_HID_MAX_CLIENT_NAME_LENGTH. */
57 /* */
58 /* INPUT */
59 /* */
60 /* hid_client_name Name of HID client */
61 /* hid_client_handler Handler for HID client */
62 /* */
63 /* OUTPUT */
64 /* */
65 /* Completion Status */
66 /* */
67 /* CALLS */
68 /* */
69 /* _ux_host_stack_class_get Get class */
70 /* _ux_utility_memory_allocate Allocate memory block */
71 /* _ux_utility_memory_copy Copy memory block */
72 /* _ux_utility_string_length_check Check C string and return */
73 /* length if null-terminated */
74 /* */
75 /* CALLED BY */
76 /* */
77 /* Application */
78 /* HID Class */
79 /* */
80 /* RELEASE HISTORY */
81 /* */
82 /* DATE NAME DESCRIPTION */
83 /* */
84 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
85 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
86 /* verified memset and memcpy */
87 /* cases, */
88 /* resulting in version 6.1 */
89 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
90 /* fixed parameter/variable */
91 /* names conflict C++ keyword, */
92 /* resulting in version 6.1.12 */
93 /* */
94 /**************************************************************************/
95 UINT _ux_host_class_hid_client_register(UCHAR *hid_client_name,
96 UINT (*hid_client_handler)(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *))
97 {
98
99 UX_HOST_CLASS *class_ptr;
100 ULONG hid_client_index;
101 UINT status;
102 UX_HOST_CLASS_HID_CLIENT *hid_client;
103 UINT client_name_length = 0;
104
105 /* If trace is enabled, insert this event into the trace buffer. */
106 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_HID_CLIENT_REGISTER, hid_client_name, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
107
108 /* Get the length of the client name (exclude null-terminator). */
109 status = _ux_utility_string_length_check(hid_client_name, &client_name_length, UX_HOST_CLASS_HID_MAX_CLIENT_NAME_LENGTH);
110 if (status)
111 return(status);
112
113 /* We need to locate our class container. */
114 status = _ux_host_stack_class_get(_ux_system_host_class_hid_name, &class_ptr);
115
116 /* If we cannot get the class container, it means the HID class was not registered. */
117 if (status != UX_SUCCESS)
118 return(status);
119
120 /* From the class container, we get the client pointer which has the list of
121 HID clients. If the pointer is NULL, the client list was not assigned. */
122 if (class_ptr -> ux_host_class_client == UX_NULL)
123 {
124
125 /* Allocate memory for the class client.
126 * Allocate size overflow static checked outside the function.
127 */
128 class_ptr -> ux_host_class_client = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,
129 sizeof(UX_HOST_CLASS_HID_CLIENT)*UX_HOST_CLASS_HID_MAX_CLIENTS);
130
131 /* Check for successful allocation. */
132 if (class_ptr -> ux_host_class_client == UX_NULL)
133 return(UX_MEMORY_INSUFFICIENT);
134 }
135
136 /* De-reference the client pointer into a HID client array pointer. */
137 hid_client = (UX_HOST_CLASS_HID_CLIENT *) class_ptr -> ux_host_class_client;
138
139 /* We need to parse the HID client handler table to find an empty spot. */
140 for (hid_client_index = 0; hid_client_index < UX_HOST_CLASS_HID_MAX_CLIENTS; hid_client_index++)
141 {
142
143 /* Check if this HID client is already used. */
144 if (hid_client -> ux_host_class_hid_client_status == UX_UNUSED)
145 {
146
147 /* We have found a free container for the HID client. Copy the name (with null-terminator). */
148 _ux_utility_memory_copy(hid_client -> ux_host_class_hid_client_name, hid_client_name, client_name_length + 1); /* Use case of memcpy is verified. */
149
150 /* Memorize the handler address of this client. */
151 hid_client -> ux_host_class_hid_client_handler = hid_client_handler;
152
153 /* Mark it as being in use. */
154 hid_client -> ux_host_class_hid_client_status = UX_USED;
155
156 /* Return successful completion. */
157 return(UX_SUCCESS);
158 }
159 else
160 {
161
162 /* Do a sanity check to make sure the handler is not already installed by
163 mistake. To verify this, we simple check for the handler entry point. */
164 if (hid_client -> ux_host_class_hid_client_handler == hid_client_handler)
165 {
166
167 /* Error trap. */
168 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_ALREADY_INSTALLED);
169
170 /* If trace is enabled, insert this event into the trace buffer. */
171 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_ALREADY_INSTALLED, hid_client_name, 0, 0, UX_TRACE_ERRORS, 0, 0)
172
173 return(UX_HOST_CLASS_ALREADY_INSTALLED);
174 }
175 }
176
177 /* Try the next class. */
178 hid_client++;
179 }
180
181 /* Error trap. */
182 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_ARRAY_FULL);
183
184 /* If trace is enabled, insert this event into the trace buffer. */
185 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_ARRAY_FULL, hid_client_name, 0, 0, UX_TRACE_ERRORS, 0, 0)
186
187 /* No more entries in the class table. */
188 return(UX_MEMORY_ARRAY_FULL);
189 }
190
191 /**************************************************************************/
192 /* */
193 /* FUNCTION RELEASE */
194 /* */
195 /* _uxe_host_class_hid_client_register PORTABLE C */
196 /* 6.3.0 */
197 /* AUTHOR */
198 /* */
199 /* Chaoqiong Xiao, Microsoft Corporation */
200 /* */
201 /* DESCRIPTION */
202 /* */
203 /* This function checks errors in HID client register function call. */
204 /* */
205 /* INPUT */
206 /* */
207 /* hid_client_name Name of HID client */
208 /* hid_client_handler Handler for HID client */
209 /* */
210 /* OUTPUT */
211 /* */
212 /* Status */
213 /* */
214 /* CALLS */
215 /* */
216 /* _ux_host_class_hid_client_register Register an HID client */
217 /* */
218 /* CALLED BY */
219 /* */
220 /* Application */
221 /* */
222 /* RELEASE HISTORY */
223 /* */
224 /* DATE NAME DESCRIPTION */
225 /* */
226 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
227 /* */
228 /**************************************************************************/
_uxe_host_class_hid_client_register(UCHAR * hid_client_name,UINT (* hid_client_handler)(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *))229 UINT _uxe_host_class_hid_client_register(UCHAR *hid_client_name,
230 UINT (*hid_client_handler)(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *))
231 {
232
233 /* Sanity checks. */
234 if ((hid_client_name == UX_NULL) || (hid_client_handler == UX_NULL))
235 return(UX_INVALID_PARAMETER);
236
237 /* Invoke client register function. */
238 return(_ux_host_class_hid_client_register(hid_client_name, hid_client_handler));
239 }
240