GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_device_classes/src/ux_device_class_hid_initialize.c Lines: 42 49 85.7 %
Date: 2026-03-06 18:57:10 Branches: 14 20 70.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** USBX Component                                                        */
16
/**                                                                       */
17
/**   Device HID Class                                                    */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
#define UX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "ux_api.h"
28
#include "ux_device_class_hid.h"
29
#include "ux_device_stack.h"
30
31
32
/**************************************************************************/
33
/*                                                                        */
34
/*  FUNCTION                                               RELEASE        */
35
/*                                                                        */
36
/*    _ux_device_class_hid_initialize                     PORTABLE C      */
37
/*                                                           6.3.0        */
38
/*  AUTHOR                                                                */
39
/*                                                                        */
40
/*    Chaoqiong Xiao, Microsoft Corporation                               */
41
/*                                                                        */
42
/*  DESCRIPTION                                                           */
43
/*                                                                        */
44
/*    This function initializes the USB HID device.                       */
45
/*    This function is called by the class register function. It is only  */
46
/*    done once.                                                          */
47
/*                                                                        */
48
/*  INPUT                                                                 */
49
/*                                                                        */
50
/*    command                              Pointer to hid command         */
51
/*                                                                        */
52
/*  OUTPUT                                                                */
53
/*                                                                        */
54
/*    Completion Status                                                   */
55
/*                                                                        */
56
/*  CALLS                                                                 */
57
/*                                                                        */
58
/*    _ux_utility_memory_allocate           Allocate memory               */
59
/*    _ux_utility_memory_free               Free memory                   */
60
/*    _ux_device_thread_create              Create thread                 */
61
/*    _ux_device_thread_delete              Delete thread                 */
62
/*    _ux_utility_event_flags_create        Create event flags group      */
63
/*                                                                        */
64
/*  CALLED BY                                                             */
65
/*                                                                        */
66
/*    USBX Source Code                                                    */
67
/*                                                                        */
68
/**************************************************************************/
69
206
UINT  _ux_device_class_hid_initialize(UX_SLAVE_CLASS_COMMAND *command)
70
{
71
72
UX_SLAVE_CLASS_HID                      *hid;
73
UX_SLAVE_CLASS_HID_PARAMETER            *hid_parameter;
74
UX_SLAVE_CLASS                          *class_ptr;
75
206
UINT                                    status = UX_SUCCESS;
76
ULONG                                   array_memory_size;
77
#if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY)
78
UINT                                    i;
79
UCHAR                                   *buffer;
80
#endif
81
82
83
    /* Compile option checks.  */
84
    UX_ASSERT(UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH <= UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH);
85
#if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 0
86
    UX_ASSERT(UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
87
#endif
88
89
90
    /* Get the pointer to the application parameters for the hid class.  */
91
206
    hid_parameter =  command -> ux_slave_class_command_parameter;
92
93
    /* Get the class container.  */
94
206
    class_ptr =  command -> ux_slave_class_command_class_ptr;
95
96
    /* Create an instance of the device hid class.  */
97
206
    hid =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_HID));
98
99
    /* Check for successful allocation.  */
100
206
    if (hid == UX_NULL)
101
24
        return(UX_MEMORY_INSUFFICIENT);
102
103
    /* Save the address of the HID instance inside the HID container.  */
104
182
    class_ptr -> ux_slave_class_instance = (VOID *) hid;
105
106
#if defined(UX_DEVICE_CLASS_HID_OWN_ENDPOINT_BUFFER)
107
108
    /* Allocate buffer(s) for endpoint(s).  */
109
    UX_ASSERT(!UX_DEVICE_CLASS_HID_ENDPOINT_BUFFER_SIZE_CALC_OVERFLOW);
110
    hid -> ux_device_class_hid_endpoint_buffer = _ux_utility_memory_allocate(
111
                            UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY,
112
                            UX_DEVICE_CLASS_HID_ENDPOINT_BUFFER_SIZE);
113
    if (hid -> ux_device_class_hid_endpoint_buffer == UX_NULL)
114
    {
115
        _ux_utility_memory_free(hid);
116
        return(UX_MEMORY_INSUFFICIENT);
117
    }
118
#endif
119
120
#if !defined(UX_DEVICE_STANDALONE)
121
122
    /* Allocate some memory for the thread stack. */
123
182
    class_ptr -> ux_slave_class_thread_stack =
124
182
            _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_DEVICE_CLASS_HID_THREAD_STACK_SIZE);
