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