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_interface_set                      PORTABLE C      */
36 /*                                                           6.1.12       */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function sets one alternate setting of one interface and       */
44 /*    enable all endpoints associated with this alternate setting.        */
45 /*    configuration.                                                      */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    device_framework                      Address in device framework   */
50 /*                                          for selected alternate setting*/
51 /*    device_framework_length               Length of device framework    */
52 /*    alternate_setting_value               Alternate setting             */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    Completion Status                                                   */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    (ux_slave_dcd_function)               DCD dispatch function         */
61 /*    _ux_device_stack_interface_start      Start 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 /*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            calculated payload size,    */
80 /*                                            resulting in version 6.1.9  */
81 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            fixed parameter/variable    */
83 /*                                            names conflict C++ keyword, */
84 /*                                            resulting in version 6.1.12 */
85 /*                                                                        */
86 /**************************************************************************/
_ux_device_stack_interface_set(UCHAR * device_framework,ULONG device_framework_length,ULONG alternate_setting_value)87 UINT  _ux_device_stack_interface_set(UCHAR * device_framework, ULONG device_framework_length,
88                                                     ULONG alternate_setting_value)
89 {
90 
91 UX_SLAVE_DCD            *dcd;
92 UX_SLAVE_DEVICE         *device;
93 UX_SLAVE_TRANSFER       *transfer_request;
94 UX_SLAVE_INTERFACE      *interface_ptr;
95 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
96 UX_SLAVE_INTERFACE      *interface_link;
97 ULONG                   interfaces_pool_number;
98 #endif
99 UX_SLAVE_ENDPOINT       *endpoint;
100 UX_SLAVE_ENDPOINT       *endpoint_link;
101 ULONG                   descriptor_length;
102 UCHAR                   descriptor_type;
103 ULONG                   endpoints_pool_number;
104 UINT                    status;
105 ULONG                   max_transfer_length, n_trans;
106 
107     UX_PARAMETER_NOT_USED(alternate_setting_value);
108 
109     /* If trace is enabled, insert this event into the trace buffer.  */
110     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_INTERFACE_SET, alternate_setting_value, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
111 
112     /* Get the pointer to the DCD.  */
113     dcd =  &_ux_system_slave -> ux_system_slave_dcd;
114 
115     /* Get the pointer to the device.  */
116     device =  &_ux_system_slave -> ux_system_slave_device;
117 
118     /* Find a free interface in the pool and hook it to the
119        existing interface.  */
120     interface_ptr = device -> ux_slave_device_interfaces_pool;
121 
122 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
123     interfaces_pool_number = device -> ux_slave_device_interfaces_pool_number;
124     while (interfaces_pool_number != 0)
125     {
126         /* Check if this interface is free.  */
127         if (interface_ptr -> ux_slave_interface_status == UX_UNUSED)
128             break;
129 
130         /* Try the next interface.  */
131         interface_ptr++;
132 
133         /* Decrement the number of interfaces left to scan in the pool.  */
134         interfaces_pool_number--;
135     }
136 
137     /* Did we find a free interface ?  */
138     if (interfaces_pool_number == 0)
139         return(UX_MEMORY_INSUFFICIENT);
140 #else
141 
142     /* Check if this interface is free.  */
143     if (interface_ptr -> ux_slave_interface_status != UX_UNUSED)
144         return(UX_MEMORY_INSUFFICIENT);
145 
146 #endif
147 
148     /* Mark this interface as used now.  */
149     interface_ptr -> ux_slave_interface_status = UX_USED;
150 
151     /* If trace is enabled, register this object.  */
152     UX_TRACE_OBJECT_REGISTER(UX_TRACE_DEVICE_OBJECT_TYPE_INTERFACE, interface_ptr, 0, 0, 0)
153 
154     /* Parse the descriptor in something more readable.  */
155     _ux_utility_descriptor_parse(device_framework,
156                 _ux_system_interface_descriptor_structure,
157                 UX_INTERFACE_DESCRIPTOR_ENTRIES,
158                 (UCHAR *) &interface_ptr -> ux_slave_interface_descriptor);
159 
160 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
161 
162     /* Attach this interface to the end of the interface chain.  */
163     if (device -> ux_slave_device_first_interface == UX_NULL)
164     {
165 
166         device -> ux_slave_device_first_interface =  interface_ptr;
167     }
168     else
169     {
170         /* Multiple interfaces exist, so find the end of the chain.  */
171         interface_link =  device -> ux_slave_device_first_interface;
172         while (interface_link -> ux_slave_interface_next_interface != UX_NULL)
173             interface_link =  interface_link -> ux_slave_interface_next_interface;
174         interface_link -> ux_slave_interface_next_interface =  interface_ptr;
175     }
176 #else
177 
178     /* It must be very first one.  */
179     device -> ux_slave_device_first_interface = interface_ptr;
180 #endif
181 
182     /* Point beyond the interface descriptor.  */
183     device_framework_length -=  (ULONG) *device_framework;
184     device_framework +=  (ULONG) *device_framework;
185 
186     /* Parse the device framework and locate endpoint descriptor(s).  */
187     while (device_framework_length != 0)
188     {
189 
190         /* Get the length of the current descriptor.  */
191         descriptor_length =  (ULONG) *device_framework;
192 
193         /* And its type.  */
194         descriptor_type =  *(device_framework + 1);
195 
196         /* Check if this is an endpoint descriptor.  */
197         switch(descriptor_type)
198         {
199 
200         case UX_ENDPOINT_DESCRIPTOR_ITEM:
201 
202             /* Find a free endpoint in the pool and hook it to the
203                existing interface after it's created by DCD.  */
204             endpoint = device -> ux_slave_device_endpoints_pool;
205             endpoints_pool_number = device -> ux_slave_device_endpoints_pool_number;
206             while (endpoints_pool_number != 0)
207             {
208                 /* Check if this endpoint is free.  */
209                 if (endpoint ->    ux_slave_endpoint_status == UX_UNUSED)
210                 {
211                     /* Mark this endpoint as used now.  */
212                     endpoint ->    ux_slave_endpoint_status = UX_USED;
213                     break;
214                 }
215 
216                 /* Try the next endpoint.  */
217                 endpoint++;
218 
219                 /* Decrement the number of endpoints to scan from the pool.  */
220                endpoints_pool_number--;
221             }
222 
223             /* Did we find a free endpoint ?  */
224             if (endpoints_pool_number == 0)
225                 return(UX_MEMORY_INSUFFICIENT);
226 
227             /* Parse the descriptor in something more readable.  */
228             _ux_utility_descriptor_parse(device_framework,
229                             _ux_system_endpoint_descriptor_structure,
230                             UX_ENDPOINT_DESCRIPTOR_ENTRIES,
231                             (UCHAR *) &endpoint -> ux_slave_endpoint_descriptor);
232 
233             /* Now we create a transfer request to accept transfer on this endpoint.  */
234             transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
235 
236             /* Validate endpoint descriptor wMaxPacketSize.  */
237             UX_ASSERT(endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize != 0);
238 
239             /* Calculate endpoint transfer payload max size.  */
240             max_transfer_length =
241                     endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize &
242                                                         UX_MAX_PACKET_SIZE_MASK;
243             if ((_ux_system_slave -> ux_system_slave_speed == UX_HIGH_SPEED_DEVICE) &&
244                 (endpoint -> ux_slave_endpoint_descriptor.bmAttributes & 0x1u))
245             {
246                 n_trans = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize &
247                                             UX_MAX_NUMBER_OF_TRANSACTIONS_MASK;
248                 if (n_trans)
249                 {
250                     n_trans >>= UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT;
251                     n_trans ++;
252                     max_transfer_length *= n_trans;
253                 }
254             }
255 
256             /* Validate max transfer size and save it.  */
257             UX_ASSERT(max_transfer_length <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
258             transfer_request -> ux_slave_transfer_request_transfer_length = max_transfer_length;
259 
260             /* We store the endpoint in the transfer request as well.  */
261             transfer_request -> ux_slave_transfer_request_endpoint =  endpoint;
262 
263             /* By default the timeout is infinite on request.  */
264             transfer_request -> ux_slave_transfer_request_timeout = UX_WAIT_FOREVER;
265 
266             /* Attach the interface to the endpoint.  */
267             endpoint -> ux_slave_endpoint_interface =  interface_ptr;
268 
269             /* Attach the device to the endpoint.  */
270             endpoint -> ux_slave_endpoint_device =  device;
271 
272             /* Create the endpoint at the DCD level.  */
273             status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_CREATE_ENDPOINT, (VOID *) endpoint);
274 
275             /* Do a sanity check on endpoint creation.  */
276             if (status != UX_SUCCESS)
277             {
278 
279                 /* Error was returned, endpoint cannot be created.  */
280                 endpoint -> ux_slave_endpoint_status = UX_UNUSED;
281                 return(status);
282             }
283 
284             /* Attach this endpoint to the end of the endpoint chain.  */
285             if (interface_ptr -> ux_slave_interface_first_endpoint == UX_NULL)
286             {
287 
288                 interface_ptr -> ux_slave_interface_first_endpoint =  endpoint;
289             }
290             else
291             {
292                 /* Multiple endpoints exist, so find the end of the chain.  */
293                 endpoint_link =  interface_ptr -> ux_slave_interface_first_endpoint;
294                 while (endpoint_link -> ux_slave_endpoint_next_endpoint != UX_NULL)
295                     endpoint_link =  endpoint_link -> ux_slave_endpoint_next_endpoint;
296                 endpoint_link -> ux_slave_endpoint_next_endpoint =  endpoint;
297             }
298             break;
299 
300         case UX_CONFIGURATION_DESCRIPTOR_ITEM:
301         case UX_INTERFACE_DESCRIPTOR_ITEM:
302 
303             /* If the descriptor is a configuration or interface,
304                we have parsed and mounted all endpoints.
305                The interface attached to this configuration must be started at the class level.  */
306             status =  _ux_device_stack_interface_start(interface_ptr);
307 
308             /* Return the status to the caller.  */
309             return(status);
310 
311         default:
312             break;
313         }
314 
315         /* Adjust what is left of the device framework.  */
316         device_framework_length -=  descriptor_length;
317 
318         /* Point to the next descriptor.  */
319         device_framework +=  descriptor_length;
320     }
321 
322     /* The interface attached to this configuration must be started at the class
323        level.  */
324     status =  _ux_device_stack_interface_start(interface_ptr);
325 
326     /* Return the status to the caller.  */
327     return(status);
328 }
329 
330