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