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