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