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 /**   Acm Cdc 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_cdc_acm.h"
29 #include "ux_host_stack.h"
30 
31 
32 #if defined(UX_HOST_STANDALONE)
33 #define UX_HOST_CLASS_CDC_ACM_INIT_TRANSFER_WAIT        (UX_STATE_WAIT)
34 #define UX_HOST_CLASS_CDC_ACM_INIT_DESCRIPTORS_PARSE    (UX_STATE_NEXT)
35 
36 #define UX_HOST_CLASS_CDC_ACM_INIT_DELAY_WAIT           (UX_STATE_CLASS_STEP + 0)
37 #define UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_SET      (UX_STATE_CLASS_STEP + 1)
38 #define UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_GET      (UX_STATE_CLASS_STEP + 2)
39 #define UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_CHECK    (UX_STATE_CLASS_STEP + 3)
40 #define UX_HOST_CLASS_CDC_ACM_INIT_LINE_STATE_SET       (UX_STATE_CLASS_STEP + 4)
41 #define UX_HOST_CLASS_CDC_ACM_INIT_ERROR                (UX_STATE_CLASS_STEP + 5)
42 #define UX_HOST_CLASS_CDC_ACM_INIT_DONE                 (UX_STATE_CLASS_STEP + 6)
43 
44 
45 static inline UINT  _ux_host_class_cdc_acm_activate_wait(UX_HOST_CLASS_COMMAND *command);
46 #endif
47 
48 
49 /**************************************************************************/
50 /*                                                                        */
51 /*  FUNCTION                                               RELEASE        */
52 /*                                                                        */
53 /*    _ux_host_class_cdc_acm_entry                        PORTABLE C      */
54 /*                                                           6.1.12       */
55 /*  AUTHOR                                                                */
56 /*                                                                        */
57 /*    Chaoqiong Xiao, Microsoft Corporation                               */
58 /*                                                                        */
59 /*  DESCRIPTION                                                           */
60 /*                                                                        */
61 /*    This function is the entry point of the cdc_acm class. It will be   */
62 /*    called by the USBX stack enumeration module when there is a new     */
63 /*    cdc_acm on the bus or when the USB cdc_acm is removed.              */
64 /*                                                                        */
65 /*    A CDC class can have multiple interfaces, one for Control and one   */
66 /*    for Data. Here we filter for the Communication Class with ACM       */
67 /*    subclass and the Communication Data Class.                          */
68 /*                                                                        */
69 /*                                                                        */
70 /*  INPUT                                                                 */
71 /*                                                                        */
72 /*    command                                  Acm Cdc class command      */
73 /*                                                                        */
74 /*  OUTPUT                                                                */
75 /*                                                                        */
76 /*    Completion Status                                                   */
77 /*                                                                        */
78 /*  CALLS                                                                 */
79 /*                                                                        */
80 /*    _ux_host_class_cdc_acm_activate       Activate cdc_acm class        */
81 /*    _ux_host_class_cdc_acm_deactivate     Deactivate cdc_acm class      */
82 /*                                                                        */
83 /*  CALLED BY                                                             */
84 /*                                                                        */
85 /*    Acm Cdc Class                                                       */
86 /*                                                                        */
87 /*  RELEASE HISTORY                                                       */
88 /*                                                                        */
89 /*    DATE              NAME                      DESCRIPTION             */
90 /*                                                                        */
91 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
92 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
93 /*                                            resulting in version 6.1    */
94 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
95 /*                                            added standalone support,   */
96 /*                                            resulting in version 6.1.10 */
97 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
98 /*                                            fixed parameter/variable    */
99 /*                                            names conflict C++ keyword, */
100 /*                                            resulting in version 6.1.12 */
101 /*                                                                        */
102 /**************************************************************************/
_ux_host_class_cdc_acm_entry(UX_HOST_CLASS_COMMAND * command)103 UINT  _ux_host_class_cdc_acm_entry(UX_HOST_CLASS_COMMAND *command)
104 {
105 
106 UINT    status;
107 
108 
109     /* The command request will tell us we need to do here, either a enumeration
110        query, an activation or a deactivation.  */
111     switch (command -> ux_host_class_command_request)
112     {
113 
114     case UX_HOST_CLASS_COMMAND_QUERY:
115 
116         /* The query command is used to let the stack enumeration process know if we want to own
117            this device or not.  */
118         if((command -> ux_host_class_command_usage == UX_HOST_CLASS_COMMAND_USAGE_CSP) &&
119                              ((command -> ux_host_class_command_class == UX_HOST_CLASS_CDC_DATA_CLASS) ||
120                              ((command -> ux_host_class_command_class == UX_HOST_CLASS_CDC_CONTROL_CLASS) &&
121                              (command -> ux_host_class_command_subclass == UX_HOST_CLASS_CDC_ACM_SUBCLASS)) ||
122                              ((command -> ux_host_class_command_class == UX_HOST_CLASS_CDC_CONTROL_CLASS) &&
123                              (command -> ux_host_class_command_subclass == UX_HOST_CLASS_CDC_DLC_SUBCLASS))))
124         {
125             /* Check for IAD presence.  */
126             if ((command -> ux_host_class_command_iad_class == 0) && (command -> ux_host_class_command_iad_subclass == 0))
127 
128                 /* No IAD, we accept this class.  */
129                 return(UX_SUCCESS);
130 
131             else
132             {
133 
134                 if ((command -> ux_host_class_command_iad_class == UX_HOST_CLASS_CDC_CONTROL_CLASS) &&
135                         (command -> ux_host_class_command_iad_subclass == UX_HOST_CLASS_CDC_ACM_SUBCLASS))
136 
137                     /* There is an IAD and this is for CDC-ACM.  */
138                     return(UX_SUCCESS);
139 
140                 else
141 
142                     /* The IAD does not match with CDC-ACM.  */
143                     return(UX_NO_CLASS_MATCH);
144             }
145         }
146 
147         else
148 
149             /* No match.  */
150             return(UX_NO_CLASS_MATCH);
151 
152     case UX_HOST_CLASS_COMMAND_ACTIVATE:
153 
154         /* The activate command is used when the device inserted has found a parent and
155            is ready to complete the enumeration.  */
156         status =  _ux_host_class_cdc_acm_activate(command);
157         return(status);
158 
159 #if defined(UX_HOST_STANDALONE)
160     case UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT:
161         status = _ux_host_class_cdc_acm_activate_wait(command);
162         return(status);
163 #endif
164 
165     case UX_HOST_CLASS_COMMAND_DEACTIVATE:
166 
167         /* The deactivate command is used when the device has been extracted either
168            directly or when its parents has been extracted.  */
169         status =  _ux_host_class_cdc_acm_deactivate(command);
170         return(status);
171 
172     default:
173 
174         /* Error trap. */
175         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
176 
177         /* If trace is enabled, insert this event into the trace buffer.  */
178         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
179 
180         return(UX_FUNCTION_NOT_SUPPORTED);
181     }
182 }
183 
184 #if defined(UX_HOST_STANDALONE)
_ux_host_class_cdc_acm_descriptors_parse(UX_HOST_CLASS_CDC_ACM * cdc_acm)185 static inline VOID  _ux_host_class_cdc_acm_descriptors_parse(UX_HOST_CLASS_CDC_ACM *cdc_acm)
186 {
187 
188 UX_ENDPOINT                 *control_endpoint;
189 UX_TRANSFER                 *transfer_request;
190 UX_INTERFACE                *interface_ptr;
191 UCHAR                       *descriptor;
192 ULONG                       total_descriptor_length;
193 UCHAR                       descriptor_length;
194 UCHAR                       descriptor_type;
195 UCHAR                       descriptor_byte2;
196 ULONG                       interface_found;
197 ULONG                       interface_parsed;
198 UCHAR                       offset;
199 
200     /* We need to get the default control endpoint transfer request pointer.  */
201     control_endpoint =  &cdc_acm -> ux_host_class_cdc_acm_device -> ux_device_control_endpoint;
202     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
203 
204     /* Check if transfer is done success.  */
205     if (transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS ||
206         transfer_request -> ux_transfer_request_actual_length !=
207             transfer_request -> ux_transfer_request_requested_length)
208     {
209         cdc_acm -> ux_host_class_cdc_acm_status = UX_DESCRIPTOR_CORRUPTED;
210         cdc_acm -> ux_host_class_cdc_acm_cmd_state = UX_HOST_CLASS_CDC_ACM_INIT_ERROR;
211         return;
212     }
213 
214     /* Get the interface.  */
215     interface_ptr = cdc_acm -> ux_host_class_cdc_acm_interface;
216 
217     /* Parse the descriptor.  */
218     total_descriptor_length = transfer_request -> ux_transfer_request_actual_length;
219     descriptor = (UCHAR *)cdc_acm -> ux_host_class_cdc_acm_allocated;
220     interface_found = UX_FALSE;
221     interface_parsed = UX_FALSE;
222 
223     while(total_descriptor_length)
224     {
225 
226         /* Get descriptor length, type, subtype.  */
227         descriptor_length  = *descriptor;
228         descriptor_type    = *(descriptor + 1);
229         descriptor_byte2   = *(descriptor + 2);
230 
231         /* Make sure this descriptor has at least the minimum length.  */
232         if (descriptor_length < 3 || descriptor_length > total_descriptor_length)
233         {
234             /* Descriptor is corrupted.  */
235             break;
236         }
237 
238         /* Process related descriptors.  */
239         switch(descriptor_type)
240         {
241         case UX_INTERFACE_DESCRIPTOR_ITEM:
242 
243             /* Check if interface is what we expected.  */
244             if (interface_ptr -> ux_interface_descriptor.bInterfaceNumber == descriptor_byte2)
245             {
246 
247                 /* Mark found.  */
248                 interface_found = UX_TRUE;
249             }
250             else
251             {
252 
253                 /* Run out of expected interface.  */
254                 if (interface_found)
255                 {
256 
257                     interface_parsed = UX_TRUE;
258                 }
259             }
260             break;
261 
262         case UX_HOST_CLASS_CDC_ACM_CS_INTERFACE:
263 
264             /* Check if we are in correct interface.  */
265             if (interface_found)
266             {
267 
268                 /* Check bDescriptorSubType.  */
269                 switch(descriptor_byte2)
270                 {
271                 case UX_HOST_CLASS_CDC_ACM_CALL_MANAGEMENT_DESCRIPTOR:
272 
273                     /* Store capabilities.  */
274                     cdc_acm -> ux_host_class_cdc_acm_capabilities =
275                         *(descriptor + UX_HOST_CLASS_CDC_ACM_CALL_MANAGEMENT_CAPABILITIES);
276                     break;
277 
278                 case UX_HOST_CLASS_CDC_ACM_UNION_DESCRIPTOR:
279 
280                     /* Check related interfaces.  */
281                     for (offset = UX_HOST_CLASS_CDC_ACM_UNION_FUNCTIONAL_MASTER;
282                         offset < descriptor_length;
283                         offset ++)
284                     {
285 
286                         /* Save the interface in interface bitmap.  */
287                         cdc_acm -> ux_host_class_cdc_acm_interfaces_bitmap |=
288                                                 1u << *(descriptor + offset);
289                     }
290                     break;
291 
292                 default:
293                     break;
294                 }
295             }
296             break;
297 
298         default:
299             break;
300         }
301 
302         /* Next descriptor.  */
303         descriptor += descriptor_length;
304         total_descriptor_length -= descriptor_length;
305     }
306 
307     /* We can free the resource now.  */
308     _ux_utility_memory_free(cdc_acm -> ux_host_class_cdc_acm_allocated);
309     cdc_acm -> ux_host_class_cdc_acm_allocated = UX_NULL;
310 
311     /* Descriptor fail.  */
312     if (interface_parsed == UX_FALSE)
313     {
314 
315         /* Error trap. */
316         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
317 
318         /* If trace is enabled, insert this event into the trace buffer.  */
319         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
320 
321         /* Descriptor is corrupted.  */
322         cdc_acm -> ux_host_class_cdc_acm_status = UX_DESCRIPTOR_CORRUPTED;
323         cdc_acm -> ux_host_class_cdc_acm_cmd_state = UX_HOST_CLASS_CDC_ACM_INIT_ERROR;
324         return;
325     }
326 
327     /* Descriptor is parsed.  */
328     cdc_acm -> ux_host_class_cdc_acm_tick = _ux_utility_time_get();
329     cdc_acm -> ux_host_class_cdc_acm_cmd_state = UX_HOST_CLASS_CDC_ACM_INIT_DELAY_WAIT;
330 }
331 
_ux_host_class_cdc_acm_activate_wait(UX_HOST_CLASS_COMMAND * command)332 static inline UINT  _ux_host_class_cdc_acm_activate_wait(UX_HOST_CLASS_COMMAND *command)
333 {
334 
335 UX_HOST_CLASS               *cdc_acm_class;
336 UX_HOST_CLASS_CDC_ACM       *cdc_acm_inst;
337 UX_INTERFACE                *interface_ptr;
338 UX_HOST_CLASS_CDC_ACM       *cdc_acm;
339 UX_ENDPOINT                 *control_endpoint;
340 UX_TRANSFER                 *transfer;
341 UCHAR                       *buffer;
342 ULONG                       rate, stop_bit, parity, data_bit;
343 UINT                        status;
344 ULONG                       tick, diff;
345 
346     /* Get the instance for this class.  */
347     interface_ptr = (UX_INTERFACE *)command -> ux_host_class_command_container;
348     cdc_acm =  (UX_HOST_CLASS_CDC_ACM *) interface_ptr -> ux_interface_class_instance;
349 
350     /* Run initialize state machine.  */
351     switch(cdc_acm -> ux_host_class_cdc_acm_cmd_state)
352     {
353     case UX_HOST_CLASS_CDC_ACM_INIT_DESCRIPTORS_PARSE:
354         _ux_host_class_cdc_acm_descriptors_parse(cdc_acm);
355         break;
356 
357     case UX_HOST_CLASS_CDC_ACM_INIT_DELAY_WAIT:
358         tick = _ux_utility_time_get();
359         diff = _ux_utility_time_elapsed(cdc_acm -> ux_host_class_cdc_acm_tick, tick);
360         if (diff > UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ACM_DEVICE_INIT_DELAY))
361         {
362             /* Allocate some buffer for commands.  */
363             cdc_acm -> ux_host_class_cdc_acm_allocated =
364                 _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY,
365                                                            8);
366 
367             if (cdc_acm -> ux_host_class_cdc_acm_allocated == UX_NULL)
368             {
369                 cdc_acm -> ux_host_class_cdc_acm_status = UX_MEMORY_INSUFFICIENT;
370                 cdc_acm -> ux_host_class_cdc_acm_cmd_state =
371                                             UX_HOST_CLASS_CDC_ACM_INIT_ERROR;
372                 break;
373             }
374             control_endpoint = &cdc_acm -> ux_host_class_cdc_acm_device ->
375                                                     ux_device_control_endpoint;
376             transfer = &control_endpoint -> ux_endpoint_transfer_request;
377 
378             /* Initialize transfer buffer.  */
379             transfer -> ux_transfer_request_data_pointer = (UCHAR *)
380                                     cdc_acm -> ux_host_class_cdc_acm_allocated;
381 
382             /* Initialize transfer flags.  */
383             transfer -> ux_transfer_request_flags = 0;
384 
385             cdc_acm -> ux_host_class_cdc_acm_cmd_state =
386                                     UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_SET;
387         }
388         break;
389 
390     case UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_SET:
391 
392         /* Put line coding things in buffer.  */
393         buffer = (UCHAR *)cdc_acm -> ux_host_class_cdc_acm_allocated;
394         rate     = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE;
395         stop_bit = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT;
396         parity   = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY;
397         data_bit = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT;
398         _ux_utility_long_put(buffer + UX_HOST_CLASS_CDC_ACM_LINE_CODING_RATE, rate);
399         *(buffer + UX_HOST_CLASS_CDC_ACM_LINE_CODING_STOP_BIT) = (UCHAR)stop_bit;
400         *(buffer + UX_HOST_CLASS_CDC_ACM_LINE_CODING_PARITY)   = (UCHAR)parity;
401         *(buffer + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DATA_BIT) = (UCHAR)data_bit;
402 
403         status = _ux_host_class_cdc_acm_command(cdc_acm,
404                             UX_HOST_CLASS_CDC_ACM_REQ_SET_LINE_CODING, 0,
405                             buffer, UX_HOST_CLASS_CDC_ACM_LINE_CODING_LENGTH);
406         if (status != UX_SUCCESS)
407         {
408             cdc_acm -> ux_host_class_cdc_acm_status = status;
409             cdc_acm -> ux_host_class_cdc_acm_cmd_state =
410                                         UX_HOST_CLASS_CDC_ACM_INIT_ERROR;
411             break;
412         }
413         cdc_acm -> ux_host_class_cdc_acm_cmd_state =
414                                     UX_HOST_CLASS_CDC_ACM_INIT_TRANSFER_WAIT;
415         cdc_acm -> ux_host_class_cdc_acm_next_state =
416                                     UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_GET;
417         break;
418 
419     case UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_GET:
420 
421         /* Get line coding things from device.  */
422         buffer = (UCHAR *)cdc_acm -> ux_host_class_cdc_acm_allocated;
423         status = _ux_host_class_cdc_acm_command(cdc_acm,
424                             UX_HOST_CLASS_CDC_ACM_REQ_GET_LINE_CODING, 0,
425                             buffer, UX_HOST_CLASS_CDC_ACM_LINE_CODING_LENGTH);
426         if (status != UX_SUCCESS)
427         {
428             cdc_acm -> ux_host_class_cdc_acm_status = status;
429             cdc_acm -> ux_host_class_cdc_acm_cmd_state =
430                                         UX_HOST_CLASS_CDC_ACM_INIT_ERROR;
431             break;
432         }
433         cdc_acm -> ux_host_class_cdc_acm_cmd_state =
434                                 UX_HOST_CLASS_CDC_ACM_INIT_TRANSFER_WAIT;
435         cdc_acm -> ux_host_class_cdc_acm_next_state =
436                                 UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_CHECK;
437         break;
438 
439     case UX_HOST_CLASS_CDC_ACM_INIT_LINE_CODING_CHECK:
440 
441         /* Check line coding things in buffer.  */
442         buffer = (UCHAR *)cdc_acm -> ux_host_class_cdc_acm_allocated;
443         rate     = _ux_utility_long_get(buffer + UX_HOST_CLASS_CDC_ACM_LINE_CODING_RATE);
444         stop_bit = *(buffer + UX_HOST_CLASS_CDC_ACM_LINE_CODING_STOP_BIT);
445         parity   = *(buffer + UX_HOST_CLASS_CDC_ACM_LINE_CODING_PARITY);
446         data_bit = *(buffer + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DATA_BIT);
447         if (rate != UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE ||
448             stop_bit != UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT ||
449             parity != UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY ||
450             data_bit != UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT)
451         {
452             cdc_acm -> ux_host_class_cdc_acm_status = UX_DEVICE_ENUMERATION_FAILURE;
453             cdc_acm -> ux_host_class_cdc_acm_cmd_state = UX_HOST_CLASS_CDC_ACM_INIT_ERROR;
454             break;
455         }
456 
457         /* Fall through.  */
458     case UX_HOST_CLASS_CDC_ACM_INIT_LINE_STATE_SET:
459 
460         /* Put line state things.  */
461         buffer = (UCHAR *)cdc_acm -> ux_host_class_cdc_acm_allocated;
462         *(buffer) = UX_HOST_CLASS_CDC_ACM_CTRL_DTR | UX_HOST_CLASS_CDC_ACM_CTRL_RTS;
463         status = _ux_host_class_cdc_acm_command(cdc_acm,
464                                     UX_HOST_CLASS_CDC_ACM_REQ_SET_LINE_STATE,
465                                     *(buffer), UX_NULL, 0);
466         if (status != UX_SUCCESS)
467         {
468             cdc_acm -> ux_host_class_cdc_acm_status = status;
469             cdc_acm -> ux_host_class_cdc_acm_cmd_state =
470                                         UX_HOST_CLASS_CDC_ACM_INIT_ERROR;
471             break;
472         }
473         cdc_acm -> ux_host_class_cdc_acm_cmd_state =
474                                     UX_HOST_CLASS_CDC_ACM_INIT_TRANSFER_WAIT;
475         cdc_acm -> ux_host_class_cdc_acm_next_state =
476                                     UX_HOST_CLASS_CDC_ACM_INIT_DONE;
477         break;
478 
479     case UX_HOST_CLASS_CDC_ACM_INIT_ERROR:
480         /* Fall through.  */
481     case UX_HOST_CLASS_CDC_ACM_INIT_DONE:
482 
483         /* Free allocated buffer.  */
484         if (cdc_acm -> ux_host_class_cdc_acm_allocated)
485         {
486             _ux_utility_memory_free(cdc_acm -> ux_host_class_cdc_acm_allocated);
487             cdc_acm -> ux_host_class_cdc_acm_allocated = UX_NULL;
488         }
489 
490         /* Check status.  */
491         if (cdc_acm -> ux_host_class_cdc_acm_status == UX_SUCCESS)
492         {
493 
494             /* We are here only if it's control interface.  */
495             /* We scan CDC ACM instances to find the DATA instance.  */
496             /* Get class.  */
497             cdc_acm_class = cdc_acm -> ux_host_class_cdc_acm_class;
498 
499             /* Get first instance linked to the class.  */
500             cdc_acm_inst = (UX_HOST_CLASS_CDC_ACM *)cdc_acm_class -> ux_host_class_first_instance;
501 
502             /* Scan all data instances to update control links.  */
503             while(cdc_acm_inst)
504             {
505 
506                 /* Get interface of the instance.  */
507                 interface_ptr = cdc_acm_inst -> ux_host_class_cdc_acm_interface;
508 
509                 /* If this data interface is inside the associate list on the same device, link it.  */
510                 if ((cdc_acm_inst -> ux_host_class_cdc_acm_device ==
511                         cdc_acm -> ux_host_class_cdc_acm_device) &&
512                     (cdc_acm -> ux_host_class_cdc_acm_interfaces_bitmap &
513                         (1ul << interface_ptr -> ux_interface_descriptor.bInterfaceNumber)))
514                 {
515 
516                     /* Link this control to the data instance.  */
517                     cdc_acm_inst -> ux_host_class_cdc_acm_control = cdc_acm;
518                 }
519 
520                 /* Next instance.  */
521                 cdc_acm_inst = cdc_acm_inst -> ux_host_class_cdc_acm_next_instance;
522             }
523 
524             /* Mark the cdc_acm as live now.  Both interfaces need to be live. */
525             cdc_acm -> ux_host_class_cdc_acm_state =  UX_HOST_CLASS_INSTANCE_LIVE;
526 
527             /* If all is fine and the device is mounted, we may need to inform the application
528                 if a function has been programmed in the system structure.  */
529             if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
530             {
531 
532                 /* Call system change function.  */
533                 _ux_system_host ->  ux_system_host_change_function(UX_DEVICE_INSERTION, cdc_acm -> ux_host_class_cdc_acm_class, (VOID *) cdc_acm);
534             }
535 
536             /* If trace is enabled, insert this event into the trace buffer.  */
537             UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ACM_ACTIVATE, cdc_acm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
538 
539             /* If trace is enabled, register this object.  */
540             UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, cdc_acm, 0, 0, 0)
541 
542             /* Reset CMD state.  */
543             cdc_acm -> ux_host_class_cdc_acm_cmd_state = UX_STATE_RESET;
544         }
545         else
546         {
547 
548             /* On error case, it's possible data buffer allocated for interrupt endpoint and transfer started, stop and free it.  */
549             if (cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint &&
550                 cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer)
551             {
552 
553                 /* The first transfer request has already been initiated. Abort it.  */
554                 _ux_host_stack_endpoint_transfer_abort(cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint);
555 
556                 /* Free the memory for the data pointer.  */
557                 _ux_utility_memory_free(cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer);
558             }
559 
560             /* Destroy the instance.  */
561             _ux_host_stack_class_instance_destroy(cdc_acm -> ux_host_class_cdc_acm_class, (VOID *) cdc_acm);
562 
563             /* Unmount instance. */
564             interface_ptr = cdc_acm -> ux_host_class_cdc_acm_interface;
565             interface_ptr -> ux_interface_class_instance = UX_NULL;
566 
567             /* Free instance. */
568             _ux_utility_memory_free(cdc_acm);
569         }
570 
571         /* Done, OK to go on.  */
572         return(UX_STATE_NEXT);
573 
574     case UX_HOST_CLASS_CDC_ACM_INIT_TRANSFER_WAIT:
575 
576         /* Get transfer.  */
577         control_endpoint = &cdc_acm -> ux_host_class_cdc_acm_device -> ux_device_control_endpoint;
578         transfer = &control_endpoint -> ux_endpoint_transfer_request;
579 
580         /* Transfer state machine.  */
581         status = _ux_host_stack_transfer_run(transfer);
582 
583         /* Is it done?  */
584         if (status <= UX_STATE_NEXT)
585         {
586 
587             /* Is there error?  */
588             if (transfer -> ux_transfer_request_completion_code != UX_SUCCESS)
589             {
590                 cdc_acm -> ux_host_class_cdc_acm_cmd_state = UX_STATE_EXIT;
591                 break;
592             }
593 
594             /* No error, next state.  */
595             cdc_acm -> ux_host_class_cdc_acm_cmd_state =
596                                     cdc_acm -> ux_host_class_cdc_acm_next_state;
597             break;
598         }
599 
600         /* Keep waiting.  */
601         break;
602 
603     /* UX_STATE_RESET, UX_STATE_EXIT, UX_STATE_IDLE, ...  */
604     default:
605 
606         /* Do nothing.  */
607         return(UX_STATE_NEXT);
608     }
609 
610     /* Keep waiting.  */
611     return(UX_STATE_WAIT);
612 }
613 #endif
614