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