GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_hid_keyboard_activate.c Lines: 81 81 100.0 %
Date: 2024-12-12 17:16:36 Branches: 42 42 100.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
/**************************************************************************/
14
/**                                                                       */
15
/** USBX Component                                                        */
16
/**                                                                       */
17
/**   HID Keyboard Client                                                 */
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_class_hid_keyboard.h"
30
#include "ux_host_stack.h"
31
32
/* Define USB HID keyboard mapping tables.  */
33
34
#ifndef UX_HOST_CLASS_HID_KEYBOARD_REGULAR_ARRAY_DEFAULT
35
#define UX_HOST_CLASS_HID_KEYBOARD_REGULAR_ARRAY_DEFAULT UX_HID_KEYBOARD_REGULAR_ARRAY_US
36
#endif
37
#ifndef UX_HOST_CLASS_HID_KEYBOARD_SHIFT_ARRAY_DEFAULT
38
#define UX_HOST_CLASS_HID_KEYBOARD_SHIFT_ARRAY_DEFAULT UX_HID_KEYBOARD_SHIFT_ARRAY_US
39
#endif
40
#ifndef UX_HOST_CLASS_HID_KEYBOARD_NUMLOCK_ON_ARRAY_DEFAULT
41
#define UX_HOST_CLASS_HID_KEYBOARD_NUMLOCK_ON_ARRAY_DEFAULT UX_HID_KEYBOARD_NUMLOCK_ON_ARRAY
42
#endif
43
#ifndef UX_HOST_CLASS_HID_KEYBOARD_NUMLOCK_OFF_ARRAY_DEFAULT
44
#define UX_HOST_CLASS_HID_KEYBOARD_NUMLOCK_OFF_ARRAY_DEFAULT UX_HID_KEYBOARD_NUMLOCK_OFF_ARRAY
45
#endif
46
#ifndef UX_HOST_CLASS_HID_KEYBOARD_KEYS_UPPER_RANGE_DEFAULT
47
#define UX_HOST_CLASS_HID_KEYBOARD_KEYS_UPPER_RANGE_DEFAULT UX_HID_KEYBOARD_KEYS_UPPER_RANGE
48
#endif
49
#ifndef UX_HOST_CLASS_HID_KEYBOARD_KEY_LETTER_A_DEFAULT
50
#define UX_HOST_CLASS_HID_KEYBOARD_KEY_LETTER_A_DEFAULT UX_HID_KEYBOARD_KEY_LETTER_A
51
#endif
52
#ifndef UX_HOST_CLASS_HID_KEYBOARD_KEY_LETTER_Z_DEFAULT
53
#define UX_HOST_CLASS_HID_KEYBOARD_KEY_LETTER_Z_DEFAULT UX_HID_KEYBOARD_KEY_LETTER_Z
54
#endif
55
#ifndef UX_HOST_CLASS_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE_DEFAULT
56
#define UX_HOST_CLASS_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE_DEFAULT UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE
57
#endif
58
#ifndef UX_HOST_CLASS_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE_DEFAULT
59
#define UX_HOST_CLASS_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE_DEFAULT UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE
60
#endif
61
62
UCHAR ux_host_class_hid_keyboard_regular_array[] =
63
{
64
   UX_HOST_CLASS_HID_KEYBOARD_REGULAR_ARRAY_DEFAULT
65
};
66
67
UCHAR ux_host_class_hid_keyboard_shift_array[] =
68
{
69
   UX_HOST_CLASS_HID_KEYBOARD_SHIFT_ARRAY_DEFAULT
70
};
71
72
UCHAR ux_host_class_hid_keyboard_numlock_on_array[] =
73
{
74
   UX_HOST_CLASS_HID_KEYBOARD_NUMLOCK_ON_ARRAY_DEFAULT
75
};
76
77
UCHAR ux_host_class_hid_keyboard_numlock_off_array[] =
78
{
79
   UX_HOST_CLASS_HID_KEYBOARD_NUMLOCK_OFF_ARRAY_DEFAULT
80
};
81
82
UX_HOST_CLASS_HID_KEYBOARD_LAYOUT ux_host_class_hid_keyboard_layout =
83
{
84
    ux_host_class_hid_keyboard_regular_array,
85
    ux_host_class_hid_keyboard_shift_array,
86
    ux_host_class_hid_keyboard_numlock_on_array,
87
    ux_host_class_hid_keyboard_numlock_off_array,
88
    UX_HOST_CLASS_HID_KEYBOARD_KEYS_UPPER_RANGE_DEFAULT,
89
    UX_HOST_CLASS_HID_KEYBOARD_KEY_LETTER_A_DEFAULT,
90
    UX_HOST_CLASS_HID_KEYBOARD_KEY_LETTER_Z_DEFAULT,
91
    UX_HOST_CLASS_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE_DEFAULT,
92
    UX_HOST_CLASS_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE_DEFAULT,
93
};
94
95
/**************************************************************************/
96
/*                                                                        */
97
/*  FUNCTION                                               RELEASE        */
98
/*                                                                        */
99
/*    _ux_host_class_hid_keyboard_activate                PORTABLE C      */
100
/*                                                           6.1.11       */
101
/*  AUTHOR                                                                */
102
/*                                                                        */
103
/*    Chaoqiong Xiao, Microsoft Corporation                               */
104
/*                                                                        */
105
/*  DESCRIPTION                                                           */
106
/*                                                                        */
107
/*    This function performs the enumeration of a HID Keyboard Client.    */
108
/*                                                                        */
109
/*  INPUT                                                                 */
110
/*                                                                        */
111
/*    command                               Pointer to command            */
112
/*                                                                        */
113
/*  OUTPUT                                                                */
114
/*                                                                        */
115
/*    Completion Status                                                   */
116
/*                                                                        */
117
/*  CALLS                                                                 */
118
/*                                                                        */
119
/*    _ux_host_class_hid_periodic_report_start                            */
120
/*                                          Start periodic report         */
121
/*    _ux_host_class_hid_report_callback_register                         */
122
/*                                          Register callback             */
123
/*    _ux_host_class_hid_report_id_get      Get the report ID             */
124
/*    _ux_host_class_hid_idle_set           Set the idle rate             */
125
/*    _ux_host_class_hid_report_set         Do SET_REPORT                 */
126
/*    _ux_utility_memory_allocate           Allocate memory block         */
127
/*    _ux_utility_memory_free               Free memory block             */
128
/*    _ux_host_semaphore_create             Create semaphore              */
129
/*    _ux_host_semaphore_delete             Delete semaphore              */
130
/*    _ux_utility_thread_create             Create thread                 */
131
/*    _ux_utility_thread_delete             Delete thread                 */
132
/*                                                                        */
133
/*  CALLED BY                                                             */
134
/*                                                                        */
135
/*    HID Class                                                           */
136
/*                                                                        */
137
/*  RELEASE HISTORY                                                       */
138
/*                                                                        */
139
/*    DATE              NAME                      DESCRIPTION             */
140
/*                                                                        */
141
/*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
142
/*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
143
/*                                            used UX prefix to refer to  */
144
/*                                            TX symbols instead of using */
145
/*                                            them directly,              */
146
/*                                            resulting in version 6.1    */
147
/*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
148
/*                                            added standalone support,   */
149
/*                                            resulting in version 6.1.10 */
150
/*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
151
/*                                            fixed clients management,   */
152
/*                                            resulting in version 6.1.11 */
153
/*                                                                        */
154
/**************************************************************************/
155
168
UINT  _ux_host_class_hid_keyboard_activate(UX_HOST_CLASS_HID_CLIENT_COMMAND *command)
156
{
157
158
UX_HOST_CLASS_HID_REPORT_CALLBACK       call_back;
159
#if !defined(UX_HOST_STANDALONE)
160
UX_HOST_CLASS_HID_CLIENT_REPORT         client_report;
161
#endif
162
UX_HOST_CLASS_HID_REPORT_GET_ID         report_id;
163
UX_HOST_CLASS_HID                       *hid;
164
UX_HOST_CLASS_HID_CLIENT                *hid_client;
165
UX_HOST_CLASS_HID_CLIENT_KEYBOARD       *client_keyboard;
166
UX_HOST_CLASS_HID_KEYBOARD              *keyboard_instance;
167
ULONG                                   event_process_memory_size;
168
168
UINT                                    status = UX_SUCCESS;
169
#ifdef UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE
170
UX_HOST_CLASS_HID_FIELD                 *field;
171
#endif
172
173
174
    /* Get the instance to the HID class.  */
175
168
    hid =  command -> ux_host_class_hid_client_command_instance;
176
177
    /* Get some memory for both the HID class instance and copy of this client
178
       and for the callback.  */
179
    client_keyboard =  (UX_HOST_CLASS_HID_CLIENT_KEYBOARD *)
180
168
                    _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,
181
                                    sizeof(UX_HOST_CLASS_HID_CLIENT_KEYBOARD));
