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 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_stack_new_device_create PORTABLE C */
37 /* 6.1.12 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function creates a new device on the USB. It may be called */
45 /* either by a hub or by the root hub. */
46 /* */
47 /* INPUT */
48 /* */
49 /* HCD HCD that owns that device */
50 /* device_owner Either a root hub instance */
51 /* or a hub instance */
52 /* port_index Port the new device is mounted*/
53 /* device_speed Speed at which the device is */
54 /* running (low, full, high) */
55 /* port_power_available Power available on the root */
56 /* or hub port. This value is */
57 /* used to ensure that the */
58 /* device can be configured */
59 /* without creating an */
60 /* OVER_CURRENT condition on */
61 /* the bus */
62 /* created_device Destination to fill created */
63 /* device instance */
64 /* */
65 /* OUTPUT */
66 /* */
67 /* Completion Status */
68 /* */
69 /* An Error code could be an indication that the device could not be */
70 /* created in which case the error is fatal to the enumeration and */
71 /* will not be retried. The error code can also indicate a failure */
72 /* for the device to respond to the GET_DEVICE_DESCRIPTOR. This error */
73 /* is not fatal and the caller should retry the enumeration process */
74 /* after the port to which the device is attached has been reset. */
75 /* */
76 /* CALLS */
77 /* */
78 /* _ux_host_stack_class_device_scan Scan class devices */
79 /* _ux_host_stack_class_interface_scan Scan class interfaces */
80 /* _ux_host_stack_device_address_set Set device address */
81 /* _ux_host_stack_device_descriptor_read Read device descriptor */
82 /* _ux_host_stack_configuration_enumerate */
83 /* Enumerate device config */
84 /* _ux_host_stack_new_device_get Get new device */
85 /* _ux_utility_semaphore_create Create a semaphore */
86 /* (ux_hcd_entry_function) HCD entry function */
87 /* */
88 /* CALLED BY */
89 /* */
90 /* USBX Components */
91 /* */
92 /* RELEASE HISTORY */
93 /* */
94 /* DATE NAME DESCRIPTION */
95 /* */
96 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
97 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
98 /* optimized based on compile */
99 /* definitions, */
100 /* resulting in version 6.1 */
101 /* 02-02-2021 Chaoqiong Xiao Modified comment(s), */
102 /* added a new parameter to */
103 /* return created device, */
104 /* resulting in version 6.1.4 */
105 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
106 /* added standalone support, */
107 /* reset device power source, */
108 /* resulting in version 6.1.10 */
109 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
110 /* freed shared device config */
111 /* descriptor after enum scan, */
112 /* resulting in version 6.1.12 */
113 /* */
114 /**************************************************************************/
_ux_host_stack_new_device_create(UX_HCD * hcd,UX_DEVICE * device_owner,UINT port_index,UINT device_speed,UINT port_max_power,UX_DEVICE ** created_device)115 UINT _ux_host_stack_new_device_create(UX_HCD *hcd, UX_DEVICE *device_owner,
116 UINT port_index, UINT device_speed,
117 UINT port_max_power,
118 UX_DEVICE **created_device)
119 {
120
121 UX_DEVICE *device;
122 UINT status;
123 UX_ENDPOINT *control_endpoint;
124
125
126 #if UX_MAX_DEVICES > 1
127 /* Verify the number of devices attached to the HCD already. Normally a HCD
128 can have up to 127 devices but that can be tailored. */
129 if (hcd -> ux_hcd_nb_devices > UX_MAX_USB_DEVICES)
130 {
131
132 /* Error trap. */
133 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_TOO_MANY_DEVICES);
134
135 /* If trace is enabled, insert this event into the trace buffer. */
136 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TOO_MANY_DEVICES, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
137
138 return(UX_TOO_MANY_DEVICES);
139 }
140 #endif
141
142 /* Get a new device container to store this new device. */
143 device = _ux_host_stack_new_device_get();
144 if (device == UX_NULL)
145 {
146
147 /* Error trap. */
148 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_TOO_MANY_DEVICES);
149
150 /* If trace is enabled, insert this event into the trace buffer. */
151 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TOO_MANY_DEVICES, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
152
153 return(UX_TOO_MANY_DEVICES);
154 }
155
156 /* Store the device instance. */
157 *created_device = device;
158
159 /* Increment the number of devices on this bus. */
160 hcd -> ux_hcd_nb_devices++;
161
162 /* If trace is enabled, insert this event into the trace buffer. */
163 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_NEW_DEVICE_CREATE, hcd, device_owner, port_index, device, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
164
165 /* At this stage the device is attached but not configured.
166 we don't have to worry about power consumption yet.
167 Initialize the device structure. */
168 device -> ux_device_handle = (ULONG) (ALIGN_TYPE) device;
169 device -> ux_device_state = UX_DEVICE_ATTACHED;
170 device -> ux_device_address = 0;
171 device -> ux_device_speed = device_speed;
172 UX_DEVICE_MAX_POWER_SET(device, port_max_power);
173 UX_DEVICE_PARENT_SET(device, device_owner);
174 UX_DEVICE_HCD_SET(device, hcd);
175 UX_DEVICE_PORT_LOCATION_SET(device, port_index);
176 device -> ux_device_power_source = UX_DEVICE_BUS_POWERED;
177
178 /* Create a semaphore for the device. This is to protect endpoint 0 mostly for OTG HNP polling. The initial count is 1 as
179 a mutex mechanism. */
180 status = _ux_host_semaphore_create(&device -> ux_device_protection_semaphore, "ux_host_endpoint0_semaphore", 1);
181
182 /* Check semaphore creation. */
183 if (status != UX_SUCCESS)
184 {
185
186 /* Return error. Device resources that have been allocated until this
187 point should be freed by the caller via _ux_host_stack_device_resources_free. */
188 return(UX_SEMAPHORE_ERROR);
189 }
190
191 /* Initialize the default control endpoint permanently attached
192 to the device. */
193 control_endpoint = &device -> ux_device_control_endpoint;
194 control_endpoint -> ux_endpoint = (ULONG) (ALIGN_TYPE) control_endpoint;
195 control_endpoint -> ux_endpoint_next_endpoint = UX_NULL;
196 control_endpoint -> ux_endpoint_interface = UX_NULL;
197 control_endpoint -> ux_endpoint_device = device;
198 control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_endpoint = control_endpoint;
199
200 /* Create a semaphore for this endpoint to be attached to its transfer request. */
201 status = _ux_host_semaphore_create(&control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore, "ux_host_transfer_request_semaphore", 0);
202
203 /* Check semaphore creation. */
204 if (status != UX_SUCCESS)
205 {
206
207 /* Return error. Device resources that have been allocated until this
208 point should be freed by the caller via _ux_host_stack_device_resources_free. */
209 return(UX_SEMAPHORE_ERROR);
210 }
211
212 /* If the device is running in high speed the default max packet size for the control endpoint is 64.
213 All other speeds the size is 8. */
214 if (device_speed == UX_HIGH_SPEED_DEVICE)
215 control_endpoint -> ux_endpoint_descriptor.wMaxPacketSize = UX_DEFAULT_HS_MPS;
216 else
217 control_endpoint -> ux_endpoint_descriptor.wMaxPacketSize = UX_DEFAULT_MPS;
218
219 /* Create the default control endpoint at the HCD level. */
220 status = hcd -> ux_hcd_entry_function(hcd, UX_HCD_CREATE_ENDPOINT, (VOID *) control_endpoint);
221
222 #if defined(UX_HOST_STANDALONE)
223 if (status == UX_SUCCESS)
224 {
225
226 /* Now control endpoint is ready, set state to running. */
227 control_endpoint -> ux_endpoint_state = UX_ENDPOINT_RUNNING;
228
229 /* Setup default control request timeout. */
230 control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_timeout_value =
231 UX_MS_TO_TICK_NON_ZERO(UX_CONTROL_TRANSFER_TIMEOUT);
232
233 /* Set default control request mode to wait. */
234 control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_flags |=
235 UX_TRANSFER_FLAG_AUTO_WAIT;
236 }
237
238 /* Enumeration steps will be done in task state machine. */
239
240 #else
241
242 /* Going on to do enumeration (requests). */
243 if (status == UX_SUCCESS)
244 {
245
246 /* Now control endpoint is ready, set state to running. */
247 control_endpoint -> ux_endpoint_state = UX_ENDPOINT_RUNNING;
248
249 /* Set the address of the device. The first time a USB device is
250 accessed, it responds to the address 0. We need to change the address
251 to a free device address between 1 and 127 ASAP. */
252 status = _ux_host_stack_device_address_set(device);
253 if (status == UX_SUCCESS)
254 {
255
256 /* Get the device descriptor. */
257 status = _ux_host_stack_device_descriptor_read(device);
258 if (status == UX_SUCCESS)
259 {
260
261 /* Get the configuration descriptor(s) for the device
262 and parse all the configuration, interface, endpoints... */
263 status = _ux_host_stack_configuration_enumerate(device);
264 }
265 }
266 }
267
268 /* Check the status of the previous operations. If there was an
269 error during any of the phases, the device resources must be
270 freed based on if we want to retry. */
271 if (status == UX_SUCCESS)
272 {
273
274 /* The device, configuration(s), interface(s), endpoint(s) are
275 now in order for this device to work. No configuration is set
276 yet. First we need to find a class driver that wants to own
277 it. There is no need to have an orphan device in a configured state. */
278 status = _ux_host_stack_class_device_scan(device);
279 if (status == UX_NO_CLASS_MATCH)
280 {
281
282 status = _ux_host_stack_class_interface_scan(device);
283
284 }
285
286 /* Check if there is unnecessary resource to free. */
287 if (device -> ux_device_packed_configuration &&
288 device -> ux_device_packed_configuration_keep_count == 0)
289 {
290 _ux_utility_memory_free(device -> ux_device_packed_configuration);
291 device -> ux_device_packed_configuration = UX_NULL;
292 }
293
294 /* If trace is enabled, register this object. */
295 UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_DEVICE, hcd, device_owner, port_index, 0);
296 }
297 #endif
298
299 /* Return status. If there's an error, device resources that have been
300 allocated until this point should be freed by the caller via _ux_host_stack_device_resources_free. */
301 return(status);
302 }
303