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 Simulator Controller Driver                                    */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define UX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 
28 #include "ux_api.h"
29 #include "ux_hcd_sim_host.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_hcd_sim_host_request_control_transfer           PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*     This function performs a control transfer from a transfer request. */
46 /*     The USB control transfer is in 3 phases (setup, data, status).     */
47 /*     This function will chain all phases of the control sequence before */
48 /*     setting the sim_host endpoint as a candidate for transfer.         */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    hcd_sim_host                          Pointer to host controller    */
53 /*    transfer_request                      Pointer to transfer request   */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    Completion Status                                                   */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _ux_hcd_sim_host_regular_td_obtain    Obtain regular TD             */
62 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
63 /*    _ux_utility_memory_allocate           Allocate memory block         */
64 /*    _ux_utility_memory_free               Release memory block          */
65 /*    _ux_utility_semaphore_get             Get semaphore                 */
66 /*    _ux_utility_short_put                 Write 16-bit value            */
67 /*                                                                        */
68 /*  CALLED BY                                                             */
69 /*                                                                        */
70 /*    Host Simulator Controller Driver                                    */
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 /*                                            prefixed UX to MS_TO_TICK,  */
79 /*                                            resulting in version 6.1    */
80 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            added standalone support,   */
82 /*                                            resulting in version 6.1.10 */
83 /*                                                                        */
84 /**************************************************************************/
_ux_hcd_sim_host_request_control_transfer(UX_HCD_SIM_HOST * hcd_sim_host,UX_TRANSFER * transfer_request)85 UINT  _ux_hcd_sim_host_request_control_transfer(UX_HCD_SIM_HOST *hcd_sim_host, UX_TRANSFER *transfer_request)
86 {
87 
88 UX_ENDPOINT             *endpoint;
89 UCHAR                   *setup_request;
90 UX_HCD_SIM_HOST_ED      *ed;
91 UX_HCD_SIM_HOST_TD      *setup_td;
92 UX_HCD_SIM_HOST_TD      *chain_td;
93 UX_HCD_SIM_HOST_TD      *data_td;
94 UX_HCD_SIM_HOST_TD      *tail_td;
95 UX_HCD_SIM_HOST_TD      *status_td;
96 UX_HCD_SIM_HOST_TD      *start_data_td;
97 UX_HCD_SIM_HOST_TD      *next_data_td;
98 ULONG                   transfer_request_payload_length;
99 ULONG                   control_packet_payload_length;
100 UCHAR                   *data_pointer;
101 #if !defined(UX_HOST_STANDALONE)
102 UINT                    status;
103 #endif
104 
105 
106     /* Get the pointer to the endpoint.  */
107     endpoint =  (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
108 
109     /* Now get the physical ED attached to this endpoint.  */
110     ed =  endpoint -> ux_endpoint_ed;
111 
112     /* Build the SETUP packet (phase 1 of the control transfer).  */
113     setup_request =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_SETUP_SIZE);
114     if (setup_request == UX_NULL)
115         return(UX_MEMORY_INSUFFICIENT);
116 
117     *setup_request =                            (UCHAR)transfer_request -> ux_transfer_request_function;
118     *(setup_request + UX_SETUP_REQUEST_TYPE) =  (UCHAR)transfer_request -> ux_transfer_request_type;
119     *(setup_request + UX_SETUP_REQUEST) =       (UCHAR)transfer_request -> ux_transfer_request_function;
120     _ux_utility_short_put(setup_request + UX_SETUP_VALUE, (USHORT)transfer_request -> ux_transfer_request_value);
121     _ux_utility_short_put(setup_request + UX_SETUP_INDEX, (USHORT)transfer_request -> ux_transfer_request_index);
122     _ux_utility_short_put(setup_request + UX_SETUP_LENGTH, (USHORT) transfer_request -> ux_transfer_request_requested_length);
123 
124     /* Use the TD pointer by ed -> tail for our setup TD and chain from this one on.  */
125     setup_td =  ed -> ux_sim_host_ed_tail_td;
126     setup_td -> ux_sim_host_td_buffer =  setup_request;
127     setup_td -> ux_sim_host_td_length =  UX_SETUP_SIZE;
128     chain_td =  setup_td;
129 
130     /* Attach the endpoint and transfer_request to the TD.  */
131     setup_td -> ux_sim_host_td_transfer_request =  transfer_request;
132     setup_td -> ux_sim_host_td_ed =  ed;
133 
134     /* Setup is OUT.  */
135     setup_td -> ux_sim_host_td_direction =  UX_HCD_SIM_HOST_TD_OUT;
136 
137     /* Mark TD toggle as being DATA0.  */
138     setup_td -> ux_sim_host_td_toggle =  0;
139 
140     /* Mark the TD with the SETUP phase.  */
141     setup_td -> ux_sim_host_td_status |=  UX_HCD_SIM_HOST_TD_SETUP_PHASE;
142 
143     /* Check if there is a data phase, if not jump to status phase.  */
144     data_td =  UX_NULL;
145     start_data_td =  UX_NULL;
146 
147     /* Use local variables to manipulate data pointer and length.  */
148     transfer_request_payload_length =  transfer_request -> ux_transfer_request_requested_length;
149     data_pointer =  transfer_request -> ux_transfer_request_data_pointer;
150 
151     /* Data starts with DATA1. For the data phase, we use the ED to contain the toggle.  */
152     ed -> ux_sim_host_ed_toggle =  1;
153 
154     /* The Control data payload may be split into several smaller blocks.  */
155     while (transfer_request_payload_length != 0)
156     {
157 
158         /* Get a new TD to hook this payload.  */
159         data_td =  _ux_hcd_sim_host_regular_td_obtain(hcd_sim_host);
160         if (data_td == UX_NULL)
161         {
162 
163             /* Free the Setup packet resources.  */
164             _ux_utility_memory_free(setup_request);
165 
166             /* If there was already a TD chain in progress, free it.  */
167             if (start_data_td != UX_NULL)
168             {
169 
170                 data_td =  start_data_td;
171                 while (data_td)
172                 {
173 
174                     next_data_td =  data_td -> ux_sim_host_td_next_td;
175                     data_td -> ux_sim_host_td_status =  UX_UNUSED;
176                     data_td =  next_data_td;
177                 }
178             }
179 
180             return(UX_NO_TD_AVAILABLE);
181         }
182 
183         /* Check the current payload requirement for the max size.  */
184         if (transfer_request_payload_length > UX_HCD_SIM_HOST_MAX_PAYLOAD)
185 
186             control_packet_payload_length =  UX_HCD_SIM_HOST_MAX_PAYLOAD;
187         else
188 
189             control_packet_payload_length =  transfer_request_payload_length;
190 
191         /* Store the beginning of the buffer address in the TD.  */
192         data_td -> ux_sim_host_td_buffer =  data_pointer;
193 
194         /* Update the length of the transfer for this TD.  */
195         data_td -> ux_sim_host_td_length =  control_packet_payload_length;
196 
197         /* Attach the endpoint and transfer request to the TD.  */
198         data_td -> ux_sim_host_td_transfer_request =  transfer_request;
199         data_td -> ux_sim_host_td_ed =  ed;
200 
201         /* Adjust the data payload length and the data payload pointer.  */
202         transfer_request_payload_length -=  control_packet_payload_length;
203         data_pointer +=  control_packet_payload_length;
204 
205         /* The direction of the transaction is set in the TD.  */
206         if ((transfer_request -> ux_transfer_request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
207 
208             data_td -> ux_sim_host_td_direction =  UX_HCD_SIM_HOST_TD_IN;
209         else
210 
211             data_td -> ux_sim_host_td_direction =  UX_HCD_SIM_HOST_TD_OUT;
212 
213         /* Mark the TD with the DATA phase.  */
214         data_td -> ux_sim_host_td_status |=  UX_HCD_SIM_HOST_TD_DATA_PHASE;
215 
216         /* The Toggle value is in the ED.  */
217         data_td -> ux_sim_host_td_toggle =  UX_HCD_SIM_HOST_TD_TOGGLE_FROM_ED;
218 
219         /* The first obtained TD in the chain has to be remembered.  */
220         if (start_data_td == UX_NULL)
221             start_data_td =  data_td;
222 
223         /* Attach this new TD to the previous one.  */
224         chain_td -> ux_sim_host_td_next_td =  data_td;
225         chain_td -> ux_sim_host_td_next_td_transfer_request =  data_td;
226         chain_td =  data_td;
227     }
228 
229     /* Now, program the status phase.  */
230     status_td =  _ux_hcd_sim_host_regular_td_obtain(hcd_sim_host);
231 
232     if (status_td == UX_NULL)
233     {
234 
235         _ux_utility_memory_free(setup_request);
236         if (data_td != UX_NULL)
237         {
238 
239             data_td =  start_data_td;
240             while (data_td)
241             {
242 
243                 next_data_td =  data_td -> ux_sim_host_td_next_td;
244                 data_td -> ux_sim_host_td_status =  UX_UNUSED;
245                 data_td =  next_data_td;
246             }
247         }
248 
249         return(UX_NO_TD_AVAILABLE);
250     }
251 
252     /* Attach the endpoint and transfer request to the TD.  */
253     status_td -> ux_sim_host_td_transfer_request =  transfer_request;
254     status_td -> ux_sim_host_td_ed =  ed;
255 
256     /* Mark the TD with the STATUS phase.  */
257     status_td -> ux_sim_host_td_status |=  UX_HCD_SIM_HOST_TD_STATUS_PHASE;
258 
259     /* The direction of the status phase is IN if data phase is OUT and
260        vice versa.  */
261     if ((transfer_request -> ux_transfer_request_type&UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
262 
263         status_td -> ux_sim_host_td_direction =  UX_HCD_SIM_HOST_TD_OUT;
264     else
265 
266         status_td -> ux_sim_host_td_direction =  UX_HCD_SIM_HOST_TD_IN;
267 
268     /* No data payload for the status phase.  */
269     status_td -> ux_sim_host_td_buffer =  0;
270     status_td -> ux_sim_host_td_length =  0;
271 
272     /* Status Phase toggle is ALWAYS 1.  */
273     status_td -> ux_sim_host_td_toggle =  1;
274 
275     /* Hook the status phase to the previous TD.  */
276     chain_td -> ux_sim_host_td_next_td =  status_td;
277 
278     /* Since we have consumed out tail TD for the setup packet, we must get another one
279        and hook it to the ED's tail.  */
280     tail_td =  _ux_hcd_sim_host_regular_td_obtain(hcd_sim_host);
281     if (tail_td == UX_NULL)
282     {
283 
284         _ux_utility_memory_free(setup_request);
285         if (data_td != UX_NULL)
286             data_td -> ux_sim_host_td_status =  UX_UNUSED;
287         status_td -> ux_sim_host_td_status =  UX_UNUSED;
288         return(UX_NO_TD_AVAILABLE);
289     }
290 
291     /* Hook the new TD to the status TD.  */
292     status_td -> ux_sim_host_td_next_td =  tail_td;
293 
294     /* At this stage, the Head and Tail in the ED are still the same and
295        the host simulator controller will skip this ED until we have hooked the new
296        tail TD.  */
297     ed -> ux_sim_host_ed_tail_td =  tail_td;
298 
299     /* Now we can tell the scheduler to wake up.  */
300     hcd_sim_host -> ux_hcd_sim_host_queue_empty =  UX_FALSE;
301 
302 #if defined(UX_HOST_STANDALONE)
303     /* Transfer started in background, fine.  */
304     return(UX_SUCCESS);
305 #else
306     /* Wait for the completion of the transfer request.  */
307     status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_CONTROL_TRANSFER_TIMEOUT));
308 
309     /* If the semaphore did not succeed we probably have a time out.  */
310     if (status != UX_SUCCESS)
311     {
312 
313         /* All transfers pending need to abort. There may have been a partial transfer.  */
314         _ux_host_stack_transfer_request_abort(transfer_request);
315 
316         /* There was an error, return to the caller.  */
317         transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
318 
319         /* Error trap. */
320         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_TIMEOUT);
321 
322         /* If trace is enabled, insert this event into the trace buffer.  */
323         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
324 
325     }
326 
327     /* Free the resources.  */
328     _ux_utility_memory_free(setup_request);
329 
330     /* Return completion to caller.  */
331     return(transfer_request -> ux_transfer_request_completion_code);
332 #endif
333 }
334