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 Class                                                           */
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_stack.h"
30 
31 
32 #if defined(UX_HOST_STANDALONE)
33 #define UX_HOST_CLASS_HID_ENUM_HID_DESC_READ            (UX_STATE_WAIT)
34 #define UX_HOST_CLASS_HID_ENUM_HID_DESC_PARSE           (UX_STATE_CLASS_STEP + 1)
35 #define UX_HOST_CLASS_HID_ENUM_REPORT_DESC_READ         (UX_STATE_CLASS_STEP + 2)
36 #define UX_HOST_CLASS_HID_ENUM_REPORT_DESC_PARSE        (UX_STATE_CLASS_STEP + 3)
37 #define UX_HOST_CLASS_HID_ENUM_CLIENT_SEARCH            (UX_STATE_CLASS_STEP + 4)
38 #define UX_HOST_CLASS_HID_ENUM_CLIENT_ACTIVATE_WAIT     (UX_STATE_CLASS_STEP + 6)
39 #define UX_HOST_CLASS_HID_ENUM_TRANSFER_WAIT            (UX_STATE_CLASS_STEP + 7)
40 #define UX_HOST_CLASS_HID_ENUM_ERROR                    (UX_STATE_CLASS_STEP + 8)
41 #define UX_HOST_CLASS_HID_ENUM_DONE                     (UX_STATE_CLASS_STEP + 9)
42 
43 
44 static inline UINT _ux_host_class_hid_activate_wait(UX_HOST_CLASS_COMMAND *command);
45 #endif
46 
47 
48 /**************************************************************************/
49 /*                                                                        */
50 /*  FUNCTION                                               RELEASE        */
51 /*                                                                        */
52 /*    _ux_host_class_hid_entry                            PORTABLE C      */
53 /*                                                           6.1.12       */
54 /*  AUTHOR                                                                */
55 /*                                                                        */
56 /*    Chaoqiong Xiao, Microsoft Corporation                               */
57 /*                                                                        */
58 /*  DESCRIPTION                                                           */
59 /*                                                                        */
60 /*    This function is the entry point of the HID class. It will be       */
61 /*    called by the USB stack enumeration module when there is a new      */
62 /*    device on the bus or when there is a device extraction.             */
63 /*                                                                        */
64 /*  INPUT                                                                 */
65 /*                                                                        */
66 /*    command                               Pointer to command            */
67 /*                                                                        */
68 /*  OUTPUT                                                                */
69 /*                                                                        */
70 /*    Completion Status                                                   */
71 /*                                                                        */
72 /*  CALLS                                                                 */
73 /*                                                                        */
74 /*    _ux_host_class_hid_activate           Activate HID class            */
75 /*    _ux_host_class_hid_deactivate         Deactivate HID class          */
76 /*    _ux_utility_memory_free               Free memory                   */
77 /*                                                                        */
78 /*  CALLED BY                                                             */
79 /*                                                                        */
80 /*    Application                                                         */
81 /*    HID Class                                                           */
82 /*                                                                        */
83 /*  RELEASE HISTORY                                                       */
84 /*                                                                        */
85 /*    DATE              NAME                      DESCRIPTION             */
86 /*                                                                        */
87 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
88 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            added destroy command,      */
90 /*                                            resulting in version 6.1    */
91 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
92 /*                                            added standalone support,   */
93 /*                                            resulting in version 6.1.10 */
94 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
95 /*                                            fixed uninited variable,    */
96 /*                                            fixed parameter/variable    */
97 /*                                            names conflict C++ keyword, */
98 /*                                            resulting in version 6.1.12 */
99 /*                                                                        */
100 /**************************************************************************/
_ux_host_class_hid_entry(UX_HOST_CLASS_COMMAND * command)101 UINT  _ux_host_class_hid_entry(UX_HOST_CLASS_COMMAND *command)
102 {
103 
104 UINT                                status;
105 INT                                 scan_index;
106 UX_HOST_CLASS_HID_CLIENT            *client;
107 UX_HOST_CLASS_HID_CLIENT_COMMAND    client_command;
108 
109 
110     /* The command request will tell us we need to do here, either a enumeration
111        query, an activation or a deactivation.  */
112     switch (command -> ux_host_class_command_request)
113     {
114 
115     case UX_HOST_CLASS_COMMAND_QUERY:
116 
117         /* The query command is used to let the stack enumeration process know if we want to own
118            this device or not.  */
119         if ((command -> ux_host_class_command_usage == UX_HOST_CLASS_COMMAND_USAGE_CSP) &&
120             (command -> ux_host_class_command_class == UX_HOST_CLASS_HID_CLASS))
121             return(UX_SUCCESS);
122         else
123             return(UX_NO_CLASS_MATCH);
124 
125 
126     case UX_HOST_CLASS_COMMAND_ACTIVATE:
127 
128         /* The activate command is used when the device inserted has found a parent and
129            is ready to complete the enumeration.   */
130 
131         status =  _ux_host_class_hid_activate(command);
132         return(status);
133 
134 
135 #if defined(UX_HOST_STANDALONE)
136     case UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT:
137         status = _ux_host_class_hid_activate_wait(command);
138         return(status);
139 #endif
140 
141 
142     case UX_HOST_CLASS_COMMAND_DEACTIVATE:
143 
144         /* The deactivate command is used when the device has been extracted either
145            directly or when its parents has been extracted.  */
146 
147         status =  _ux_host_class_hid_deactivate(command);
148         return(status);
149 
150     case UX_HOST_CLASS_COMMAND_DESTROY:
151 
152         /* The destroy command is used when the class is unregistered.  */
153 
154         /* Free allocated resources for clients.  */
155         if (command -> ux_host_class_command_class_ptr -> ux_host_class_client != UX_NULL)
156         {
157 
158             /* Get client.  */
159             client = command -> ux_host_class_command_class_ptr -> ux_host_class_client;
160 
161             /* Inform clients for destroy.  */
162             for (scan_index = 0; scan_index < UX_HOST_CLASS_HID_MAX_CLIENTS; scan_index ++)
163             {
164 
165                 /* Inform client for destroy.  */
166                 client_command.ux_host_class_hid_client_command_request = UX_HOST_CLASS_COMMAND_DESTROY;
167                 client_command.ux_host_class_hid_client_command_container = (VOID *)command -> ux_host_class_command_class_ptr;
168                 client -> ux_host_class_hid_client_handler(&client_command);
169             }
170 
171             /* Free clients memory.  */
172             _ux_utility_memory_free(command -> ux_host_class_command_class_ptr -> ux_host_class_client);
173             command -> ux_host_class_command_class_ptr -> ux_host_class_client = UX_NULL;
174         }
175         return(UX_SUCCESS);
176 
177     default:
178 
179         /* Error trap. */
180         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
181 
182         /* If trace is enabled, insert this event into the trace buffer.  */
183         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
184 
185         /* Return error status.  */
186         return(UX_FUNCTION_NOT_SUPPORTED);
187     }
188 }
189 
190 #if defined(UX_HOST_STANDALONE)
_ux_host_class_hid_descriptor_read(UX_HOST_CLASS_HID * hid)191 static inline VOID _ux_host_class_hid_descriptor_read(UX_HOST_CLASS_HID *hid)
192 {
193 UX_INTERFACE                    *interface_ptr;
194 UX_CONFIGURATION                *configuration;
195 UX_ENDPOINT                     *control_endpoint;
196 UX_TRANSFER                     *transfer_request;
197 
198     /* We need to get the default control endpoint transfer request pointer.  */
199     control_endpoint =  &hid -> ux_host_class_hid_device -> ux_device_control_endpoint;
200     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
201 
202     /* Need to allocate memory for the descriptor.  */
203     interface_ptr = hid -> ux_host_class_hid_interface;
204     configuration = interface_ptr -> ux_interface_configuration;
205     hid -> ux_host_class_hid_allocated = _ux_utility_memory_allocate(
206                     UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY,
207                     configuration -> ux_configuration_descriptor.wTotalLength);
208     if (hid -> ux_host_class_hid_allocated == UX_NULL)
209     {
210 
211         /* Next: error.  */
212         hid -> ux_host_class_hid_status = UX_MEMORY_INSUFFICIENT;
213         hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_ERROR;
214         return;
215     }
216 
217     /* Create a transfer request for the GET_DESCRIPTOR request.  */
218     transfer_request -> ux_transfer_request_data_pointer =      hid -> ux_host_class_hid_allocated;
219     transfer_request -> ux_transfer_request_requested_length =  configuration -> ux_configuration_descriptor.wTotalLength;
220     transfer_request -> ux_transfer_request_function =          UX_GET_DESCRIPTOR;
221     transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
222     transfer_request -> ux_transfer_request_value =             UX_CONFIGURATION_DESCRIPTOR_ITEM << 8;
223     transfer_request -> ux_transfer_request_index =             0;
224     UX_TRANSFER_STATE_RESET(transfer_request);
225 
226     /* Next: transfer and parse.  */
227     hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_TRANSFER_WAIT;
228     hid -> ux_host_class_hid_next_state = UX_HOST_CLASS_HID_ENUM_HID_DESC_PARSE;
229 }
_ux_host_class_hid_report_descriptor_read(UX_HOST_CLASS_HID * hid)230 static inline VOID _ux_host_class_hid_report_descriptor_read(UX_HOST_CLASS_HID *hid)
231 {
232 UX_ENDPOINT                     *control_endpoint;
233 UX_TRANSFER                     *transfer_request;
234 
235     /* We need to get the default control endpoint transfer request pointer.  */
236     control_endpoint =  &hid -> ux_host_class_hid_device -> ux_device_control_endpoint;
237     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
238 
239     /* Need to allocate memory for the descriptor.  */
240     hid -> ux_host_class_hid_allocated = _ux_utility_memory_allocate(
241                     UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY,
242                     hid -> ux_host_class_hid_descriptor.wItemLength);
243     if (hid -> ux_host_class_hid_allocated == UX_NULL)
244     {
245 
246         /* Next: error.  */
247         hid -> ux_host_class_hid_status = UX_MEMORY_INSUFFICIENT;
248         hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_ERROR;
249         return;
250     }
251 
252     /* Create a transfer request for the GET_DESCRIPTOR request.  */
253     transfer_request -> ux_transfer_request_data_pointer =      hid -> ux_host_class_hid_allocated;
254     transfer_request -> ux_transfer_request_requested_length =  hid -> ux_host_class_hid_descriptor.wItemLength;
255     transfer_request -> ux_transfer_request_function =          UX_GET_DESCRIPTOR;
256     transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE;
257     transfer_request -> ux_transfer_request_value =             UX_HOST_CLASS_HID_REPORT_DESCRIPTOR << 8;
258     transfer_request -> ux_transfer_request_index =             hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber;
259     UX_TRANSFER_STATE_RESET(transfer_request);
260 
261     /* Next: transfer and parse.  */
262     hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_TRANSFER_WAIT;
263     hid -> ux_host_class_hid_next_state = UX_HOST_CLASS_HID_ENUM_REPORT_DESC_PARSE;
264 }
_ux_host_class_hid_hid_descriptor_parse(UX_HOST_CLASS_HID * hid)265 static inline VOID _ux_host_class_hid_hid_descriptor_parse(UX_HOST_CLASS_HID *hid)
266 {
267 UX_DEVICE                       *device;
268 UX_TRANSFER                     *transfer;
269 UCHAR                           *descriptor;
270 UINT                            descriptor_length;
271 UINT                            descriptor_type;
272 UINT                            descriptor_2;
273 ULONG                           total_length;
274 ULONG                           interface_number;
275 UINT                            interface_found = UX_FALSE;
276 
277     /* Get transfer.  */
278     device = hid -> ux_host_class_hid_device;
279     transfer = &device -> ux_device_control_endpoint.ux_endpoint_transfer_request;
280 
281     /* Get current interface number.  */
282     interface_number = hid -> ux_host_class_hid_interface ->
283                                     ux_interface_descriptor.bInterfaceNumber;
284 
285     /* Get received descriptor.  */
286     descriptor = transfer -> ux_transfer_request_data_pointer;
287     total_length = transfer -> ux_transfer_request_actual_length;
288 
289     /* The HID descriptor is embedded within the configuration descriptor.
290         We parse the entire descriptor to locate the HID portion.  */
291     while(total_length)
292     {
293 
294         /* Get length and type of the descriptor.  */
295         descriptor_length = *descriptor;
296         descriptor_type   = *(descriptor + 1);
297         descriptor_2      = *(descriptor + 2);
298 
299         /* Make sure this descriptor has at least the minimum length.  */
300         if (descriptor_length < 3)
301             break;
302 
303         switch(descriptor_type)
304         {
305         case UX_INTERFACE_DESCRIPTOR_ITEM:
306 
307             /* Check if interface is what we expected.  */
308             interface_found = (interface_number == descriptor_2) ? UX_TRUE : UX_FALSE;
309             break;
310 
311         case UX_HOST_CLASS_HID_DESCRIPTOR:
312 
313             /* Check if we are in expected interface.  */
314             if (!interface_found)
315                 break;
316 
317             /* Save HID descriptor for later usage.
318                 Note only first 7 entries are saved, since we only support first
319                 9 bytes, no optional descriptors are supported for now. */
320             _ux_utility_descriptor_parse(descriptor,
321                 _ux_system_hid_descriptor_structure, UX_HID_DESCRIPTOR_ENTRIES,
322                 (UCHAR *) &hid -> ux_host_class_hid_descriptor);
323 
324             /* Free allocated bytes.  */
325             _ux_utility_memory_free(hid -> ux_host_class_hid_allocated);
326             hid -> ux_host_class_hid_allocated = UX_NULL;
327 
328             /* Next: HID report descriptor read.  */
329             hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_REPORT_DESC_READ;
330             return;
331 
332         default:
333             break;
334         }
335 
336         /* Verify if the descriptor is still valid.  */
337         if (descriptor_length > total_length)
338             break;
339 
340         /* Next descriptor.  */
341         descriptor += descriptor_length;
342         total_length -= descriptor_length;
343     }
344 
345     /* Error trap. */
346     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
347 
348     /* If trace is enabled, insert this event into the trace buffer.  */
349     UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
350 
351     /* Return an error.  */
352     hid -> ux_host_class_hid_status = UX_DESCRIPTOR_CORRUPTED;
353     hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_ERROR;
354 }
_ux_host_class_hid_report_descriptor_parse(UX_HOST_CLASS_HID * hid)355 static inline VOID _ux_host_class_hid_report_descriptor_parse(UX_HOST_CLASS_HID *hid)
356 {
357 UX_DEVICE               *device;
358 UX_TRANSFER             *transfer;
359 UCHAR                   *descriptor;
360 ULONG                   length;
361 UX_HOST_CLASS_HID_ITEM  item;
362 UINT                    status = UX_SUCCESS;
363 
364     /* Get transfer.  */
365     device = hid -> ux_host_class_hid_device;
366     transfer = &device -> ux_device_control_endpoint.ux_endpoint_transfer_request;
367 
368     /* Get buffer and length.  */
369     descriptor = hid -> ux_host_class_hid_allocated;
370     length = transfer -> ux_transfer_request_actual_length;
371 
372     /* Parse the report descriptor and build the report items.  */
373     while (length)
374     {
375 
376         /* Get one item from the report and analyze it.  */
377         _ux_host_class_hid_report_item_analyse(descriptor, &item);
378 
379         /* Point the descriptor right after the item identifier.  */
380         descriptor +=  item.ux_host_class_hid_item_report_format;
381 
382         /* Process relative to the item type.  */
383         switch (item.ux_host_class_hid_item_report_type)
384         {
385 
386         case UX_HOST_CLASS_HID_TYPE_GLOBAL:
387 
388             /* This is a global item.  */
389             status =  _ux_host_class_hid_global_item_parse(hid, &item, descriptor);
390             break;
391 
392 
393         case UX_HOST_CLASS_HID_TYPE_MAIN:
394 
395             /* This is a main item.  */
396             status =  _ux_host_class_hid_main_item_parse(hid, &item, descriptor);
397             break;
398 
399 
400         case UX_HOST_CLASS_HID_TYPE_LOCAL:
401 
402             /* This is a local item.  */
403             status =  _ux_host_class_hid_local_item_parse(hid, &item, descriptor);
404             break;
405 
406         default:
407 
408             /* This is a reserved item, meaning it shouldn't be used!  */
409 
410             /* Set status to error. The check after this switch statement
411                 will handle the rest.  */
412             status =  UX_DESCRIPTOR_CORRUPTED;
413             break;
414         }
415 
416         /* Recheck the status code.  */
417         if (status != UX_SUCCESS)
418         {
419             break;
420         }
421 
422         /* Jump to the next item.  */
423         descriptor +=  item.ux_host_class_hid_item_report_length;
424 
425         /* Verify that the report descriptor is not corrupted.  */
426         if (length < item.ux_host_class_hid_item_report_length)
427         {
428 
429             /* Return error status.  */
430             status = (UX_DESCRIPTOR_CORRUPTED);
431             break;
432         }
433 
434         /* Adjust the length.  */
435         length -=  (ULONG)(item.ux_host_class_hid_item_report_length + item.ux_host_class_hid_item_report_format);
436     }
437 
438     if (status != UX_SUCCESS)
439     {
440         hid -> ux_host_class_hid_status = status;
441         hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_ERROR;
442         return;
443     }
444 
445     /* Search the HID interrupt endpoint.  */
446     status = _ux_host_class_hid_interrupt_endpoint_search(hid);
447     if (status != UX_SUCCESS)
448     {
449         hid -> ux_host_class_hid_status = status;
450         hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_ERROR;
451         return;
452     }
453 
454     /* Allocated memory is no use now, free.  */
455     _ux_utility_memory_free(hid -> ux_host_class_hid_allocated);
456     hid -> ux_host_class_hid_allocated = UX_NULL;
457 
458     /* Next: search & activate client.  */
459     hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_CLIENT_SEARCH;
460 }
_ux_host_class_hid_client_activate_wait(UX_HOST_CLASS_HID * hid)461 static inline VOID _ux_host_class_hid_client_activate_wait(UX_HOST_CLASS_HID *hid)
462 {
463 UX_HOST_CLASS_HID_CLIENT_COMMAND    hid_client_command;
464 UINT                                status;
465 
466     hid_client_command.ux_host_class_hid_client_command_instance =   hid;
467     hid_client_command.ux_host_class_hid_client_command_request =    UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT;
468 
469     /* Call the HID client with an activate command.  */
470     status = hid -> ux_host_class_hid_client -> ux_host_class_hid_client_handler(&hid_client_command);
471 
472     /* Error.  */
473     if (status < UX_STATE_NEXT)
474     {
475         hid -> ux_host_class_hid_client = UX_NULL;
476         hid -> ux_host_class_hid_status = UX_DEVICE_ENUMERATION_FAILURE;
477         hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_ERROR;
478         return;
479     }
480 
481     /* Success.  */
482     if (status == UX_STATE_NEXT)
483     {
484         hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_DONE;
485         return;
486     }
487 
488     /* Wait.  */
489     return;
490 }
_ux_host_class_hid_activate_wait(UX_HOST_CLASS_COMMAND * command)491 static inline UINT _ux_host_class_hid_activate_wait(UX_HOST_CLASS_COMMAND *command)
492 {
493 
494 UX_INTERFACE            *interface_ptr;
495 UX_ENDPOINT             *control_endpoint;
496 UX_TRANSFER             *transfer;
497 UX_HOST_CLASS_HID       *hid;
498 UINT                    status;
499 
500     /* Get the instance for this class.  */
501     interface_ptr = (UX_INTERFACE *)command -> ux_host_class_command_container;
502     hid =  (UX_HOST_CLASS_HID *) interface_ptr -> ux_interface_class_instance;
503 
504     /* Run initialize state machine.  */
505     switch(hid -> ux_host_class_hid_enum_state)
506     {
507     case UX_HOST_CLASS_HID_ENUM_HID_DESC_READ            :
508         _ux_host_class_hid_descriptor_read(hid);
509         break;
510 
511     case UX_HOST_CLASS_HID_ENUM_HID_DESC_PARSE           :
512         _ux_host_class_hid_hid_descriptor_parse(hid);
513         break;
514 
515     case UX_HOST_CLASS_HID_ENUM_REPORT_DESC_READ         :
516         _ux_host_class_hid_report_descriptor_read(hid);
517         break;
518 
519     case UX_HOST_CLASS_HID_ENUM_REPORT_DESC_PARSE        :
520         _ux_host_class_hid_report_descriptor_parse(hid);
521         break;
522 
523     case UX_HOST_CLASS_HID_ENUM_CLIENT_SEARCH            :
524 
525         /* Search and activate client.  */
526         status = _ux_host_class_hid_client_search(hid);
527         if (status != UX_SUCCESS)
528         {
529 
530             /* There is no client, but HID can still be used.  */
531             hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_DONE;
532             break;
533         }
534 
535         /* Activate wait in case there is still steps for client.  */
536         hid -> ux_host_class_hid_enum_state = UX_HOST_CLASS_HID_ENUM_CLIENT_ACTIVATE_WAIT;
537 
538         /* Fall through.  */
539     case UX_HOST_CLASS_HID_ENUM_CLIENT_ACTIVATE_WAIT     :
540         _ux_host_class_hid_client_activate_wait(hid);
541         break;
542 
543     case UX_HOST_CLASS_HID_ENUM_TRANSFER_WAIT            :
544 
545         /* Get transfer.  */
546         control_endpoint = &hid -> ux_host_class_hid_device -> ux_device_control_endpoint;
547         transfer = &control_endpoint -> ux_endpoint_transfer_request;
548 
549         /* Transfer state machine.  */
550         status = _ux_host_stack_transfer_run(transfer);
551 
552         /* Is it done?  */
553         if (status <= UX_STATE_NEXT)
554         {
555 
556             /* Is there error?  */
557             if (transfer -> ux_transfer_request_completion_code != UX_SUCCESS)
558             {
559                 hid -> ux_host_class_hid_status = transfer -> ux_transfer_request_completion_code;
560                 hid -> ux_host_class_hid_enum_state = UX_STATE_EXIT;
561                 break;
562             }
563 
564             /* No error, next state.  */
565             hid -> ux_host_class_hid_enum_state = hid -> ux_host_class_hid_next_state;
566             break;
567         }
568 
569         /* Keep waiting.  */
570         break;
571 
572     case UX_HOST_CLASS_HID_ENUM_ERROR                    :
573 
574         /* Clean interrupt endpoint.  */
575         if (hid -> ux_host_class_hid_interrupt_endpoint &&
576             hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer)
577             _ux_utility_memory_free(hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer);
578 
579         /* Clean instance. */
580         _ux_host_class_hid_instance_clean(hid);
581 
582         /* Error, destroy the class instance and return error code. */
583         _ux_host_stack_class_instance_destroy(hid -> ux_host_class_hid_class, (VOID *) hid);
584 
585         /* Unmount instance. */
586         interface_ptr -> ux_interface_class_instance = UX_NULL;
587 
588         /* Free memory.  */
589         if (hid -> ux_host_class_hid_allocated)
590             _ux_utility_memory_free(hid -> ux_host_class_hid_allocated);
591 
592         /* Free instance. */
593         _ux_utility_memory_free(hid);
594         return(UX_STATE_NEXT);
595 
596     case UX_HOST_CLASS_HID_ENUM_DONE                     :
597 
598         /* Free temperary memory.  */
599         if (hid -> ux_host_class_hid_allocated)
600         {
601             _ux_utility_memory_free(hid -> ux_host_class_hid_allocated);
602             hid -> ux_host_class_hid_allocated = UX_NULL;
603         }
604 
605         /* Mark the HID class as live now.  */
606         hid -> ux_host_class_hid_state =  UX_HOST_CLASS_INSTANCE_LIVE;
607 
608         /* We may need to inform the application if a function has been programmed in the system structure.  */
609         if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
610         {
611 
612             /* Call system change function.  */
613             _ux_system_host ->  ux_system_host_change_function(UX_DEVICE_INSERTION, hid -> ux_host_class_hid_class, (VOID *) hid);
614         }
615 
616         /* If trace is enabled, insert this event into the trace buffer.  */
617         UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_HID_ACTIVATE, hid, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
618 
619         /* If trace is enabled, register this object.  */
620         UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, hid, 0, 0, 0)
621 
622         hid -> ux_host_class_hid_enum_state = UX_STATE_IDLE;
623         return(UX_STATE_NEXT);
624 
625     default: /* IDLE, Other states.  */
626         return(UX_STATE_NEXT);
627     }
628 
629     /* By default, keep waiting.  */
630     return(UX_STATE_WAIT);
631 }
632 #endif
633