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_asynch_td_process PORTABLE C */
38 /* 6.1.10 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function processes the isochronous, periodic and asynchronous */
46 /* lists in search for transfers that occurred in the past */
47 /* (micro-)frame. */
48 /* */
49 /* INPUT */
50 /* */
51 /* ed Pointer to ED */
52 /* td Pointer to TD */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* UX_EHCI_TD * Pointer to TD */
57 /* */
58 /* CALLS */
59 /* */
60 /* (ux_transfer_request_completion_function) Completion function */
61 /* _ux_hcd_ehci_ed_clean Clean ED */
62 /* _ux_host_semaphore_put Put semaphore */
63 /* _ux_utility_virtual_address Get virtual address */
64 /* */
65 /* CALLED BY */
66 /* */
67 /* EHCI Controller Driver */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
74 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
75 /* resulting in version 6.1 */
76 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
77 /* refined macros names, */
78 /* resulting in version 6.1.10 */
79 /* */
80 /**************************************************************************/
_ux_hcd_ehci_asynch_td_process(UX_EHCI_ED * ed,UX_EHCI_TD * td)81 UX_EHCI_TD *_ux_hcd_ehci_asynch_td_process(UX_EHCI_ED *ed, UX_EHCI_TD *td)
82 {
83
84 UX_TRANSFER *transfer_request;
85 ULONG td_residual_length;
86 UINT td_error;
87 UX_EHCI_TD *next_td;
88 ULONG td_element;
89 ULONG pid;
90
91
92 /* If the TD is still active, we know that the transfer has not taken place yet. In this case,
93 the TDs following this one do not need to be process and we return a NULL TD. */
94 if (td -> ux_ehci_td_control & UX_EHCI_TD_ACTIVE)
95 return(UX_NULL);
96
97 /* We need the transfer request associated with this TD. */
98 transfer_request = td -> ux_ehci_td_transfer_request;
99
100 /* We have a non active TD, meaning the TD was processed. We should explore the error code and
101 translate it into a generic USBX code. */
102 td_error = UX_SUCCESS;
103
104 /* Check if the TD was halted due to a major error. Note that the error status may contain an error
105 but unless the Halt bit is set, it is not fatal. */
106 if (td -> ux_ehci_td_control & UX_EHCI_TD_HALTED)
107 {
108
109 /* Default to STALL. */
110 td_error = UX_TRANSFER_STALLED;
111
112 /* What else could it be ? Buffer underrun/overrun ? */
113 if (td -> ux_ehci_td_control & UX_EHCI_TD_DATA_BUFFER_ERROR)
114 td_error = UX_TRANSFER_ERROR;
115
116 /* Babble ? */
117 if (td -> ux_ehci_td_control & UX_EHCI_TD_BABBLE_DETECTED)
118 td_error = UX_TRANSFER_ERROR;
119
120 /* Timeout, CRD, Bad PID ... ? */
121 if (td -> ux_ehci_td_control & UX_EHCI_TD_TRANSACTION_ERROR)
122 td_error = UX_TRANSFER_NO_ANSWER;
123
124 }
125
126 /* If there is an error, we should terminate this transfer and clean things. */
127 if (td_error != UX_SUCCESS)
128 {
129
130 /* Update the transfer code. */
131 transfer_request -> ux_transfer_request_completion_code = td_error;
132
133 /* Clean the link. */
134 _ux_hcd_ehci_ed_clean(ed);
135
136 /* Free the TD that was just treated. */
137 td -> ux_ehci_td_status = UX_UNUSED;
138
139 /* We may do a call back. */
140 if (transfer_request -> ux_transfer_request_completion_function != UX_NULL)
141 transfer_request -> ux_transfer_request_completion_function(transfer_request);
142
143 /* Notify the application for debugging purposes. */
144 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, td_error);
145
146 /* If trace is enabled, insert this event into the trace buffer. */
147 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, td_error, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
148
149 /* Wake up the semaphore for this request. */
150 _ux_host_semaphore_put(&transfer_request -> ux_transfer_request_semaphore);
151
152 /* Nothing else to be processed in this queue. */
153 return(UX_NULL);
154 }
155
156 /* Update the length of this transaction if the PID is IN or OUT. */
157 pid = td -> ux_ehci_td_control & UX_EHCI_PID_MASK;
158 td_residual_length = 0;
159 if ((pid == UX_EHCI_PID_OUT) || (pid == UX_EHCI_PID_IN))
160 {
161
162 td_residual_length = (td -> ux_ehci_td_control >> UX_EHCI_TD_LG_LOC) & UX_EHCI_TD_LG_MASK;
163 transfer_request -> ux_transfer_request_actual_length += td -> ux_ehci_td_length - td_residual_length;
164 }
165
166 /* We get here when there is no error on the transfer. It may be that this transfer is not the last
167 one in the link and therefore we process the length received but do not complete the transfer request. */
168 if (td -> ux_ehci_td_control & UX_EHCI_TD_IOC)
169 {
170
171 /* Check if this transaction is complete or a short packet occurred, in both case, complete the
172 transaction. In the case of a control endpoint in STATUS phase we complete regardless. */
173 if ((td_residual_length != 0) ||
174 (transfer_request -> ux_transfer_request_actual_length == transfer_request -> ux_transfer_request_requested_length) ||
175 (td -> ux_ehci_td_phase & UX_EHCI_TD_STATUS_PHASE))
176 {
177
178 /* Update the transfer code. */
179 transfer_request -> ux_transfer_request_completion_code = UX_SUCCESS;
180
181 /* Clean the link. */
182 _ux_hcd_ehci_ed_clean(ed);
183
184 /* Free the TD that was just treated. */
185 td -> ux_ehci_td_status = UX_UNUSED;
186
187 /* We may do a call back. */
188 if (transfer_request -> ux_transfer_request_completion_function != UX_NULL)
189 transfer_request -> ux_transfer_request_completion_function(transfer_request);
190
191 /* Wake up the semaphore for this request. */
192 _ux_host_semaphore_put(&transfer_request -> ux_transfer_request_semaphore);
193
194 /* Nothing else to be processed in this queue */
195 return(UX_NULL);
196 }
197 }
198
199 /* Get the next TD attached to this TD. */
200 td_element = (ULONG) td -> ux_ehci_td_link_pointer;
201 td_element &= ~UX_EHCI_TD_T;
202 next_td = _ux_utility_virtual_address((VOID *) td_element);
203
204 /* Free the TD that was just treated. */
205 td -> ux_ehci_td_status = UX_UNUSED;
206
207 /* This TD is now the first TD. */
208 ed -> ux_ehci_ed_first_td = next_td;
209
210 /* We get here when we have reached a non completion of a request transfer
211 we need to return the next TD in the linked list. */
212 return(next_td);
213 }
214
215