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_configuration_set PORTABLE C */
36 /* 6.1.12 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function sets the configuration from the host and will enable */
44 /* the default alternate setting 0 for all the interfaces attached to */
45 /* this configuration. */
46 /* */
47 /* INPUT */
48 /* */
49 /* endpoint Pointer to endpoint */
50 /* configuration_value Configuration selected */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* Completion Status */
55 /* */
56 /* CALLS */
57 /* */
58 /* (ux_slave_class_entry_function) Device class entry function */
59 /* (ux_slave_dcd_function) DCD dispatch function */
60 /* _ux_device_stack_interface_delete Delete interface */
61 /* _ux_device_stack_interface_set Set 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 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
79 /* fixed parameter/variable */
80 /* names conflict C++ keyword, */
81 /* resulting in version 6.1.12 */
82 /* */
83 /**************************************************************************/
_ux_device_stack_configuration_set(ULONG configuration_value)84 UINT _ux_device_stack_configuration_set(ULONG configuration_value)
85 {
86
87 UX_SLAVE_DCD *dcd;
88 UCHAR * device_framework;
89 ULONG device_framework_length;
90 ULONG descriptor_length;
91 UCHAR descriptor_type;
92 UX_CONFIGURATION_DESCRIPTOR configuration_descriptor = { 0 };
93 UX_INTERFACE_DESCRIPTOR interface_descriptor;
94 UX_SLAVE_INTERFACE *interface_ptr;
95 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
96 UX_SLAVE_INTERFACE *next_interface;
97 #endif
98 UX_SLAVE_CLASS *class_inst;
99 UX_SLAVE_CLASS *current_class = UX_NULL;
100 UX_SLAVE_CLASS_COMMAND class_command;
101 UX_SLAVE_DEVICE *device;
102 ULONG iad_flag;
103 ULONG iad_first_interface = 0;
104 ULONG iad_number_interfaces = 0;
105 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
106 ULONG class_index;
107 #endif
108
109
110 /* If trace is enabled, insert this event into the trace buffer. */
111 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_CONFIGURATION_SET, configuration_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 /* Reset the IAD flag. */
120 iad_flag = UX_FALSE;
121
122 /* If the configuration value is already selected, keep it. */
123 if (device -> ux_slave_device_configuration_selected == configuration_value)
124 return(UX_SUCCESS);
125
126 /* We may have multiple configurations !, the index will tell us what
127 configuration descriptor we need to return. */
128 device_framework = _ux_system_slave -> ux_system_slave_device_framework;
129 device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length;
130
131 /* Parse the device framework and locate a configuration descriptor. */
132 while (device_framework_length != 0)
133 {
134 /* Get the length of the current descriptor. */
135 descriptor_length = (ULONG) *device_framework;
136
137 /* And its type. */
138 descriptor_type = *(device_framework + 1);
139
140 /* Check if this is a configuration descriptor. */
141 if (descriptor_type == UX_CONFIGURATION_DESCRIPTOR_ITEM)
142 {
143 /* Parse the descriptor in something more readable. */
144 _ux_utility_descriptor_parse(device_framework,
145 _ux_system_configuration_descriptor_structure,
146 UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
147 (UCHAR *) &configuration_descriptor);
148
149 /* Now we need to check the configuration value. It has
150 to be the same as the one specified in the setup function. */
151 if (configuration_descriptor.bConfigurationValue == configuration_value)
152 /* The configuration is found. */
153 break;
154 }
155
156 /* Adjust what is left of the device framework. */
157 device_framework_length -= descriptor_length;
158 /* Point to the next descriptor. */
159 device_framework += descriptor_length;
160 }
161
162 /* Configuration not found. */
163 if (device_framework_length == 0 && configuration_value != 0)
164 return(UX_ERROR);
165
166 /* We unmount the configuration if there is previous configuration selected. */
167 if (device -> ux_slave_device_configuration_selected)
168 {
169
170 /* Get the pointer to the first interface. */
171 interface_ptr = device -> ux_slave_device_first_interface;
172
173 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
174 /* Deactivate all the interfaces if any. */
175 while (interface_ptr != UX_NULL)
176 {
177 #endif
178 /* Build all the fields of the Class Command. */
179 class_command.ux_slave_class_command_request = UX_SLAVE_CLASS_COMMAND_DEACTIVATE;
180 class_command.ux_slave_class_command_interface = (VOID *) interface_ptr;
181
182 /* Get the pointer to the class container of this interface. */
183 class_inst = interface_ptr -> ux_slave_interface_class;
184
185 /* Store the class container. */
186 class_command.ux_slave_class_command_class_ptr = class_inst;
187
188 /* If there is a class container for this instance, deactivate it. */
189 if (class_inst != UX_NULL)
190
191 /* Call the class with the DEACTIVATE signal. */
192 class_inst -> ux_slave_class_entry_function(&class_command);
193
194 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
195 /* Get the next interface. */
196 next_interface = interface_ptr -> ux_slave_interface_next_interface;
197 #endif
198
199 /* Remove the interface and all endpoints associated with it. */
200 _ux_device_stack_interface_delete(interface_ptr);
201
202 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
203 /* Now we refresh the interface pointer. */
204 interface_ptr = next_interface;
205 }
206 #endif
207
208 }
209
210 /* No configuration is selected. */
211 device -> ux_slave_device_configuration_selected = 0;
212
213 /* Mark the device as attached now. */
214 device -> ux_slave_device_state = UX_DEVICE_ATTACHED;
215
216 /* The DCD needs to update the device state too. */
217 dcd -> ux_slave_dcd_function(dcd, UX_DCD_CHANGE_STATE, (VOID *) UX_DEVICE_ATTACHED);
218
219 /* If the host tries to unconfigure, we are done. */
220 if (configuration_value == 0)
221 return(UX_SUCCESS);
222
223 /* Memorize the configuration selected. */
224 device -> ux_slave_device_configuration_selected = configuration_value;
225
226 /* We have found the configuration value requested by the host.
227 Create the configuration descriptor and attach it to the device. */
228 _ux_utility_descriptor_parse(device_framework,
229 _ux_system_configuration_descriptor_structure,
230 UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
231 (UCHAR *) &device -> ux_slave_device_configuration_descriptor);
232
233 /* Configuration character D6 is for Self-powered */
234 _ux_system_slave -> ux_system_slave_power_state = (configuration_descriptor.bmAttributes & 0x40) ? UX_DEVICE_SELF_POWERED : UX_DEVICE_BUS_POWERED;
235
236 /* Configuration character D5 is for Remote Wakeup */
237 _ux_system_slave -> ux_system_slave_remote_wakeup_capability = (configuration_descriptor.bmAttributes & 0x20) ? UX_TRUE : UX_FALSE;
238
239 /* Search only in current configuration */
240 device_framework_length = configuration_descriptor.wTotalLength;
241
242 /* We need to scan all the interface descriptors following this
243 configuration descriptor and enable all endpoints associated
244 with the default alternate setting of each interface. */
245 while (device_framework_length != 0)
246 {
247
248 /* Get the length of the current descriptor. */
249 descriptor_length = (ULONG) *device_framework;
250
251 /* And its type. */
252 descriptor_type = *(device_framework + 1);
253
254 /* Check if this is an interface association descriptor. */
255 if(descriptor_type == UX_INTERFACE_ASSOCIATION_DESCRIPTOR_ITEM)
256 {
257
258 /* Set the IAD flag. */
259 iad_flag = UX_TRUE;
260
261 /* Get the first interface we have in the IAD. */
262 iad_first_interface = (ULONG) *(device_framework + 2);
263
264 /* Get the number of interfaces we have in the IAD. */
265 iad_number_interfaces = (ULONG) *(device_framework + 3);
266 }
267
268 /* Check if this is an interface descriptor. */
269 if(descriptor_type == UX_INTERFACE_DESCRIPTOR_ITEM)
270 {
271
272 /* Parse the descriptor in something more readable. */
273 _ux_utility_descriptor_parse(device_framework,
274 _ux_system_interface_descriptor_structure,
275 UX_INTERFACE_DESCRIPTOR_ENTRIES,
276 (UCHAR *) &interface_descriptor);
277
278 /* If the alternate setting is 0 for this interface, we need to
279 memorize its class association and start it. */
280 if (interface_descriptor.bAlternateSetting == 0)
281 {
282
283 /* Are we in a IAD scenario ? */
284 if (iad_flag == UX_TRUE)
285 {
286
287 /* Check if this is the first interface from the IAD. In this case,
288 we need to match a class to this interface. */
289 if (interface_descriptor.bInterfaceNumber == iad_first_interface)
290 {
291
292 /* First interface. Scan the list of classes to find a match. */
293 class_inst = _ux_system_slave -> ux_system_slave_class_array;
294
295 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
296 /* Parse all the class drivers. */
297 for (class_index = 0; class_index < _ux_system_slave -> ux_system_slave_max_class; class_index++)
298 {
299 #endif
300
301 /* Check if this class driver is used. */
302 if (class_inst -> ux_slave_class_status == UX_USED)
303 {
304
305 /* Check if this is the same interface for the same configuration. */
306 if ((interface_descriptor.bInterfaceNumber == class_inst -> ux_slave_class_interface_number) &&
307 (configuration_value == class_inst -> ux_slave_class_configuration_number))
308 {
309
310 /* Memorize the class in the class/interface array. */
311 _ux_system_slave -> ux_system_slave_interface_class_array[interface_descriptor.bInterfaceNumber] = class_inst;
312
313 /* And again as the current class. */
314 current_class = class_inst;
315
316 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
317 /* We are done here. */
318 break;
319 #endif
320 }
321 }
322
323 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
324 /* Move to the next registered class. */
325 class_inst ++;
326 }
327 #endif
328 }
329 else
330
331 /* Memorize the class in the class/interface array. We use the current class. */
332 _ux_system_slave -> ux_system_slave_interface_class_array[interface_descriptor.bInterfaceNumber] = current_class;
333
334 /* Decrement the number of interfaces found in the same IAD. */
335 iad_number_interfaces--;
336
337 /* If none are left, get out of the IAD state machine. */
338 if (iad_number_interfaces == 0)
339
340 /* We have exhausted the interfaces within the IAD. */
341 iad_flag = UX_FALSE;
342
343 }
344 else
345 {
346
347 /* First interface. Scan the list of classes to find a match. */
348 class_inst = _ux_system_slave -> ux_system_slave_class_array;
349
350 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
351 /* Parse all the class drivers. */
352 for (class_index = 0; class_index < _ux_system_slave -> ux_system_slave_max_class; class_index++)
353 {
354 #endif
355
356 /* Check if this class driver is used. */
357 if (class_inst -> ux_slave_class_status == UX_USED)
358 {
359
360 /* Check if this is the same interface for the same configuration. */
361 if ((interface_descriptor.bInterfaceNumber == class_inst -> ux_slave_class_interface_number) &&
362 (configuration_value == class_inst -> ux_slave_class_configuration_number))
363 {
364
365 /* Memorize the class in the class/interface array. */
366 _ux_system_slave -> ux_system_slave_interface_class_array[interface_descriptor.bInterfaceNumber] = class_inst;
367
368 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
369 /* We are done here. */
370 break;
371 #endif
372 }
373 }
374
375 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
376 /* Move to the next registered class. */
377 class_inst ++;
378 }
379 #endif
380 }
381
382 /* Set the interface. */
383 _ux_device_stack_interface_set(device_framework, device_framework_length, 0);
384 }
385 }
386
387 /* Adjust what is left of the device framework. */
388 device_framework_length -= descriptor_length;
389
390 /* Point to the next descriptor. */
391 device_framework += descriptor_length;
392 }
393
394 /* Mark the device as configured now. */
395 device -> ux_slave_device_state = UX_DEVICE_CONFIGURED;
396
397 /* The DCD needs to update the device state too. */
398 dcd -> ux_slave_dcd_function(dcd, UX_DCD_CHANGE_STATE, (VOID *) UX_DEVICE_CONFIGURED);
399
400 /* Configuration mounted. */
401 return(UX_SUCCESS);
402 }
403
404