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