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 /**   Host Data Pump 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_dpump.h"
29 #include "ux_host_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_host_class_dpump_write                          PORTABLE C      */
37 /*                                                           6.1.11       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function writes to the dpump interface. The call is blocking   */
45 /*    and only returns when there is either an error or when the transfer */
46 /*    is complete.                                                        */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    dpump                                 Pointer to dpump class        */
51 /*    data_pointer                          Pointer to data to write      */
52 /*    requested_length                      Length of data to write       */
53 /*    actual_length                         Actual length of data written */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    Completion Status                                                   */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _ux_host_stack_class_instance_verify  Verify the class instance     */
62 /*    _ux_host_stack_transfer_request       Process transfer request      */
63 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
64 /*    _ux_utility_semaphore_get             Get protection semaphore      */
65 /*    _ux_utility_semaphore_put             Release protection semaphore  */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    Application                                                         */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
76 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            resulting in version 6.1    */
78 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            added standalone support,   */
80 /*                                            resulting in version 6.1.10 */
81 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            internal clean up,          */
83 /*                                            resulting in version 6.1.11 */
84 /*                                                                        */
85 /**************************************************************************/
_ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP * dpump,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)86 UINT  _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer,
87                                     ULONG requested_length, ULONG *actual_length)
88 {
89 
90 #if defined(UX_HOST_STANDALONE)
91 UX_INTERRUPT_SAVE_AREA
92 #endif
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_DPUMP_WRITE, dpump, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
99 
100     /* Ensure the instance is valid.  */
101     if(_ux_host_stack_class_instance_verify((UCHAR *) _ux_system_host_class_dpump_name, (VOID *) dpump) != UX_SUCCESS)
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, dpump, 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 #if defined(UX_HOST_STANDALONE)
115     UX_DISABLE
116     if (dpump -> ux_host_class_dpump_flags & UX_HOST_CLASS_DPUMP_WRITE_LOCK)
117     {
118         UX_RESTORE
119         return(UX_BUSY);
120     }
121     dpump -> ux_host_class_dpump_flags |= UX_HOST_CLASS_DPUMP_WRITE_LOCK;
122     UX_RESTORE
123 #else
124     status =  _ux_host_semaphore_get(&dpump -> ux_host_class_dpump_semaphore, UX_WAIT_FOREVER);
125     if (status != UX_SUCCESS)
126         return(status);
127 #endif
128 
129     /* Start by resetting the actual length of the transfer.  */
130     *actual_length =  0;
131 
132     /* Get the pointer to the bulk out endpoint transfer request.  */
133     transfer_request =  &dpump -> ux_host_class_dpump_bulk_out_endpoint -> ux_endpoint_transfer_request;
134 
135 #if defined(UX_HOST_STANDALONE)
136 
137     /* Here wait blocking mode is used.  */
138     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
139 #endif
140 
141     /* Perform a transfer on the bulk out endpoint until either the transfer is
142        completed or when there is an error.  */
143     while (requested_length)
144     {
145 
146         /* Program the maximum authorized length for this transfer_request.  */
147         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
148             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
149         else
150             transfer_request_length =  requested_length;
151 
152         /* Initialize the transfer_request.  */
153         transfer_request -> ux_transfer_request_data_pointer =  data_pointer;
154         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
155 
156         /* Perform the transfer.  */
157         status =  _ux_host_stack_transfer_request(transfer_request);
158 
159 #if defined(UX_HOST_STANDALONE)
160 
161         /* If the transfer is not success, return error.  */
162         if (status != UX_SUCCESS)
163         {
164             dpump -> ux_host_class_dpump_flags &= ~UX_HOST_CLASS_DPUMP_WRITE_LOCK;
165             return(status);
166         }
167 #else
168         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
169         if (status == UX_SUCCESS)
170         {
171 
172             /* Wait for the completion of the transfer request.  */
173             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_DPUMP_CLASS_TRANSFER_TIMEOUT);
174 
175             /* If the semaphore did not succeed we probably have a time out.  */
176             if (status != UX_SUCCESS)
177             {
178 
179                 /* All transfers pending need to abort. There may have been a partial transfer.  */
180                 _ux_host_stack_transfer_request_abort(transfer_request);
181 
182                 /* Update the length of the actual data transferred. We do this after the
183                    abort of the transfer_request in case some data actually went out.  */
184                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
185 
186                 /* Unprotect thread reentry to this instance.  */
187                 _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
188 
189                 /* Set the completion code.  */
190                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
191 
192                 /* Error trap. */
193                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
194 
195                 /* If trace is enabled, insert this event into the trace buffer.  */
196                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
197 
198                 /* There was an error, return to the caller.  */
199                 return(UX_TRANSFER_TIMEOUT);
200             }
201         }
202         else
203         {
204 
205             /* Unprotect thread reentry to this instance.  */
206             status =  _ux_host_semaphore_put_rc(&dpump -> ux_host_class_dpump_semaphore);
207 
208             /* There was a non transfer error, no partial transfer to be checked */
209             return(status);
210         }
211 #endif
212 
213         /* Update the length of the transfer. Normally all the data has to be sent.  */
214         *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
215 
216         /* Check for completion of transfer. If the transfer is partial, return to caller.
217            The transfer is marked as successful but the caller will need to check the length
218            actually sent and determine if a partial transfer is OK. */
219         if (transfer_request_length !=  transfer_request -> ux_transfer_request_actual_length)
220         {
221 
222             /* Unprotect thread reentry to this instance.  */
223             _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
224 
225             /* Return success.  */
226             return(UX_SUCCESS);
227         }
228 
229         /* Update the data pointer for next transfer.  */
230         data_pointer +=  transfer_request_length;
231 
232         /* Update what is left to send out.  */
233         requested_length -=  transfer_request_length;
234     }
235 
236     /* Unprotect thread reentry to this instance.  */
237 #if defined(UX_HOST_STANDALONE)
238     dpump -> ux_host_class_dpump_flags &= ~UX_HOST_CLASS_DPUMP_WRITE_LOCK;
239 #else
240     _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
241 #endif
242 
243     /* We get here when all the transfers went through without errors.  */
244     return(UX_SUCCESS);
245 }
246 
247