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 /**                                                                       */
15 /** USBX Component                                                        */
16 /**                                                                       */
17 /**   Generic Serial Host module class                                    */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 
23 /* Include necessary system files.  */
24 
25 #define UX_SOURCE_CODE
26 
27 #include "ux_api.h"
28 #include "ux_host_class_gser.h"
29 #include "ux_host_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_host_class_gser_read                            PORTABLE C      */
37 /*                                                           6.1.11       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function reads from the gser interface. The call is            */
45 /*    blocking and only returns when there is either an error or when     */
46 /*    the transfer is complete.                                           */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    gser                                  Pointer to gser class         */
51 /*    data_pointer                          Pointer to buffer             */
52 /*    requested_length                      Requested data read           */
53 /*    actual_length                         Actual data read              */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    Completion Status                                                   */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _ux_host_stack_transfer_request       Process transfer request      */
62 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
63 /*    _ux_host_semaphore_get                Get protection semaphore      */
64 /*    _ux_host_semaphore_put                Release 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 /*                                            prefixed UX to MS_TO_TICK,  */
77 /*                                            resulting in version 6.1    */
78 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            refined macros names,       */
80 /*                                            resulting in version 6.1.10 */
81 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            fixed standalone compile,   */
83 /*                                            resulting in version 6.1.11 */
84 /*                                                                        */
85 /**************************************************************************/
_ux_host_class_gser_read(UX_HOST_CLASS_GSER * gser,ULONG interface_index,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)86 UINT  _ux_host_class_gser_read(UX_HOST_CLASS_GSER *gser,
87                                     ULONG interface_index,
88                                     UCHAR *data_pointer,
89                                     ULONG requested_length,
90                                     ULONG *actual_length)
91 {
92 
93 UX_TRANSFER     *transfer_request;
94 UINT            status;
95 ULONG           transfer_request_length;
96 
97     /* If trace is enabled, insert this event into the trace buffer.  */
98     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_GSER_READ, gser, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
99 
100     /* Ensure the instance is valid.  */
101     if (gser -> ux_host_class_gser_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
102     {
103 
104         /* Error trap. */
105         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
106 
107         /* If trace is enabled, insert this event into the trace buffer.  */
108         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, gser, 0, 0, UX_TRACE_ERRORS, 0, 0)
109 
110         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
111     }
112 
113     /* Protect thread reentry to this instance.  */
114     status =  _ux_host_semaphore_get(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore, UX_WAIT_FOREVER);
115     if (status != UX_SUCCESS)
116         return(status);
117 
118     /* Start by resetting the actual length of the transfer to zero.  */
119     *actual_length =  0;
120 
121     /* Get the pointer to the bulk in endpoint in the transfer_request.  */
122     transfer_request =  &gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_bulk_in_endpoint -> ux_endpoint_transfer_request;
123 
124     /* Save the interface number in the Transfer Request. */
125     transfer_request -> ux_transfer_request_user_specific = (VOID *)(ALIGN_TYPE)interface_index;
126 
127     /* Perform a transfer on the bulk in endpoint until either the transfer is
128        completed or until there is an error.  */
129     while (requested_length)
130     {
131 
132         /* Program the maximum authorized length for this transfer request.  */
133         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
134             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
135         else
136             transfer_request_length =  requested_length;
137 
138         /* Initialize the transfer request.  */
139         transfer_request -> ux_transfer_request_data_pointer =      data_pointer;
140         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
141 
142         /* Perform the transfer.  */
143         status =  _ux_host_stack_transfer_request(transfer_request);
144 
145         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
146         if (status == UX_SUCCESS)
147         {
148 
149             /* Wait for the completion of the transfer_request.  */
150             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_GSER_CLASS_TRANSFER_TIMEOUT));
151 
152             /* If the semaphore did not succeed we probably have a time out.  */
153             if (status != UX_SUCCESS)
154             {
155 
156                 /* All transfers pending need to abort. There may have been a partial transfer.  */
157                 _ux_host_stack_transfer_request_abort(transfer_request);
158 
159                 /* Update the length of the actual data transferred. We do this after the
160                    abort of the transfer request in case some data was actually received.  */
161                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
162 
163                 /* Unprotect thread reentry to this instance.  */
164                 _ux_host_semaphore_put(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore);
165 
166                 /* Set the completion code.  */
167                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
168 
169                 /* Error trap. */
170                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
171 
172                 /* If trace is enabled, insert this event into the trace buffer.  */
173                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
174 
175                 /* There was an error, return to the caller */
176                 return(UX_TRANSFER_TIMEOUT);
177             }
178         }
179         else
180         {
181 
182             /* Unprotect thread reentry to this instance.  */
183             _ux_host_semaphore_put(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore);
184 
185             /* There was a non transfer error, no partial transfer to be checked.  */
186             return(status);
187         }
188 
189         /* Update the length of the transfer. Normally all the data has to be received.  */
190         *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
191 
192         /* Check for completion of transfer. If the transfer is partial, return to caller.
193            The transfer is marked as successful but the caller will need to check the length
194            actually received and determine if a partial transfer is OK.  */
195         if (transfer_request_length != transfer_request -> ux_transfer_request_actual_length)
196         {
197 
198             /* Unprotect thread reentry to this instance.  */
199             _ux_host_semaphore_put(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore);
200 
201             /* Return success to caller.  */
202             return(UX_SUCCESS);
203         }
204 
205         /* Update the data pointer for next transfer. */
206         data_pointer +=  transfer_request_length;
207 
208         /* Update what is left to receive.  */
209         requested_length -=  transfer_request_length;
210     }
211 
212     /* Unprotect thread reentry to this instance.  */
213     _ux_host_semaphore_put(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore);
214 
215     /* We get here when all the transfers went through without errors.  */
216     return(UX_SUCCESS);
217 }
218 
219 
220 /**************************************************************************/
221 /*                                                                        */
222 /*  FUNCTION                                               RELEASE        */
223 /*                                                                        */
224 /*    _uxe_host_class_gser_read                           PORTABLE C      */
225 /*                                                           6.3.0        */
226 /*  AUTHOR                                                                */
227 /*                                                                        */
228 /*    Chaoqiong Xiao, Microsoft Corporation                               */
229 /*                                                                        */
230 /*  DESCRIPTION                                                           */
231 /*                                                                        */
232 /*    This function checks errors in GSER read function call.             */
233 /*                                                                        */
234 /*  INPUT                                                                 */
235 /*                                                                        */
236 /*    gser                                  Pointer to GSER class         */
237 /*    data_pointer                          Pointer to buffer             */
238 /*    requested_length                      Requested data read           */
239 /*    actual_length                         Actual data read              */
240 /*                                                                        */
241 /*  OUTPUT                                                                */
242 /*                                                                        */
243 /*    Status                                                              */
244 /*                                                                        */
245 /*  CALLS                                                                 */
246 /*                                                                        */
247 /*    _ux_host_class_gser_read              GSER read                     */
248 /*                                                                        */
249 /*  CALLED BY                                                             */
250 /*                                                                        */
251 /*    Application                                                         */
252 /*                                                                        */
253 /*  RELEASE HISTORY                                                       */
254 /*                                                                        */
255 /*    DATE              NAME                      DESCRIPTION             */
256 /*                                                                        */
257 /*  10-31-2023     Chaoqiong Xiao           Initial Version 6.3.0         */
258 /*                                                                        */
259 /**************************************************************************/
_uxe_host_class_gser_read(UX_HOST_CLASS_GSER * gser,ULONG interface_index,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)260 UINT  _uxe_host_class_gser_read(UX_HOST_CLASS_GSER *gser,
261                                     ULONG interface_index,
262                                     UCHAR *data_pointer,
263                                     ULONG requested_length,
264                                     ULONG *actual_length)
265 {
266 
267     /* Sanity checks.  */
268     if ((gser == UX_NULL) || (data_pointer == UX_NULL) || (actual_length == UX_NULL))
269     {
270         return(UX_INVALID_PARAMETER);
271     }
272 
273     /* Invoke GSER read function.  */
274     return(_ux_host_class_gser_read(gser, interface_index, data_pointer, requested_length, actual_length));
275 }
276