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