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 /** Audio Class */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_host_class_audio.h"
30 #include "ux_host_stack.h"
31
32
33 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
34 static inline UINT _ux_host_class_audio_alternate_setting_locate_2(
35 UX_HOST_CLASS_AUDIO *audio,
36 UX_HOST_CLASS_AUDIO_SAMPLING *audio_sampling,
37 UINT *alternate_setting);
38 #endif
39
40
41 /**************************************************************************/
42 /* */
43 /* FUNCTION RELEASE */
44 /* */
45 /* _ux_host_class_audio_alternate_setting_locate PORTABLE C */
46 /* 6.1.12 */
47 /* AUTHOR */
48 /* */
49 /* Chaoqiong Xiao, Microsoft Corporation */
50 /* */
51 /* DESCRIPTION */
52 /* */
53 /* This function finds the right alternate setting according to the */
54 /* sampling desired. */
55 /* */
56 /* INPUT */
57 /* */
58 /* audio Pointer to audio class */
59 /* audio_sampling Pointer to audio sampling */
60 /* alternate_setting Pointer to located alternate */
61 /* setting */
62 /* */
63 /* OUTPUT */
64 /* */
65 /* Completion Status */
66 /* */
67 /* CALLS */
68 /* */
69 /* _ux_utility_descriptor_parse Parse descriptor */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* Audio Class */
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 /* resulting in version 6.1 */
82 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
83 /* added audio 2.0 support, */
84 /* resulting in version 6.1.12 */
85 /**************************************************************************/
_ux_host_class_audio_alternate_setting_locate(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_SAMPLING * audio_sampling,UINT * alternate_setting)86 UINT _ux_host_class_audio_alternate_setting_locate(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_SAMPLING *audio_sampling,
87 UINT *alternate_setting)
88 {
89
90 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
91 return(_ux_host_class_audio_alternate_setting_locate_2(audio, audio_sampling, alternate_setting));
92 #else
93
94 UCHAR * descriptor;
95 UX_INTERFACE_DESCRIPTOR interface_descriptor;
96 UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR audio_interface_descriptor;
97 ULONG total_descriptor_length;
98 UINT descriptor_length;
99 UINT descriptor_type;
100 UINT descriptor_subtype;
101 UINT interface_found;
102 ULONG lower_frequency;
103 ULONG higher_frequency;
104 UINT specific_frequency_count;
105
106
107 /* Get the descriptor to the entire configuration. */
108 descriptor = audio -> ux_host_class_audio_configuration_descriptor;
109 total_descriptor_length = audio -> ux_host_class_audio_configuration_descriptor_length;
110
111 /* Default is Interface descriptor not yet found. */
112 interface_found = UX_FALSE;
113
114 /* Scan the descriptor for the Audio Streaming interface. */
115 while (total_descriptor_length)
116 {
117
118 /* Gather the length, type and subtype of the descriptor. */
119 descriptor_length = *descriptor;
120 descriptor_type = *(descriptor + 1);
121 descriptor_subtype = *(descriptor + 2);
122
123 /* Make sure this descriptor has at least the minimum length. */
124 if (descriptor_length < 3)
125 {
126
127 /* Error trap. */
128 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
129
130 /* If trace is enabled, insert this event into the trace buffer. */
131 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
132
133 return(UX_DESCRIPTOR_CORRUPTED);
134 }
135 /* Process relative to descriptor type. */
136 switch (descriptor_type)
137 {
138
139
140 case UX_INTERFACE_DESCRIPTOR_ITEM:
141
142 /* Parse the interface descriptor and make it machine independent. */
143 _ux_utility_descriptor_parse(descriptor, _ux_system_interface_descriptor_structure,
144 UX_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &interface_descriptor);
145
146 /* Ensure we have the correct interface for Audio streaming. */
147 if ((interface_descriptor.bInterfaceClass == UX_HOST_CLASS_AUDIO_CLASS) &&
148 (interface_descriptor.bInterfaceSubClass == UX_HOST_CLASS_AUDIO_SUBCLASS_STREAMING))
149 {
150
151 /* Mark we have found it. */
152 interface_found = UX_TRUE;
153
154 /* And memorize the alternate setting. */
155 *alternate_setting = interface_descriptor.bAlternateSetting;
156 }
157 else
158 {
159
160 /* Haven't found it. */
161 interface_found = UX_FALSE;
162 }
163 break;
164
165
166 case UX_HOST_CLASS_AUDIO_CS_INTERFACE:
167
168 /* First make sure we have found the correct generic interface descriptor. */
169 if ((interface_found == UX_TRUE) && (descriptor_subtype == UX_HOST_CLASS_AUDIO_CS_FORMAT_TYPE))
170 {
171
172 /* Parse the FORMAT_TYPE descriptor and make it machine independent. */
173 _ux_utility_descriptor_parse(descriptor, _ux_system_class_audio_interface_descriptor_structure,
174 UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &audio_interface_descriptor);
175
176 /* This descriptor must refer to a PCM audio type. */
177 if (audio_interface_descriptor.bFormatType != UX_HOST_CLASS_AUDIO_FORMAT_TYPE_I)
178 break;
179
180 /* The number of channels demanded by the application must match. */
181 if (audio_sampling -> ux_host_class_audio_sampling_channels != audio_interface_descriptor.bNrChannels)
182 break;
183
184 /* The resolution demanded by the application must match. */
185 if (audio_sampling -> ux_host_class_audio_sampling_resolution != audio_interface_descriptor.bBitResolution)
186 break;
187
188 /* Check the frequency demanded. The descriptor frequency is either defined
189 as a min and max frequency or an array of specified values. */
190 if (audio_interface_descriptor.bSamFreqType == 0)
191 {
192
193 /* The declaration of frequency is contiguous, so get the minimum and maximum */
194 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
195 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
196 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
197
198 higher_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
199 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
200 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
201
202 /* Now compare with what is required. */
203 if ((audio_sampling -> ux_host_class_audio_sampling_frequency >= lower_frequency) &&
204 (audio_sampling -> ux_host_class_audio_sampling_frequency <= higher_frequency))
205 {
206
207 /* We have found the right alternate setting. */
208 audio -> ux_host_class_audio_sampling_descriptor = descriptor;
209 return(UX_SUCCESS);
210 }
211 }
212 else
213 {
214
215 /* The declaration of the frequency is declared as an array of specific values. */
216 for (specific_frequency_count = 0; specific_frequency_count < audio_interface_descriptor.bSamFreqType;
217 specific_frequency_count++)
218 {
219
220 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + (specific_frequency_count * 3)) |
221 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1 + (specific_frequency_count * 3))) << 8 |
222 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2 + (specific_frequency_count * 3))) << 16;
223
224 /* Now compare with what is required. */
225 if (audio_sampling -> ux_host_class_audio_sampling_frequency == lower_frequency)
226 {
227
228 /* We have found the right alternate setting. */
229 audio -> ux_host_class_audio_sampling_descriptor = descriptor;
230 return(UX_SUCCESS);
231 }
232 }
233 }
234 }
235 break;
236 }
237
238 /* Verify if the descriptor is still valid. */
239 if (descriptor_length > total_descriptor_length)
240 {
241
242 /* If trace is enabled, insert this event into the trace buffer. */
243 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
244
245 return(UX_DESCRIPTOR_CORRUPTED);
246 }
247
248 /* Jump to the next descriptor if we have not reached the end. */
249 descriptor += descriptor_length;
250
251 /* And adjust the length left to parse in the descriptor. */
252 total_descriptor_length -= descriptor_length;
253 }
254
255 /* If trace is enabled, insert this event into the trace buffer. */
256 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_ALTERNATE_SETTING, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
257
258 /* We get here when either the report descriptor has a problem or we could
259 not find the right audio device. */
260 return(UX_NO_ALTERNATE_SETTING);
261 #endif
262 }
263
264 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
265 struct UX_HOST_CLASS_AUDIO_ALT_LOCATE_PARSER {
266 UX_HOST_CLASS_AUDIO_SAMPLING *sampling;
267 UCHAR *clock_descriptor;
268 ULONG alt;
269 UINT status;
270 };
_ux_host_class_audio_alt_locate_parse(VOID * arg,UCHAR * packed_interface_descriptor,UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS * sam_attr)271 static UINT _ux_host_class_audio_alt_locate_parse(VOID *arg,
272 UCHAR *packed_interface_descriptor,
273 UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr)
274 {
275 struct UX_HOST_CLASS_AUDIO_ALT_LOCATE_PARSER *parser = (struct UX_HOST_CLASS_AUDIO_ALT_LOCATE_PARSER *)arg;
276 UX_HOST_CLASS_AUDIO_SAMPLING *sampling = parser -> sampling;
277 ULONG frequency_low, frequency_high;
278
279 /* Check bNrChannels. */
280 if (sampling -> ux_host_class_audio_sampling_channels !=
281 sam_attr -> ux_host_class_audio_sampling_characteristics_channels)
282 return(0);
283
284 /* Check bBitResolution. */
285 if (sampling -> ux_host_class_audio_sampling_resolution !=
286 sam_attr -> ux_host_class_audio_sampling_characteristics_resolution)
287 return(0);
288
289 /* Calculate frequency low. */
290 frequency_low = sam_attr -> ux_host_class_audio_sampling_characteristics_frequency_low;
291 if (UX_OVERFLOW_CHECK_MULV_ULONG(frequency_low, sam_attr -> ux_host_class_audio_sampling_characteristics_clock_mul))
292 {
293
294 /* Math error. */
295 parser -> status = UX_MATH_OVERFLOW;
296 return(1);
297 }
298 frequency_low *= sam_attr -> ux_host_class_audio_sampling_characteristics_clock_mul;
299 frequency_low /= sam_attr -> ux_host_class_audio_sampling_characteristics_clock_div;
300
301 /* Calculate frequency high. */
302 frequency_high = sam_attr -> ux_host_class_audio_sampling_characteristics_frequency_high;
303 if (UX_OVERFLOW_CHECK_MULV_ULONG(frequency_high, sam_attr -> ux_host_class_audio_sampling_characteristics_clock_mul))
304 {
305
306 /* Math error. */
307 parser -> status = UX_MATH_OVERFLOW;
308 return(1);
309 }
310 frequency_high *= sam_attr -> ux_host_class_audio_sampling_characteristics_clock_mul;
311 frequency_high /= sam_attr -> ux_host_class_audio_sampling_characteristics_clock_div;
312
313 /* Check frequency in [low, high]. */
314 if ((frequency_low <= sampling -> ux_host_class_audio_sampling_frequency) &&
315 (frequency_high >= sampling -> ux_host_class_audio_sampling_frequency))
316 {
317
318 /* Save bAlternateSetting @ 3. */
319 parser -> alt = (ULONG)packed_interface_descriptor[3];
320
321 /* Save UAC 1.0 FormatTypeI or UAC 2.0 CSD. */
322 parser -> clock_descriptor =
323 sam_attr -> ux_host_class_audio_sampling_characteristics_descriptor;
324 return(1);
325 }
326
327 /* Continue parsing. */
328 return(0);
329 }
_ux_host_class_audio_alternate_setting_locate_2(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_SAMPLING * audio_sampling,UINT * alternate_setting)330 static inline UINT _ux_host_class_audio_alternate_setting_locate_2(
331 UX_HOST_CLASS_AUDIO *audio,
332 UX_HOST_CLASS_AUDIO_SAMPLING *audio_sampling,
333 UINT *alternate_setting)
334 {
335 struct UX_HOST_CLASS_AUDIO_ALT_LOCATE_PARSER parser;
336 UINT status;
337
338 /* Parse specific sampling setting to get alt setting. */
339 parser.sampling = audio_sampling;
340 parser.clock_descriptor = UX_NULL;
341 parser.alt = 0xFF;
342 parser.status = UX_SUCCESS;
343 status = _ux_host_class_audio_raw_sampling_parse(audio, _ux_host_class_audio_alt_locate_parse, (VOID*)&parser);
344
345 /* Check descriptor error. */
346 if (status != UX_SUCCESS)
347 return(status);
348
349 /* Check if valid alternate setting is found. */
350 if (parser.alt == 0xFF)
351 {
352
353 /* If trace is enabled, insert this event into the trace buffer. */
354 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_ALTERNATE_SETTING, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
355 return(UX_NO_ALTERNATE_SETTING);
356 }
357
358 /* Save alternate setting. */
359 *alternate_setting = parser.alt;
360 audio -> ux_host_class_audio_sampling_descriptor = parser.clock_descriptor;
361 return(parser.status);
362 }
363 #endif
364