182
168
    if (client_keyboard == UX_NULL)
183
3
        return(UX_MEMORY_INSUFFICIENT);
184
185
    /* Use allocated memory.
186
     * - create a client copy.
187
     * - get keyboard instance.
188
     */
189
165
    keyboard_instance = &client_keyboard -> ux_host_class_hid_client_keyboard_keyboard;
190
165
    hid_client = &client_keyboard -> ux_host_class_hid_client_keyboard_client;
191
165
    _ux_utility_memory_copy(hid_client, hid -> ux_host_class_hid_client, sizeof(UX_HOST_CLASS_HID_CLIENT)); /* Use case of memcpy is verified. */
192
193
    /* Attach the remote control instance to the client instance.  */
194
165
    hid_client -> ux_host_class_hid_client_local_instance =  (VOID *) keyboard_instance;
195
196
    /* Save the HID instance in the client instance.  */
197
165
    keyboard_instance -> ux_host_class_hid_keyboard_hid =  hid;
198
199
#if defined(UX_HOST_STANDALONE)
200
201
    /* Set client task function.  */
202
    hid_client -> ux_host_class_hid_client_function = _ux_host_class_hid_keyboard_tasks_run;
203
204
    /* The instance is mounting now.  */
205
    keyboard_instance -> ux_host_class_hid_keyboard_state =  UX_HOST_CLASS_INSTANCE_MOUNTING;
