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 /**   Host Stack                                                          */
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_host_stack.h"
29 
30 
31 #if defined(UX_OTG_SUPPORT)
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_host_stack_hnp_polling_thread_entry             PORTABLE C      */
37 /*                                                           6.1.10       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function is awaken every 2 seconds to check if there is a      */
45 /*    OTG device on the bus and if so perform a GET_STATUS as the device  */
46 /*    may request a change of role.                                       */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    none                                                                */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    None                                                                */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _ux_host_stack_transfer_request       Transfer request              */
59 /*    _ux_utility_thread_sleep              Sleep thread                  */
60 /*    _ux_utility_semaphore_get             Get semaphore                 */
61 /*    _ux_utility_memory_allocate           Allocate memory               */
62 /*    _ux_utility_memory_free               Free memory                   */
63 /*    _ux_host_stack_role_swap              Swapping role                 */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    ThreadX                                                             */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
74 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
75 /*                                            optimized based on compile  */
76 /*                                            definitions,                */
77 /*                                            resulting in version 6.1    */
78 /*  02-02-2021     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            used pointer for current    */
80 /*                                            selected configuration,     */
81 /*                                            resulting in version 6.1.4  */
82 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            refined macros names,       */
84 /*                                            resulting in version 6.1.10 */
85 /*                                                                        */
86 /**************************************************************************/
_ux_host_stack_hnp_polling_thread_entry(ULONG argument)87 VOID  _ux_host_stack_hnp_polling_thread_entry(ULONG argument)
88 {
89 
90 UINT                        hcd_index;
91 UX_DEVICE                   *device;
92 UX_CONFIGURATION            *configuration;
93 UX_ENDPOINT                 *control_endpoint;
94 UX_TRANSFER                 *transfer_request;
95 UX_HCD                      *hcd;
96 UCHAR                       *otg_status;
97 ULONG                       port_index;
98 ULONG                       port_status;
99 ULONG                       container_index;
100 UINT                        status;
101 
102     UX_PARAMETER_NOT_USED(argument);
103 
104     /* This thread goes on forever once started.  */
105     while(1)
106     {
107 
108         /* We need to wake every 2 seconds or so.  */
109         _ux_utility_thread_sleep(UX_OTG_HNP_THREAD_SLEEP_TIME);
110 
111         /* We need to parse the controller driver table to find all controllers that registered
112                as OTG.  */
113         for (hcd_index = 0; hcd_index < _ux_system_host -> ux_system_host_registered_hcd; hcd_index++)
114         {
115 
116             /* Pickup HCD pointer.  */
117             hcd =  &_ux_system_host -> ux_system_host_hcd_array[hcd_index];
118 
119             /* Check type of controller.  Is it OTG capable ? Must be operational too. */
120             if ((hcd -> ux_hcd_otg_capabilities & UX_HCD_OTG_CAPABLE) &&
121                 (hcd -> ux_hcd_status == UX_HCD_STATUS_OPERATIONAL))
122             {
123 
124                 /* Yes, we can parse the root hub and see if any devices attached to it.  */
125                 for (port_index = 0; port_index < hcd -> ux_hcd_nb_root_hubs; port_index++)
126                 {
127 
128                     /* Call HCD for port status.  */
129                     port_status =  hcd -> ux_hcd_entry_function(hcd, UX_HCD_GET_PORT_STATUS, (VOID *)((ALIGN_TYPE)port_index));
130 
131                     /* Check return status.  */
132                     if (port_status != UX_PORT_INDEX_UNKNOWN)
133                     {
134 
135                         /* the port_status value is valid and will tell us if there is
136                            a device attached\detached on the downstream port and if the port is powered.  */
137                         if ((port_status & UX_PS_CCS) && (port_status & UX_PS_PPS))
138                         {
139 
140                              /* There is a device attached to one of the root hub port.  Parse the device
141                                to find out which one it is.  */
142                             device =  _ux_system_host -> ux_system_host_device_array;
143 
144                             /* Start at the beginning of the list.  */
145                             container_index =  0;
146 
147                             /* Search the list until the end.  */
148                             while (container_index++ < UX_SYSTEM_HOST_MAX_DEVICES_GET())
149                             {
150 
151                                 /* Until we have found a used entry.  */
152                                 if (device -> ux_device_handle != UX_UNUSED)
153                                 {
154 
155                                     /* Check for the parent device and the port location and the controller.  */
156                                     if(UX_DEVICE_PORT_LOCATION_MATCH(device, port_index) &&
157                                        UX_DEVICE_HCD_MATCH(device, hcd))
158                                     {
159 
160                                         /* We have a device on a OTG port. But is it a OTG HNP capable device ?
161                                            We need to parse the configuration until we find the one current. */
162                                         configuration = device -> ux_device_current_configuration;
163 
164                                         /* Check for OTG HNP support.  */
165                                         if (configuration -> ux_configuration_otg_capabilities & UX_OTG_HNP_SUPPORT)
166                                         {
167 
168                                             /* Allocate memory for the OTG status.  */
169                                             otg_status =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 16);
170 
171                                             /* Check for status.  */
172                                             if (otg_status == UX_NULL)
173                                                 return;
174 
175                                             /* Retrieve the control endpoint and the transfer request associated with it.  */
176                                             control_endpoint =  &device -> ux_device_control_endpoint;
177                                             transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
178 
179                                             /* Protect the control endpoint semaphore here.  It will be unprotected in the
180                                                transfer request function.  */
181                                             status =  _ux_host_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
182 
183                                             /* Perform a GET_STATUS on this device to see if it wants to become the host.  */
184                                             /* Create a transfer_request for the SET_CONFIGURATION request. No data for this request.  */
185                                             transfer_request -> ux_transfer_request_data_pointer =      otg_status;
186                                             transfer_request -> ux_transfer_request_requested_length =  1;
187                                             transfer_request -> ux_transfer_request_function =          UX_GET_STATUS;
188                                             transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
189                                             transfer_request -> ux_transfer_request_value =             0;
190                                             transfer_request -> ux_transfer_request_index =             UX_OTG_STATUS_SELECTOR;
191 
192                                             /* Send request to HCD layer.  */
193                                             status =  _ux_host_stack_transfer_request(transfer_request);
194 
195                                             /* Check completion status.  */
196                                             if(status == UX_SUCCESS && transfer_request -> ux_transfer_request_actual_length == 1)
197                                             {
198 
199                                                 /* We have an answer from the device. Check the HNP flag.  */
200                                                 if (*otg_status & UX_OTG_HOST_REQUEST_FLAG)
201                                                 {
202 
203                                                     /* The device has requested a Host swap. Initiate the command and perform the
204                                                         stopping of the host.  */
205                                                     _ux_host_stack_role_swap(device);
206                                                 }
207 
208                                             }
209 
210                                             /* Free all used resources.  */
211                                             _ux_utility_memory_free(otg_status);
212 
213                                         }
214                                     }
215                                 }
216 
217                                 /* Move to the next device entry.  */
218                                 device++;
219 
220                             }
221                         }
222                     }
223                 }
224             }
225         }
226     }
227 }
228 #endif /* #if defined(UX_OTG_SUPPORT) */
229