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 /**   Host Data Pump 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_dpump.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_host_class_dpump_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 dpump 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 /*    dpump                                 Pointer to dpump 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_class_instance_verify  Verify the class instance     */
63 /*    _ux_host_stack_transfer_request       Process transfer request      */
64 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
65 /*    _ux_utility_semaphore_get             Get protection semaphore      */
66 /*    _ux_utility_semaphore_put             Release protection semaphore  */
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 /*                                            resulting in version 6.1    */
79 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            added standalone support,   */
81 /*                                            resulting in version 6.1.10 */
82 /*                                                                        */
83 /**************************************************************************/
_ux_host_class_dpump_read(UX_HOST_CLASS_DPUMP * dpump,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)84 UINT  _ux_host_class_dpump_read(UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer,
85                                     ULONG requested_length, ULONG *actual_length)
86 {
87 
88 #if defined(UX_HOST_STANDALONE)
89 UX_INTERRUPT_SAVE_AREA
90 #endif
91 UX_TRANSFER     *transfer_request;
92 UINT            status;
93 ULONG           transfer_request_length;
94 
95     /* If trace is enabled, insert this event into the trace buffer.  */
96     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_DPUMP_READ, dpump, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
97 
98     /* Ensure the instance is valid.  */
99     if (_ux_host_stack_class_instance_verify(_ux_system_host_class_dpump_name, (VOID *) dpump) != UX_SUCCESS)
100     {
101 
102         /* Error trap. */
103         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
104 
105         /* If trace is enabled, insert this event into the trace buffer.  */
106         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, dpump, 0, 0, UX_TRACE_ERRORS, 0, 0)
107 
108         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
109     }
110 
111     /* Protect thread reentry to this instance.  */
112 #if defined(UX_HOST_STANDALONE)
113     UX_DISABLE
114     if (dpump -> ux_host_class_dpump_flags & UX_HOST_CLASS_DPUMP_READ_LOCK)
115     {
116         UX_RESTORE
117         return(UX_BUSY);
118     }
119     dpump -> ux_host_class_dpump_flags |= UX_HOST_CLASS_DPUMP_READ_LOCK;
120     UX_RESTORE
121 #else
122     status =  _ux_host_semaphore_get(&dpump -> ux_host_class_dpump_semaphore, UX_WAIT_FOREVER);
123     if (status != UX_SUCCESS)
124         return(status);
125 #endif
126 
127     /* Start by resetting the actual length of the transfer to zero.  */
128     *actual_length =  0;
129 
130     /* Get the pointer to the bulk in endpoint in the transfer_request.  */
131     transfer_request =  &dpump -> ux_host_class_dpump_bulk_in_endpoint -> ux_endpoint_transfer_request;
132 
133 #if defined(UX_HOST_STANDALONE)
134 
135     /* Here wait blocking mode is used.  */
136     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
137 #endif
138 
139     /* Perform a transfer on the bulk in endpoint until either the transfer is
140        completed or until there is an error.  */
141     while (requested_length)
142     {
143 
144         /* Program the maximum authorized length for this transfer request.  */
145         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
146             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
147         else
148             transfer_request_length =  requested_length;
149 
150         /* Initialize the transfer request.  */
151         transfer_request -> ux_transfer_request_data_pointer =      data_pointer;
152         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
153 
154         /* Perform the transfer.  */
155         status =  _ux_host_stack_transfer_request(transfer_request);
156 
157 #if defined(UX_HOST_STANDALONE)
158 
159         /* If the transfer is not success, return error.  */
160         if (status != UX_SUCCESS)
161         {
162             dpump -> ux_host_class_dpump_flags &= ~UX_HOST_CLASS_DPUMP_READ_LOCK;
163             return(status);
164         }
165 #else
166 
167         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
168         if (status == UX_SUCCESS)
169         {
170 
171             /* Wait for the completion of the transfer_request.  */
172             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_DPUMP_CLASS_TRANSFER_TIMEOUT);
173 
174             /* If the semaphore did not succeed we probably have a time out.  */
175             if (status != UX_SUCCESS)
176             {
177 
178                 /* All transfers pending need to abort. There may have been a partial transfer.  */
179                 _ux_host_stack_transfer_request_abort(transfer_request);
180 
181                 /* Update the length of the actual data transferred. We do this after the
182                    abort of the transfer request in case some data was actually received.  */
183                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
184 
185                 /* Unprotect thread reentry to this instance.  */
186                 _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
187 
188                 /* Set the completion code.  */
189                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
190 
191                 /* Error trap. */
192                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
193 
194                 /* If trace is enabled, insert this event into the trace buffer.  */
195                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
196 
197                 /* There was an error, return to the caller */
198                 return(UX_TRANSFER_TIMEOUT);
199             }
200         }
201         else
202         {
203 
204             /* Unprotect thread reentry to this instance.  */
205             status =  _ux_host_semaphore_put_rc(&dpump -> ux_host_class_dpump_semaphore);
206 
207             /* There was a non transfer error, no partial transfer to be checked.  */
208             return(status);
209         }
210 #endif
211 
212         /* Update the length of the transfer. Normally all the data has to be received.  */
213         *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
214 
215         /* Check for completion of transfer. If the transfer is partial, return to caller.
216            The transfer is marked as successful but the caller will need to check the length
217            actually received and determine if a partial transfer is OK.  */
218         if (transfer_request_length != transfer_request -> ux_transfer_request_actual_length)
219         {
220 
221             /* Unprotect thread reentry to this instance.  */
222             _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
223 
224             /* Return success to caller.  */
225             return(UX_SUCCESS);
226         }
227 
228         /* Update the data pointer for next transfer. */
229         data_pointer +=  transfer_request_length;
230 
231         /* Update what is left to receive.  */
232         requested_length -=  transfer_request_length;
233     }
234 
235     /* Unprotect thread reentry to this instance.  */
236 #if defined(UX_HOST_STANDALONE)
237     dpump -> ux_host_class_dpump_flags &= ~UX_HOST_CLASS_DPUMP_READ_LOCK;
238 #else
239     _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
240 #endif
241 
242     /* We get here when all the transfers went through without errors.  */
243     return(UX_SUCCESS);
244 }
245 
246