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