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 /** USBX Component */
15 /** */
16 /** Device CDC Class */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 #define UX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "ux_api.h"
27 #include "ux_device_class_cdc_acm.h"
28 #include "ux_device_stack.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_class_cdc_acm_ioctl PORTABLE C */
36 /* 6.3.0 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function performs certain functions on the cdc acm instance */
44 /* */
45 /* INPUT */
46 /* */
47 /* cdc_acm Address of cdc_acm class */
48 /* instance */
49 /* */
50 /* OUTPUT */
51 /* */
52 /* Status */
53 /* */
54 /* CALLS */
55 /* */
56 /* _ux_device_stack_transfer_abort Abort transfer */
57 /* _ux_utility_memory_allocate Allocate memory */
58 /* _ux_utility_memory_free Free memory */
59 /* _ux_utility_event_flags_create Create event flags */
60 /* _ux_utility_event_flags_delete Delete event flags */
61 /* _ux_device_thread_create Create thread */
62 /* _ux_device_thread_delete Delete thread */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* Application */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
73 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
74 /* used UX prefix to refer to */
75 /* TX symbols instead of using */
76 /* them directly, */
77 /* resulting in version 6.1 */
78 /* 03-02-2021 Xiuwen Cai Modified comment(s), removed */
79 /* unreachable statement, */
80 /* resulting in version 6.1.5 */
81 /* 04-02-2021 Chaoqiong Xiao Modified comment(s), */
82 /* added macro to disable */
83 /* transmission support, */
84 /* moved transmission resource */
85 /* management to init/uninit, */
86 /* resulting in version 6.1.6 */
87 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
88 /* fixed compile issue, */
89 /* resulting in version 6.1.9 */
90 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
91 /* added standalone support, */
92 /* fixed aborting return code, */
93 /* resulting in version 6.1.10 */
94 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
95 /* fixed parameter/variable */
96 /* names conflict C++ keyword, */
97 /* resulting in version 6.1.12 */
98 /* 10-31-2023 Yajun Xia Modified comment(s), */
99 /* resulting in version 6.3.0 */
100 /* */
101 /**************************************************************************/
_ux_device_class_cdc_acm_ioctl(UX_SLAVE_CLASS_CDC_ACM * cdc_acm,ULONG ioctl_function,VOID * parameter)102 UINT _ux_device_class_cdc_acm_ioctl(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ioctl_function,
103 VOID *parameter)
104 {
105
106 UINT status;
107 UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER *line_coding;
108 UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER *line_state;
109 #ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE
110 UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER *callback;
111 #endif
112 UX_SLAVE_ENDPOINT *endpoint;
113 UX_SLAVE_INTERFACE *interface_ptr;
114 UX_SLAVE_TRANSFER *transfer_request;
115
116 /* Let's be optimist ! */
117 status = UX_SUCCESS;
118
119 /* The command request will tell us what we need to do here. */
120 switch (ioctl_function)
121 {
122
123 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING:
124
125 /* Properly cast the parameter pointer. */
126 line_coding = (UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER *) parameter;
127
128 /* Save the parameters in the cdc_acm function. */
129 cdc_acm -> ux_slave_class_cdc_acm_baudrate = line_coding -> ux_slave_class_cdc_acm_parameter_baudrate;
130 cdc_acm -> ux_slave_class_cdc_acm_stop_bit = line_coding -> ux_slave_class_cdc_acm_parameter_stop_bit;
131 cdc_acm -> ux_slave_class_cdc_acm_parity = line_coding -> ux_slave_class_cdc_acm_parameter_parity;
132 cdc_acm -> ux_slave_class_cdc_acm_data_bit = line_coding -> ux_slave_class_cdc_acm_parameter_data_bit;
133
134 break;
135
136 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING:
137
138 /* Properly cast the parameter pointer. */
139 line_coding = (UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER *) parameter;
140
141 /* Save the parameters in the cdc_acm function. */
142 line_coding -> ux_slave_class_cdc_acm_parameter_baudrate = cdc_acm -> ux_slave_class_cdc_acm_baudrate;
143 line_coding -> ux_slave_class_cdc_acm_parameter_stop_bit = cdc_acm -> ux_slave_class_cdc_acm_stop_bit;
144 line_coding -> ux_slave_class_cdc_acm_parameter_parity = cdc_acm -> ux_slave_class_cdc_acm_parity;
145 line_coding -> ux_slave_class_cdc_acm_parameter_data_bit = cdc_acm -> ux_slave_class_cdc_acm_data_bit;
146
147 break;
148
149
150 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE:
151
152 /* Properly cast the parameter pointer. */
153 line_state = (UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER *) parameter;
154
155 /* Return the DTR/RTS signals. */
156 line_state -> ux_slave_class_cdc_acm_parameter_rts = cdc_acm -> ux_slave_class_cdc_acm_data_rts_state;
157 line_state -> ux_slave_class_cdc_acm_parameter_dtr = cdc_acm -> ux_slave_class_cdc_acm_data_dtr_state;
158
159 break;
160
161 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE:
162
163 /* Properly cast the parameter pointer. */
164 line_state = (UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER *) parameter;
165
166 /* Set the DTR/RTS signals. */
167 cdc_acm -> ux_slave_class_cdc_acm_data_rts_state = line_state -> ux_slave_class_cdc_acm_parameter_rts;
168 cdc_acm -> ux_slave_class_cdc_acm_data_dtr_state = line_state -> ux_slave_class_cdc_acm_parameter_dtr;
169
170 break;
171
172
173 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE:
174
175 /* Get the interface from the instance. */
176 interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface;
177
178 /* Locate the endpoints. */
179 endpoint = interface_ptr -> ux_slave_interface_first_endpoint;
180
181 /* What direction ? */
182 switch( (ULONG) (ALIGN_TYPE) parameter)
183 {
184 case UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT :
185
186 /* Check the endpoint direction, if IN we have the correct endpoint. */
187 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN)
188 {
189
190 /* So the next endpoint has to be the XMIT endpoint. */
191 endpoint = endpoint -> ux_slave_endpoint_next_endpoint;
192 }
193 break;
194
195 case UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV :
196
197 /* Check the endpoint direction, if OUT we have the correct endpoint. */
198 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT)
199 {
200
201 /* So the next endpoint has to be the RCV endpoint. */
202 endpoint = endpoint -> ux_slave_endpoint_next_endpoint;
203 }
204 break;
205
206
207
208 default :
209
210 /* Parameter not supported. Return an error. */
211 status = UX_ENDPOINT_HANDLE_UNKNOWN;
212 }
213
214 /* Get the transfer request associated with the endpoint. */
215 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
216
217 #if defined(UX_DEVICE_STANDALONE)
218
219 /* Abort the transfer. */
220 _ux_device_stack_transfer_abort(transfer_request, UX_TRANSFER_STATUS_ABORT);
221 if ((ULONG) (ALIGN_TYPE) parameter == UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT)
222 cdc_acm -> ux_device_class_cdc_acm_write_state = UX_STATE_RESET;
223 else
224 cdc_acm -> ux_device_class_cdc_acm_read_state = UX_STATE_RESET;
225 #else
226
227 /* Check the status of the transfer. */
228 if (transfer_request -> ux_slave_transfer_request_status == UX_TRANSFER_STATUS_PENDING)
229 {
230
231 /* Abort the transfer. */
232 _ux_device_stack_transfer_abort(transfer_request, UX_ABORTED);
233
234 }
235 #endif
236 break;
237
238 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT:
239 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT:
240
241 /* Get the interface from the instance. */
242 interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface;
243
244 /* Locate the endpoints. */
245 endpoint = interface_ptr -> ux_slave_interface_first_endpoint;
246
247 /* If it's reading timeout but endpoint is OUT, it should be the next one. */
248 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) !=
249 (ULONG)((ioctl_function == UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT) ? UX_ENDPOINT_OUT : UX_ENDPOINT_IN))
250 endpoint = endpoint -> ux_slave_endpoint_next_endpoint;
251
252 /* Get the transfer request associated with the endpoint. */
253 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
254
255 /* Check the status of the transfer. */
256 if (transfer_request -> ux_slave_transfer_request_status == UX_TRANSFER_STATUS_PENDING)
257 status = UX_ERROR;
258 else
259 transfer_request -> ux_slave_transfer_request_timeout = (ULONG) (ALIGN_TYPE) parameter;
260
261 break;
262
263 #ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE
264
265 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START:
266
267 /* Check if we are in callback transmission already. */
268 if (cdc_acm -> ux_slave_class_cdc_acm_transmission_status == UX_TRUE)
269 {
270 /* We should not to that ! */
271 return(UX_ERROR);
272
273 }
274
275 /* Properly cast the parameter pointer. */
276 callback = (UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER *) parameter;
277
278 /* Save the callback function for write. */
279 cdc_acm -> ux_device_class_cdc_acm_write_callback = callback -> ux_device_class_cdc_acm_parameter_write_callback;
280
281 /* Save the callback function for read. */
282 cdc_acm -> ux_device_class_cdc_acm_read_callback = callback -> ux_device_class_cdc_acm_parameter_read_callback;
283
284 #if !defined(UX_DEVICE_STANDALONE)
285
286 /* Start transmission threads. */
287 _ux_utility_thread_resume(&cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread);
288 _ux_utility_thread_resume(&cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread);
289 #endif
290
291 /* Declare the transmission with callback on. */
292 cdc_acm -> ux_slave_class_cdc_acm_transmission_status = UX_TRUE;
293
294 /* We are done here. */
295 return(UX_SUCCESS);
296
297 case UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP:
298
299 /* Check if we are in callback transmission already. */
300 if (cdc_acm -> ux_slave_class_cdc_acm_transmission_status == UX_TRUE)
301 {
302
303 /* Get the interface from the instance. */
304 interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface;
305
306 /* Locate the endpoints. */
307 endpoint = interface_ptr -> ux_slave_interface_first_endpoint;
308
309 /* Get the transfer request associated with the endpoint. */
310 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
311
312 /* Abort the transfer. */
313 _ux_device_stack_transfer_abort(transfer_request, UX_ABORTED);
314
315 /* Next endpoint. */
316 endpoint = endpoint -> ux_slave_endpoint_next_endpoint;
317
318 /* Get the transfer request associated with the endpoint. */
319 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
320
321 /* Abort the transfer. */
322 _ux_device_stack_transfer_abort(transfer_request, UX_ABORTED);
323
324 #if !defined(UX_DEVICE_STANDALONE)
325
326 /* Suspend threads. */
327 _ux_device_thread_suspend(&cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread);
328 _ux_device_thread_suspend(&cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread);
329 #endif
330
331 /* Clear scheduled write flag. */
332 cdc_acm -> ux_slave_class_cdc_acm_scheduled_write = UX_FALSE;
333
334 /* Declare the transmission with callback off. */
335 cdc_acm -> ux_slave_class_cdc_acm_transmission_status = UX_FALSE;
336 }
337 else
338
339 /* We should not try to stop an non existing transmission. */
340 return(UX_ERROR);
341
342 break;
343 #endif
344
345 default:
346
347 /* Error trap. */
348 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
349
350 /* If trace is enabled, insert this event into the trace buffer. */
351 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
352
353 /* Function not supported. Return an error. */
354 status = UX_FUNCTION_NOT_SUPPORTED;
355 }
356
357 /* Return status to caller. */
358 return(status);
359
360 }
361
362 /**************************************************************************/
363 /* */
364 /* FUNCTION RELEASE */
365 /* */
366 /* _uxe_device_class_cdc_acm_ioctl PORTABLE C */
367 /* 6.3.0 */
368 /* AUTHOR */
369 /* */
370 /* Yajun Xia, Microsoft Corporation */
371 /* */
372 /* DESCRIPTION */
373 /* */
374 /* This function checks errors in CDC ACM class ioctl function. */
375 /* */
376 /* INPUT */
377 /* */
378 /* cdc_acm Address of cdc_acm class */
379 /* instance */
380 /* ioctl_function Ioctl function */
381 /* Parameter Parameter of ioctl function */
382 /* */
383 /* OUTPUT */
384 /* */
385 /* Status */
386 /* */
387 /* CALLS */
388 /* */
389 /* _ux_device_class_cdc_acm_ioctl CDC ACM class ioctl function */
390 /* */
391 /* CALLED BY */
392 /* */
393 /* Application */
394 /* */
395 /* RELEASE HISTORY */
396 /* */
397 /* DATE NAME DESCRIPTION */
398 /* */
399 /* 10-31-2023 Yajun Xia Initial Version 6.3.0 */
400 /* */
401 /**************************************************************************/
_uxe_device_class_cdc_acm_ioctl(UX_SLAVE_CLASS_CDC_ACM * cdc_acm,ULONG ioctl_function,VOID * parameter)402 UINT _uxe_device_class_cdc_acm_ioctl(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ioctl_function,
403 VOID *parameter)
404 {
405
406 /* Sanity checks. */
407 if (cdc_acm == UX_NULL)
408 {
409 return (UX_INVALID_PARAMETER);
410 }
411
412 return (_ux_device_class_cdc_acm_ioctl(cdc_acm, ioctl_function, parameter));
413 }