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