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