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