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_done_queue_process PORTABLE C */
37 /* 6.1.11 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function process the isochronous, periodic and asynchronous */
45 /* lists in search for transfers that occurred in the past */
46 /* (micro-)frame. */
47 /* */
48 /* INPUT */
49 /* */
50 /* hcd_ehci Pointer to EHCI controller */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* None */
55 /* */
56 /* CALLS */
57 /* */
58 /* _ux_hcd_ehci_asynch_td_process Process asynch TD */
59 /* _ux_hcd_ehci_hsisochronous_tds_process */
60 /* Process high speed */
61 /* isochronous TDs */
62 /* _ux_hcd_ehci_fsisochronous_tds_process */
63 /* Process full speed (split) */
64 /* isochronous TDs */
65 /* _ux_utility_virtual_address Get virtual address */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* EHCI Controller Driver */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
76 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
77 /* resulting in version 6.1 */
78 /* 11-09-2020 Chaoqiong Xiao Modified comment(s), */
79 /* fixed compile warning, */
80 /* resulting in version 6.1.2 */
81 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
82 /* fixed standalone compile, */
83 /* resulting in version 6.1.11 */
84 /* */
85 /**************************************************************************/
_ux_hcd_ehci_done_queue_process(UX_HCD_EHCI * hcd_ehci)86 VOID _ux_hcd_ehci_done_queue_process(UX_HCD_EHCI *hcd_ehci)
87 {
88
89 UX_EHCI_TD *td;
90 UX_EHCI_PERIODIC_LINK_POINTER ed;
91 UX_EHCI_ED *start_ed;
92
93
94 #if UX_MAX_ISO_TD
95 UX_EHCI_PERIODIC_LINK_POINTER lp;
96
97 /* We scan the active isochronous list first. */
98 _ux_host_mutex_on(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
99 lp.itd_ptr = hcd_ehci -> ux_hcd_ehci_hsiso_scan_list;
100 while(lp.itd_ptr != UX_NULL)
101 {
102
103 /* Process the iTD, return next active TD. */
104 lp.itd_ptr = _ux_hcd_ehci_hsisochronous_tds_process(hcd_ehci, lp.itd_ptr);
105 }
106 _ux_host_mutex_off(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
107
108 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
109
110 /* We scan the split isochronous list then. */
111 _ux_host_mutex_on(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
112 lp.sitd_ptr = hcd_ehci -> ux_hcd_ehci_fsiso_scan_list;
113 while(lp.sitd_ptr != UX_NULL)
114 {
115
116 /* Process the iTD, return next active TD. */
117 lp.sitd_ptr = _ux_hcd_ehci_fsisochronous_tds_process(hcd_ehci, lp.sitd_ptr);
118 }
119 _ux_host_mutex_off(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
120
121 #endif
122 #endif
123
124 /* We scan the linked interrupt list then. */
125 _ux_host_mutex_on(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
126 ed.ed_ptr = hcd_ehci -> ux_hcd_ehci_interrupt_ed_list;
127 while(ed.ed_ptr != UX_NULL)
128 {
129
130 /* Retrieve the fist TD attached to this ED. */
131 td = ed.ed_ptr -> ux_ehci_ed_first_td;
132
133 /* Process TD until there is no next available. */
134 while (td != UX_NULL)
135 td = _ux_hcd_ehci_asynch_td_process(ed.ed_ptr, td);
136
137 /* Next ED. */
138 ed.ed_ptr = ed.ed_ptr -> ux_ehci_ed_next_ed;
139 }
140 _ux_host_mutex_off(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
141
142 /* Now we can parse the asynchronous list. The head ED is always empty and
143 used as an anchor only. */
144 start_ed = hcd_ehci -> ux_hcd_ehci_asynch_head_list;
145
146 /* Point to the next ED in the asynchronous tree. */
147 ed.ed_ptr = start_ed -> ux_ehci_ed_queue_head;
148 ed.value &= UX_EHCI_LINK_ADDRESS_MASK;
149
150 /* Obtain the virtual address from the element. */
151 ed.void_ptr = _ux_utility_virtual_address(ed.void_ptr);
152
153 /* Now traverse this list until we have found a non anchor endpoint that
154 has transfers done. */
155 while (ed.ed_ptr != start_ed)
156 {
157
158 /* Retrieve the fist TD attached to this ED. */
159 td = ed.ed_ptr -> ux_ehci_ed_first_td;
160 while (td != UX_NULL)
161 {
162
163 td = _ux_hcd_ehci_asynch_td_process(ed.ed_ptr, td);
164 }
165
166 /* Point to the next ED in the asynchronous tree. */
167 ed.ed_ptr = ed.ed_ptr -> ux_ehci_ed_queue_head;
168 ed.value &= UX_EHCI_LINK_ADDRESS_MASK;
169
170 /* Obtain the virtual address from the element. */
171 ed.void_ptr = _ux_utility_virtual_address(ed.void_ptr);
172 }
173 }
174
175