206
#else
207
208
    /* The instance is live now.  */
209
165
    keyboard_instance -> ux_host_class_hid_keyboard_state =  UX_HOST_CLASS_INSTANCE_LIVE;
210
#endif
211
212
    /* Allocate the round-robin buffer that the remote control instance will use
213
     * to store the usages as they come in.
214
     * Size calculation overflow is checked near where _USAGE_ARRAY_LENGTH is defined.
215
     */
216
165
    keyboard_instance -> ux_host_class_hid_keyboard_usage_array =  (ULONG *)
217
165
                            _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_HOST_CLASS_HID_KEYBOARD_USAGE_ARRAY_LENGTH*4);
218
165
    if (keyboard_instance -> ux_host_class_hid_keyboard_usage_array == UX_NULL)
219
2
        status = (UX_MEMORY_INSUFFICIENT);
220
221
    /* If we are OK, go on.  */
222
165
    if (status == UX_SUCCESS)
223
    {
224
225
        /* Initialize the head and tail of this array.  */
226
163
        keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head =  keyboard_instance -> ux_host_class_hid_keyboard_usage_array;
227
163
        keyboard_instance -> ux_host_class_hid_keyboard_usage_array_tail =  keyboard_instance -> ux_host_class_hid_keyboard_usage_array;
228
229
        /* Get the report ID for the keyboard. The keyboard is a INPUT report.
230
        This should be 0 but in case. */
231
163
        report_id.ux_host_class_hid_report_get_report = UX_NULL;
232
163
        report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT;
233
163
        status =  _ux_host_class_hid_report_id_get(hid, &report_id);
234
    }
