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_ACM 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 #if !defined(UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE) && !defined(UX_DEVICE_STANDALONE)
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_device_class_cdc_acm_bulkout_thread PORTABLE C */
37 /* 6.3.0 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function is the thread of the cdc_acm bulk out endpoint. It */
45 /* is waiting for the host to send data on the bulk out endpoint to */
46 /* the device. */
47 /* */
48 /* It's for RTOS mode. */
49 /* */
50 /* INPUT */
51 /* */
52 /* cdc_acm_class Address of cdc_acm class */
53 /* container */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* None */
58 /* */
59 /* CALLS */
60 /* */
61 /* _ux_device_stack_transfer_request Request transfer */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* ThreadX */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
72 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
73 /* resulting in version 6.1 */
74 /* 04-02-2021 Chaoqiong Xiao Modified comment(s), */
75 /* added macro to disable */
76 /* transmission support, */
77 /* resulting in version 6.1.6 */
78 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
79 /* refined macros names, */
80 /* resulting in version 6.1.10 */
81 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
82 /* fixed parameter/variable */
83 /* names conflict C++ keyword, */
84 /* resulting in version 6.1.12 */
85 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
86 /* added zero copy support, */
87 /* added a new mode to manage */
88 /* endpoint buffer in classes, */
89 /* resulting in version 6.3.0 */
90 /* */
91 /**************************************************************************/
_ux_device_class_cdc_acm_bulkout_thread(ULONG cdc_acm_class)92 VOID _ux_device_class_cdc_acm_bulkout_thread(ULONG cdc_acm_class)
93 {
94
95 UX_SLAVE_CLASS_CDC_ACM *cdc_acm;
96 UX_SLAVE_DEVICE *device;
97 UX_SLAVE_ENDPOINT *endpoint;
98 UX_SLAVE_INTERFACE *interface_ptr;
99 UX_SLAVE_TRANSFER *transfer_request;
100 UINT status;
101
102 /* Cast properly the cdc_acm instance. */
103 UX_THREAD_EXTENSION_PTR_GET(cdc_acm, UX_SLAVE_CLASS_CDC_ACM, cdc_acm_class)
104
105 /* Get the pointer to the device. */
106 device = &_ux_system_slave -> ux_system_slave_device;
107
108 /* This is the first time we are activated. We need the interface to the class. */
109 interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface;
110
111 /* Locate the endpoints. */
112 endpoint = interface_ptr -> ux_slave_interface_first_endpoint;
113
114 /* Check the endpoint direction, if OUT we have the correct endpoint. */
115 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT)
116 {
117
118 /* So the next endpoint has to be the OUT endpoint. */
119 endpoint = endpoint -> ux_slave_endpoint_next_endpoint;
120 }
121
122 /* This thread runs forever but can be suspended or resumed by the user application. */
123 while(1)
124 {
125
126 /* Select the transfer request associated with BULK OUT endpoint. */
127 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
128
129 /* As long as the device is in the CONFIGURED state. */
130 while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
131 {
132
133 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
134
135 /* Use class managed buffer. */
136 transfer_request -> ux_slave_transfer_request_data_pointer =
137 UX_DEVICE_CLASS_CDC_ACM_READ_BUFFER(cdc_acm);
138 #endif
139
140 /* Send the request to the device controller. */
141 status = _ux_device_stack_transfer_request(transfer_request, endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize,
142 endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize);
143
144 /* Check the completion code. */
145 if (status == UX_SUCCESS)
146 {
147
148 /* Check the state of the transfer. If there is an error, we do not proceed with this report. */
149 if (transfer_request -> ux_slave_transfer_request_completion_code == UX_SUCCESS)
150 {
151
152 /* If there is a callback defined by the application, send the transaction event to it. */
153 if (cdc_acm -> ux_device_class_cdc_acm_read_callback != UX_NULL)
154
155 /* Callback exists. */
156 cdc_acm -> ux_device_class_cdc_acm_read_callback(cdc_acm, UX_SUCCESS, transfer_request -> ux_slave_transfer_request_data_pointer,
157 transfer_request -> ux_slave_transfer_request_actual_length);
158
159 }
160 else
161 {
162
163 /* We have an error. If there is a callback defined by the application, send the transaction event to it. */
164 if (cdc_acm -> ux_device_class_cdc_acm_read_callback != UX_NULL)
165
166 /* Callback exists. */
167 cdc_acm -> ux_device_class_cdc_acm_read_callback(cdc_acm, status, UX_NULL, 0);
168
169 }
170 }
171 }
172
173 /* We need to suspend ourselves. We will be resumed by the application if needed. */
174 _ux_device_thread_suspend(&cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread);
175 }
176 }
177 #endif
178