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: 2024-12-12 17:16:36 Branches: 14 20 70.0 %

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