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