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