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 /** Device Stack */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define UX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "ux_api.h"
28 #include "ux_device_stack.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_stack_interface_set PORTABLE C */
36 /* 6.1.12 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function sets one alternate setting of one interface and */
44 /* enable all endpoints associated with this alternate setting. */
45 /* configuration. */
46 /* */
47 /* INPUT */
48 /* */
49 /* device_framework Address in device framework */
50 /* for selected alternate setting*/
51 /* device_framework_length Length of device framework */
52 /* alternate_setting_value Alternate setting */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* Completion Status */
57 /* */
58 /* CALLS */
59 /* */
60 /* (ux_slave_dcd_function) DCD dispatch function */
61 /* _ux_device_stack_interface_start Start interface */
62 /* _ux_utility_descriptor_parse Parse descriptor */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* Application */
67 /* Device Stack */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
74 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
75 /* optimized based on compile */
76 /* definitions, */
77 /* resulting in version 6.1 */
78 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
79 /* calculated payload size, */
80 /* resulting in version 6.1.9 */
81 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
82 /* fixed parameter/variable */
83 /* names conflict C++ keyword, */
84 /* resulting in version 6.1.12 */
85 /* */
86 /**************************************************************************/
_ux_device_stack_interface_set(UCHAR * device_framework,ULONG device_framework_length,ULONG alternate_setting_value)87 UINT _ux_device_stack_interface_set(UCHAR * device_framework, ULONG device_framework_length,
88 ULONG alternate_setting_value)
89 {
90
91 UX_SLAVE_DCD *dcd;
92 UX_SLAVE_DEVICE *device;
93 UX_SLAVE_TRANSFER *transfer_request;
94 UX_SLAVE_INTERFACE *interface_ptr;
95 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
96 UX_SLAVE_INTERFACE *interface_link;
97 ULONG interfaces_pool_number;
98 #endif
99 UX_SLAVE_ENDPOINT *endpoint;
100 UX_SLAVE_ENDPOINT *endpoint_link;
101 ULONG descriptor_length;
102 UCHAR descriptor_type;
103 ULONG endpoints_pool_number;
104 UINT status;
105 ULONG max_transfer_length, n_trans;
106
107 UX_PARAMETER_NOT_USED(alternate_setting_value);
108
109 /* If trace is enabled, insert this event into the trace buffer. */
110 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_INTERFACE_SET, alternate_setting_value, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
111
112 /* Get the pointer to the DCD. */
113 dcd = &_ux_system_slave -> ux_system_slave_dcd;
114
115 /* Get the pointer to the device. */
116 device = &_ux_system_slave -> ux_system_slave_device;
117
118 /* Find a free interface in the pool and hook it to the
119 existing interface. */
120 interface_ptr = device -> ux_slave_device_interfaces_pool;
121
122 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
123 interfaces_pool_number = device -> ux_slave_device_interfaces_pool_number;
124 while (interfaces_pool_number != 0)
125 {
126 /* Check if this interface is free. */
127 if (interface_ptr -> ux_slave_interface_status == UX_UNUSED)
128 break;
129
130 /* Try the next interface. */
131 interface_ptr++;
132
133 /* Decrement the number of interfaces left to scan in the pool. */
134 interfaces_pool_number--;
135 }
136
137 /* Did we find a free interface ? */
138 if (interfaces_pool_number == 0)
139 return(UX_MEMORY_INSUFFICIENT);
140 #else
141
142 /* Check if this interface is free. */
143 if (interface_ptr -> ux_slave_interface_status != UX_UNUSED)
144 return(UX_MEMORY_INSUFFICIENT);
145
146 #endif
147
148 /* Mark this interface as used now. */
149 interface_ptr -> ux_slave_interface_status = UX_USED;
150
151 /* If trace is enabled, register this object. */
152 UX_TRACE_OBJECT_REGISTER(UX_TRACE_DEVICE_OBJECT_TYPE_INTERFACE, interface_ptr, 0, 0, 0)
153
154 /* Parse the descriptor in something more readable. */
155 _ux_utility_descriptor_parse(device_framework,
156 _ux_system_interface_descriptor_structure,
157 UX_INTERFACE_DESCRIPTOR_ENTRIES,
158 (UCHAR *) &interface_ptr -> ux_slave_interface_descriptor);
159
160 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
161
162 /* Attach this interface to the end of the interface chain. */
163 if (device -> ux_slave_device_first_interface == UX_NULL)
164 {
165
166 device -> ux_slave_device_first_interface = interface_ptr;
167 }
168 else
169 {
170 /* Multiple interfaces exist, so find the end of the chain. */
171 interface_link = device -> ux_slave_device_first_interface;
172 while (interface_link -> ux_slave_interface_next_interface != UX_NULL)
173 interface_link = interface_link -> ux_slave_interface_next_interface;
174 interface_link -> ux_slave_interface_next_interface = interface_ptr;
175 }
176 #else
177
178 /* It must be very first one. */
179 device -> ux_slave_device_first_interface = interface_ptr;
180 #endif
181
182 /* Point beyond the interface descriptor. */
183 device_framework_length -= (ULONG) *device_framework;
184 device_framework += (ULONG) *device_framework;
185
186 /* Parse the device framework and locate endpoint descriptor(s). */
187 while (device_framework_length != 0)
188 {
189
190 /* Get the length of the current descriptor. */
191 descriptor_length = (ULONG) *device_framework;
192
193 /* And its type. */
194 descriptor_type = *(device_framework + 1);
195
196 /* Check if this is an endpoint descriptor. */
197 switch(descriptor_type)
198 {
199
200 case UX_ENDPOINT_DESCRIPTOR_ITEM:
201
202 /* Find a free endpoint in the pool and hook it to the
203 existing interface after it's created by DCD. */
204 endpoint = device -> ux_slave_device_endpoints_pool;
205 endpoints_pool_number = device -> ux_slave_device_endpoints_pool_number;
206 while (endpoints_pool_number != 0)
207 {
208 /* Check if this endpoint is free. */
209 if (endpoint -> ux_slave_endpoint_status == UX_UNUSED)
210 {
211 /* Mark this endpoint as used now. */
212 endpoint -> ux_slave_endpoint_status = UX_USED;
213 break;
214 }
215
216 /* Try the next endpoint. */
217 endpoint++;
218
219 /* Decrement the number of endpoints to scan from the pool. */
220 endpoints_pool_number--;
221 }
222
223 /* Did we find a free endpoint ? */
224 if (endpoints_pool_number == 0)
225 return(UX_MEMORY_INSUFFICIENT);
226
227 /* Parse the descriptor in something more readable. */
228 _ux_utility_descriptor_parse(device_framework,
229 _ux_system_endpoint_descriptor_structure,
230 UX_ENDPOINT_DESCRIPTOR_ENTRIES,
231 (UCHAR *) &endpoint -> ux_slave_endpoint_descriptor);
232
233 /* Now we create a transfer request to accept transfer on this endpoint. */
234 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
235
236 /* Validate endpoint descriptor wMaxPacketSize. */
237 UX_ASSERT(endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize != 0);
238
239 /* Calculate endpoint transfer payload max size. */
240 max_transfer_length =
241 endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize &
242 UX_MAX_PACKET_SIZE_MASK;
243 if ((_ux_system_slave -> ux_system_slave_speed == UX_HIGH_SPEED_DEVICE) &&
244 (endpoint -> ux_slave_endpoint_descriptor.bmAttributes & 0x1u))
245 {
246 n_trans = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize &
247 UX_MAX_NUMBER_OF_TRANSACTIONS_MASK;
248 if (n_trans)
249 {
250 n_trans >>= UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT;
251 n_trans ++;
252 max_transfer_length *= n_trans;
253 }
254 }
255
256 /* Validate max transfer size and save it. */
257 UX_ASSERT(max_transfer_length <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
258 transfer_request -> ux_slave_transfer_request_transfer_length = max_transfer_length;
259
260 /* We store the endpoint in the transfer request as well. */
261 transfer_request -> ux_slave_transfer_request_endpoint = endpoint;
262
263 /* By default the timeout is infinite on request. */
264 transfer_request -> ux_slave_transfer_request_timeout = UX_WAIT_FOREVER;
265
266 /* Attach the interface to the endpoint. */
267 endpoint -> ux_slave_endpoint_interface = interface_ptr;
268
269 /* Attach the device to the endpoint. */
270 endpoint -> ux_slave_endpoint_device = device;
271
272 /* Create the endpoint at the DCD level. */
273 status = dcd -> ux_slave_dcd_function(dcd, UX_DCD_CREATE_ENDPOINT, (VOID *) endpoint);
274
275 /* Do a sanity check on endpoint creation. */
276 if (status != UX_SUCCESS)
277 {
278
279 /* Error was returned, endpoint cannot be created. */
280 endpoint -> ux_slave_endpoint_status = UX_UNUSED;
281 return(status);
282 }
283
284 /* Attach this endpoint to the end of the endpoint chain. */
285 if (interface_ptr -> ux_slave_interface_first_endpoint == UX_NULL)
286 {
287
288 interface_ptr -> ux_slave_interface_first_endpoint = endpoint;
289 }
290 else
291 {
292 /* Multiple endpoints exist, so find the end of the chain. */
293 endpoint_link = interface_ptr -> ux_slave_interface_first_endpoint;
294 while (endpoint_link -> ux_slave_endpoint_next_endpoint != UX_NULL)
295 endpoint_link = endpoint_link -> ux_slave_endpoint_next_endpoint;
296 endpoint_link -> ux_slave_endpoint_next_endpoint = endpoint;
297 }
298 break;
299
300 case UX_CONFIGURATION_DESCRIPTOR_ITEM:
301 case UX_INTERFACE_DESCRIPTOR_ITEM:
302
303 /* If the descriptor is a configuration or interface,
304 we have parsed and mounted all endpoints.
305 The interface attached to this configuration must be started at the class level. */
306 status = _ux_device_stack_interface_start(interface_ptr);
307
308 /* Return the status to the caller. */
309 return(status);
310
311 default:
312 break;
313 }
314
315 /* Adjust what is left of the device framework. */
316 device_framework_length -= descriptor_length;
317
318 /* Point to the next descriptor. */
319 device_framework += descriptor_length;
320 }
321
322 /* The interface attached to this configuration must be started at the class
323 level. */
324 status = _ux_device_stack_interface_start(interface_ptr);
325
326 /* Return the status to the caller. */
327 return(status);
328 }
329
330