235
236
    /* If we are OK, go on.  */
237
165
    if (status == UX_SUCCESS)
238
    {
239
240
        /* Save the keyboard report ID. */
241
161
        keyboard_instance -> ux_host_class_hid_keyboard_id = (USHORT)(report_id.ux_host_class_hid_report_get_id);
242
243
#ifdef UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE
244
245
        /* Summarize number of usages to allocate state buffer for keyboard report.
246
           We reserve 3 bits for lock status, 8 bits for modifier status.
247
           We get number of keys from report of 8-bit array.
248
           Key usages bytes then saved if it's down.
249
           - 3 Locks - 8 Modifiers - N regular keys ...
250
         */
251
        keyboard_instance -> ux_host_class_hid_keyboard_key_count = 3 + 8;
252
        field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field;
253
        while(field)
254
        {
255
            if (field -> ux_host_class_hid_field_report_size == 8)
256
                keyboard_instance -> ux_host_class_hid_keyboard_key_count += field -> ux_host_class_hid_field_report_count;
257
            field = field -> ux_host_class_hid_field_next_field;
258
        }
259
260
        /* Process memory includes:
261
            - states for last [usage, value] and new [usage, value], (2 * 2) * max number of keys to log
262
            - actions for last and new buffers, 2 * max number of keys to log
263
         */
264
        UX_UTILITY_MULC_SAFE(keyboard_instance -> ux_host_class_hid_keyboard_key_count, 6, event_process_memory_size, status);
265
266
        /* Calculation overflow check.  */
267
        if (status == UX_SUCCESS)
268
#else
269
270
        /* We reserve 3 bytes for lock keys, 3 for processing.  */
271
161
        keyboard_instance -> ux_host_class_hid_keyboard_key_count = 3;
272
273
        /* key count 3, multiply 2 is int safe.  */
274
161
        event_process_memory_size = keyboard_instance -> ux_host_class_hid_keyboard_key_count * 2;
275
#endif
276
277
        {
278
279
        /* Allocate memory for usages states.  */
280
161
        keyboard_instance -> ux_host_class_hid_keyboard_key_state = (UCHAR *)
281
161
                            _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, event_process_memory_size);
282
161
        if (keyboard_instance -> ux_host_class_hid_keyboard_key_state == UX_NULL)
283
2
            status = UX_MEMORY_INSUFFICIENT;
284
    }
285
    }
286
287
    /* If we are OK, go on.  */
288
165
    if (status == UX_SUCCESS)
289
    {
290
291
        /* Initialize the report callback.  */
292
159
        call_back.ux_host_class_hid_report_callback_id =         keyboard_instance -> ux_host_class_hid_keyboard_id;
293
159
        call_back.ux_host_class_hid_report_callback_function =   _ux_host_class_hid_keyboard_callback;
294
159
        call_back.ux_host_class_hid_report_callback_buffer =     UX_NULL;
295
159
        call_back.ux_host_class_hid_report_callback_flags =      UX_HOST_CLASS_HID_REPORT_DECOMPRESSED;
296
159
        call_back.ux_host_class_hid_report_callback_length =     0;
297
298
        /* Register the report call back when data comes it on this report.  */
299
159
        status =  _ux_host_class_hid_report_callback_register(hid, &call_back);
300
    }
301
302
#if !defined(UX_HOST_STANDALONE)
303
304
    /* If we are OK, go on.  */
305
165
    if (status == UX_SUCCESS)
306
    {
307
308
        /* We need a semaphore now. This will be used to synchronize the HID report with the keyboard thread.  */
309
159
        status =  _ux_host_semaphore_create(&keyboard_instance -> ux_host_class_hid_keyboard_semaphore, "ux_host_class_hid_keyboard_semaphore", 0);
310
159
        if(status != UX_SUCCESS)
311
1
            status = (UX_SEMAPHORE_ERROR);
312
    }
