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_device_address_set                   PORTABLE C      */
36 /*                                                           6.1.10       */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function sets the device address to the new device.            */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    device                                Pointer to device             */
48 /*                                                                        */
49 /*  OUTPUT                                                                */
50 /*                                                                        */
51 /*    Completion Status                                                   */
52 /*                                                                        */
53 /*  CALLS                                                                 */
54 /*                                                                        */
55 /*    _ux_utility_delay_ms                  Thread sleep                  */
56 /*    _ux_host_stack_transfer_request       Process transfer request      */
57 /*                                                                        */
58 /*  CALLED BY                                                             */
59 /*                                                                        */
60 /*    USBX Components                                                     */
61 /*                                                                        */
62 /*  RELEASE HISTORY                                                       */
63 /*                                                                        */
64 /*    DATE              NAME                      DESCRIPTION             */
65 /*                                                                        */
66 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
67 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
68 /*                                            optimized based on compile  */
69 /*                                            definitions,                */
70 /*                                            resulting in version 6.1    */
71 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
72 /*                                            added standalone support,   */
73 /*                                            resulting in version 6.1.10 */
74 /*                                                                        */
75 /**************************************************************************/
_ux_host_stack_device_address_set(UX_DEVICE * device)76 UINT  _ux_host_stack_device_address_set(UX_DEVICE *device)
77 {
78 
79 
80 UINT            status = UX_ERROR;
81 UX_TRANSFER     *transfer_request;
82 UX_ENDPOINT     *control_endpoint;
83 USHORT          device_address;
84 #if UX_MAX_DEVICES > 1
85 UX_HCD          *hcd;
86 UINT            address_byte_index;
87 UINT            address_bit_index;
88 UCHAR           device_address_byte;
89 #endif
90 
91     /* Retrieve the pointer to the control endpoint.  */
92     control_endpoint =  &device -> ux_device_control_endpoint;
93 
94     /* Retrieve the transfer request pointer.  */
95     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
96 
97     /* Initialize device address to 1.  */
98     device_address =  1;
99 
100 #if UX_MAX_DEVICES > 1
101 
102     /* We need the HCD pointer as well.  */
103     hcd = UX_DEVICE_HCD_GET(device);
104 
105     /* Calculate the new address of this device. We start with address 1.  */
106     for (address_byte_index = 0; address_byte_index < 16; address_byte_index++)
107     {
108 
109         /* Get the address mask byte.  */
110         device_address_byte =  hcd -> ux_hcd_address[address_byte_index];
111 
112         /* Scan each bit for an empty spot.  */
113         for (address_bit_index = 0; address_bit_index < 8; address_bit_index++)
114         {
115 
116             if ((device_address_byte & (1 << address_bit_index)) == 0)
117             {
118 
119                 /* We have found an empty spot. Reserve this address.  */
120                 device_address_byte = (UCHAR)((UCHAR)device_address_byte | (UCHAR)(1 << address_bit_index));
121 
122                 /* Store the address mask byte.  */
123                 hcd -> ux_hcd_address[address_byte_index] =  device_address_byte;
124 
125                 /* OK, apply address.  */
126                 status = UX_SUCCESS;
127                 break;
128             }
129 
130             /* This address was already taken, increment to the next address.  */
131             device_address++;
132         }
133 
134         /* If address found, break the loop.  */
135         if (status == UX_SUCCESS)
136         {
137             break;
138         }
139     }
140     if (status == UX_ERROR)
141 
142         /* We should never get here!  */
143         return(UX_ERROR);
144 #endif
145 
146     /* If trace is enabled, insert this event into the trace buffer.  */
147     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_DEVICE_ADDRESS_SET, device, device_address, 0, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
148 
149     /* Create a transfer request for the SET_ADDRESS request.  */
150     transfer_request -> ux_transfer_request_data_pointer =      UX_NULL;
151     transfer_request -> ux_transfer_request_requested_length =  0;
152     transfer_request -> ux_transfer_request_function =          UX_SET_ADDRESS;
153     transfer_request -> ux_transfer_request_type =              UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
154     transfer_request -> ux_transfer_request_value =             device_address;
155     transfer_request -> ux_transfer_request_index =             0;
156 
157 #if defined(UX_HOST_STANDALONE)
158     device -> ux_device_enum_trans = transfer_request;
159     status = UX_SUCCESS;
160     return(status);
161 #else
162 
163     /* Send request to HCD layer.  */
164     status =  _ux_host_stack_transfer_request(transfer_request);
165 
166     /* Now, this address will be the one used in future transfers.  The transfer may have failed and therefore
167         all the device resources including the new address will be free.*/
168     device -> ux_device_address =  (ULONG) device_address;
169 
170     /* Check completion status.  */
171     if (status == UX_SUCCESS)
172     {
173 
174         /* Mark the device as ADDRESSED now.  */
175         device -> ux_device_state = UX_DEVICE_ADDRESSED;
176 
177         /* Some devices need some time to accept this address.  */
178         _ux_utility_delay_ms(UX_DEVICE_ADDRESS_SET_WAIT);
179 
180         /* Return successful status.  */
181         return(status);
182     }
183     else
184     {
185 
186         /* We have an error at the first device transaction. This is mostly
187             due to the device having failed on the reset after power up.
188             we will try again either at the root hub or regular hub. */
189         return(status);
190     }
191 #endif
192 }
193