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 /**   CDC ACM 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 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_host_class_cdc_acm_deactivate                   PORTABLE C      */
37 /*                                                           6.1.10       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function is called when this instance of the cdc_acm has been  */
45 /*    removed from the bus either directly or indirectly. The bulk in\out */
46 /*    and optional interrupt pipes will be destroyed and the instance     */
47 /*    removed.                                                            */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    command                               CDC ACM class command pointer */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    Completion Status                                                   */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _ux_host_stack_class_instance_destroy Destroy the class instance    */
60 /*    _ux_host_stack_endpoint_transfer_abort Abort endpoint transfer      */
61 /*    _ux_utility_memory_free               Free memory block             */
62 /*    _ux_host_semaphore_get                Get protection semaphore      */
63 /*    _ux_host_semaphore_delete             Delete protection semaphore   */
64 /*    _ux_utility_thread_schedule_other     Schedule other threads        */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    _ux_host_class_cdc_acm_entry          Entry of cdc_acm class        */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
75 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            resulting in version 6.1    */
77 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            added standalone support,   */
79 /*                                            resulting in version 6.1.10 */
80 /*                                                                        */
81 /**************************************************************************/
_ux_host_class_cdc_acm_deactivate(UX_HOST_CLASS_COMMAND * command)82 UINT  _ux_host_class_cdc_acm_deactivate(UX_HOST_CLASS_COMMAND *command)
83 {
84 
85 UX_HOST_CLASS_CDC_ACM       *cdc_acm;
86 UX_TRANSFER                 *transfer_request;
87 #if !defined(UX_HOST_STANDALONE)
88 UINT                        status;
89 #else
90 UX_HOST_CLASS_CDC_ACM       *cdc_acm_inst;
91 #endif
92 
93     /* Get the instance for this class.  */
94     cdc_acm =  (UX_HOST_CLASS_CDC_ACM *) command -> ux_host_class_command_instance;
95 
96     /* The cdc_acm is being shut down.  */
97     cdc_acm -> ux_host_class_cdc_acm_state =  UX_HOST_CLASS_INSTANCE_SHUTDOWN;
98 
99 #if !defined(UX_HOST_STANDALONE)
100 
101     /* Protect thread reentry to this instance.  */
102     status =  _ux_host_semaphore_get(&cdc_acm -> ux_host_class_cdc_acm_semaphore, UX_WAIT_FOREVER);
103     if (status != UX_SUCCESS)
104 
105         /* Return error.  */
106         return(status);
107 #endif
108 
109     /* If we have the Control Class, we only unmount the interrupt endpoint if it is active.  */
110     if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
111     {
112 
113         /* If the interrupt endpoint is defined, clean any pending transfer.  */
114         if (cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint != UX_NULL)
115         {
116             transfer_request =  &cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint -> ux_endpoint_transfer_request;
117 
118             /* And abort any transfer.  */
119             _ux_host_stack_endpoint_transfer_abort(cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint);
120 
121             /* Free data buffer for the interrupt transfer.  */
122             _ux_utility_memory_free(transfer_request -> ux_transfer_request_data_pointer);
123         }
124 
125 #if defined(UX_HOST_STANDALONE)
126 
127         /* Linked from data instance must be removed then.  */
128         /* We scan CDC ACM instances to find the master instance.  */
129         /* Get first instance linked to the class.  */
130         cdc_acm_inst = (UX_HOST_CLASS_CDC_ACM *) cdc_acm ->
131                     ux_host_class_cdc_acm_class -> ux_host_class_first_instance;
132 
133         /* Scan all instances.  */
134         while(cdc_acm_inst)
135         {
136 
137             /* If this data interface is linking to the control instance, unlink it.  */
138             if (cdc_acm_inst -> ux_host_class_cdc_acm_control == cdc_acm)
139                 cdc_acm_inst -> ux_host_class_cdc_acm_control = UX_NULL;
140 
141             /* Next instance.  */
142             cdc_acm_inst = cdc_acm_inst -> ux_host_class_cdc_acm_next_instance;
143         }
144 #endif
145     }
146     else
147     {
148 
149         /* We come to this point when the device has been extracted and this is the data class.
150            So there may have been a transaction being scheduled.
151            We make sure the transaction has been completed by the controller driver.
152            When the device is extracted, the controller tries multiple times the transaction and retires it
153            with a DEVICE_NOT_RESPONDING error code.
154 
155            First we take care of endpoint IN.  */
156         transfer_request =  &cdc_acm -> ux_host_class_cdc_acm_bulk_in_endpoint -> ux_endpoint_transfer_request;
157         if (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_PENDING)
158 
159             /* We need to abort transactions on the bulk In pipe.  */
160             _ux_host_stack_endpoint_transfer_abort(cdc_acm -> ux_host_class_cdc_acm_bulk_in_endpoint);
161 
162         /* Then endpoint OUT.  */
163         transfer_request =  &cdc_acm -> ux_host_class_cdc_acm_bulk_out_endpoint -> ux_endpoint_transfer_request;
164         if (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_PENDING)
165 
166             /* We need to abort transactions on the bulk Out pipe. */
167             _ux_host_stack_endpoint_transfer_abort(cdc_acm -> ux_host_class_cdc_acm_bulk_out_endpoint);
168 
169     }
170 
171 #if !defined(UX_HOST_STANDALONE)
172 
173     /* The enumeration thread needs to sleep a while to allow the application or the class that may be using
174        endpoints to exit properly.  */
175     _ux_host_thread_schedule_other(UX_THREAD_PRIORITY_ENUM);
176 #else
177 
178     /* If there is allocated resource, free it.  */
179     if (cdc_acm -> ux_host_class_cdc_acm_allocated)
180     {
181         _ux_utility_memory_free(cdc_acm -> ux_host_class_cdc_acm_allocated);
182     }
183 #endif
184 
185     /* Destroy the instance.  */
186     _ux_host_stack_class_instance_destroy(cdc_acm -> ux_host_class_cdc_acm_class, (VOID *) cdc_acm);
187 
188 #if !defined(UX_HOST_STANDALONE)
189 
190     /* Destroy the semaphore.  */
191     _ux_host_semaphore_delete(&cdc_acm -> ux_host_class_cdc_acm_semaphore);
192 #endif
193 
194     /* Before we free the device resources, we need to inform the application
195         that the device is removed.  */
196     if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
197     {
198 
199         /* Inform the application the device is removed.  */
200         _ux_system_host -> ux_system_host_change_function(UX_DEVICE_REMOVAL, cdc_acm -> ux_host_class_cdc_acm_class, (VOID *) cdc_acm);
201     }
202 
203     /* Free the cdc_acm instance memory.  */
204     _ux_utility_memory_free(cdc_acm);
205 
206     /* If trace is enabled, insert this event into the trace buffer.  */
207     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ACM_DEACTIVATE, cdc_acm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
208 
209     /* If trace is enabled, register this object.  */
210     UX_TRACE_OBJECT_UNREGISTER(cdc_acm);
211 
212     /* Return successful status.  */
213     return(UX_SUCCESS);
214 }
215 
216