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 /** OHCI 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_ohci.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_hcd_ohci_interrupt_handler PORTABLE C */
37 /* 6.1.12 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function is the interrupt handler for the OHCI 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. */
48 /* */
49 /* All we need to do in the ISR is scan the controllers to find out */
50 /* which one has issued a IRQ. If there is work to do for this */
51 /* controller we need to wake up the corresponding thread to take */
52 /* care of the job. */
53 /* */
54 /* INPUT */
55 /* */
56 /* None */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* None */
61 /* */
62 /* CALLS */
63 /* */
64 /* _ux_hcd_ohci_register_read Read OHCI register */
65 /* _ux_hcd_ohci_register_write Write OHCI register */
66 /* _ux_host_semaphore_put Put semaphore */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* ThreadX Interrupt Handler */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
77 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
78 /* resulting in version 6.1 */
79 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
80 /* refined macros names, */
81 /* resulting in version 6.1.10 */
82 /* 07-29-2022 Yajun Xia Modified comment(s), */
83 /* fixed OHCI PRSC issue, */
84 /* resulting in version 6.1.12 */
85 /* */
86 /**************************************************************************/
_ux_hcd_ohci_interrupt_handler(VOID)87 VOID _ux_hcd_ohci_interrupt_handler(VOID)
88 {
89
90 UINT hcd_index;
91 UX_HCD *hcd;
92 UX_HCD_OHCI *hcd_ohci;
93 ULONG ohci_register = 0;
94 ULONG ohci_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
100 registered as OHCI. */
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_OHCI_CONTROLLER)
106 {
107
108 /* Get the pointers to the generic HCD and OHCI specific areas. */
109 hcd = &_ux_system_host -> ux_system_host_hcd_array[hcd_index];
110 hcd_ohci = (UX_HCD_OHCI *) 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 /* We get the current interrupt status for this controller. */
117 ohci_register = _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_INTERRUPT_STATUS);
118
119 /* Examine the source of interrupts. */
120 if (ohci_register & OHCI_HC_INT_WDH)
121 {
122
123 /* We have some transferred EDs in the done queue. The controller thread needs
124 to wake up and process them. */
125 hcd_ohci -> ux_hcd_ohci_done_head = hcd_ohci -> ux_hcd_ohci_hcca -> ux_hcd_ohci_hcca_done_head;
126 hcd_ohci -> ux_hcd_ohci_hcca -> ux_hcd_ohci_hcca_done_head = UX_NULL;
127 hcd -> ux_hcd_thread_signal++;
128 _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_hcd_semaphore);
129
130 /* Since we have delayed the processing of the done queue to a thread.
131 We need to ensure the host controller will not overwrite the done
132 queue pointer. So we disable the WDH bit in the interrupt status
133 before we acknowledge the IRQ register. */
134 _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_INTERRUPT_DISABLE, OHCI_HC_INT_WDH);
135 }
136
137 if (ohci_register & OHCI_HC_INT_UE)
138 {
139
140 /* The controller has issued a Unrecoverable Error signal. The controller will
141 be reset now, and we wake up the HCD thread. */
142 _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_COMMAND_STATUS, OHCI_HC_CS_HCR);
143 hcd -> ux_hcd_thread_signal++;
144 hcd -> ux_hcd_status = UX_HCD_STATUS_DEAD;
145 _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_hcd_semaphore);
146 }
147
148 if (ohci_register & OHCI_HC_INT_RHSC)
149 {
150
151 /* The controller has issued a Root HUB status change signal. There may be one or more events
152 that caused this status change. Only device insertion/extraction are monitored here. */
153 for (port_index = 0; port_index < hcd_ohci -> ux_hcd_ohci_nb_root_hubs; port_index++)
154 {
155
156 /* Read the port status. */
157 ohci_register_port_status = _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_RH_PORT_STATUS + port_index);
158
159 /* Check for Connect Status Change signal. */
160 if (ohci_register_port_status & OHCI_HC_PS_CSC)
161 {
162 /* Something happened on this port. Signal it to the root hub thread. */
163 hcd -> ux_hcd_root_hub_signal[port_index]++;
164
165 /* Memorize wake up signal. */
166 root_hub_thread_wakeup ++;
167 }
168
169 if (ohci_register_port_status & OHCI_HC_PS_PRSC)
170 {
171 _ux_host_event_flags_set(&hcd_ohci -> ux_hcd_ohci_event_flags_group, UX_OHCI_PRSC_EVENT, UX_OR);
172 }
173
174 /* Clear the root hub interrupt signal. */
175 _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_RH_PORT_STATUS + port_index,
176 (OHCI_HC_PS_CSC | OHCI_HC_PS_PESC | OHCI_HC_PS_PSSC | OHCI_HC_PS_OCIC | OHCI_HC_PS_PRSC));
177 }
178
179 /* We only wake up the root hub thread if there has been device insertion/extraction. */
180 if (root_hub_thread_wakeup != 0)
181 _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore);
182 }
183 }
184
185 /* We have processed the interrupts for this controller, acknowledge them
186 so that the controller can continue to work. */
187 _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_INTERRUPT_STATUS, ohci_register);
188 }
189 }
190 }
191
192