1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
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 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_host_class_hid_keyboard_callback                PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function is the callback mechanism for a report registration.  */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    callback                              Pointer to callback           */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    None                                                                */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    _ux_utility_memory_copy               Copy memory                   */
58 /*    _ux_utility_memory_set                Set memory                    */
59 /*                                                                        */
60 /*  CALLED BY                                                             */
61 /*                                                                        */
62 /*    HID Class when a report is generated                                */
63 /*                                                                        */
64 /*  RELEASE HISTORY                                                       */
65 /*                                                                        */
66 /*    DATE              NAME                      DESCRIPTION             */
67 /*                                                                        */
68 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
69 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
70 /*                                            verified memset and memcpy  */
71 /*                                            cases,                      */
72 /*                                            resulting in version 6.1    */
73 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
74 /*                                            added standalone support,   */
75 /*                                            resulting in version 6.1.10 */
76 /*                                                                        */
77 /**************************************************************************/
_ux_host_class_hid_keyboard_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK * callback)78 VOID  _ux_host_class_hid_keyboard_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback)
79 {
80 
81 /* This array contains the bit for each alternate key (modifier or lock key)
82    that we report to the application.  For example, if you wanted to set the
83    bit for the CAPS_LOCK key, you would do:
84         keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= alternate_key_bits[0];
85    Index 0 is used since it corresponds to the CAPS_LOCK bit in the array. Note
86    that _alternate_key_state is what we report to the application.  */
87 const ULONG                         alternate_key_bits[] = {
88     UX_HID_KEYBOARD_STATE_CAPS_LOCK,
89     UX_HID_KEYBOARD_STATE_NUM_LOCK,
90     UX_HID_KEYBOARD_STATE_SCROLL_LOCK,
91     UX_HID_KEYBOARD_STATE_LEFT_CTRL,
92     UX_HID_KEYBOARD_STATE_LEFT_SHIFT,
93     UX_HID_KEYBOARD_STATE_LEFT_ALT,
94     UX_HID_KEYBOARD_STATE_LEFT_GUI,
95     UX_HID_KEYBOARD_STATE_RIGHT_CTRL,
96     UX_HID_KEYBOARD_STATE_RIGHT_SHIFT,
97     UX_HID_KEYBOARD_STATE_RIGHT_ALT,
98     UX_HID_KEYBOARD_STATE_RIGHT_GUI,
99 };
100 
101 /* Define the indices for each alternate key in the alternate key bits array.  */
102 
103 #define ALTERNATE_KEY_BITS_IDX_CAPS_LOCK        ( 0)
104 #define ALTERNATE_KEY_BITS_IDX_NUM_LOCK         ( 1)
105 #define ALTERNATE_KEY_BITS_IDX_SCROLL_LOCK      ( 2)
106 
107 #define ALTERNATE_KEY_BITS_IDX_LEFT_CTRL        ( 3)
108 #define ALTERNATE_KEY_BITS_IDX_LEFT_SHIFT       ( 4)
109 #define ALTERNATE_KEY_BITS_IDX_LEFT_ALT         ( 5)
110 #define ALTERNATE_KEY_BITS_IDX_LEFT_GUI         ( 6)
111 #define ALTERNATE_KEY_BITS_IDX_RIGHT_CTRL       ( 7)
112 #define ALTERNATE_KEY_BITS_IDX_RIGHT_SHIFT      ( 8)
113 #define ALTERNATE_KEY_BITS_IDX_RIGHT_ALT        ( 9)
114 #define ALTERNATE_KEY_BITS_IDX_RIGHT_GUI        (10)
115 
116 /* Define a macro to get the index of a modifier key in the alternate key bits array.  */
117 #define GET_ALTERNATE_KEY_BITS_IDX(usage)       ((usage) - UX_HID_MODIFIER_KEY_LEFT_CONTROL + ALTERNATE_KEY_BITS_IDX_LEFT_CTRL)
118 
119 /* Define key states.  */
120 #define KEY_STATE_REGULAR                       (11)
121 #define KEY_STATE_NO_KEY                        (12)
122 
123 #define KEY_UP                                  ( 0)
124 #define KEY_KEEP                                ( 1)
125 #define KEY_DOWN                                ( 2)
126 #define KEY_DEL                                 ( 3)
127 
128 
129 UX_HOST_CLASS_HID_CLIENT            *hid_client;
130 UX_HOST_CLASS_HID_KEYBOARD          *keyboard_instance;
131 UX_HOST_CLASS_HID_KEYBOARD_LAYOUT   *keyboard_layout;
132 UCHAR                               *keypad_array;
133 ULONG                               *array_head;
134 ULONG                               *array_tail;
135 ULONG                               *array_end;
136 ULONG                               *array_start;
137 ULONG                               *report_buffer;
138 ULONG                               *report_buffer_end;
139 ULONG                               keyboard_char = 0;
140 ULONG                               shift_on;
141 ULONG                               capslock_on;
142 ULONG                               numlock_on;
143 ULONG                               key_usage;
144 ULONG                               key_value;
145 
146 /* This variable either contains an index into the alternate key bit array,
147    or a value that describes the current key i.e. regular key or no key.  */
148 UINT                                key_state;
149 
150 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
151 UCHAR                               *previous_lock_key_states;
152 UCHAR                               *current_lock_key_states;
153 #else
154 UINT                                i, i_save, new_count;
155 UCHAR                               *state_usage;
156 UCHAR                               *state_value;
157 UCHAR                               *state_action;
158 #endif
159 
160 
161     /* Get the HID client instance that issued the callback.  */
162     hid_client = callback -> ux_host_class_hid_report_callback_client;
163 
164     /* Get the keyboard local instance.  */
165     keyboard_instance =  (UX_HOST_CLASS_HID_KEYBOARD *) hid_client -> ux_host_class_hid_client_local_instance;
166 
167     /* Get the report buffer.  */
168     report_buffer = (ULONG *)callback -> ux_host_class_hid_report_callback_buffer;
169 
170     /* Get the end of report buffer.  */
171     report_buffer_end = &report_buffer[callback -> ux_host_class_hid_report_callback_actual_length];
172 
173 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
174 
175     /* Get the previous states of the lock keys.  */
176     previous_lock_key_states = &keyboard_instance -> ux_host_class_hid_keyboard_key_state[0];
177 
178     /* Get the current states of the lock keys and immediately initialize them to zero;
179        if a lock key is not pressed in this report, it will remain zero (not pressed).  */
180     current_lock_key_states = &keyboard_instance -> ux_host_class_hid_keyboard_key_state[3];
181     _ux_utility_memory_set(current_lock_key_states, 0, 3); /* Use case of memset is verified. */
182 
183     /* Scan the report buffer and decode it.  */
184     while(report_buffer < report_buffer_end)
185     {
186 
187         /* Get usage and value from buffer.  */
188         key_usage = *report_buffer ++;
189         key_value = *report_buffer ++;
190 
191         /* Analyze the usage we have received.  We eliminate the page from the usage.  */
192         key_usage &= 0xFF;
193 #else
194 
195     /* Initialize key states for report processing.  */
196     state_usage  = keyboard_instance -> ux_host_class_hid_keyboard_key_state;
197     state_value  = state_usage  + keyboard_instance -> ux_host_class_hid_keyboard_key_count * 2;
198     state_action = state_value  + keyboard_instance -> ux_host_class_hid_keyboard_key_count * 2;
199 
200     /* Reset state actions to DEL(not received).  */
201     _ux_utility_memory_set(state_usage + keyboard_instance -> ux_host_class_hid_keyboard_key_count, 0, keyboard_instance -> ux_host_class_hid_keyboard_key_count); /* Use case of memset is verified. */
202     _ux_utility_memory_set(state_value + keyboard_instance -> ux_host_class_hid_keyboard_key_count, 0, keyboard_instance -> ux_host_class_hid_keyboard_key_count); /* Use case of memset is verified. */
203     _ux_utility_memory_set(state_action, KEY_DEL, keyboard_instance -> ux_host_class_hid_keyboard_key_count * 2); /* Use case of memset is verified. */
204 
205     new_count = keyboard_instance -> ux_host_class_hid_keyboard_key_count;
206     while(report_buffer < report_buffer_end)
207     {
208 
209         /* Get usage and value from buffer.  */
210         key_usage = *report_buffer ++;
211         key_value = *report_buffer ++;
212 
213         /* Analyze the usage we have received.  We eliminate the page from the usage.  */
214         key_usage &= 0xFF;
215         key_value &= 0xFF;
216 
217         /* If there is no key or in phantom state (roll over), skip.  */
218         if (key_usage <= UX_HID_KEYBOARD_PHANTOM_STATE)
219             continue;
220 
221         /* Check if the key is previously reported.  */
222         for (i = 0; i < keyboard_instance -> ux_host_class_hid_keyboard_key_count; i ++)
223         {
224 
225             /* Check if it's modified.  */
226             if (state_usage[i] == key_usage)
227             {
228 
229                 /* Replace action state.  */
230                 state_action[i] = (state_value[i] == key_value) ? KEY_KEEP : (key_value ? KEY_DOWN : KEY_UP);
231 
232                 /* Replace key value.  */
233                 state_value[i] = key_value;
234                 break;
235             }
236         }
237 
238         /* When there is new key, add to new key list.  */
239         if (i == keyboard_instance -> ux_host_class_hid_keyboard_key_count)
240         {
241 
242             /* Add key value.  */
243             state_usage [new_count] = key_usage;
244             state_value [new_count] = key_value;
245 
246             /* Add key action.  */
247             state_action[new_count] = key_value ? KEY_DOWN : KEY_KEEP;
248 
249             new_count ++;
250         }
251     } /* while(report_buffer < report_buffer_end) */
252 
253     /* Process pending key states.  */
254     i_save = 0;
255     for (i = 0; i < new_count; i ++)
256     {
257 
258         /* Get state value from buffer.  */
259         key_usage = state_usage[i];
260         key_value = state_value[i];
261         key_state  = state_action[i];
262 
263         /* If no key, just skip.  */
264         if (key_usage == 0)
265             continue;
266 
267         /* If key not reported, add up event if it's enabled.  */
268         if (key_state == KEY_DEL)
269         {
270 
271             /* Clear state, do not save.  */
272             state_usage[i]  = 0;
273             state_action[i] = KEY_UP;
274         }
275 
276         /* Key reported, process it.  */
277         else
278         {
279 
280             /* We need to save key anyway.  */
281             if (i_save < i)
282             {
283                 state_usage[i_save] = key_usage;
284                 state_value[i_save] = key_value;
285             }
286             i_save ++;
287         }
288 
289         /* Skip keep keys.  */
290         if (state_action[i] == KEY_KEEP)
291             continue;
292 
293         /* Now handle key event.  */
294         keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state &= ~(UX_HID_KEYBOARD_STATE_FUNCTION | UX_HID_KEYBOARD_STATE_KEY_UP);
295 #endif /* UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE */
296 
297         /* Determine what key this is.  */
298         switch(key_usage)
299         {
300 
301         /* This is the usage of a modifier key. Set or clear the appropriate
302            bits in the alternate key state bitmap.  */
303         case    UX_HID_MODIFIER_KEY_LEFT_SHIFT           :
304         case    UX_HID_MODIFIER_KEY_RIGHT_SHIFT          :
305         case    UX_HID_MODIFIER_KEY_LEFT_ALT             :
306         case    UX_HID_MODIFIER_KEY_RIGHT_ALT            :
307         case    UX_HID_MODIFIER_KEY_RIGHT_CONTROL        :
308         case    UX_HID_MODIFIER_KEY_LEFT_CONTROL         :
309         case    UX_HID_MODIFIER_KEY_RIGHT_GUI            :
310         case    UX_HID_MODIFIER_KEY_LEFT_GUI             :
311 
312             key_state =  GET_ALTERNATE_KEY_BITS_IDX(key_usage);
313 
314             /* We have received a modifier Key. Remember the state. */
315             if (key_value > 0)
316                 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= alternate_key_bits[key_state];
317             else
318                 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state &= ~alternate_key_bits[key_state];
319 
320             break;
321 
322         /* This is the usage of a LOCK key. Just save the its index in the alternate
323            key bit array.  */
324 
325         case    UX_HID_LED_KEY_CAPS_LOCK                 :
326             key_state = ALTERNATE_KEY_BITS_IDX_CAPS_LOCK;
327             break;
328 
329         case    UX_HID_LED_KEY_NUM_LOCK                  :
330             key_state = ALTERNATE_KEY_BITS_IDX_NUM_LOCK;
331             break;
332 
333         case    UX_HID_LED_KEY_SCROLL_LOCK               :
334             key_state = ALTERNATE_KEY_BITS_IDX_SCROLL_LOCK;
335             break;
336 
337 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
338 
339         /* Usage no key.  */
340         case    UX_HID_KEYBOARD_NO_KEY                  :
341         case    UX_HID_KEYBOARD_PHANTOM_STATE           :
342             key_state = KEY_STATE_NO_KEY;
343             break;
344 #endif
345 
346         /* This is the usage of a regular key. Here, we just get the decoded
347            value; we will add it to the queue later.  */
348         default :
349 
350             /* By default the key will be saved.  */
351             key_state = KEY_STATE_REGULAR;
352 
353             /* Skip decode if decode is disabled.  */
354             if (keyboard_instance -> ux_host_class_hid_keyboard_keys_decode_disable == UX_TRUE)
355             {
356 
357                 /* Use raw data (scan code) as key code.  */
358                 keyboard_char = key_value;
359                 break;
360             }
361 
362             /* Get keyboard layout instance.  */
363             keyboard_layout = keyboard_instance -> ux_host_class_hid_keyboard_layout;
364 
365             /* Is this key outside the valid range?   */
366             if (key_value > keyboard_layout -> ux_host_class_hid_keyboard_layout_keys_upper_range)
367             {
368 
369                 /* Set a flag to discard it.  */
370                 key_state = KEY_STATE_NO_KEY;
371                 break;
372             }
373 
374             /* We have received a regular key. Depending on the state of the shift or numlock status, the key should be mapped into
375                 one of the translation tables.  We verify if the key is within our mapping range. */
376 
377             /* Get SHIFT, CAPS_LOCK and NUM_LOCK states.  */
378             shift_on = (keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state & UX_HID_KEYBOARD_STATE_SHIFT) ? UX_TRUE : UX_FALSE;
379             capslock_on = (keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state & UX_HID_KEYBOARD_STATE_CAPS_LOCK) ? UX_TRUE : UX_FALSE;
380             numlock_on = (keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state & UX_HID_KEYBOARD_STATE_NUM_LOCK) ? UX_TRUE : UX_FALSE;
381 
382             /* Check if we have letters ('a' to 'z').  */
383             if (key_value >= keyboard_layout -> ux_host_class_hid_keyboard_layout_letters_lower_range &&
384                 key_value <= keyboard_layout -> ux_host_class_hid_keyboard_layout_letters_upper_range)
385             {
386 
387                 /* We have letters, check the Shift and CapsLock state.  */
388                 if (shift_on != capslock_on)
389 
390                     /* Shift and CapsLock in different state: upper case.  */
391                     keyboard_char = keyboard_layout -> ux_host_class_hid_keyboard_layout_shift_array[key_value];
392                 else
393 
394                     /* Lower case.  */
395                     keyboard_char = keyboard_layout -> ux_host_class_hid_keyboard_layout_regular_array[key_value];
396 
397                 break; /* default: */
398             }
399 
400             /* Check if we have received a keypad key. They may be multiplexed. */
401             if (key_value >= keyboard_layout -> ux_host_class_hid_keyboard_layout_keypad_lower_range &&
402                 key_value <= keyboard_layout -> ux_host_class_hid_keyboard_layout_keypad_upper_range)
403             {
404 
405                 /* We have a keypad key. Check the NumLock state.  */
406                 if (numlock_on)
407 
408                     /* Numlock is on.  */
409                     keypad_array = keyboard_layout -> ux_host_class_hid_keyboard_layout_numlock_on_array;
410 
411                 else
412 
413                     /* Numlock is off. */
414                     keypad_array = keyboard_layout -> ux_host_class_hid_keyboard_layout_numlock_off_array;
415 
416                 /* Decode the keypad key.  */
417                 keyboard_char = keypad_array[key_value -
418                                                 keyboard_layout -> ux_host_class_hid_keyboard_layout_keypad_lower_range];
419 
420                 break; /* default: */
421             }
422 
423             /* Check the state of the shift.  */
424             if (shift_on)
425 
426                 /* We get the key from the shifted array.  */
427                 keyboard_char = keyboard_layout -> ux_host_class_hid_keyboard_layout_shift_array[key_value];
428 
429             else
430 
431                 /* We get the key from the regular array.  */
432                 keyboard_char = keyboard_layout -> ux_host_class_hid_keyboard_layout_regular_array[key_value];
433 
434             break; /* default: */
435 
436         } /* switch(key_usage)  */
437 
438 #if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
439 
440         if (state_action[i] == KEY_UP)
441 
442 #if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY)
443 
444             /* Skip save.  */
445             continue;
446 #else
447 
448             /* Save key up state.  */
449             keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= UX_HID_KEYBOARD_STATE_KEY_UP;
450 #endif
451 #endif
452 
453         /* If there is no key, just try next.  */
454         if (key_state == KEY_STATE_NO_KEY)
455             continue;
456 
457         /* Is this a LOCK key (i.e. caps lock, scroll lock or num lock)?  */
458         if (key_state <= ALTERNATE_KEY_BITS_IDX_SCROLL_LOCK)
459         {
460 
461             /* Skip decode if decode is disabled.  */
462             if (keyboard_instance -> ux_host_class_hid_keyboard_keys_decode_disable == UX_TRUE)
463             {
464 
465                 /* Use raw data (scan code) as key code.  */
466                 keyboard_char = key_value;
467             }
468             else
469             {
470 
471 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
472 
473                 /* Reflect the press in the current lock key state. */
474                 current_lock_key_states[key_state] = (UCHAR)key_value;
475 
476                 /* Take action only if key state changes from up to down (pressed).
477                    Remember that the nothing happens when lock keys are released.  */
478                 if (previous_lock_key_states[key_state] == 0)
479 #elif !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY)
480 
481                 /* Take action only if key state changes from up to down (pressed).  */
482                 if (state_action[i] == KEY_DOWN)
483 #endif
484                 {
485 
486                     /* Reflect the change in the keyboard state.  The state should be inverted.  */
487                     if (keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state & alternate_key_bits[key_state])
488                         keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state &= (ULONG)~alternate_key_bits[key_state];
489                     else
490                         keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= alternate_key_bits[key_state];
491 
492 #if defined(UX_HOST_STANDALONE)
493 
494                     /* Let background task to set LED status.  */
495                     keyboard_instance -> ux_host_class_hid_keyboard_out_state = UX_STATE_WAIT;
496 #else
497 
498                     /* Wake up the keyboard thread semaphore.  */
499                     _ux_host_semaphore_put(&keyboard_instance -> ux_host_class_hid_keyboard_semaphore);
500 #endif
501                 }
502 
503 #if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE) && defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_LOCK_KEYS)
504 
505                 /* Use usage and UX_HID_KEYBOARD_STATE_FUNCTION.  */
506                 keyboard_char = key_usage;
507                 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= UX_HID_KEYBOARD_STATE_FUNCTION;
508 
509 #else
510 
511                 /* Check next usage & value.  */
512                 continue;
513 #endif
514             }
515         }
516 
517         /* If it's modifier, check next usage & value.  */
518         else if (key_state < KEY_STATE_REGULAR)
519         {
520 #if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE) && defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_MODIFIER_KEYS)
521 
522             /* Use usage and UX_HID_KEYBOARD_STATE_FUNCTION.  */
523             keyboard_char = key_usage;
524             keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= UX_HID_KEYBOARD_STATE_FUNCTION;
525 #else
526 
527             /* Check next usage & value.  */
528             continue;
529 #endif
530         }
531 
532         /* If we get here, then we have a regular key. Now it's time to save
533            raw/decoded key in the key queue.  */
534 
535         /* This key should now be inserted in the circular array for the application to retrieve it.  */
536         array_start =  keyboard_instance -> ux_host_class_hid_keyboard_usage_array;
537         array_end =    array_start + UX_HOST_CLASS_HID_KEYBOARD_USAGE_ARRAY_LENGTH;
538         array_head =   keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head;
539         array_tail =   keyboard_instance -> ux_host_class_hid_keyboard_usage_array_tail;
540 
541         /* We have a single usage/value. We have to store it into the array. If the array overflows,
542             there is no mechanism for flow control here so we ignore the usage/value until the
543             applications makes more room in the array.  */
544 
545         /* Is the head at the end of the array and need to loop back?  */
546         if ((array_head + 2) >= array_end)
547             array_head =  array_start;
548         else
549             array_head +=  2;
550 
551         /* Do we have enough space to store the new usage? */
552         if (array_head != array_tail)
553         {
554 
555             /* Yes, we have some space.  */
556             *keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head =        keyboard_char;
557             *(keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head + 1) =  keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state;
558 
559             /* Now update the array head.  */
560             keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head =  array_head;
561         }
562         else
563 
564             /* Error trap. */
565             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW);
566 
567     } /* while(report_buffer < report_buffer_end) */
568 
569 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
570 
571     /* Copy the current lock key states to the previous states. Note that if
572        a lock key wasn't down in this report, its current state would have
573        remained zero (not pressed).  */
574     _ux_utility_memory_copy(previous_lock_key_states, current_lock_key_states, 3); /* Use case of memcpy is verified. */
575 #else
576 
577     /* Clear redundant data after last saved key.  */
578     _ux_utility_memory_set(state_usage + i_save, 0, keyboard_instance -> ux_host_class_hid_keyboard_key_count - i_save); /* Use case of memset is verified. */
579 #endif
580 
581     /* Return to caller.  */
582     return;
583 }
584 
585