313
314
    /* If we are OK, go on.  */
315
165
    if (status == UX_SUCCESS)
316
    {
317
318
        /* The HID Keyboard needs a Thread to process LED changes. This process is asynchronous
319
        to the callback because it involves using the commands on the Control Pipe which cannot
320
        be done during callbacks.  First allocate some stack memory.  */
321
158
        keyboard_instance -> ux_host_class_hid_keyboard_thread_stack =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
322
323
        /* Check if stack memory was allocated.  */
324
158
        if (keyboard_instance -> ux_host_class_hid_keyboard_thread_stack == UX_NULL)
325
2
            status = (UX_MEMORY_INSUFFICIENT);
326
    }
327
328
    /* If we are OK, go on.  */
329
165
    if (status == UX_SUCCESS)
330
331
        /* Then create the actual thread.  */
332
156
        status =  _ux_utility_thread_create(&keyboard_instance -> ux_host_class_hid_keyboard_thread, "ux_host_stack_keyboard_thread",_ux_host_class_hid_keyboard_thread,
333
                (ULONG) (ALIGN_TYPE) keyboard_instance, keyboard_instance -> ux_host_class_hid_keyboard_thread_stack,
334
                UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_KEYBOARD,
335
                UX_THREAD_PRIORITY_KEYBOARD, UX_NO_TIME_SLICE, UX_AUTO_START);
336
337
#endif
338
339
    /* If we are OK, go on.  */
340
165
    if (status == UX_SUCCESS)
