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 }