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 /**   Audio Class                                                         */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 
23 /* Include necessary system files.  */
24 
25 #define UX_SOURCE_CODE
26 
27 #include "ux_api.h"
28 #include "ux_host_class_audio.h"
29 #include "ux_host_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_host_class_audio_descriptors_parse              PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function parses all interface descriptors and their audio      */
45 /*    class specific descriptors relates to current audio instance.       */
46 /*                                                                        */
47 /*    The function scans the device configuration descriptor. Once the    */
48 /*    interface descriptors of the audio instance are found, each audio   */
49 /*    class descriptors belong to the interface are passed to parse       */
50 /*    function for caller one by one to parse. The interface descriptor   */
51 /*    is also passed to provide more information. Another pointer to      */
52 /*    arguments is also available as parse function parameter for caller  */
53 /*    to pass necessary caller specific data to process in parse function.*/
54 /*                                                                        */
55 /*    The descriptor parsing can be terminated by returning non-zero      */
56 /*    code in parse function.                                             */
57 /*                                                                        */
58 /*  INPUT                                                                 */
59 /*                                                                        */
60 /*    audio                                 Pointer to audio instance     */
61 /*    parse_function                        Parse function for each       */
62 /*                                          audio class descriptor        */
63 /*    arg                                   Parse function argument       */
64 /*                                                                        */
65 /*  OUTPUT                                                                */
66 /*                                                                        */
67 /*    Completion Status                                                   */
68 /*                                                                        */
69 /*  CALLS                                                                 */
70 /*                                                                        */
71 /*  CALLED BY                                                             */
72 /*                                                                        */
73 /*    Audio Class                                                         */
74 /*    Application                                                         */
75 /*                                                                        */
76 /*  RELEASE HISTORY                                                       */
77 /*                                                                        */
78 /*    DATE              NAME                      DESCRIPTION             */
79 /*                                                                        */
80 /*  07-29-2022     Chaoqiong Xiao           Initial Version 6.1.12        */
81 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            resulting in version 6.3.0  */
83 /*                                                                        */
84 /**************************************************************************/
_ux_host_class_audio_descriptors_parse(UX_HOST_CLASS_AUDIO * audio,UINT (* parse_function)(VOID * arg,UCHAR * packed_interface_descriptor,UCHAR * packed_endpoint_descriptor,UCHAR * packed_audio_descriptor),VOID * arg)85 UINT _ux_host_class_audio_descriptors_parse(UX_HOST_CLASS_AUDIO *audio,
86         UINT(*parse_function)(VOID  *arg,
87                               UCHAR *packed_interface_descriptor,
88                               UCHAR *packed_endpoint_descriptor,
89                               UCHAR *packed_audio_descriptor),
90         VOID* arg)
91 {
92 
93 UCHAR                                           *descriptor;
94 UCHAR                                           *interface_descriptor;
95 UCHAR                                           *endpoint_descriptor;
96 ULONG                                           ac_interface, as_interface;
97 ULONG                                           total_descriptor_length;
98 ULONG                                           descriptor_length;
99 ULONG                                           descriptor_type;
100 UINT                                            status;
101 
102 
103     /* Ensure the instance is valid.  */
104     if (_ux_host_stack_class_instance_verify(_ux_system_host_class_audio_name, (VOID *) audio) != UX_SUCCESS)
105     {
106 
107         /* Error trap. */
108         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
109 
110         /* If trace is enabled, insert this event into the trace buffer.  */
111         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
112         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
113     }
114 
115     /* Device state check.  */
116     if (audio -> ux_host_class_audio_device -> ux_device_state != UX_DEVICE_CONFIGURED)
117         return(UX_INVALID_STATE);
118 
119     /* Get the descriptor to the selected format.  */
120     descriptor =  audio -> ux_host_class_audio_configuration_descriptor;
121     total_descriptor_length =  audio -> ux_host_class_audio_configuration_descriptor_length;
122 
123     /* Get target interface number of control/streaming.  */
124     ac_interface = audio -> ux_host_class_audio_control_interface_number;
125     as_interface = audio -> ux_host_class_audio_streaming_interface -> ux_interface_descriptor.bInterfaceNumber;
126 
127     /* Haven't found interface, endpoint yet.  */
128     interface_descriptor = UX_NULL;
129     endpoint_descriptor = UX_NULL;
130 
131     /* Scan the descriptor for the Audio Control/Streaming interface.  */
132     while (total_descriptor_length)
133     {
134 
135         /* Gather the length, type and subtype of the descriptor.  */
136         descriptor_length =   *descriptor;
137         descriptor_type =     *(descriptor + 1);
138 
139         /* Make sure this descriptor has at least the minimum length.  */
140         if (descriptor_length < 3)
141             return(UX_DESCRIPTOR_CORRUPTED);
142 
143         /* Process relative to descriptor type.  */
144         switch (descriptor_type)
145         {
146 
147         case UX_INTERFACE_DESCRIPTOR_ITEM:
148 
149             /* Ensure we have the correct interface for Audio Control/Streaming.  */
150             if (descriptor[2] == ac_interface || descriptor[2] == as_interface)
151             {
152 
153                 /* Mark we have found it.  */
154                 interface_descriptor = descriptor;
155             }
156             else
157             {
158 
159                 /* Haven't found it.  */
160                 interface_descriptor = UX_NULL;
161             }
162             break;
163 
164         case UX_ENDPOINT_DESCRIPTOR_ITEM:
165 
166             /* Log endpoint descriptor for following CS_ENDPOINT.  */
167             endpoint_descriptor = descriptor;
168             break;
169 
170         case UX_HOST_CLASS_AUDIO_CS_ENDPOINT:
171         case UX_HOST_CLASS_AUDIO_CS_INTERFACE:
172 
173             /* Have we found the audio interface yet?  */
174             if (interface_descriptor != UX_NULL)
175             {
176 
177                 /* Yes, parse the audio specific descriptor.  */
178                 status = parse_function(arg, interface_descriptor, endpoint_descriptor, descriptor);
179 
180                 /* Terminate the parsing if status is not 0.  */
181                 if (status)
182                 {
183 
184                     /* Parsing terminated by user, it's OK.  */
185                     return(UX_SUCCESS);
186                 }
187             }
188             break;
189 
190         default:
191             break;
192         }
193 
194         /* Verify if the descriptor is still valid.  */
195         if (descriptor_length > total_descriptor_length)
196             return(UX_DESCRIPTOR_CORRUPTED);
197 
198         /* Jump to the next descriptor if we have not reached the end.  */
199         descriptor +=  descriptor_length;
200 
201         /* And adjust the length left to parse in the descriptor.  */
202         total_descriptor_length -=  descriptor_length;
203     }
204 
205     /* We get here when all descriptors scanned.  */
206     return(UX_SUCCESS);
207 }
208 
209 
210 /**************************************************************************/
211 /*                                                                        */
212 /*  FUNCTION                                               RELEASE        */
213 /*                                                                        */
214 /*    _uxe_host_class_audio_descriptors_parse             PORTABLE C      */
215 /*                                                           6.3.0        */
216 /*  AUTHOR                                                                */
217 /*                                                                        */
218 /*    Chaoqiong Xiao, Microsoft Corporation                               */
219 /*                                                                        */
220 /*  DESCRIPTION                                                           */
221 /*                                                                        */
222 /*    This function checks errors in audio descriptors parse function     */
223 /*    call.                                                               */
224 /*                                                                        */
225 /*  INPUT                                                                 */
226 /*                                                                        */
227 /*    audio                                 Pointer to audio instance     */
228 /*    parse_function                        Parse function for each       */
229 /*                                          audio class descriptor        */
230 /*    arg                                   Parse function argument       */
231 /*                                                                        */
232 /*  OUTPUT                                                                */
233 /*                                                                        */
234 /*    Status                                                              */
235 /*                                                                        */
236 /*  CALLS                                                                 */
237 /*                                                                        */
238 /*    _uxe_host_class_audio_descriptors_parse                              */
239 /*                                          Parse audio descriptors       */
240 /*                                                                        */
241 /*  CALLED BY                                                             */
242 /*                                                                        */
243 /*    Application                                                         */
244 /*                                                                        */
245 /*  RELEASE HISTORY                                                       */
246 /*                                                                        */
247 /*    DATE              NAME                      DESCRIPTION             */
248 /*                                                                        */
249 /*  10-31-2023     Chaoqiong Xiao           Initial Version 6.3.0         */
250 /*                                                                        */
251 /**************************************************************************/
_uxe_host_class_audio_descriptors_parse(UX_HOST_CLASS_AUDIO * audio,UINT (* parse_function)(VOID * arg,UCHAR * packed_interface_descriptor,UCHAR * packed_endpoint_descriptor,UCHAR * packed_audio_descriptor),VOID * arg)252 UINT _uxe_host_class_audio_descriptors_parse(UX_HOST_CLASS_AUDIO *audio,
253         UINT(*parse_function)(VOID  *arg,
254                               UCHAR *packed_interface_descriptor,
255                               UCHAR *packed_endpoint_descriptor,
256                               UCHAR *packed_audio_descriptor),
257         VOID* arg)
258 {
259 
260     /* Sanity checks.  */
261     if ((audio == UX_NULL) || (parse_function == UX_NULL))
262         return(UX_INVALID_PARAMETER);
263 
264     /* Invoke audio descriptor parse function.  */
265     return(_ux_host_class_audio_descriptors_parse(audio, parse_function, arg));
266 }
267