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