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