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 /**   EHCI Controller Driver                                              */
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_hcd_ehci.h"
29 #include "ux_host_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_hcd_ehci_request_control_transfer               PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*     This function performs a control transfer from a transfer request. */
45 /*     The USB control transfer is in 3 phases (setup, data, status).     */
46 /*     This function will chain all phases of the control sequence before */
47 /*     setting the EHCI endpoint as a candidate for transfer.             */
48 /*                                                                        */
49 /*     The max aggregated size of a data payload in EHCI is 16K. We are   */
50 /*     assuming that this size will be sufficient to contain the control  */
51 /*     packet.                                                            */
52 /*                                                                        */
53 /*  INPUT                                                                 */
54 /*                                                                        */
55 /*    hcd_ehci                              Pointer to EHCI controller    */
56 /*    transfer_request                      Pointer to transfer request   */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    Completion Status                                                   */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _ux_hcd_ehci_ed_clean                 Clean TDs                     */
65 /*    _ux_hcd_ehci_request_transfer_add     Add transfer to ED            */
66 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
67 /*    _ux_utility_memory_allocate           Allocate memory block         */
68 /*    _ux_utility_memory_free               Release memory block          */
69 /*    _ux_host_semaphore_get                Get semaphore                 */
70 /*    _ux_utility_short_put                 Write a 16-bit value          */
71 /*                                                                        */
72 /*  CALLED BY                                                             */
73 /*                                                                        */
74 /*    EHCI Controller Driver                                              */
75 /*                                                                        */
76 /*  RELEASE HISTORY                                                       */
77 /*                                                                        */
78 /*    DATE              NAME                      DESCRIPTION             */
79 /*                                                                        */
80 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
81 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            prefixed UX to MS_TO_TICK,  */
83 /*                                            resulting in version 6.1    */
84 /*  11-09-2020     Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            refined macros names,       */
86 /*                                            fixed compile warnings,     */
87 /*                                            resulting in version 6.1.2  */
88 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            fixed compile warnings,     */
90 /*                                            resulting in version 6.3.0  */
91 /*                                                                        */
92 /**************************************************************************/
_ux_hcd_ehci_request_control_transfer(UX_HCD_EHCI * hcd_ehci,UX_TRANSFER * transfer_request)93 UINT  _ux_hcd_ehci_request_control_transfer(UX_HCD_EHCI *hcd_ehci, UX_TRANSFER *transfer_request)
94 {
95 
96 UX_DEVICE       *device;
97 UX_ENDPOINT     *endpoint;
98 UCHAR *         setup_request;
99 UX_EHCI_ED      *ed;
100 ULONG           td_component;
101 UINT            status;
102 UINT            pid;
103 
104 
105     /* Get the pointer to the Endpoint and to the device.  */
106     endpoint =  (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
107     device =    endpoint -> ux_endpoint_device;
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_CACHE_SAFE_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     /* Reset the last TD pointer since it is the first time we hook a transaction.  */
125     ed -> ux_ehci_ed_last_td =  UX_NULL;
126 
127     /* Set the ED address and MPS values since they may have changed from 0 to x
128        The ED direction will be set from the TD.  */
129     ed -> ux_ehci_ed_cap0 |=  (endpoint -> ux_endpoint_descriptor.bEndpointAddress & ~UX_ENDPOINT_DIRECTION) << UX_EHCI_QH_ED_AD_LOC;
130 
131     /* Set the endpoint address (this should have changed after address setting).  */
132     ed -> ux_ehci_ed_cap0 |=  device -> ux_device_address;
133 
134     /* Set the default MPS Capability info in the ED.  */
135     ed -> ux_ehci_ed_cap0 &=  ~UX_EHCI_QH_MPS_MASK;
136     ed -> ux_ehci_ed_cap0 |=  (ULONG)endpoint -> ux_endpoint_descriptor.wMaxPacketSize << UX_EHCI_QH_MPS_LOC;
137 
138     /* On Control transfers, the toggle is set in the TD, not the QH.  */
139     ed -> ux_ehci_ed_cap0 |=  UX_EHCI_QH_DTC;
140 
141     /* The overlay parameters should be reset now.  */
142     ed -> ux_ehci_ed_current_td =     UX_NULL;
143     ed -> ux_ehci_ed_queue_element =  (UX_EHCI_TD *) UX_EHCI_TD_T;
144     ed -> ux_ehci_ed_alternate_td =   (UX_EHCI_TD *) UX_EHCI_TD_T;
145     ed -> ux_ehci_ed_state &=         UX_EHCI_QH_TOGGLE;
146     ed -> ux_ehci_ed_bp0 =            UX_NULL;
147     ed -> ux_ehci_ed_bp1 =            UX_NULL;
148     ed -> ux_ehci_ed_bp2 =            UX_NULL;
149     ed -> ux_ehci_ed_bp3 =            UX_NULL;
150     ed -> ux_ehci_ed_bp4 =            UX_NULL;
151 
152     /* Build and hook the setup phase to the ED.  */
153     status =  _ux_hcd_ehci_request_transfer_add(hcd_ehci, ed, UX_EHCI_TD_SETUP_PHASE, UX_EHCI_PID_SETUP, UX_EHCI_TOGGLE_0,
154                                     setup_request, UX_SETUP_SIZE, transfer_request);
155     if (status != UX_SUCCESS)
156     {
157 
158         /* We need to clean the tds attached if any.  */
159         _ux_hcd_ehci_ed_clean(ed);
160         return(status);
161     }
162 
163     /* Test if data phase required, if so decide the PID to use and build/hook it to the ED.  */
164     if (transfer_request -> ux_transfer_request_requested_length != 0)
165     {
166 
167         if ((transfer_request -> ux_transfer_request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
168 
169             pid =  UX_EHCI_PID_IN;
170         else
171 
172             pid =  UX_EHCI_PID_OUT;
173 
174         status =  _ux_hcd_ehci_request_transfer_add(hcd_ehci, ed, UX_EHCI_TD_DATA_PHASE, pid, UX_EHCI_TOGGLE_1,
175                                                         transfer_request -> ux_transfer_request_data_pointer,
176                                                         transfer_request -> ux_transfer_request_requested_length,
177                                                         transfer_request);
178         if (status != UX_SUCCESS)
179         {
180 
181             /* We need to clean the tds attached if any.  */
182             _ux_hcd_ehci_ed_clean(ed);
183             return(status);
184         }
185     }
186 
187     /* Program the status phase. the PID is the opposite of the data phase.  */
188     if ((transfer_request -> ux_transfer_request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
189         pid =  UX_EHCI_PID_OUT;
190     else
191         pid =  UX_EHCI_PID_IN;
192 
193     status =  _ux_hcd_ehci_request_transfer_add(hcd_ehci, ed, UX_EHCI_TD_STATUS_PHASE, pid,
194                                     UX_EHCI_TOGGLE_1, UX_NULL, 0, transfer_request);
195 
196     if (status != UX_SUCCESS)
197     {
198 
199         /* We need to clean the tds attached if any.  */
200         _ux_hcd_ehci_ed_clean(ed);
201         return(status);
202     }
203 
204     /* Set the IOC bit in the last TD.  */
205     ed -> ux_ehci_ed_last_td -> ux_ehci_td_control |=  UX_EHCI_TD_IOC;
206 
207     /* Ensure the IOC bit is set before activating the TD. This is necessary
208        for some processors that perform writes out of order as an optimization.  */
209     UX_DATA_MEMORY_BARRIER
210 
211     /* Activate the first TD linked to the ED.  */
212     td_component =  (ULONG) ed -> ux_ehci_ed_queue_element;
213     td_component &=  ~UX_EHCI_TD_T;
214     ed -> ux_ehci_ed_queue_element =  (UX_EHCI_TD *) td_component;
215 
216     /* Wait for the completion of the transfer request.  */
217     status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_CONTROL_TRANSFER_TIMEOUT));
218 
219     /* If the semaphore did not succeed we probably have a time out.  */
220     if (status != UX_SUCCESS)
221     {
222 
223         /* All transfers pending need to abort. There may have been a partial transfer.  */
224         _ux_host_stack_transfer_request_abort(transfer_request);
225 
226         /* There was an error, return to the caller.  */
227         transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
228 
229         /* Error trap. */
230         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_TIMEOUT);
231 
232         /* If trace is enabled, insert this event into the trace buffer.  */
233         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
234 
235     }
236 
237     /* Free the resources.  */
238     _ux_utility_memory_free(setup_request);
239 
240     /* Return completion status.  */
241     return(transfer_request -> ux_transfer_request_completion_code);
242 }
243 
244