125
126
    /* Check for successful allocation.  */
127
182
    if (class_ptr -> ux_slave_class_thread_stack == UX_NULL)
128
6
        status = UX_MEMORY_INSUFFICIENT;
129
130
    /* This instance needs to be running in a different thread. So start
131
       a new thread. We pass a pointer to the class to the new thread.  This thread
132
       does not start until we have a instance of the class. */
133
182
    if (status == UX_SUCCESS)
134
176
        status =  _ux_device_thread_create(&class_ptr -> ux_slave_class_thread, "ux_slave_hid_thread",
135
                    _ux_device_class_hid_interrupt_thread,
136
                    (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) class_ptr -> ux_slave_class_thread_stack,
137
                    UX_DEVICE_CLASS_HID_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
138
                    UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
139
#else
140
141
#if defined(UX_DEVICE_CLASS_HID_FLEXIBLE_EVENTS_QUEUE)
142
143
    /* Set event buffer.  */
144
    hid -> ux_device_class_hid_event.ux_device_class_hid_event_buffer =
145
                                    UX_DEVICE_CLASS_HID_INTERRUPTIN_BUFFER(hid);
146
#endif
147
148
    /* Set task function.  */
149
    class_ptr -> ux_slave_class_task_function = _ux_device_class_hid_tasks_run;
150
#endif
151
152
    /* Check the creation of this thread.  */
153
182
    if (status == UX_SUCCESS)
154
    {
155
156
#if !defined(UX_DEVICE_STANDALONE)
157
        UX_THREAD_EXTENSION_PTR_SET(&(class_ptr -> ux_slave_class_thread), class_ptr)
158
#endif
159
160
161
        /* Store all the application parameter information about the report.  */
162
175
        hid -> ux_device_class_hid_report_address             = hid_parameter -> ux_device_class_hid_parameter_report_address;
163
175
        hid -> ux_device_class_hid_report_length              = hid_parameter -> ux_device_class_hid_parameter_report_length;
164
175
        hid -> ux_device_class_hid_report_id                  = hid_parameter -> ux_device_class_hid_parameter_report_id;
165
166
        /* Store the callback function.  */
167
175
        hid -> ux_device_class_hid_callback                   = hid_parameter -> ux_device_class_hid_parameter_callback;
168
175
        hid -> ux_device_class_hid_get_callback               = hid_parameter -> ux_device_class_hid_parameter_get_callback;
169
170
#if defined(UX_DEVICE_CLASS_HID_FLEXIBLE_EVENTS_QUEUE)
171
172
        /* If event length is invalid, UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH is used.  */
173
        if (UX_DEVICE_CLASS_HID_PARAM_EVENT_MAX_LENGTH(hid_parameter) == 0 ||
174
            UX_DEVICE_CLASS_HID_PARAM_EVENT_MAX_LENGTH(hid_parameter) > UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH)
175
            UX_DEVICE_CLASS_HID_PARAM_EVENT_MAX_LENGTH(hid_parameter) = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH;
176
177
        /* If event queue size is invalid, UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE is used.  */
178
        if (UX_DEVICE_CLASS_HID_PARAM_EVENT_QUEUE_SIZE(hid_parameter) < 2 ||
179
            UX_DEVICE_CLASS_HID_PARAM_EVENT_QUEUE_SIZE(hid_parameter) > UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE)
180
            UX_DEVICE_CLASS_HID_PARAM_EVENT_QUEUE_SIZE(hid_parameter) = UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE;
181
182
        /* Save event size.  */
183
        UX_DEVICE_CLASS_HID_EVENT_MAX_LENGTH(hid) = UX_DEVICE_CLASS_HID_PARAM_EVENT_MAX_LENGTH(hid_parameter);
184
#endif
185
186
        /* Create the event array.  */
187
        UX_ASSERT(!UX_OVERFLOW_CHECK_MULC_ULONG(
188
                    UX_DEVICE_CLASS_HID_EVENT_QUEUE_ITEM_SIZE(hid),
189
                    UX_DEVICE_CLASS_HID_PARAM_EVENT_QUEUE_SIZE(hid_parameter)));
190
175
        array_memory_size = UX_DEVICE_CLASS_HID_EVENT_QUEUE_ITEM_SIZE(hid) * UX_DEVICE_CLASS_HID_PARAM_EVENT_QUEUE_SIZE(hid_parameter);
191
175
        hid -> ux_device_class_hid_event_array =  _ux_utility_memory_allocate(UX_NO_ALIGN,
192
                                        UX_REGULAR_MEMORY, array_memory_size);
193
194
        /* Do we need event buffer?
195
         * 1. Even zero copy, report copy is kept to avoid keep buffers in application.
196
         * 2. Other cases, buffer must be allocated.
197
         */
198
        /* Allocate buffer if needed.  */
199
        {
200
201
#if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY)
202
203
            /* Allocate cache safe event buffers.  */
204
            buffer = _ux_utility_memory_allocate_mulv_safe(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY,
205
                        UX_DEVICE_CLASS_HID_PARAM_EVENT_MAX_LENGTH(hid_parameter),
206
                        UX_DEVICE_CLASS_HID_PARAM_EVENT_QUEUE_SIZE(hid_parameter));
207
208
            /* Allocation error check.  */
209
            if (buffer == UX_NULL)
210
            {
211
                if (hid -> ux_device_class_hid_event_array != UX_NULL)
212
                {
213
                    _ux_utility_memory_free(hid -> ux_device_class_hid_event_array);
214
                    hid -> ux_device_class_hid_event_array = UX_NULL;
215
                }
216
            }
217
            else
218
            {
219
220
                /* Assign event buffers.  */
221
                for (i = 0; i < UX_DEVICE_CLASS_HID_PARAM_EVENT_QUEUE_SIZE(hid_parameter); i ++)
222
                {
223
                    hid -> ux_device_class_hid_event_array[i].ux_device_class_hid_event_buffer = buffer;
224
                    buffer += UX_DEVICE_CLASS_HID_PARAM_EVENT_MAX_LENGTH(hid_parameter);
225
                }
226
            }
227
#else
228
229
            /* Regular event place data following id,type and length.  */
230
#endif
231
        }
232
233
        /* Check for successful allocation.  */
234
175
        if (hid -> ux_device_class_hid_event_array != UX_NULL)
235
        {
236
237
            /* Initialize the head and tail of the notification round robin buffers.
238
               At first, the head and tail are pointing to the beginning of the array.  */
239
169
            hid -> ux_device_class_hid_event_array_head =  hid -> ux_device_class_hid_event_array;
240
169
            hid -> ux_device_class_hid_event_array_tail =  hid -> ux_device_class_hid_event_array;
241
169
            hid -> ux_device_class_hid_event_array_end  =  (UX_DEVICE_CLASS_HID_EVENT*)((UCHAR*)hid -> ux_device_class_hid_event_array + array_memory_size);
242
243
            /* Store the start and stop signals if needed by the application.  */
244
169
            hid -> ux_slave_class_hid_instance_activate = hid_parameter -> ux_slave_class_hid_instance_activate;
245
169
            hid -> ux_slave_class_hid_instance_deactivate = hid_parameter -> ux_slave_class_hid_instance_deactivate;
246
247
            /* By default no event wait timeout.  */
248
169
            hid -> ux_device_class_hid_event_wait_timeout = UX_WAIT_FOREVER;
249
250
#if !defined(UX_DEVICE_STANDALONE)
251
252
            /* Create a event flag group for the hid class to synchronize with the event interrupt thread.  */
253
169
            status =  _ux_utility_event_flags_create(&hid -> ux_device_class_hid_event_flags_group, "ux_device_class_hid_event_flag");
254
255
            /* Check status.  */
256
169
            if (status != UX_SUCCESS)
257
1
                status = UX_EVENT_ERROR;
258
            else
259
#endif
260
            {
261
#if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT)
262
263
#if !defined(UX_DEVICE_STANDALONE)
264
265
                /* Create a mutex for reading reentry check.  */
266
                status = _ux_utility_mutex_create(&hid -> ux_device_class_hid_read_mutex,
267
                                                  "ux_device_class_hid_read_mutex");
268
                if (status == UX_SUCCESS)
269
                {
270
#endif
271
272
                    /* If receiver is enabled by parameter, initialize it.  */
273
                    if (hid_parameter -> ux_device_class_hid_parameter_receiver_initialize)
274
                    {
275
276
                        /* Allocate buffer for receiver and receiver events.  */
277
                        status = hid_parameter ->
278
                                ux_device_class_hid_parameter_receiver_initialize(hid,
279
                                                hid_parameter,
280
                                                &hid -> ux_device_class_hid_receiver);
281
                    }
282
283
                    /* Done success, return.  */
284
                    if (status == UX_SUCCESS)
285
                        return(status);
286
287
#if !defined(UX_DEVICE_STANDALONE)
288
289
                    /* There is error, delete mutex.  */
290
                    _ux_device_mutex_delete(&hid -> ux_device_class_hid_read_mutex);
291
                }
292
                else
293
                    status = UX_MUTEX_ERROR;
294
295
                /* There is error, delete event flags.  */
296
                _ux_utility_event_flags_delete(&hid -> ux_device_class_hid_event_flags_group);
297
#endif
298
#else
299
168
                return(status);
300
#endif
301
302
            }
303
304
#if !defined(UX_DEVICE_STANDALONE) || defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT)
305
306
            /* There is still initialization activities after array creation,
307
             * and some error occurs in this stage.  */
308
            /* Free allocated event array memory.  */
309
#if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY)
310
            _ux_utility_memory_free(hid -> ux_device_class_hid_event_array -> ux_device_class_hid_event_buffer);
311
#endif
312
1
            _ux_utility_memory_free(hid -> ux_device_class_hid_event_array);
313
#endif
314
315
        }
316
        else
317
6
            status =  UX_MEMORY_INSUFFICIENT;
318
319
#if !defined(UX_DEVICE_STANDALONE)
320
321
        /* Delete thread.  */
322
7
        _ux_device_thread_delete(&class_ptr -> ux_slave_class_thread);
323
#endif
324
    }
325
    else
326
7
        status = (UX_THREAD_ERROR);
327
328
#if !defined(UX_DEVICE_STANDALONE)
329
330
    /* Free stack. */
331
14
    if (class_ptr -> ux_slave_class_thread_stack)
332
8
        _ux_utility_memory_free(class_ptr -> ux_slave_class_thread_stack);
333
#endif
334
335
#if defined(UX_DEVICE_CLASS_HID_OWN_ENDPOINT_BUFFER)
336
    _ux_utility_memory_free(hid -> ux_device_class_hid_endpoint_buffer);
337
#endif
338
339
    /* Unmount instance. */
340
14
    class_ptr -> ux_slave_class_instance =  UX_NULL;
341
342
    /* Free HID instance. */
343
14
    _ux_utility_memory_free(hid);
344
345
    /* Return completion status.  */
346
14
    return(status);
347
}
348
349
350
/**************************************************************************/
351
/*                                                                        */
352
/*  FUNCTION                                               RELEASE        */
353
/*                                                                        */
354
/*    _uxe_device_class_hid_initialize                    PORTABLE C      */
355
/*                                                           6.3.0        */
356
/*  AUTHOR                                                                */
357
/*                                                                        */
358
/*    Chaoqiong Xiao, Microsoft Corporation                               */
359
/*                                                                        */
360
/*  DESCRIPTION                                                           */
361
/*                                                                        */
362
/*    This function checks errors in HID initialize function call.        */
363
/*                                                                        */
364
/*  INPUT                                                                 */
365
/*                                                                        */
366
/*    command                               Pointer to hid command        */
367
/*                                                                        */
368
/*  OUTPUT                                                                */
369
/*                                                                        */
370
/*    None                                                                */
371
/*                                                                        */
372
/*  CALLS                                                                 */
373
/*                                                                        */
374
/*    _ux_device_class_hid_initialize       Initialize HID instance       */
375
/*                                                                        */
376
/*  CALLED BY                                                             */
377
/*                                                                        */
378
/*    Device Stack                                                        */
379
/*                                                                        */
380
/**************************************************************************/
381
UINT  _uxe_device_class_hid_initialize(UX_SLAVE_CLASS_COMMAND *command)
382
{
383
384
UX_SLAVE_CLASS_HID_PARAMETER            *hid_parameter;
385
386
    /* Get the pointer to the application parameters for the hid class.  */
387
    hid_parameter =  command -> ux_slave_class_command_parameter;
388
389
    /* Check input parameters.  */
390
    if ((hid_parameter -> ux_device_class_hid_parameter_report_address == UX_NULL) ||
391
        (hid_parameter -> ux_device_class_hid_parameter_report_length == 0) ||
392
        (hid_parameter -> ux_device_class_hid_parameter_report_length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH))
393
    {
394
        return(UX_INVALID_PARAMETER);
395
    }
396
397
    /* Invoke initialize function.  */
398
    return(_ux_device_class_hid_initialize(command));
399
}