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