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