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_write                          PORTABLE C      */
38 /*                                                           6.1.11       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function writes to the dpump interface. The call is blocking   */
46 /*    and only returns when there is either an error or when the transfer */
47 /*    is complete.                                                        */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    dpump                                 Pointer to dpump class        */
52 /*    data_pointer                          Pointer to data to write      */
53 /*    requested_length                      Length of data to write       */
54 /*    actual_length                         Actual length of data written */
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 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            internal clean up,          */
84 /*                                            resulting in version 6.1.11 */
85 /*                                                                        */
86 /**************************************************************************/
_ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP * dpump,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)87 UINT  _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer,
88                                     ULONG requested_length, ULONG *actual_length)
89 {
90 
91 #if defined(UX_HOST_STANDALONE)
92 UX_INTERRUPT_SAVE_AREA
93 #endif
94 UX_TRANSFER     *transfer_request;
95 UINT            status;
96 ULONG           transfer_request_length;
97 
98     /* If trace is enabled, insert this event into the trace buffer.  */
99     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_DPUMP_WRITE, dpump, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
100 
101     /* Ensure the instance is valid.  */
102     if(_ux_host_stack_class_instance_verify((UCHAR *) _ux_system_host_class_dpump_name, (VOID *) dpump) != UX_SUCCESS)
103     {
104 
105         /* Error trap. */
106         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
107 
108         /* If trace is enabled, insert this event into the trace buffer.  */
109         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, dpump, 0, 0, UX_TRACE_ERRORS, 0, 0)
110 
111         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
112     }
113 
114     /* Protect thread reentry to this instance.  */
115 #if defined(UX_HOST_STANDALONE)
116     UX_DISABLE
117     if (dpump -> ux_host_class_dpump_flags & UX_HOST_CLASS_DPUMP_WRITE_LOCK)
118     {
119         UX_RESTORE
120         return(UX_BUSY);
121     }
122     dpump -> ux_host_class_dpump_flags |= UX_HOST_CLASS_DPUMP_WRITE_LOCK;
123     UX_RESTORE
124 #else
125     status =  _ux_host_semaphore_get(&dpump -> ux_host_class_dpump_semaphore, UX_WAIT_FOREVER);
126     if (status != UX_SUCCESS)
127         return(status);
128 #endif
129 
130     /* Start by resetting the actual length of the transfer.  */
131     *actual_length =  0;
132 
133     /* Get the pointer to the bulk out endpoint transfer request.  */
134     transfer_request =  &dpump -> ux_host_class_dpump_bulk_out_endpoint -> ux_endpoint_transfer_request;
135 
136 #if defined(UX_HOST_STANDALONE)
137 
138     /* Here wait blocking mode is used.  */
139     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
140 #endif
141 
142     /* Perform a transfer on the bulk out endpoint until either the transfer is
143        completed or when there is an error.  */
144     while (requested_length)
145     {
146 
147         /* Program the maximum authorized length for this transfer_request.  */
148         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
149             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
150         else
151             transfer_request_length =  requested_length;
152 
153         /* Initialize the transfer_request.  */
154         transfer_request -> ux_transfer_request_data_pointer =  data_pointer;
155         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
156 
157         /* Perform the transfer.  */
158         status =  _ux_host_stack_transfer_request(transfer_request);
159 
160 #if defined(UX_HOST_STANDALONE)
161 
162         /* If the transfer is not success, return error.  */
163         if (status != UX_SUCCESS)
164         {
165             dpump -> ux_host_class_dpump_flags &= ~UX_HOST_CLASS_DPUMP_WRITE_LOCK;
166             return(status);
167         }
168 #else
169         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
170         if (status == UX_SUCCESS)
171         {
172 
173             /* Wait for the completion of the transfer request.  */
174             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_DPUMP_CLASS_TRANSFER_TIMEOUT);
175 
176             /* If the semaphore did not succeed we probably have a time out.  */
177             if (status != UX_SUCCESS)
178             {
179 
180                 /* All transfers pending need to abort. There may have been a partial transfer.  */
181                 _ux_host_stack_transfer_request_abort(transfer_request);
182 
183                 /* Update the length of the actual data transferred. We do this after the
184                    abort of the transfer_request in case some data actually went out.  */
185                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
186 
187                 /* Unprotect thread reentry to this instance.  */
188                 _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
189 
190                 /* Set the completion code.  */
191                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
192 
193                 /* Error trap. */
194                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
195 
196                 /* If trace is enabled, insert this event into the trace buffer.  */
197                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
198 
199                 /* There was an error, return to the caller.  */
200                 return(UX_TRANSFER_TIMEOUT);
201             }
202         }
203         else
204         {
205 
206             /* Unprotect thread reentry to this instance.  */
207             status =  _ux_host_semaphore_put_rc(&dpump -> ux_host_class_dpump_semaphore);
208 
209             /* There was a non transfer error, no partial transfer to be checked */
210             return(status);
211         }
212 #endif
213 
214         /* Update the length of the transfer. Normally all the data has to be sent.  */
215         *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
216 
217         /* Check for completion of transfer. If the transfer is partial, return to caller.
218            The transfer is marked as successful but the caller will need to check the length
219            actually sent and determine if a partial transfer is OK. */
220         if (transfer_request_length !=  transfer_request -> ux_transfer_request_actual_length)
221         {
222 
223             /* Unprotect thread reentry to this instance.  */
224             _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
225 
226             /* Return success.  */
227             return(UX_SUCCESS);
228         }
229 
230         /* Update the data pointer for next transfer.  */
231         data_pointer +=  transfer_request_length;
232 
233         /* Update what is left to send out.  */
234         requested_length -=  transfer_request_length;
235     }
236 
237     /* Unprotect thread reentry to this instance.  */
238 #if defined(UX_HOST_STANDALONE)
239     dpump -> ux_host_class_dpump_flags &= ~UX_HOST_CLASS_DPUMP_WRITE_LOCK;
240 #else
241     _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
242 #endif
243 
244     /* We get here when all the transfers went through without errors.  */
245     return(UX_SUCCESS);
246 }
247 
248