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