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