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_transfer_abort PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function will abort transactions attached to a transfer */
46 /* request. */
47 /* */
48 /* INPUT */
49 /* */
50 /* hcd_ehci Pointer to EHCI controller */
51 /* transfer_request Pointer to transfer request */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* Completion Status */
56 /* */
57 /* CALLS */
58 /* */
59 /* _ux_utility_virtual_address Get virtual address */
60 /* _ux_host_mutex_on Get mutex */
61 /* _ux_host_mutex_off Put mutex */
62 /* _ux_utility_delay_ms Delay milliseconds */
63 /* _ux_hcd_ehci_ed_clean Clean TDs on ED */
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 /* 11-09-2020 Chaoqiong Xiao Modified comment(s), */
77 /* fixed compile warnings, */
78 /* resulting in version 6.1.2 */
79 /* 08-02-2021 Wen Wang Modified comment(s), */
80 /* fixed spelling error, */
81 /* resulting in version 6.1.8 */
82 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
83 /* fixed standalone compile, */
84 /* resulting in version 6.1.11 */
85 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
86 /* improved iso abort support, */
87 /* resulting in version 6.1.12 */
88 /* */
89 /**************************************************************************/
_ux_hcd_ehci_transfer_abort(UX_HCD_EHCI * hcd_ehci,UX_TRANSFER * transfer_request)90 UINT _ux_hcd_ehci_transfer_abort(UX_HCD_EHCI *hcd_ehci,UX_TRANSFER *transfer_request)
91 {
92
93 UX_ENDPOINT *endpoint;
94 UX_EHCI_HSISO_ED *ied;
95 UX_EHCI_PERIODIC_LINK_POINTER lp;
96 UX_EHCI_HSISO_TD *fr_td;
97 UX_TRANSFER **list_head;
98 UX_TRANSFER *transfer;
99 ULONG max_load_count;
100 ULONG frindex;
101 ULONG fr_start;
102 ULONG fr_req;
103 ULONG first_new_aborted = 1;
104
105
106 UX_PARAMETER_NOT_USED(hcd_ehci);
107
108
109 /* Get the pointer to the endpoint associated with the transfer request*/
110 endpoint = (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
111
112 /* From the endpoint container, get the address of the physical endpoint. */
113 lp.void_ptr = endpoint -> ux_endpoint_ed;
114
115 /* Check if this physical endpoint has been initialized properly! */
116 if (lp.void_ptr == UX_NULL)
117 {
118
119 /* If trace is enabled, insert this event into the trace buffer. */
120 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_ENDPOINT_HANDLE_UNKNOWN, endpoint, 0, 0, UX_TRACE_ERRORS, 0, 0)
121
122 return(UX_ENDPOINT_HANDLE_UNKNOWN);
123 }
124
125 /* Check endpoint type. */
126 if ((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_ISOCHRONOUS_ENDPOINT)
127 {
128
129 /* Lock the periodic table. */
130 _ux_host_mutex_on(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
131
132 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
133 if (endpoint -> ux_endpoint_device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
134 {
135 list_head = &lp.sitd_ptr -> ux_ehci_fsiso_td_transfer_head;
136 }
137 else
138 #endif
139 {
140 /* Get ED for the iTD(s). */
141 ied = lp.itd_ptr -> ux_ehci_hsiso_td_ed;
142
143 /* Get list head for further process. */
144 list_head = &ied -> ux_ehci_hsiso_ed_transfer_head;
145
146 /* Max load count (in 1 ms): 8, 4, 2, 1 ... */
147 max_load_count = 8u >> ied -> ux_ehci_hsiso_ed_frinterval_shift;
148 }
149
150 /* The whole list is aborted. */
151 if ((transfer_request == 0) ||
152 (transfer_request == &endpoint -> ux_endpoint_transfer_request) ||
153 (*list_head) == transfer_request)
154 {
155 *list_head = UX_NULL;
156
157 /* Clear controls any way. */
158 for (frindex = 0; frindex < 4; frindex ++)
159 {
160
161 /* Get actual iTD used and clear controls. */
162 fr_td = ied -> ux_ehci_hsiso_ed_fr_td[frindex];
163 fr_td -> ux_ehci_hsiso_td_control[(frindex << 1)] &= ~UX_EHCI_HSISO_STATUS_ACTIVE;
164 fr_td -> ux_ehci_hsiso_td_control[(frindex << 1) + 1] &= ~UX_EHCI_HSISO_STATUS_ACTIVE;
165 fr_td -> ux_ehci_hsiso_td_frload = 0;
166 fr_td -> ux_ehci_hsiso_td_fr_transfer[0] = UX_NULL;
167 fr_td -> ux_ehci_hsiso_td_fr_transfer[1] = UX_NULL;
168 }
169
170 /* Transfer needs restart. */
171 ied -> ux_ehci_hsiso_ed_frstart = 0xFF;
172 ied -> ux_ehci_hsiso_ed_fr_hc = 0;
173 ied -> ux_ehci_hsiso_ed_fr_sw = 0;
174 ied -> ux_ehci_hsiso_ed_transfer_tail = UX_NULL;
175 ied -> ux_ehci_hsiso_ed_transfer_first_new = UX_NULL;
176 ied -> ux_ehci_hsiso_ed_frload = 0;
177 }
178 else
179 {
180
181 /* At least one request remains (no restart). */
182
183 /* Get the next micro-frame index. */
184 fr_start = (ULONG)ied -> ux_ehci_hsiso_ed_fr_hc << ied -> ux_ehci_hsiso_ed_frinterval_shift;
185 fr_start += ied -> ux_ehci_hsiso_ed_frstart;
186 fr_start &= 0x7u;
187
188 /* First request micro-frame index offset is 0. */
189 fr_req = 0;
190
191 /* Remove the transfer and transfers after it. */
192 transfer = (*list_head) -> ux_transfer_request_next_transfer_request;
193 while(transfer)
194 {
195
196 /* Check next micro-frame index. */
197 fr_req += ied -> ux_ehci_hsiso_ed_frinterval;
198
199 /* If next is transfer we expect, remove from it. */
200 if (transfer -> ux_transfer_request_next_transfer_request == transfer_request)
201 {
202
203 /* Point to NULL to remove all things after it. */
204 transfer -> ux_transfer_request_next_transfer_request = UX_NULL;
205 break;
206 }
207
208 /* If that's first new, it means first new is in remained list. */
209 if (transfer == ied -> ux_ehci_hsiso_ed_transfer_first_new)
210 first_new_aborted = 0;
211
212 /* Next transfer. */
213 transfer = transfer -> ux_transfer_request_next_transfer_request;
214 }
215
216 /* If first new is removed, set to null. */
217 if (first_new_aborted)
218 ied -> ux_ehci_hsiso_ed_transfer_first_new = UX_NULL;
219
220 /* If some micro-frames are removed, modify control. */
221 for (; fr_req < max_load_count; fr_req += ied -> ux_ehci_hsiso_ed_frinterval)
222 {
223 frindex = fr_start + fr_req;
224 frindex &= 0x7u;
225
226 /* Get actual iTD used and clear control. */
227 fr_td = ied -> ux_ehci_hsiso_ed_fr_td[frindex >> 1];
228 fr_td -> ux_ehci_hsiso_td_frload &= (UCHAR)~(1u << frindex);
229 fr_td -> ux_ehci_hsiso_td_control[frindex] &= ~UX_EHCI_HSISO_STATUS_ACTIVE;
230 fr_td -> ux_ehci_hsiso_td_fr_transfer[frindex & 1u] = UX_NULL;
231 }
232 }
233
234 /* Release the periodic table. */
235 _ux_host_mutex_off(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
236 }
237 else
238
239 /* Clean the TDs attached to the ED. */
240 _ux_hcd_ehci_ed_clean(lp.ed_ptr);
241
242 /* Return successful completion. */
243 return(UX_SUCCESS);
244 }
245