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