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 /** HUB Class */
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_class_hub.h"
30 #include "ux_host_stack.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_hub_configure PORTABLE C */
38 /* 6.1.11 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function calls the USBX stack to do a SET_CONFIGURATION to the */
46 /* HUB. Once the HUB is configured, its interface will be activated */
47 /* and all the endpoints enumerated (1 interrupt endpoint in the case */
48 /* of the HUB). */
49 /* */
50 /* INPUT */
51 /* */
52 /* hub Pointer to HUB */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* Completion Status */
57 /* */
58 /* CALLS */
59 /* */
60 /* _ux_host_stack_device_configuration_get Get device configuration */
61 /* _ux_host_stack_device_configuration_select */
62 /* Select device configuration */
63 /* _ux_host_stack_configuration_interface_get */
64 /* Get interface */
65 /* _ux_host_stack_transfer_request Process transfer request */
66 /* _ux_utility_memory_allocate Allocate memory block */
67 /* _ux_utility_memory_free Release memory block */
68 /* */
69 /* CALLED BY */
70 /* */
71 /* HUB Class */
72 /* */
73 /* RELEASE HISTORY */
74 /* */
75 /* DATE NAME DESCRIPTION */
76 /* */
77 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
78 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
79 /* optimized based on compile */
80 /* definitions, */
81 /* resulting in version 6.1 */
82 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
83 /* internal clean up, */
84 /* resulting in version 6.1.11 */
85 /* */
86 /**************************************************************************/
_ux_host_class_hub_configure(UX_HOST_CLASS_HUB * hub)87 UINT _ux_host_class_hub_configure(UX_HOST_CLASS_HUB *hub)
88 {
89
90 UINT status;
91 UX_CONFIGURATION *configuration;
92 UX_DEVICE *device;
93 UX_ENDPOINT *control_endpoint;
94 UCHAR *device_status_data;
95 UX_TRANSFER *transfer_request;
96 #if UX_MAX_DEVICES > 1
97 UX_DEVICE *parent_device;
98 #endif
99
100
101 /* A HUB normally has one configuration. So retrieve the 1st configuration
102 only. */
103 _ux_host_stack_device_configuration_get(hub -> ux_host_class_hub_device, 0, &configuration);
104
105 /* Get the device container for this configuration. */
106 device = configuration -> ux_configuration_device;
107
108 /* To find the true source of the HUB power source, we need to do a GET_STATUS of
109 the device. */
110 control_endpoint = &device -> ux_device_control_endpoint;
111 transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
112
113 /* Allocate a buffer for the device status: 2 bytes. */
114 device_status_data = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 2);
115 if (device_status_data == UX_NULL)
116 return(UX_MEMORY_INSUFFICIENT);
117
118 /* Create a transfer_request for the GET_STATUS request, 2 bytes are returned. */
119 transfer_request -> ux_transfer_request_requested_length = 2;
120 transfer_request -> ux_transfer_request_data_pointer = device_status_data;
121 transfer_request -> ux_transfer_request_function = UX_GET_STATUS;
122 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
123 transfer_request -> ux_transfer_request_value = 0;
124 transfer_request -> ux_transfer_request_index = 0;
125
126 /* Send request to HCD layer. */
127 status = _ux_host_stack_transfer_request(transfer_request);
128
129 /* Check the status and the length of the data returned. */
130 if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == 2))
131 {
132
133 /* The data returned is good, now analyze power source. */
134 if (*device_status_data & UX_STATUS_DEVICE_SELF_POWERED)
135 device -> ux_device_power_source = UX_DEVICE_SELF_POWERED;
136 else
137 device -> ux_device_power_source = UX_DEVICE_BUS_POWERED;
138
139 /* Free the buffer resource now. */
140 _ux_utility_memory_free(device_status_data);
141 }
142 else
143 {
144
145 /* Free the buffer resource now. */
146 _ux_utility_memory_free(device_status_data);
147
148 /* Error trap. */
149 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_CONNECTION_INCOMPATIBLE);
150
151 /* If trace is enabled, insert this event into the trace buffer. */
152 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONNECTION_INCOMPATIBLE, hub, 0, 0, UX_TRACE_ERRORS, 0, 0)
153
154 /* Return an error. */
155 return(UX_CONNECTION_INCOMPATIBLE);
156 }
157
158 #if UX_MAX_DEVICES > 1
159 /* Check the HUB power source and check the parent power source for
160 incompatible connections. */
161 if (hub -> ux_host_class_hub_device -> ux_device_power_source == UX_DEVICE_BUS_POWERED)
162 {
163
164 /* Get the parent container for this device. */
165 parent_device = device -> ux_device_parent;
166
167 /* If the device is NULL, the parent is the root HUB and we don't have to worry
168 if the parent is not the root HUB, check for its power source. */
169 if ((parent_device != UX_NULL) && (parent_device -> ux_device_power_source == UX_DEVICE_BUS_POWERED))
170 {
171
172 /* Error trap. */
173 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_CONNECTION_INCOMPATIBLE);
174
175 /* If trace is enabled, insert this event into the trace buffer. */
176 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONNECTION_INCOMPATIBLE, hub, 0, 0, UX_TRACE_ERRORS, 0, 0)
177
178 return(UX_CONNECTION_INCOMPATIBLE);
179 }
180 }
181 #endif
182
183 /* We have the valid configuration. Ask the USBX stack to set this configuration. */
184 _ux_host_stack_device_configuration_select(configuration);
185
186 /* If the operation went well, the HUB default alternate setting for the HUB interface is
187 active and the interrupt endpoint is now enabled. We have to memorize the first interface
188 since the interrupt endpoint is hooked to it. */
189 status = _ux_host_stack_configuration_interface_get(configuration, 0, 0, &hub -> ux_host_class_hub_interface);
190
191 /* Return completion status. */
192 return(status);
193 }
194
195