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 /**   ACM CDC 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_read                         PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function reads from the cdc_acm interface. The call is         */
46 /*    blocking and only returns when there is either an error or when     */
47 /*    the transfer is complete.                                           */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    cdc_acm                               Pointer to cdc_acm class      */
52 /*    data_pointer                          Pointer to buffer             */
53 /*    requested_length                      Requested data read           */
54 /*    actual_length                         Actual data read              */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    Completion Status                                                   */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _ux_host_stack_transfer_request       Process transfer request      */
63 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
64 /*    _ux_host_semaphore_get                Get protection semaphore      */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    Application                                                         */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
75 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            resulting in version 6.1    */
77 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            added standalone support,   */
79 /*                                            resulting in version 6.1.10 */
80 /*                                                                        */
81 /**************************************************************************/
_ux_host_class_cdc_acm_read(UX_HOST_CLASS_CDC_ACM * cdc_acm,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)82 UINT  _ux_host_class_cdc_acm_read (UX_HOST_CLASS_CDC_ACM *cdc_acm, UCHAR *data_pointer,
83                                     ULONG requested_length, ULONG *actual_length)
84 {
85 
86 UX_TRANSFER     *transfer_request;
87 UINT            status;
88 ULONG           transfer_request_length;
89 #if defined(UX_HOST_STANDALONE)
90 ULONG           transfer_flags;
91 #endif
92 
93     /* If trace is enabled, insert this event into the trace buffer.  */
94     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ACM_READ, cdc_acm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
95 
96     /* Ensure the instance is valid.  */
97     if (cdc_acm -> ux_host_class_cdc_acm_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
98     {
99 
100         /* Error trap. */
101         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
102 
103         /* If trace is enabled, insert this event into the trace buffer.  */
104         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, cdc_acm, 0, 0, UX_TRACE_ERRORS, 0, 0)
105 
106         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
107     }
108 
109     /* As further protection, we must ensure this instance of the interface is the data interface and not
110        the control interface !  */
111     if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass != UX_HOST_CLASS_CDC_DATA_CLASS)
112     {
113 
114         /* Error trap. */
115         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
116 
117         /* If trace is enabled, insert this event into the trace buffer.  */
118         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, cdc_acm, 0, 0, UX_TRACE_ERRORS, 0, 0)
119 
120         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
121     }
122 
123     /* Start by resetting the actual length of the transfer to zero.  */
124     *actual_length =  0;
125 
126     /* Get the pointer to the bulk in endpoint in the transfer_request.  */
127     transfer_request =  &cdc_acm -> ux_host_class_cdc_acm_bulk_in_endpoint -> ux_endpoint_transfer_request;
128 
129 #if defined(UX_HOST_STANDALONE)
130 
131     /* Enable auto wait.  */
132     transfer_flags = transfer_request -> ux_transfer_request_flags;
133     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
134 #endif
135 
136     /* Perform a transfer on the bulk in endpoint until either the transfer is
137        completed or until there is an error.  */
138     while (requested_length)
139     {
140 
141         /* Program the maximum authorized length for this transfer request.  */
142         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
143             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
144         else
145             transfer_request_length =  requested_length;
146 
147         /* Initialize the transfer request.  */
148         transfer_request -> ux_transfer_request_data_pointer =      data_pointer;
149         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
150 
151         /* Perform the transfer.  */
152         status =  _ux_host_stack_transfer_request(transfer_request);
153 
154         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
155         if (status == UX_SUCCESS)
156         {
157 #if !defined(UX_HOST_STANDALONE)
158 
159             /* Wait for the completion of the transfer_request.  */
160             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore,
161                                              transfer_request -> ux_transfer_request_timeout_value);
162 
163             /* If the semaphore did not succeed we probably have a time out.  */
164             if (status != UX_SUCCESS)
165             {
166 
167                 /* All transfers pending need to abort. There may have been a partial transfer.  */
168                 _ux_host_stack_transfer_request_abort(transfer_request);
169 
170                 /* Update the length of the actual data transferred. We do this after the
171                    abort of the transfer request in case some data was actually received.  */
172                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
173 
174                 /* Set the completion code.  */
175                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
176 
177                 /* Error trap. */
178                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
179 
180                 /* If trace is enabled, insert this event into the trace buffer.  */
181                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
182 
183                 /* There was an error, return to the caller */
184                 return(UX_TRANSFER_TIMEOUT);
185             }
186 #endif
187         }
188         else
189         {
190 
191 #if defined(UX_HOST_STANDALONE)
192 
193             /* Update the length of the actual data transferred. We do this after the
194                 abort of the transfer request in case some data was actually received.  */
195             *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
196 
197             /* Restore previous setting.  */
198             transfer_request -> ux_transfer_request_flags = transfer_flags;
199 #endif
200 
201             /* There was a non transfer error, no partial transfer to be checked.  */
202             return(status);
203         }
204 
205         /* Update the length of the transfer. Normally all the data has to be received.  */
206         *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
207 
208         /* Check for completion of transfer. If the transfer is partial, return to caller.
209            The transfer is marked as successful but the caller will need to check the length
210            actually received and determine if a partial transfer is OK.  */
211         if (transfer_request_length != transfer_request -> ux_transfer_request_actual_length)
212         {
213 
214             /* Return success to caller.  */
215             return(UX_SUCCESS);
216         }
217 
218         /* Update the data pointer for next transfer. */
219         data_pointer +=  transfer_request_length;
220 
221         /* Update what is left to receive.  */
222         requested_length -=  transfer_request_length;
223     }
224 
225 #if defined(UX_HOST_STANDALONE)
226 
227     /* Restore previous setting.  */
228     transfer_request -> ux_transfer_request_flags = transfer_flags;
229 #endif
230 
231     /* We get here when all the transfers went through without errors.  */
232     return(UX_SUCCESS);
233 }
234 
235