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