341
    {
342
343
#if !defined(UX_HOST_STANDALONE)
344
        UX_THREAD_EXTENSION_PTR_SET(&(keyboard_instance -> ux_host_class_hid_keyboard_thread), keyboard_instance)
345
#endif
346
347
        /* Default state of keyboard is with NumLock on.  */
348
156
        keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= UX_HID_KEYBOARD_STATE_NUM_LOCK;
349
350
        /* We need to build the field for the LEDs. */
351
156
        keyboard_instance -> ux_host_class_hid_keyboard_led_mask =  keyboard_instance ->  ux_host_class_hid_keyboard_alternate_key_state &
352
                                                                    UX_HID_KEYBOARD_STATE_MASK_LOCK;
353
354
#if defined(UX_HOST_STANDALONE)
355
356
        /* Initialize the keyboard layout and use it to decode keys.  */
357
        keyboard_instance -> ux_host_class_hid_keyboard_layout = &ux_host_class_hid_keyboard_layout;
358
        keyboard_instance -> ux_host_class_hid_keyboard_keys_decode_disable = UX_FALSE;
359
360
        /* Remaining things will be done in ACTIVATE_WAIT.
361
            - SET_REPORT(LEDs)
362
            - SET_IDLE(KEYs, 0)
363
            - _periodic_report_start()  */
364
        keyboard_instance -> ux_host_class_hid_keyboard_enum_state = UX_STATE_WAIT;
365
366
        /* It's fine, replace client with our copy.  */
367
        hid -> ux_host_class_hid_client = hid_client;
368
        return(status);
369
#else
370
371
        /* We need to find the OUTPUT report for the keyboard LEDs.  */
372
156
        report_id.ux_host_class_hid_report_get_report = UX_NULL;
373
156
        report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT;
374
156
        status =  _ux_host_class_hid_report_id_get(hid, &report_id);
375
376
        /* The report ID should exist.  If there is an error, we do not proceed.  */
377
156
        if (status == UX_SUCCESS)
378
        {
379
380
            /* Memorize the report pointer.  */
381
152
            client_report.ux_host_class_hid_client_report =  report_id.ux_host_class_hid_report_get_report;
382
383
            /* The report set is raw since the LEDs mask is already in the right format.  */
384
152
            client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW;
385
386
            /* The length of this report is 1 byte.  */
387
152
            client_report.ux_host_class_hid_client_report_length = 1;
388
389
            /* The output report buffer is the LED mask field.  */
390
152
            client_report.ux_host_class_hid_client_report_buffer = &keyboard_instance -> ux_host_class_hid_keyboard_led_mask;
391
392
            /* The HID class will perform the SET_REPORT command.  Do not check for error here, this is
393
               handled by the function itself.  */
394
152
            status = _ux_host_class_hid_report_set(hid, &client_report);
395
        }
396
397
        /* If we are OK, go on.  */
398
156
        if (status == UX_SUCCESS)
399
        {
400
401
            /* Set the idle rate of the keyboard to 0. This way a report is generated only when there is an activity.  */
402
148
            status = _ux_host_class_hid_idle_set(hid, 0, keyboard_instance -> ux_host_class_hid_keyboard_id);
403
        }
404
405
        /* If we are OK, go on.  */
406
156
        if (status == UX_SUCCESS)
407
        {
408
409
            /* Initialize the keyboard layout and use it to decode keys.  */
410
146
            keyboard_instance -> ux_host_class_hid_keyboard_layout = &ux_host_class_hid_keyboard_layout;
411
146
            keyboard_instance -> ux_host_class_hid_keyboard_keys_decode_disable = UX_FALSE;
412
413
            /* Start the periodic report.  */
414
146
            status =  _ux_host_class_hid_periodic_report_start(hid);
415
        }
416
417
        /* If we are OK, go on.  */
418
156
        if (status == UX_SUCCESS)
419
        {
420
421
            /* It's fine, replace client copy.  */
422
145
            hid -> ux_host_class_hid_client = hid_client;
423
424
            /* If all is fine and the device is mounted, we may need to inform the application
425
               if a function has been programmed in the system structure.  */
426
145
            if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
427
            {
428
429
                /* Call system change function.  */
430
119
                _ux_system_host ->  ux_system_host_change_function(UX_HID_CLIENT_INSERTION, hid -> ux_host_class_hid_class, (VOID *) hid_client);
431
            }
432
433
            /* If trace is enabled, insert this event into the trace buffer.  */
434
            UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_HID_KEYBOARD_ACTIVATE, hid, keyboard_instance, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
435
436
            /* Return completion status.  */
437
145
            return(status);
438
        }
439
440
        /* There is error, delete thread.  */
441
11
        _ux_utility_thread_delete(&keyboard_instance -> ux_host_class_hid_keyboard_thread);
442
#endif
443
    }
444
445
    /* We are here if there is error.  */
446
447
    /* Free usage state.  */
448
20
    if (keyboard_instance -> ux_host_class_hid_keyboard_key_state)
449
14
        _ux_utility_memory_free(keyboard_instance -> ux_host_class_hid_keyboard_key_state);
450
451
#if !defined(UX_HOST_STANDALONE)
452
453
    /* Free stack.  */
454
20
    if (keyboard_instance -> ux_host_class_hid_keyboard_thread_stack)
455
11
        _ux_utility_memory_free(keyboard_instance -> ux_host_class_hid_keyboard_thread_stack);
456
457
    /* Delete semaphore.  */
458
20
    if (keyboard_instance -> ux_host_class_hid_keyboard_semaphore.tx_semaphore_id != UX_EMPTY)
459
13
        _ux_host_semaphore_delete(&keyboard_instance -> ux_host_class_hid_keyboard_semaphore);
460
461
#endif
462
463
    /* Free usage array.  */
464
20
    if (keyboard_instance -> ux_host_class_hid_keyboard_usage_array)
465
18
        _ux_utility_memory_free(keyboard_instance -> ux_host_class_hid_keyboard_usage_array);
466
467
    /* Free instance.  */
468
20
    _ux_utility_memory_free(keyboard_instance);
469
470
    /* Return completion status.  */
471
20
    return(status);
472
}