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