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 #if (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_DESCRIPTOR_LENGTH) || \
33     (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH) || \
34     (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_OTG_DESCRIPTOR_LENGTH)
35 #error UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH too small, please check
36 #endif
37 
38 /**************************************************************************/
39 /*                                                                        */
40 /*  FUNCTION                                               RELEASE        */
41 /*                                                                        */
42 /*    _ux_device_stack_descriptor_send                    PORTABLE C      */
43 /*                                                           6.1.11       */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    Chaoqiong Xiao, Microsoft Corporation                               */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*    This function sends back the device descriptor required by the host.*/
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    descriptor_type                       Descriptor type               */
55 /*    descriptor_index                      Index of descriptor           */
56 /*    host_length                           Length requested by host      */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    Completion Status                                                   */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    (ux_slave_dcd_function)               DCD dispatch function         */
65 /*    _ux_device_stack_transfer_request     Process transfer request      */
66 /*    _ux_utility_descriptor_parse          Parse descriptor              */
67 /*    _ux_utility_memory_copy               Memory copy                   */
68 /*    _ux_utility_short_get                 Get short value               */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    Application                                                         */
73 /*    Device Stack                                                        */
74 /*                                                                        */
75 /*  RELEASE HISTORY                                                       */
76 /*                                                                        */
77 /*    DATE              NAME                      DESCRIPTION             */
78 /*                                                                        */
79 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
80 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            optimized descriptor search */
82 /*                                            logic, verified memset and  */
83 /*                                            memcpy cases,               */
84 /*                                            resulting in version 6.1    */
85 /*  12-31-2020     Chaoqiong Xiao           Modified comment(s),          */
86 /*                                            added BOS support,          */
87 /*                                            resulting in version 6.1.3  */
88 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            internal clean up,          */
90 /*                                            resulting in version 6.1.11 */
91 /*                                                                        */
92 /**************************************************************************/
_ux_device_stack_descriptor_send(ULONG descriptor_type,ULONG request_index,ULONG host_length)93 UINT  _ux_device_stack_descriptor_send(ULONG descriptor_type, ULONG request_index, ULONG host_length)
94 {
95 
96 UX_SLAVE_DCD                    *dcd;
97 UX_SLAVE_DEVICE                 *device;
98 ULONG                           descriptor_index;
99 ULONG                           parsed_descriptor_index;
100 UX_SLAVE_TRANSFER               *transfer_request;
101 UX_CONFIGURATION_DESCRIPTOR     configuration_descriptor;
102 #ifndef UX_BOS_SUPPORT_DISABLE
103 UX_BOS_DESCRIPTOR               bos_descriptor;
104 #endif
105 UX_SLAVE_ENDPOINT               *endpoint;
106 UCHAR                           *device_framework;
107 UCHAR                           *device_framework_end;
108 ULONG                           device_framework_length;
109 ULONG                           descriptor_length;
110 ULONG                           target_descriptor_length = 0;
111 UINT                            status =  UX_ERROR;
112 ULONG                           length;
113 UCHAR                           *string_memory;
114 UCHAR                           *string_framework;
115 ULONG                           string_framework_length;
116 ULONG                           string_length;
117 
118     /* If trace is enabled, insert this event into the trace buffer.  */
119     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_DESCRIPTOR_SEND, descriptor_type, request_index, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
120 
121     /* Get the pointer to the DCD.  */
122     dcd =  &_ux_system_slave -> ux_system_slave_dcd;
123 
124     /* Get the pointer to the device.  */
125     device =  &_ux_system_slave -> ux_system_slave_device;
126 
127     /* Get the control endpoint associated with the device.  */
128     endpoint =  &device -> ux_slave_device_control_endpoint;
129 
130     /* Get the pointer to the transfer request associated with the endpoint.  */
131     transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
132 
133     /* Set the direction to OUT.  */
134     transfer_request -> ux_slave_transfer_request_phase =  UX_TRANSFER_PHASE_DATA_OUT;
135 
136     /* Isolate the descriptor index.  */
137     descriptor_index =  descriptor_type & 0xff;
138 
139     /* Reset the parsed index.  */
140     parsed_descriptor_index =  0;
141 
142     /* Shift the descriptor type in the low byte field.  */
143     descriptor_type =  (UCHAR) ((descriptor_type >> 8) & 0xff);
144 
145     /* Default descriptor length is host length.  */
146     length =  host_length;
147 
148     /* What type of descriptor do we need to return?  */
149     switch (descriptor_type)
150     {
151 
152     case UX_DEVICE_DESCRIPTOR_ITEM:
153 
154 		/* Setup device descriptor length.  */
155         if (host_length > UX_DEVICE_DESCRIPTOR_LENGTH)
156             length =  UX_DEVICE_DESCRIPTOR_LENGTH;
157 
158         /* Fall through.  */
159     case UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM:
160 
161         /* Setup qualifier descriptor length.  */
162         if (descriptor_type == UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM &&
163             host_length > UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH)
164             length =  UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH;
165 
166         /* Fall through.  */
167     case UX_OTG_DESCRIPTOR_ITEM:
168 
169         /* Setup OTG descriptor length.  */
170         if (descriptor_type == UX_OTG_DESCRIPTOR_ITEM &&
171             host_length > UX_OTG_DESCRIPTOR_LENGTH)
172             length =  UX_OTG_DESCRIPTOR_LENGTH;
173 
174         /* We may or may not have a device qualifier descriptor.  */
175         device_framework =  _ux_system_slave -> ux_system_slave_device_framework;
176         device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length;
177         device_framework_end = device_framework + device_framework_length;
178 
179         /* Parse the device framework and locate a device qualifier descriptor.  */
180         while (device_framework < device_framework_end)
181         {
182 
183             /* Get descriptor length.  */
184             descriptor_length =  (ULONG) *device_framework;
185 
186             /* Check if this is a descriptor expected.  */
187             if (*(device_framework + 1) == descriptor_type)
188             {
189 
190                 /* Copy the device descriptor into the transfer request memory.  */
191                 _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
192                                                 device_framework, length); /* Use case of memcpy is verified. */
193 
194                 /* Perform the data transfer.  */
195                 status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
196                 break;
197             }
198 
199             /* Adjust what is left of the device framework.  */
200             device_framework_length -=  descriptor_length;
201 
202             /* Point to the next descriptor.  */
203             device_framework +=  descriptor_length;
204         }
205         break;
206 
207 #ifndef UX_BOS_SUPPORT_DISABLE
208     case UX_BOS_DESCRIPTOR_ITEM:
209         /* Fall through.  */
210 #endif
211     case UX_OTHER_SPEED_DESCRIPTOR_ITEM:
212         /* Fall through.  */
213     case UX_CONFIGURATION_DESCRIPTOR_ITEM:
214 
215         if (descriptor_type == UX_OTHER_SPEED_DESCRIPTOR_ITEM)
216         {
217 
218             /* This request is used by the host to find out the capability of this device
219             if it was running at full speed. The behavior is the same as in a GET_CONFIGURATIOn descriptor
220             but we do not use the current device framework but rather the full speed framework. */
221             device_framework =  _ux_system_slave -> ux_system_slave_device_framework_full_speed;
222             device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length_full_speed;
223             device_framework_end = device_framework + device_framework_length;
224         }
225         else
226         {
227 
228             /* We may have multiple configurations !, the index will tell us what
229             configuration descriptor we need to return.  */
230             device_framework =  _ux_system_slave -> ux_system_slave_device_framework;
231             device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length;
232             device_framework_end = device_framework + device_framework_length;
233         }
234 
235         /* Parse the device framework and locate a configuration descriptor.  */
236         while (device_framework < device_framework_end)
237         {
238 
239             /* Get descriptor length. */
240             descriptor_length =  (ULONG) *device_framework;
241 
242 #ifndef UX_BOS_SUPPORT_DISABLE
243 
244             /* Check if we are finding BOS descriptor.  */
245             if (descriptor_type == UX_BOS_DESCRIPTOR_ITEM)
246             {
247                 if (*(device_framework + 1) == UX_BOS_DESCRIPTOR_ITEM)
248                 {
249 
250                     /* Parse the BOS descriptor.  */
251                     _ux_utility_descriptor_parse(device_framework,
252                                 _ux_system_bos_descriptor_structure,
253                                 UX_BOS_DESCRIPTOR_ENTRIES,
254                                 (UCHAR *) &bos_descriptor);
255 
256                     /* Get the length of entire BOS descriptor.  */
257                     target_descriptor_length = bos_descriptor.wTotalLength;
258 
259                     /* Descriptor is found.  */
260                     status = UX_SUCCESS;
261                     break;
262                 }
263             }
264             else
265 #endif
266 
267             {
268 
269                 /* Check if this is a configuration descriptor.  We are cheating here. Instead of creating
270                 a OTHER SPEED descriptor, we simply scan the configuration descriptor for the Full Speed
271                 framework and return this configuration after we manually changed the configuration descriptor
272                 item into a Other Speed Descriptor. */
273                 if (*(device_framework + 1) == UX_CONFIGURATION_DESCRIPTOR_ITEM)
274                 {
275 
276                     /* Check the index. It must be the same as the one requested.  */
277                     if (parsed_descriptor_index == descriptor_index)
278                     {
279 
280                         /* Parse the configuration descriptor. */
281                         _ux_utility_descriptor_parse(device_framework,
282                                     _ux_system_configuration_descriptor_structure,
283                                     UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
284                                     (UCHAR *) &configuration_descriptor);
285 
286                         /* Get the length of entire configuration descriptor.  */
287                         target_descriptor_length = configuration_descriptor.wTotalLength;
288 
289                         /* Descriptor is found.  */
290                         status = UX_SUCCESS;
291                         break;
292                     }
293                     else
294                     {
295 
296                         /* There may be more configuration descriptors in this framework.  */
297                         parsed_descriptor_index++;
298                     }
299                 }
300             }
301 
302             /* Adjust what is left of the device framework.  */
303             device_framework_length -=  descriptor_length;
304 
305             /* Point to the next descriptor.  */
306             device_framework +=  descriptor_length;
307         }
308 
309         /* Send the descriptor.  */
310         if (status == UX_SUCCESS)
311         {
312 
313             /* Ensure the host does not demand a length beyond our descriptor (Windows does that)
314                 and do not return more than what is allowed.  */
315             if (target_descriptor_length < host_length)
316                 length =  target_descriptor_length;
317             else
318                 length =  host_length;
319 
320             /* Check buffer length, since total descriptors length may exceed buffer...  */
321             if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
322             {
323                 /* Error trap. */
324                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
325 
326                 /* If trace is enabled, insert this event into the trace buffer.  */
327                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
328 
329                 /* Stall the endpoint.  */
330                 status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
331                 break;
332             }
333 
334             /* Copy the device descriptor into the transfer request memory.  */
335             _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
336                                 device_framework, length); /* Use case of memcpy is verified. */
337 
338             /* Now we need to hack the found descriptor because this request expect a requested
339                 descriptor type instead of the regular descriptor.  */
340             *(transfer_request -> ux_slave_transfer_request_data_pointer + 1) = (UCHAR)descriptor_type;
341 
342             /* We can return the configuration descriptor.  */
343             status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
344         }
345         break;
346 
347     case UX_STRING_DESCRIPTOR_ITEM:
348 
349         /* We need to filter for the index 0 which is the language ID string.  */
350         if (descriptor_index == 0)
351         {
352 
353             /* We need to check request buffer size in case it's possible exceed. */
354             if (_ux_system_slave -> ux_system_slave_language_id_framework_length + 2 > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
355             {
356 
357                 /* Error trap. */
358                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
359 
360                 /* If trace is enabled, insert this event into the trace buffer.  */
361                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
362 
363                 /* Stall the endpoint.  */
364                 status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
365                 break;
366             }
367 
368             /* We have a request to send back the language ID list. Use the transfer request buffer.  */
369             string_memory =  transfer_request -> ux_slave_transfer_request_data_pointer;
370 
371             /* Store the total length of the response.  */
372             *string_memory =  (UCHAR)(_ux_system_slave -> ux_system_slave_language_id_framework_length + 2);
373 
374             /* Store the descriptor type.  */
375             *(string_memory +1) =  UX_STRING_DESCRIPTOR_ITEM;
376 
377             /* Store the language ID into the buffer.  */
378             _ux_utility_memory_copy(string_memory+2, _ux_system_slave -> ux_system_slave_language_id_framework,
379                                                         _ux_system_slave -> ux_system_slave_language_id_framework_length); /* Use case of memcpy is verified. */
380 
381             /* Filter the length asked/required.  */
382             if (host_length > _ux_system_slave -> ux_system_slave_language_id_framework_length + 2)
383                 length =  _ux_system_slave -> ux_system_slave_language_id_framework_length + 2;
384             else
385                 length =  host_length;
386 
387             /* We can return the string language ID descriptor.  */
388             status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
389         }
390         else
391         {
392 
393             /* The host wants a specific string index returned. Get the string framework pointer
394                and length.  */
395             string_framework =  _ux_system_slave -> ux_system_slave_string_framework;
396             string_framework_length =  _ux_system_slave -> ux_system_slave_string_framework_length;
397 
398             /* We search through the string framework until we find the right index.
399                The index is in the lower byte of the descriptor type. */
400             while (string_framework_length != 0)
401             {
402 
403                 /* Ensure we have the correct language page.  */
404                 if (_ux_utility_short_get(string_framework) == request_index)
405                 {
406 
407                     /* Check the index.  */
408                     if (*(string_framework + 2) == descriptor_index)
409                     {
410 
411                         /* We need to check request buffer size in case it's possible exceed. */
412                         if (((*(string_framework + 3)*2) + 2) > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
413                         {
414 
415                             /* Error trap. */
416                             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
417 
418                             /* If trace is enabled, insert this event into the trace buffer.  */
419                             UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
420 
421                             /* Stall the endpoint.  */
422                             status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
423                             break;
424                         }
425 
426                         /* We have a request to send back a string. Use the transfer request buffer.  */
427                         string_memory =  transfer_request -> ux_slave_transfer_request_data_pointer;
428 
429                         /* Store the length in the string buffer. The length
430                            of the string descriptor is stored in the third byte,
431                            hence the ' + 3'. The encoding must be in 16-bit
432                            unicode, hence the '*2'. The length includes the size
433                            of the length itself as well as the descriptor type,
434                            hence the ' + 2'.  */
435                         *string_memory =  (UCHAR)((*(string_framework + 3)*2) + 2);
436 
437                         /* Store the Descriptor type. */
438                         *(string_memory + 1) =  UX_STRING_DESCRIPTOR_ITEM;
439 
440                         /* Create the Unicode string.  */
441                         for (string_length = 0; string_length <  *(string_framework + 3) ; string_length ++)
442                         {
443 
444                             /* Insert a Unicode byte.  */
445                             *(string_memory + 2 + (string_length * 2)) =  *(string_framework + 4 + string_length);
446 
447                             /* Insert a zero after the Unicode byte.  */
448                             *(string_memory + 2 + (string_length * 2) + 1) =  0;
449                         }
450 
451                         /* Filter the length asked/required.  */
452                         if (host_length > (UINT)((*(string_framework + 3)*2) + 2))
453                             length =  (ULONG)((*(string_framework + 3)*2) + 2);
454                         else
455                             length =  host_length;
456 
457                         /* We can return the string descriptor.  */
458                         status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
459                         break;
460                     }
461                 }
462 
463                 /* This is the wrong string descriptor, jump to the next.  */
464                 string_framework_length -=  (ULONG) *(string_framework + 3) + 4;
465                 string_framework +=  (ULONG) *(string_framework + 3) + 4;
466             }
467 
468             /* Have we exhausted all the string descriptors?  */
469             if (string_framework_length == 0)
470             {
471 
472                 /* Could not find the required string index. Stall the endpoint.  */
473                 dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
474                 return(UX_ERROR);
475             }
476         }
477         break;
478 
479     default:
480 
481         /* Stall the endpoint.  */
482         dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
483         return(UX_ERROR);
484     }
485 
486     /* Return the status to the caller.  */
487     return(status);
488 }
489 
490