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_isochronous_endpoint_destroy PORTABLE C */
38 /* 6.1.11 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function will destroy an isochronous endpoint. */
46 /* */
47 /* INPUT */
48 /* */
49 /* hcd_ehci Pointer to EHCI controller */
50 /* endpoint Pointer to endpoint */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* Completion Status */
55 /* */
56 /* CALLS */
57 /* */
58 /* None */
59 /* _ux_host_mutex_on Get mutex */
60 /* _ux_host_mutex_off Put mutex */
61 /* _ux_hcd_ehci_periodic_descriptor_link Link/unlink descriptor */
62 /* _ux_utility_memory_free Free memory */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* EHCI Controller Driver */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
73 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
74 /* resulting in version 6.1 */
75 /* 11-09-2020 Chaoqiong Xiao Modified comment(s), */
76 /* fixed compile warnings, */
77 /* resulting in version 6.1.2 */
78 /* 04-02-2021 Chaoqiong Xiao Modified comment(s), */
79 /* fixed compile issues with */
80 /* some macro options, */
81 /* resulting in version 6.1.6 */
82 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
83 /* fixed standalone compile, */
84 /* resulting in version 6.1.11 */
85 /* */
86 /**************************************************************************/
_ux_hcd_ehci_isochronous_endpoint_destroy(UX_HCD_EHCI * hcd_ehci,UX_ENDPOINT * endpoint)87 UINT _ux_hcd_ehci_isochronous_endpoint_destroy(UX_HCD_EHCI *hcd_ehci, UX_ENDPOINT *endpoint)
88 {
89 #if UX_MAX_ISO_TD == 0
90
91 UX_PARAMETER_NOT_USED(hcd_ehci);
92 UX_PARAMETER_NOT_USED(endpoint);
93
94 /* Error trap. */
95 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_FUNCTION_NOT_SUPPORTED);
96
97 /* If trace is enabled, insert this event into the trace buffer. */
98 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
99
100 /* Not supported, return error. */
101 return(UX_FUNCTION_NOT_SUPPORTED);
102 #else
103
104 UX_EHCI_HSISO_ED *ed;
105 UX_EHCI_PERIODIC_LINK_POINTER ed_td;
106 UX_EHCI_PERIODIC_LINK_POINTER lp;
107 ULONG max_packet_size;
108 UINT frindex;
109 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
110 ULONG split_count;
111 ULONG last_frindex;
112 ULONG last_size;
113 #endif
114
115
116 /* Get ED iTD/siTD. */
117 ed_td.void_ptr = endpoint -> ux_endpoint_ed;
118
119 /* Access to periodic list. */
120 _ux_host_mutex_on(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
121
122 /* Check active iTD/siTD and unlink it. */
123 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
124 if (endpoint -> ux_endpoint_device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
125 {
126 /* TBD. */
127 }
128 else
129 #endif
130 {
131
132 /* Get ED. */
133 ed = ed_td.itd_ptr -> ux_ehci_hsiso_td_ed;
134
135 /* Unlink from periodic list. */
136 if (ed_td.itd_ptr -> ux_ehci_hsiso_td_previous_lp.void_ptr != UX_NULL)
137 {
138
139 /* Get next LP of last iTD. */
140 lp = ed -> ux_ehci_hsiso_ed_fr_td[ed -> ux_ehci_hsiso_ed_nb_tds - 1]
141 -> ux_ehci_hsiso_td_next_lp;
142 _ux_hcd_ehci_periodic_descriptor_link(
143 ed_td.itd_ptr -> ux_ehci_hsiso_td_previous_lp.void_ptr,
144 UX_NULL, UX_NULL,
145 lp.void_ptr);
146 }
147 }
148
149 /* Unlink iTD/siTD from the scan list. */
150 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
151 if (endpoint -> ux_endpoint_device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
152 {
153
154 /* Get list head. */
155 lp.sitd_ptr = hcd_ehci -> ux_hcd_ehci_fsiso_scan_list;
156
157 /* Check if unlink from head. */
158 if (lp.sitd_ptr == ed_td.sitd_ptr)
159
160 /* Unlink from list head. */
161 hcd_ehci -> ux_hcd_ehci_fsiso_scan_list = ed_td.sitd_ptr -> ux_ehci_fsiso_td_next_scan_td;
162 else
163 {
164
165 /* Scan items in list. */
166 while(lp.sitd_ptr)
167 {
168
169 /* Not the previous item, just try next. */
170 if (lp.sitd_ptr -> ux_ehci_fsiso_td_next_scan_td != ed_td.sitd_ptr)
171 {
172 lp.sitd_ptr = lp.sitd_ptr -> ux_ehci_fsiso_td_next_scan_td;
173 continue;
174 }
175
176 /* Found it, unlink and break. */
177 lp.sitd_ptr -> ux_ehci_fsiso_td_next_scan_td = ed_td.sitd_ptr -> ux_ehci_fsiso_td_next_scan_td;
178 break;
179 }
180 }
181 }
182 else
183 #endif
184 {
185
186 /* Get head. */
187 lp.itd_ptr = hcd_ehci -> ux_hcd_ehci_hsiso_scan_list;
188
189 /* Check if iTD is in head. */
190 if (lp.itd_ptr == ed_td.itd_ptr)
191
192 /* Unlink from list head. */
193 hcd_ehci -> ux_hcd_ehci_hsiso_scan_list = lp.itd_ptr -> ux_ehci_hsiso_td_next_scan_td;
194 else
195 {
196
197 /* Not in head, there must be previous. */
198
199 /* Link it's previous to next. */
200 lp.itd_ptr -> ux_ehci_hsiso_td_previous_scan_td -> ux_ehci_hsiso_td_next_scan_td =
201 lp.itd_ptr -> ux_ehci_hsiso_td_next_scan_td;
202
203 /* Link it's next to previous. */
204 if (lp.itd_ptr -> ux_ehci_hsiso_td_next_scan_td)
205 lp.itd_ptr -> ux_ehci_hsiso_td_next_scan_td -> ux_ehci_hsiso_td_previous_scan_td =
206 lp.itd_ptr -> ux_ehci_hsiso_td_previous_scan_td;
207 }
208 }
209
210 /* Update micro-frame loads of anchor. */
211
212 /* Calculate max packet size. */
213 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
214 if (endpoint -> ux_endpoint_device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
215 {
216 max_packet_size = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_PACKET_SIZE_MASK;
217
218 /* Update according to siTD S-Mask. */
219 max_packet_size = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_NUMBER_OF_TRANSACTIONS_MASK;
220
221 /* Update according to mask. */
222
223 for (frindex = 0; frindex < 8; frindex ++)
224 {
225
226 /* Update start split related. */
227 if (ed_td.sitd_ptr -> ux_ehci_fsiso_td_cap1 & (UX_EHCI_SMASK_0 << frindex))
228 {
229
230 /* Update start split count. */
231 ed_td.sitd_ptr -> ux_ehci_fsiso_td_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_ssplit_count[frindex] --;
232
233 /* Update load for OUT. */
234 if ((endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == 0)
235 {
236 split_count = (max_packet_size + 187) / 188;
237 last_frindex = ((ed_td.sitd_ptr -> ux_ehci_fsiso_td_frindex + split_count - 1) & 7);
238 last_size = max_packet_size % 188;
239 if (last_size == 0 &&
240 frindex == last_frindex)
241 ed_td.sitd_ptr -> ux_ehci_fsiso_td_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[frindex] = (USHORT)
242 (ed_td.sitd_ptr -> ux_ehci_fsiso_td_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[frindex] - last_size);
243 else
244 ed_td.sitd_ptr -> ux_ehci_fsiso_td_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[frindex] = (USHORT)
245 (ed_td.sitd_ptr -> ux_ehci_fsiso_td_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[frindex] - 188u);
246 }
247
248 }
249
250 /* Update complete split related (IN only). */
251 if (ed_td.sitd_ptr -> ux_ehci_fsiso_td_cap1 & (UX_EHCI_CMASK_0 << frindex))
252 ed_td.sitd_ptr -> ux_ehci_fsiso_td_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[frindex] = (USHORT)
253 (ed_td.sitd_ptr -> ux_ehci_fsiso_td_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[frindex] - 188u);
254 }
255 }
256 else
257 #endif
258 {
259
260 /* Get max transfer size. */
261 max_packet_size = ed_td.itd_ptr -> ux_ehci_hsiso_td_max_trans_size;
262
263 /* Update according to mask. */
264 for (frindex = ed -> ux_ehci_hsiso_ed_frindex;
265 frindex < 8;
266 frindex += ed -> ux_ehci_hsiso_ed_frinterval)
267 {
268
269 /* Decrement the microframes scheduled. */
270 ed -> ux_ehci_hsiso_ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[frindex] = (USHORT)(ed -> ux_ehci_hsiso_ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[frindex] - max_packet_size);
271 }
272 }
273
274 /* Release periodic list. */
275 _ux_host_mutex_off(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
276
277 /* Now we can safely make the iTD/siTDs free. */
278 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
279 if (endpoint -> ux_endpoint_device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
280 {
281 ed_td.sitd_ptr -> ux_ehci_fsiso_td_status = UX_UNUSED;
282 }
283 else
284 #endif
285 {
286 for (frindex = 0; frindex < ed -> ux_ehci_hsiso_ed_nb_tds; frindex ++)
287 ed -> ux_ehci_hsiso_ed_fr_td[frindex] -> ux_ehci_hsiso_td_status = UX_UNUSED;
288 _ux_utility_memory_free(ed);
289 }
290
291 return(UX_SUCCESS);
292 #endif
293 }
294