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_alternate_setting_set              PORTABLE C      */
37 /*                                                           6.1.12       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function sets the alternate setting for a specific interface.  */
45 /*    The previous interface is unmounted and all the endpoints           */
46 /*    associated with the alternate setting are mounted.                  */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    endpoint                              Pointer to endpoint           */
51 /*    interface_value                       Interface value               */
52 /*    alternate_setting_value               Alternate setting value       */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    Completion Status                                                   */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    (ux_slave_dcd_function)               DCD dispatch function         */
61 /*    _ux_utility_descriptor_parse          Parse descriptor              */
62 /*    _ux_device_stack_transfer_all_request_abort                         */
63 /*                                          Abort transfer                */
64 /*    _ux_utility_memory_copy               Copy memory                   */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    Application                                                         */
69 /*    Device Stack                                                        */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
76 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            optimized based on compile  */
78 /*                                            definitions, verified       */
79 /*                                            memset and memcpy cases,    */
80 /*                                            resulting in version 6.1    */
81 /*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            calculated payload size,    */
83 /*                                            resulting in version 6.1.9  */
84 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            fixed parameter/variable    */
86 /*                                            names conflict C++ keyword, */
87 /*                                            resulting in version 6.1.12 */
88 /*                                                                        */
89 /**************************************************************************/
_ux_device_stack_alternate_setting_set(ULONG interface_value,ULONG alternate_setting_value)90 UINT  _ux_device_stack_alternate_setting_set(ULONG interface_value, ULONG alternate_setting_value)
91 {
92 
93 UX_SLAVE_DEVICE                 *device;
94 UX_SLAVE_INTERFACE              *interface_ptr;
95 #if !defined(UX_DEVICE_ALTERNATE_SETTING_SUPPORT_DISABLE)
96 UX_SLAVE_DCD                    *dcd;
97 UX_SLAVE_TRANSFER               *transfer_request;
98 UCHAR                           *device_framework;
99 ULONG                           device_framework_length;
100 ULONG                           descriptor_length;
101 UCHAR                           descriptor_type;
102 UX_CONFIGURATION_DESCRIPTOR     configuration_descriptor;
103 UX_INTERFACE_DESCRIPTOR         interface_descriptor;
104 UX_SLAVE_ENDPOINT               *endpoint;
105 UX_SLAVE_ENDPOINT               *next_endpoint;
106 UX_SLAVE_ENDPOINT               *endpoint_link;
107 ULONG                            endpoints_pool_number;
108 UX_SLAVE_CLASS_COMMAND          class_command;
109 UX_SLAVE_CLASS                  *class_ptr;
110 UINT                            status;
111 ULONG                           max_transfer_length, n_trans;
112 #endif
113 
114     /* If trace is enabled, insert this event into the trace buffer.  */
115     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_ALTERNATE_SETTING_SET, interface_value, alternate_setting_value, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
116 
117     /* Get the pointer to the device. */
118     device =  &_ux_system_slave -> ux_system_slave_device;
119 
120     /* Protocol error must be reported when it's unconfigured */
121     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
122         return(UX_FUNCTION_NOT_SUPPORTED);
123 
124     /* Find the current interface.  */
125     interface_ptr =  device -> ux_slave_device_first_interface;
126 
127 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
128     /* Scan all interfaces if any. */
129     while (interface_ptr != UX_NULL)
130     {
131 
132         if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceNumber == interface_value)
133             break;
134         else
135             interface_ptr =  interface_ptr -> ux_slave_interface_next_interface;
136     }
137 #else
138     if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceNumber != interface_value)
139         interface_ptr = UX_NULL;
140 #endif
141 
142     /* We must have found the interface pointer for the interface value
143        requested by the caller.  */
144     if (interface_ptr == UX_NULL)
145     {
146 
147         /* Error trap. */
148         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_INTERFACE_HANDLE_UNKNOWN);
149 
150         /* If trace is enabled, insert this event into the trace buffer.  */
151         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_INTERFACE_HANDLE_UNKNOWN, interface_ptr, 0, 0, UX_TRACE_ERRORS, 0, 0)
152 
153         return(UX_INTERFACE_HANDLE_UNKNOWN);
154     }
155 
156     /* If the host is requesting a change of alternate setting to the current one,
157        we do not need to do any work.  */
158     if (interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting == alternate_setting_value)
159         return(UX_SUCCESS);
160 
161 #if defined(UX_DEVICE_ALTERNATE_SETTING_SUPPORT_DISABLE)
162 
163     /* If alternate setting is disabled, do error trap.  */
164     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
165 
166     /* If trace is enabled, insert this event into the trace buffer.  */
167     UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, interface_ptr, 0, 0, UX_TRACE_ERRORS, 0, 0)
168 
169     return(UX_FUNCTION_NOT_SUPPORTED);
170 #else
171 
172     /* Get the pointer to the DCD. */
173     dcd =  &_ux_system_slave->ux_system_slave_dcd;
174 
175     /* We may have multiple configurations!  */
176     device_framework =  _ux_system_slave -> ux_system_slave_device_framework;
177     device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length;
178 
179     /* Parse the device framework and locate a configuration descriptor. */
180     while (device_framework_length != 0)
181     {
182 
183         /* Get the length of the current descriptor.  */
184         descriptor_length =  (ULONG) *device_framework;
185 
186         /* And its length.  */
187         descriptor_type =*  (device_framework + 1);
188 
189         /* Check if this is a configuration descriptor. */
190         if (descriptor_type == UX_CONFIGURATION_DESCRIPTOR_ITEM)
191         {
192 
193             /* Parse the descriptor in something more readable. */
194             _ux_utility_descriptor_parse(device_framework,
195                         _ux_system_configuration_descriptor_structure,
196                         UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
197                         (UCHAR *) &configuration_descriptor);
198 
199             /* Now we need to check the configuration value.  */
200             if (configuration_descriptor.bConfigurationValue == device -> ux_slave_device_configuration_selected)
201             {
202 
203                 /* Limit the search in current configuration descriptor. */
204                 device_framework_length = configuration_descriptor.wTotalLength;
205 
206                 /* We have found the configuration value that was selected by the host
207                    We need to scan all the interface descriptors following this
208                    configuration descriptor and locate the interface for which the alternate
209                    setting must be changed. */
210                 while (device_framework_length != 0)
211                 {
212 
213                     /* Get the length of the current descriptor.  */
214                     descriptor_length =  (ULONG) *device_framework;
215 
216                     /* And its type.  */
217                     descriptor_type = *(device_framework + 1);
218 
219                     /* Check if this is an interface descriptor. */
220                     if (descriptor_type == UX_INTERFACE_DESCRIPTOR_ITEM)
221                     {
222 
223                         /* Parse the descriptor in something more readable. */
224                         _ux_utility_descriptor_parse(device_framework,
225                                     _ux_system_interface_descriptor_structure,
226                                     UX_INTERFACE_DESCRIPTOR_ENTRIES,
227                                     (UCHAR *) &interface_descriptor);
228 
229                         /* Check if this is the interface we are searching. */
230                         if (interface_descriptor.bInterfaceNumber == interface_value &&
231                             interface_descriptor.bAlternateSetting == alternate_setting_value)
232                         {
233 
234                             /* We have found the right interface and alternate setting. Before
235                                we mount all the endpoints for this interface, we need to
236                                unmount the endpoints associated with the previous alternate setting.  */
237                             endpoint =  interface_ptr -> ux_slave_interface_first_endpoint;
238                             while (endpoint != UX_NULL)
239                             {
240 
241                                 /* Abort any pending transfer.  */
242                                 _ux_device_stack_transfer_all_request_abort(endpoint, UX_TRANSFER_BUS_RESET);
243 
244                                 /* The device controller must be called to destroy the endpoint.  */
245                                 dcd -> ux_slave_dcd_function(dcd, UX_DCD_DESTROY_ENDPOINT, (VOID *) endpoint);
246 
247                                 /* Get the next endpoint.  */
248                                 next_endpoint =  endpoint -> ux_slave_endpoint_next_endpoint;
249 
250                                 /* Free the endpoint.  */
251                                 endpoint -> ux_slave_endpoint_status =  UX_UNUSED;
252 
253                                 /* Make sure the endpoint instance is now cleaned up.  */
254                                 endpoint -> ux_slave_endpoint_state =  0;
255                                 endpoint -> ux_slave_endpoint_next_endpoint =  UX_NULL;
256                                 endpoint -> ux_slave_endpoint_interface =  UX_NULL;
257                                 endpoint -> ux_slave_endpoint_device =  UX_NULL;
258 
259                                 /* Now we refresh the endpoint pointer.  */
260                                 endpoint =  next_endpoint;
261                             }
262 
263                             /* Now clear the interface endpoint entry.  */
264                             interface_ptr -> ux_slave_interface_first_endpoint = UX_NULL;
265 
266                             /* Point beyond the interface descriptor.  */
267                             device_framework_length -=  (ULONG) *device_framework;
268                             device_framework +=  (ULONG) *device_framework;
269 
270                             /* Parse the device framework and locate endpoint descriptor(s).  */
271                             while (device_framework_length != 0)
272                             {
273 
274                                 /* Get the length of the current descriptor.  */
275                                 descriptor_length =  (ULONG) *device_framework;
276 
277                                 /* And its type.  */
278                                 descriptor_type =  *(device_framework + 1);
279 
280                                 /* Check if this is an endpoint descriptor.  */
281                                 switch(descriptor_type)
282                                 {
283 
284                                 case UX_ENDPOINT_DESCRIPTOR_ITEM:
285 
286                                     /* Find a free endpoint in the pool and hook it to the
287                                        existing interface after it's created by DCD.  */
288                                     endpoint = device -> ux_slave_device_endpoints_pool;
289                                     endpoints_pool_number = device -> ux_slave_device_endpoints_pool_number;
290                                     while (endpoints_pool_number != 0)
291                                     {
292                                         /* Check if this endpoint is free.  */
293                                         if (endpoint ->    ux_slave_endpoint_status == UX_UNUSED)
294                                         {
295                                             /* Mark this endpoint as used now.  */
296                                             endpoint ->    ux_slave_endpoint_status = UX_USED;
297                                             break;
298                                         }
299 
300                                         /* Try the next endpoint.  */
301                                         endpoint++;
302 
303                                         /* Decrement the number of endpoints to scan from the pool.  */
304                                        endpoints_pool_number--;
305                                     }
306 
307                                     /* Did we find a free endpoint ?  */
308                                     if (endpoints_pool_number == 0)
309                                         return(UX_MEMORY_INSUFFICIENT);
310 
311                                     /* Parse the descriptor in something more readable.  */
312                                     _ux_utility_descriptor_parse(device_framework,
313                                                     _ux_system_endpoint_descriptor_structure,
314                                                     UX_ENDPOINT_DESCRIPTOR_ENTRIES,
315                                                     (UCHAR *) &endpoint -> ux_slave_endpoint_descriptor);
316 
317                                     /* Now we create a transfer request to accept transfer on this endpoint.  */
318                                     transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
319 
320                                     /* Validate descriptor wMaxPacketSize.  */
321                                     UX_ASSERT(endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize != 0);
322 
323                                     /* Calculate endpoint transfer payload max size.  */
324                                     max_transfer_length =
325                                             endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize &
326                                                                                 UX_MAX_PACKET_SIZE_MASK;
327                                     if ((_ux_system_slave -> ux_system_slave_speed == UX_HIGH_SPEED_DEVICE) &&
328                                         (endpoint -> ux_slave_endpoint_descriptor.bmAttributes & 0x1u))
329                                     {
330                                         n_trans = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize &
331                                                                     UX_MAX_NUMBER_OF_TRANSACTIONS_MASK;
332                                         if (n_trans)
333                                         {
334                                             n_trans >>= UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT;
335                                             n_trans ++;
336                                             max_transfer_length *= n_trans;
337                                         }
338                                     }
339 
340                                     /* Validate max transfer size and save it.  */
341                                     UX_ASSERT(max_transfer_length <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
342                                     transfer_request -> ux_slave_transfer_request_transfer_length = max_transfer_length;
343 
344                                     /* We store the endpoint in the transfer request as well.  */
345                                     transfer_request -> ux_slave_transfer_request_endpoint =  endpoint;
346 
347                                     /* By default the timeout is infinite on request.  */
348                                     transfer_request -> ux_slave_transfer_request_timeout = UX_WAIT_FOREVER;
349 
350                                     /* Attach the interface to the endpoint.  */
351                                     endpoint -> ux_slave_endpoint_interface =  interface_ptr;
352 
353                                     /* Attach the device to the endpoint.  */
354                                     endpoint -> ux_slave_endpoint_device =  device;
355 
356                                     /* Create the endpoint at the DCD level.  */
357                                     status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_CREATE_ENDPOINT, (VOID *) endpoint);
358 
359                                     /* Do a sanity check on endpoint creation.  */
360                                     if (status != UX_SUCCESS)
361                                     {
362 
363                                         /* Error was returned, endpoint cannot be created.  */
364                                         endpoint -> ux_slave_endpoint_status = UX_UNUSED;
365                                         return(status);
366                                     }
367 
368                                     /* Attach this endpoint to the end of the endpoint chain.  */
369                                     if (interface_ptr -> ux_slave_interface_first_endpoint == UX_NULL)
370                                     {
371 
372                                         interface_ptr -> ux_slave_interface_first_endpoint =  endpoint;
373                                     }
374                                     else
375                                     {
376                                         /* Multiple endpoints exist, so find the end of the chain.  */
377                                         endpoint_link =  interface_ptr -> ux_slave_interface_first_endpoint;
378                                         while (endpoint_link -> ux_slave_endpoint_next_endpoint != UX_NULL)
379                                             endpoint_link =  endpoint_link -> ux_slave_endpoint_next_endpoint;
380                                         endpoint_link -> ux_slave_endpoint_next_endpoint =  endpoint;
381                                     }
382 
383                                     break;
384 
385                                 case UX_CONFIGURATION_DESCRIPTOR_ITEM:
386                                 case UX_INTERFACE_DESCRIPTOR_ITEM:
387 
388                                     /* We have found a new configuration or interface descriptor, this is the end of the current
389                                        interface. The search for the endpoints must be terminated as if it was the end of the
390                                        entire descriptor.  */
391                                     device_framework_length =  descriptor_length;
392 
393                                     break;
394 
395 
396                                 default:
397 
398                                     /* We have found another descriptor embedded in the interface. Ignore it.  */
399                                     break;
400                                 }
401 
402                                 /* Adjust what is left of the device framework.  */
403                                 device_framework_length -=  descriptor_length;
404 
405                                 /* Point to the next descriptor.  */
406                                 device_framework +=  descriptor_length;
407                             }
408 
409                             /* The interface descriptor in the current class must be changed to the new alternate setting.  */
410                             _ux_utility_memory_copy(&interface_ptr -> ux_slave_interface_descriptor, &interface_descriptor, sizeof(UX_INTERFACE_DESCRIPTOR)); /* Use case of memcpy is verified. */
411 
412                             /* Get the class for the interface.  */
413                             class_ptr =  _ux_system_slave -> ux_system_slave_interface_class_array[interface_ptr -> ux_slave_interface_descriptor.bInterfaceNumber];
414 
415                             /* Check if class driver is available. */
416                             if (class_ptr == UX_NULL || class_ptr -> ux_slave_class_status == UX_UNUSED)
417                             {
418 
419                                 return (UX_NO_CLASS_MATCH);
420                             }
421 
422                             /* The interface attached to this configuration must be changed at the class
423                                level.  */
424                             class_command.ux_slave_class_command_request   =    UX_SLAVE_CLASS_COMMAND_CHANGE;
425                             class_command.ux_slave_class_command_interface =   (VOID *) interface_ptr;
426 
427                             /* And store it.  */
428                             class_command.ux_slave_class_command_class_ptr =  class_ptr;
429 
430                             /* We can now memorize the interface pointer associated with this class.  */
431                             class_ptr -> ux_slave_class_interface = interface_ptr;
432 
433                             /* We have found a potential candidate. Call this registered class entry function to change the alternate setting.  */
434                             status = class_ptr -> ux_slave_class_entry_function(&class_command);
435 
436                             /* We are done here.  */
437                             return(status);
438                         }
439                     }
440 
441                     /* Adjust what is left of the device framework.  */
442                     device_framework_length -=  descriptor_length;
443 
444                     /* Point to the next descriptor.  */
445                     device_framework +=  descriptor_length;
446                 }
447 
448                 /* In case alter setting not found, report protocol error. */
449                 break;
450             }
451         }
452 
453         /* Adjust what is left of the device framework.  */
454         device_framework_length -=  descriptor_length;
455 
456         /* Point to the next descriptor.  */
457         device_framework +=  descriptor_length;
458     }
459 
460     /* Return error completion.  */
461     return(UX_ERROR);
462 #endif
463 }
464 
465