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_activate                     PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function creates the ACM instance, configure the device ...    */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    command                                ACM  class command pointer   */
49 /*                                                                        */
50 /*  OUTPUT                                                                */
51 /*                                                                        */
52 /*    Completion Status                                                   */
53 /*                                                                        */
54 /*  CALLS                                                                 */
55 /*                                                                        */
56 /*    _ux_host_class_cdc_acm_configure        Configure cdc_acm class     */
57 /*    _ux_host_class_cdc_acm_endpoints_get    Get endpoints of cdc_acm    */
58 /*    _ux_host_class_cdc_acm_ioctl            IOCTL function for ACM      */
59 /*    _ux_host_stack_class_instance_destroy   Destroy the class instance  */
60 /*    _ux_host_stack_endpoint_transfer_abort  Abort transfer              */
61 /*    _ux_utility_memory_allocate             Allocate memory block       */
62 /*    _ux_utility_memory_free                 Free memory                 */
63 /*    _ux_host_semaphore_create               Create cdc_acm semaphore    */
64 /*    _ux_host_semaphore_delete               Delete semaphore            */
65 /*    _ux_utility_delay_ms                    Delay                       */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    _ux_host_class_cdc_acm_entry          Entry of cdc_acm class        */
70 /*    _ux_utility_delay_ms                  Delay ms                      */
71 /*                                                                        */
72 /*  RELEASE HISTORY                                                       */
73 /*                                                                        */
74 /*    DATE              NAME                      DESCRIPTION             */
75 /*                                                                        */
76 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
77 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            resulting in version 6.1    */
79 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            added standalone support,   */
81 /*                                            used defined line coding    */
82 /*                                            instead of magic number,    */
83 /*                                            resulting in version 6.1.10 */
84 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            improved error handling,    */
86 /*                                            fixed parameter/variable    */
87 /*                                            names conflict C++ keyword, */
88 /*                                            resulting in version 6.1.12 */
89 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
90 /*                                            improved control searching, */
91 /*                                            resulting in version 6.3.0  */
92 /*                                                                        */
93 /**************************************************************************/
_ux_host_class_cdc_acm_activate(UX_HOST_CLASS_COMMAND * command)94 UINT  _ux_host_class_cdc_acm_activate(UX_HOST_CLASS_COMMAND *command)
95 {
96 
97 UX_INTERFACE                        *interface_ptr;
98 UX_HOST_CLASS_CDC_ACM               *cdc_acm;
99 UINT                                status;
100 #if defined(UX_HOST_STANDALONE)
101 UX_HOST_CLASS                       *cdc_acm_class;
102 UX_HOST_CLASS_CDC_ACM               *cdc_acm_inst;
103 UX_ENDPOINT                         *control_endpoint;
104 UX_TRANSFER                         *transfer_request;
105 ULONG                               descriptors_length;
106 #else
107 UX_HOST_CLASS_CDC_ACM_LINE_CODING   line_coding;
108 UX_HOST_CLASS_CDC_ACM_LINE_STATE    line_state;
109 #endif
110 
111     /* The CDC ACM class is always activated by the interface descriptor and not the
112        device descriptor.  */
113     interface_ptr =  (UX_INTERFACE *) command -> ux_host_class_command_container;
114 
115     /* Obtain memory for this class instance.  */
116     cdc_acm =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, sizeof(UX_HOST_CLASS_CDC_ACM));
117 
118     /* Instance creation fail. */
119     if (cdc_acm == UX_NULL)
120 
121         /* Memory allocation fail. */
122         return(UX_MEMORY_INSUFFICIENT);
123 
124 #if !defined(UX_HOST_STANDALONE)
125 
126     /* Create the semaphore to protect 2 threads from accessing the same acm instance.  */
127     status =  _ux_host_semaphore_create(&cdc_acm -> ux_host_class_cdc_acm_semaphore, "ux_host_class_cdc_acm_semaphore", 1);
128     if (status != UX_SUCCESS)
129     {
130 
131         /* Free instance memory. */
132         _ux_utility_memory_free(cdc_acm);
133 
134         /* Semaphore creation error. */
135         return(UX_SEMAPHORE_ERROR);
136     }
137 #endif
138 
139     /* Store the class container into this instance.  */
140     cdc_acm -> ux_host_class_cdc_acm_class =  command -> ux_host_class_command_class_ptr;
141 
142     /* Store the interface container into the cdc_acm class instance.  */
143     cdc_acm -> ux_host_class_cdc_acm_interface =  interface_ptr;
144 
145     /* Store the device container into the cdc_acm class instance.  */
146     cdc_acm -> ux_host_class_cdc_acm_device =  interface_ptr -> ux_interface_configuration -> ux_configuration_device;
147 
148     /* This instance of the device must also be stored in the interface container.  */
149     interface_ptr -> ux_interface_class_instance =  (VOID *) cdc_acm;
150 
151     /* Create this class instance.  */
152     _ux_host_stack_class_instance_create(cdc_acm -> ux_host_class_cdc_acm_class, (VOID *) cdc_acm);
153 
154 #if defined(UX_HOST_STANDALONE)
155 
156     /* Get the cdc_acm endpoint(s). Depending on the interface type, we will need to search for
157         Bulk Out and Bulk In endpoints and the optional interrupt endpoint.  */
158     status =  _ux_host_class_cdc_acm_endpoints_get(cdc_acm);
159     if (status == UX_SUCCESS)
160     {
161 
162         /* Mark the cdc_acm as mounting.  */
163         cdc_acm -> ux_host_class_cdc_acm_state = UX_HOST_CLASS_INSTANCE_MOUNTING;
164 
165         /* If we have the Control Class, we process default setup command sequence.  */
166         if (interface_ptr -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
167         {
168 
169             /* Get descriptors to see capabilities.  */
170 
171             /* Get default control transfer.  */
172             control_endpoint = &cdc_acm -> ux_host_class_cdc_acm_device -> ux_device_control_endpoint;
173             transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
174 
175             /* Allocate memory for the descriptors.  */
176             descriptors_length = interface_ptr -> ux_interface_configuration ->
177                                         ux_configuration_descriptor.wTotalLength;
178             cdc_acm -> ux_host_class_cdc_acm_allocated =
179                     _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY,
180                                                             descriptors_length);
181             if (cdc_acm -> ux_host_class_cdc_acm_allocated != UX_NULL)
182             {
183 
184                 transfer_request -> ux_transfer_request_data_pointer =
185                                             cdc_acm -> ux_host_class_cdc_acm_allocated;
186 
187                 /* Create transfer for GET_DESCRIPTOR.  */
188                 transfer_request -> ux_transfer_request_requested_length = descriptors_length;
189                 transfer_request -> ux_transfer_request_function =         UX_GET_DESCRIPTOR;
190                 transfer_request -> ux_transfer_request_type =             UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
191                 transfer_request -> ux_transfer_request_value =            UX_CONFIGURATION_DESCRIPTOR_ITEM << 8;
192                 transfer_request -> ux_transfer_request_index =            0;
193                 UX_TRANSFER_STATE_RESET(transfer_request);
194 
195                 /* Set state to wait and next is "next".  */
196                 cdc_acm -> ux_host_class_cdc_acm_cmd_state = UX_STATE_WAIT;
197                 cdc_acm -> ux_host_class_cdc_acm_next_state = UX_STATE_NEXT;
198 
199                 /* ACTIVATE_WAIT will be processed to finish next steps.  */
200                 return(UX_SUCCESS);
201             }
202             else
203                 status = UX_MEMORY_INSUFFICIENT;
204         }
205         else
206         {
207 
208             /* We scan CDC ACM instances to find the master instance.  */
209             /* Get class.  */
210             cdc_acm_class = cdc_acm -> ux_host_class_cdc_acm_class;
211 
212             /* Get first instance linked to the class.  */
213             cdc_acm_inst = (UX_HOST_CLASS_CDC_ACM *)cdc_acm_class -> ux_host_class_first_instance;
214 
215             /* Scan all instances.  */
216             while(cdc_acm_inst)
217             {
218 
219                 /* If this data interface is on the same device and inside the associate list, link it.  */
220                 if ((cdc_acm_inst -> ux_host_class_cdc_acm_device ==
221                         cdc_acm -> ux_host_class_cdc_acm_device) &&
222                     (cdc_acm_inst -> ux_host_class_cdc_acm_interfaces_bitmap &
223                         (1ul << interface_ptr -> ux_interface_descriptor.bInterfaceNumber)))
224                 {
225 
226                     /* Save control instance.  */
227                     cdc_acm -> ux_host_class_cdc_acm_control = cdc_acm_inst;
228                 }
229 
230                 /* Next instance.  */
231                 cdc_acm_inst = cdc_acm_inst -> ux_host_class_cdc_acm_next_instance;
232             }
233 
234             /* Mark the cdc_acm as live now.  Both interfaces need to be live. */
235             cdc_acm -> ux_host_class_cdc_acm_state = UX_HOST_CLASS_INSTANCE_LIVE;
236 
237             /* If all is fine and the device is mounted, we may need to inform the application
238                 if a function has been programmed in the system structure.  */
239             if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
240             {
241 
242                 /* Call system change function.  */
243                 _ux_system_host ->  ux_system_host_change_function(UX_DEVICE_INSERTION, cdc_acm -> ux_host_class_cdc_acm_class, (VOID *) cdc_acm);
244             }
245 
246             /* If trace is enabled, insert this event into the trace buffer.  */
247             UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ACM_ACTIVATE, cdc_acm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
248 
249             /* If trace is enabled, register this object.  */
250             UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, cdc_acm, 0, 0, 0)
251 
252             /* We are done success. */
253             return(UX_SUCCESS);
254         }
255     }
256 
257 #else
258 
259     /* Configure the cdc_acm.  */
260     status =  _ux_host_class_cdc_acm_configure(cdc_acm);
261 
262     /* If we are done success, go on to get endpoints.  */
263     if (status == UX_SUCCESS)
264 
265         /* Get the cdc_acm endpoint(s). Depending on the interface type, we will need to search for
266            Bulk Out and Bulk In endpoints and the optional interrupt endpoint.  */
267         status =  _ux_host_class_cdc_acm_endpoints_get(cdc_acm);
268 
269     /* If we are done success, go on to mount interface.  */
270     if (status == UX_SUCCESS)
271     {
272         /* Mark the cdc_acm as mounting now.  Both interfaces need to be mounting. */
273         cdc_acm -> ux_host_class_cdc_acm_state =  UX_HOST_CLASS_INSTANCE_MOUNTING;
274 
275         /* If we have the Control Class, we have to configure the speed, parity ... */
276         if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
277         {
278 
279             /* We need to wait for some device to settle. The Radicom USB Modem is an example of
280                these device who fail the first Set_Line_Coding command if sent too quickly.
281                The timing does not have to be precise so we use the thread sleep function.
282                The default sleep value is 1 seconds.  */
283             _ux_utility_delay_ms(UX_HOST_CLASS_CDC_ACM_DEVICE_INIT_DELAY);
284 
285             /* Do a GET_LINE_CODING first.  */
286             status = _ux_host_class_cdc_acm_ioctl(cdc_acm, UX_HOST_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, (VOID *) &line_coding);
287 
288             /* If we are done success, go on.  */
289             if (status == UX_SUCCESS)
290             {
291 
292                 /* Set the default values to the device, first line coding.  */
293                 line_coding.ux_host_class_cdc_acm_line_coding_dter      = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE;
294                 line_coding.ux_host_class_cdc_acm_line_coding_stop_bit  = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT;
295                 line_coding.ux_host_class_cdc_acm_line_coding_parity    = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY;
296                 line_coding.ux_host_class_cdc_acm_line_coding_data_bits = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT;
297                 status = _ux_host_class_cdc_acm_ioctl(cdc_acm, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, (VOID *) &line_coding);
298             }
299 
300             /* If we are done success, go on.  */
301             if (status == UX_SUCCESS)
302             {
303 
304                 /* Set the default values to the device, line state.  */
305                 line_state.ux_host_class_cdc_acm_line_state_rts       = 1;
306                 line_state.ux_host_class_cdc_acm_line_state_dtr       = 1;
307                 status = _ux_host_class_cdc_acm_ioctl(cdc_acm, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, (VOID *) &line_state);
308             }
309 
310             /* If we are done success, go on.  */
311             if (status == UX_SUCCESS)
312             {
313 
314                 /* Get the capabilities of the device. We need to know if the commands are multiplexed over the comm
315                 interface or the data interface.  */
316                 status =  _ux_host_class_cdc_acm_capabilities_get(cdc_acm);
317             }
318         }
319 
320         /* If we are done success, go on.  */
321         if (status == UX_SUCCESS)
322         {
323             /* Mark the cdc_acm as live now.  Both interfaces need to be live. */
324             cdc_acm -> ux_host_class_cdc_acm_state =  UX_HOST_CLASS_INSTANCE_LIVE;
325 
326             /* If all is fine and the device is mounted, we may need to inform the application
327                if a function has been programmed in the system structure.  */
328             if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
329             {
330 
331                 /* Call system change function.  */
332                 _ux_system_host ->  ux_system_host_change_function(UX_DEVICE_INSERTION, cdc_acm -> ux_host_class_cdc_acm_class, (VOID *) cdc_acm);
333             }
334 
335             /* If trace is enabled, insert this event into the trace buffer.  */
336             UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ACM_ACTIVATE, cdc_acm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
337 
338             /* If trace is enabled, register this object.  */
339             UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, cdc_acm, 0, 0, 0)
340 
341             /* We are done success. */
342             return(UX_SUCCESS);
343         }
344     }
345 #endif
346 
347     /* On error case, it's possible data buffer allocated for interrupt endpoint and transfer started, stop and free it.  */
348     if (cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint &&
349         cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer)
350     {
351 
352         /* The first transfer request has already been initiated. Abort it.  */
353         _ux_host_stack_endpoint_transfer_abort(cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint);
354 
355         /* Free the memory for the data pointer.  */
356         _ux_utility_memory_free(cdc_acm -> ux_host_class_cdc_acm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer);
357     }
358 
359     /* Destroy the instance.  */
360     _ux_host_stack_class_instance_destroy(cdc_acm -> ux_host_class_cdc_acm_class, (VOID *) cdc_acm);
361 
362 #if !defined(UX_HOST_STANDALONE)
363 
364     /* Destroy the semaphore.  */
365     _ux_host_semaphore_delete(&cdc_acm -> ux_host_class_cdc_acm_semaphore);
366 #endif
367 
368     /* Unmount instance. */
369     interface_ptr -> ux_interface_class_instance = UX_NULL;
370 
371     /* Free instance. */
372     _ux_utility_memory_free(cdc_acm);
373 
374     return(status);
375 }
376 
377