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