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 #if !defined(UX_DEVICE_STANDALONE)
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_device_class_cdc_acm_read                       PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function reads from the CDC class.                             */
45 /*                                                                        */
46 /*    It's for RTOS mode.                                                 */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    cdc_acm                                   Address of cdc_acm class  */
51 /*                                              instance                  */
52 /*    buffer                                    Pointer to buffer to save */
53 /*                                              received data             */
54 /*    requested_length                          Length of bytes to read   */
55 /*    actual_length                             Pointer to save number of */
56 /*                                              bytes read                */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    None                                                                */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _ux_device_stack_transfer_request     Transfer request              */
65 /*    _ux_utility_memory_copy               Copy memory                   */
66 /*    _ux_device_mutex_off                  Release mutex                 */
67 /*                                                                        */
68 /*  CALLED BY                                                             */
69 /*                                                                        */
70 /*    Application                                                         */
71 /*                                                                        */
72 /*  RELEASE HISTORY                                                       */
73 /*                                                                        */
74 /*    DATE              NAME                      DESCRIPTION             */
75 /*                                                                        */
76 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
77 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            verified memset and memcpy  */
79 /*                                            cases,                      */
80 /*                                            resulting in version 6.1    */
81 /*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            fixed compile issue,        */
83 /*                                            resulting in version 6.1.9  */
84 /*  01-31-2022x    Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            resulting in version 6.1.10 */
86 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
87 /*                                            resulting in version 6.1.11 */
88 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            fixed parameter/variable    */
90 /*                                            names conflict C++ keyword, */
91 /*                                            resulting in version 6.1.12 */
92 /*  10-31-2023     Yajun Xia, CQ Xiao       Modified comment(s),          */
93 /*                                            added zero copy support,    */
94 /*                                            added a new mode to manage  */
95 /*                                            endpoint buffer in classes, */
96 /*                                            resulting in version 6.3.0  */
97 /*                                                                        */
98 /**************************************************************************/
_ux_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM * cdc_acm,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)99 UINT _ux_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer,
100                                 ULONG requested_length, ULONG *actual_length)
101 {
102 
103 UX_SLAVE_ENDPOINT           *endpoint;
104 UX_SLAVE_DEVICE             *device;
105 UX_SLAVE_INTERFACE          *interface_ptr;
106 UX_SLAVE_TRANSFER           *transfer_request;
107 UINT                        status= UX_SUCCESS;
108 ULONG                       local_requested_length;
109 
110     /* If trace is enabled, insert this event into the trace buffer.  */
111     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ACM_READ, cdc_acm, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
112 
113 #ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE
114 
115     /* Check if current cdc-acm is using callback or not. We cannot use direct reads with callback on.  */
116     if (cdc_acm -> ux_slave_class_cdc_acm_transmission_status == UX_TRUE)
117 
118         /* Not allowed. */
119         return(UX_ERROR);
120 #endif
121 
122     /* Get the pointer to the device.  */
123     device =  &_ux_system_slave -> ux_system_slave_device;
124 
125     /* As long as the device is in the CONFIGURED state.  */
126     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
127     {
128 
129         /* Error trap. */
130         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN);
131 
132 
133         /* If trace is enabled, insert this event into the trace buffer.  */
134         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
135 
136         /* Cannot proceed with command, the interface is down.  */
137         return(UX_CONFIGURATION_HANDLE_UNKNOWN);
138     }
139 
140     /* This is the first time we are activated. We need the interface to the class.  */
141     interface_ptr =  cdc_acm -> ux_slave_class_cdc_acm_interface;
142 
143     /* Locate the endpoints.  */
144     endpoint =  interface_ptr -> ux_slave_interface_first_endpoint;
145 
146     /* Check the endpoint direction, if OUT we have the correct endpoint.  */
147     if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT)
148     {
149 
150         /* So the next endpoint has to be the OUT endpoint.  */
151         endpoint =  endpoint -> ux_slave_endpoint_next_endpoint;
152     }
153 
154     /* Protect this thread.  */
155     _ux_device_mutex_on(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex);
156 
157     /* All CDC readings are on the endpoint OUT, from the host.  */
158     transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
159 
160 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
161 #if !defined(UX_DEVICE_CLASS_CDC_ACM_ZERO_COPY)
162     transfer_request -> ux_slave_transfer_request_data_pointer =
163                                 UX_DEVICE_CLASS_CDC_ACM_READ_BUFFER(cdc_acm);
164 #else
165     transfer_request -> ux_slave_transfer_request_data_pointer = buffer;
166 #endif
167 #endif
168 
169 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ACM_ZERO_COPY)
170 
171     /* Check if device is configured.  */
172     if (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
173     {
174 
175         /* Issue the transfer request.  */
176         local_requested_length = requested_length;
177         status = _ux_device_stack_transfer_request(transfer_request, requested_length, local_requested_length);
178         *actual_length = transfer_request -> ux_slave_transfer_request_actual_length;
179     }
180 
181 #else
182 
183     /* Reset the actual length.  */
184     *actual_length =  0;
185 
186     /* Check if we need more transactions.  */
187     while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED && requested_length != 0)
188     {
189 
190         /* Check if we have enough in the local buffer.  */
191         if (requested_length > endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize)
192 
193             /* We have too much to transfer.  */
194             local_requested_length = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize;
195 
196         else
197 
198             /* We can proceed with the demanded length.  */
199             local_requested_length = requested_length;
200 
201         /* Send the request to the device controller.  */
202         status =  _ux_device_stack_transfer_request(transfer_request, local_requested_length, local_requested_length);
203 
204         /* Check the status */
205         if (status == UX_SUCCESS)
206         {
207 
208             /* We need to copy the buffer locally.  */
209             _ux_utility_memory_copy(buffer, transfer_request -> ux_slave_transfer_request_data_pointer,
210                             transfer_request -> ux_slave_transfer_request_actual_length); /* Use case of memcpy is verified. */
211 
212             /* Next buffer address.  */
213             buffer += transfer_request -> ux_slave_transfer_request_actual_length;
214 
215             /* Set the length actually received. */
216             *actual_length += transfer_request -> ux_slave_transfer_request_actual_length;
217 
218             /* Decrement what left has to be done.  */
219             requested_length -= transfer_request -> ux_slave_transfer_request_actual_length;
220 
221 
222             /* Is this a short packet or a ZLP indicating we are done with this transfer ?  */
223             if (transfer_request -> ux_slave_transfer_request_actual_length < endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize)
224             {
225 
226                 /* We are done.  */
227                 /* Free Mutex resource.  */
228                 _ux_device_mutex_off(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex);
229 
230                 /* Return with success.  */
231                 return(UX_SUCCESS);
232 
233             }
234         }
235         else
236         {
237 
238             /* Free Mutex resource.  */
239             _ux_device_mutex_off(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex);
240 
241             /* We got an error.  */
242             return(status);
243         }
244     }
245 
246 #endif
247 
248     /* Free Mutex resource.  */
249     _ux_device_mutex_off(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex);
250 
251     /* Check why we got here, either completion or device was extracted.  */
252     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
253     {
254 
255         /* Error trap. */
256         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_NO_ANSWER);
257 
258         /* If trace is enabled, insert this event into the trace buffer.  */
259         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_NO_ANSWER, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
260 
261         /* Device must have been extracted.  */
262         return (UX_TRANSFER_NO_ANSWER);
263     }
264     else
265 
266         /* Simply return the last transaction result.  */
267         return(status);
268 }
269 
270 /**************************************************************************/
271 /*                                                                        */
272 /*  FUNCTION                                               RELEASE        */
273 /*                                                                        */
274 /*    _uxe_device_class_cdc_acm_read                      PORTABLE C      */
275 /*                                                           6.3.0        */
276 /*  AUTHOR                                                                */
277 /*                                                                        */
278 /*    Yajun Xia, Microsoft Corporation                                    */
279 /*                                                                        */
280 /*  DESCRIPTION                                                           */
281 /*                                                                        */
282 /*    This function checks errors in CDC ACM class read function.         */
283 /*                                                                        */
284 /*  INPUT                                                                 */
285 /*                                                                        */
286 /*    cdc_acm                                   Address of cdc_acm class  */
287 /*                                              instance                  */
288 /*    buffer                                    Pointer to buffer to save */
289 /*                                              received data             */
290 /*    requested_length                          Length of bytes to read   */
291 /*    actual_length                             Pointer to save number of */
292 /*                                              bytes read                */
293 /*                                                                        */
294 /*  OUTPUT                                                                */
295 /*                                                                        */
296 /*    None                                                                */
297 /*                                                                        */
298 /*  CALLS                                                                 */
299 /*                                                                        */
300 /*    _ux_device_class_cdc_acm_read         CDC ACM class read function   */
301 /*                                                                        */
302 /*  CALLED BY                                                             */
303 /*                                                                        */
304 /*    Application                                                         */
305 /*                                                                        */
306 /*  RELEASE HISTORY                                                       */
307 /*                                                                        */
308 /*    DATE              NAME                      DESCRIPTION             */
309 /*                                                                        */
310 /*  10-31-2023     Yajun Xia                Initial Version 6.3.0         */
311 /*                                                                        */
312 /**************************************************************************/
_uxe_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM * cdc_acm,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)313 UINT _uxe_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer,
314                                     ULONG requested_length, ULONG *actual_length)
315 {
316 
317     /* Sanity checks.  */
318     if ((cdc_acm == UX_NULL) || ((buffer == UX_NULL) && (requested_length > 0)) || (actual_length == UX_NULL))
319     {
320         return (UX_INVALID_PARAMETER);
321     }
322 
323     return (_ux_device_class_cdc_acm_read(cdc_acm, buffer, requested_length, actual_length));
324 }
325 
326 #endif