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_interrupt_handler PORTABLE C */
37 /* 6.1.10 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function is the interrupt handler for the EHCI interrupts. */
45 /* Normally an interrupt occurs from the controller when there is */
46 /* either a EOF signal and there has been transfers within the frame */
47 /* or when there is a change on one of the downstream ports, a */
48 /* doorbell signal or an unrecoverable error. */
49 /* */
50 /* All we need to do in the ISR is scan the controllers to find out */
51 /* which one has issued a IRQ. If there is work to do for this */
52 /* controller we need to wake up the corresponding thread to take care */
53 /* of the job. */
54 /* */
55 /* INPUT */
56 /* */
57 /* None */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* None */
62 /* */
63 /* CALLS */
64 /* */
65 /* _ux_hcd_ehci_controller_disable Disable controller */
66 /* _ux_hcd_ehci_register_read Read EHCI register */
67 /* _ux_hcd_ehci_register_write Write EHCI register */
68 /* _ux_host_semaphore_put Put semaphore */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* EHCI Controller Driver */
73 /* */
74 /* RELEASE HISTORY */
75 /* */
76 /* DATE NAME DESCRIPTION */
77 /* */
78 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
79 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
80 /* resulting in version 6.1 */
81 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
82 /* refined macros names, */
83 /* resulting in version 6.1.10 */
84 /* */
85 /**************************************************************************/
_ux_hcd_ehci_interrupt_handler(VOID)86 VOID _ux_hcd_ehci_interrupt_handler(VOID)
87 {
88
89 UINT hcd_index;
90 UX_HCD *hcd;
91 UX_HCD_EHCI *hcd_ehci;
92 ULONG ehci_register;
93 ULONG ehci_register_port_status;
94 ULONG root_hub_thread_wakeup = 0;
95 ULONG port_index;
96
97
98 /* We need to parse the controller driver table to find all controllers that registered
99 as EHCI. */
100 for (hcd_index = 0; hcd_index < _ux_system_host -> ux_system_host_registered_hcd; hcd_index++)
101 {
102
103 /* Check type of controller. */
104 if (_ux_system_host -> ux_system_host_hcd_array[hcd_index].ux_hcd_controller_type == UX_EHCI_CONTROLLER)
105 {
106
107 /* Get the pointers to the generic HCD and EHCI specific areas. */
108 hcd = &_ux_system_host -> ux_system_host_hcd_array[hcd_index];
109 hcd_ehci = (UX_HCD_EHCI *) hcd -> ux_hcd_controller_hardware;
110
111 /* Check if the controller is operational, if not, skip it. */
112 if (hcd -> ux_hcd_status == UX_HCD_STATUS_OPERATIONAL)
113 {
114
115 /* For debugging purposes, increment the interrupt count. */
116 hcd_ehci -> ux_hcd_ehci_interrupt_count++;
117
118 /* We get the current interrupt status for this controller. */
119 ehci_register = _ux_hcd_ehci_register_read(hcd_ehci, EHCI_HCOR_USB_STATUS);
120
121 /* We acknowledge the interrupts for this controller so that it
122 can continue to work. */
123 _ux_hcd_ehci_register_write(hcd_ehci, EHCI_HCOR_USB_STATUS, ehci_register);
124
125 /* Examine the source of interrupts. */
126 if ((ehci_register & EHCI_HC_STS_USB_INT) || (ehci_register & EHCI_HC_STS_USB_ERR_INT))
127 {
128
129 /* We have some transactions done in the past frame/micro-frame.
130 The controller thread needs to wake up and process them. */
131 hcd -> ux_hcd_thread_signal++;
132 _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_hcd_semaphore);
133 }
134
135 if (ehci_register & EHCI_HC_STS_HSE)
136 {
137
138 /* The controller has issued a Host System Error which is fatal.
139 The controller will be reset now, and we wake up the HCD thread. */
140 _ux_hcd_ehci_controller_disable(hcd_ehci);
141 hcd -> ux_hcd_thread_signal++;
142 hcd -> ux_hcd_status = UX_HCD_STATUS_DEAD;
143 hcd -> ux_hcd_thread_signal++;
144 _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_hcd_semaphore);
145
146 /* Error trap. */
147 _ux_system_error_handler(UX_SYSTEM_LEVEL_INTERRUPT, UX_SYSTEM_CONTEXT_HCD, UX_CONTROLLER_DEAD);
148
149 }
150
151 if (ehci_register & EHCI_HC_STS_PCD)
152 {
153
154 /* The controller has issued a Root hub status change signal. Scan all ports. */
155 for (port_index = 0; port_index < hcd_ehci -> ux_hcd_ehci_nb_root_hubs; port_index++)
156 {
157
158 /* Read the port status. */
159 ehci_register_port_status = _ux_hcd_ehci_register_read(hcd_ehci, EHCI_HCOR_PORT_SC + port_index);
160
161 /* Check for Connect Status Change signal. */
162 if (ehci_register_port_status & EHCI_HC_PS_CSC)
163 {
164 /* Something happened on this port. Signal it to the root hub thread. */
165 hcd -> ux_hcd_root_hub_signal[port_index]++;
166
167 /* Memorize wake up signal. */
168 root_hub_thread_wakeup ++;
169
170 }
171
172 }
173
174 /* We only wake up the root hub thread if there has been device insertion/extraction. */
175 if (root_hub_thread_wakeup != 0)
176
177 /* The controller has issued a Root hub status change signal.
178 We need to resume the thread in charge of the USB topology. */
179 _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore);
180 }
181
182 if (ehci_register & EHCI_HC_STS_IAA)
183 {
184
185 /* The controller has issued a Door Bell status change signal.
186 We need to resume the thread who raised the doorbell. */
187 _ux_host_semaphore_put(&hcd_ehci -> ux_hcd_ehci_doorbell_semaphore);
188 }
189 }
190 }
191 }
192 }
193
194