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 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_audio_streaming_sampling_get PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function obtains successive sampling characteristics for the */
46 /* audio streaming channel. */
47 /* */
48 /* Note only Audio 1.0 and RAW (PCM like) format is supported. */
49 /* */
50 /* INPUT */
51 /* */
52 /* audio Pointer to audio class */
53 /* audio_sampling Pointer to audio sampling */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* Completion Status */
58 /* */
59 /* CALLS */
60 /* */
61 /* _ux_host_stack_class_instance_verify Verify instance is valid */
62 /* _ux_utility_descriptor_parse Parse the descriptor */
63 /* _ux_host_mutex_on Get mutex */
64 /* _ux_host_mutex_off Put mutex */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* Application */
69 /* Audio Class */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
76 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
77 /* resulting in version 6.1 */
78 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
79 /* refined macros names, */
80 /* resulting in version 6.1.10 */
81 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
82 /* fixed standalone compile, */
83 /* resulting in version 6.1.11 */
84 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
85 /* protect reentry with mutex, */
86 /* fixed error return code, */
87 /* resulting in version 6.1.12 */
88 /* */
89 /**************************************************************************/
_ux_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS * audio_sampling)90 UINT _ux_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *audio_sampling)
91 {
92
93 UCHAR * descriptor;
94 UX_INTERFACE_DESCRIPTOR interface_descriptor;
95 UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR audio_interface_descriptor;
96 ULONG total_descriptor_length;
97 UINT descriptor_length;
98 UINT descriptor_type;
99 UINT descriptor_subtype;
100 UINT interface_found;
101 ULONG lower_frequency;
102 ULONG higher_frequency;
103 UINT specific_frequency_count;
104 UINT previous_match_found;
105
106 /* If trace is enabled, insert this event into the trace buffer. */
107 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_AUDIO_STREAMING_SAMPLING_GET, audio, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
108
109 /* Ensure the instance is valid. */
110 if (_ux_host_stack_class_instance_verify(_ux_system_host_class_audio_name, (VOID *) audio) != UX_SUCCESS)
111 {
112
113 /* Error trap. */
114 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
115
116 /* If trace is enabled, insert this event into the trace buffer. */
117 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
118
119 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
120 }
121
122 /* Protect thread reentry to this instance. */
123 _ux_host_mutex_on(&audio -> ux_host_class_audio_mutex);
124
125 /* Reset the match flag. */
126 previous_match_found = UX_FALSE;
127
128 /* Get the descriptor to the entire configuration. */
129 descriptor = audio -> ux_host_class_audio_configuration_descriptor;
130 total_descriptor_length = audio -> ux_host_class_audio_configuration_descriptor_length;
131
132 /* Default is Interface descriptor not yet found. */
133 interface_found = UX_FALSE;
134
135 /* Scan the descriptor for the Audio Streaming interface. */
136 while (total_descriptor_length)
137 {
138
139 /* Gather the length, type and subtype of the descriptor. */
140 descriptor_length = *descriptor;
141 descriptor_type = *(descriptor + 1);
142 descriptor_subtype = *(descriptor + 2);
143
144 /* Make sure this descriptor has at least the minimum length. */
145 if (descriptor_length < 3)
146 {
147
148 /* Error trap. */
149 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
150
151 /* If trace is enabled, insert this event into the trace buffer. */
152 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
153
154 /* Unprotect thread reentry to this instance. */
155 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
156
157 return(UX_DESCRIPTOR_CORRUPTED);
158 }
159
160 /* Process relative to descriptor type. */
161 switch(descriptor_type)
162 {
163
164
165 case UX_INTERFACE_DESCRIPTOR_ITEM:
166
167 /* Parse the interface descriptor and make it machine independent */
168 _ux_utility_descriptor_parse(descriptor, _ux_system_interface_descriptor_structure,
169 UX_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &interface_descriptor);
170
171 /* Ensure we have the correct interface for Audio streaming. */
172 if ((interface_descriptor.bInterfaceClass == UX_HOST_CLASS_AUDIO_CLASS) &&
173 (interface_descriptor.bInterfaceSubClass == UX_HOST_CLASS_AUDIO_SUBCLASS_STREAMING))
174 {
175
176 /* Mark we have found it. */
177 interface_found = UX_TRUE;
178 }
179 else
180 {
181 interface_found = UX_FALSE;
182 }
183 break;
184
185
186 case UX_HOST_CLASS_AUDIO_CS_INTERFACE:
187
188 /* First make sure we have found the correct generic interface descriptor. */
189 if ((interface_found == UX_TRUE) && (descriptor_subtype == UX_HOST_CLASS_AUDIO_CS_FORMAT_TYPE))
190 {
191
192 /* Parse the FORMAT_TYPE descriptor and make it machine independent. */
193 _ux_utility_descriptor_parse(descriptor, _ux_system_class_audio_interface_descriptor_structure,
194 UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &audio_interface_descriptor);
195
196 /* This descriptor must refer to a PCM audio type. */
197 if (audio_interface_descriptor.bFormatType != UX_HOST_CLASS_AUDIO_FORMAT_TYPE_I)
198 break;
199
200 /* If this is the first time we ask for a streaming interface characteristics
201 we return the first we find. */
202 if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_channels == 0) &&
203 (audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution == 0))
204 {
205
206 audio_sampling -> ux_host_class_audio_sampling_characteristics_channels = audio_interface_descriptor.bNrChannels;
207 audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution = audio_interface_descriptor.bBitResolution;
208
209 if (audio_interface_descriptor.bSamFreqType == 0)
210 {
211
212 /* The declaration of frequency is contiguous, so get the minimum and maximum */
213 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =
214 (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
215 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
216 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
217
218 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high =
219 (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
220 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
221 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
222 }
223 else
224 {
225
226 /* The declaration of the frequency is declared as an array of specific values.
227 We take the first one here. */
228 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =
229 (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH ) |
230 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1 )) << 8 |
231 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2 )) << 16;
232
233 /* High and low frequencies are the same here. */
234 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high = audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low;
235
236 /* Unprotect thread reentry to this instance. */
237 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
238
239 /* We have found the first streaming characteristics. */
240 return(UX_SUCCESS);
241 }
242 }
243 else
244 {
245
246 /* This is not the second time we ask for the characteristics, we need
247 to find 1st where we left off and look at the next characteristics. */
248 if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_channels == audio_interface_descriptor.bNrChannels) &&
249 (audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution == audio_interface_descriptor.bBitResolution))
250 {
251
252 if (audio_interface_descriptor.bSamFreqType == 0)
253 {
254
255 /* The declaration of frequency is contiguous, so get the minimum and maximum. */
256 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
257 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
258 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
259
260 higher_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
261 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
262 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
263
264 if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low == lower_frequency) &&
265 (audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high == higher_frequency))
266 {
267
268 /* We have a match. */
269 previous_match_found = UX_TRUE;
270 break;
271 }
272 }
273 else
274 {
275
276 /* The declaration of the frequency is declared as an array of specific values. */
277 for (specific_frequency_count = 0; specific_frequency_count < audio_interface_descriptor.bSamFreqType; specific_frequency_count++)
278 {
279
280 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + (specific_frequency_count * 3)) |
281 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1 + (specific_frequency_count * 3))) << 8 |
282 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2 + (specific_frequency_count * 3))) << 16;
283
284 /* Compare the frequency. */
285 if (audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low == lower_frequency)
286 {
287
288 previous_match_found = UX_TRUE;
289 }
290 else
291 {
292
293 /* Now the frequency is different, if we had a match before
294 this becomes the next characteristics found. */
295 if (previous_match_found == UX_TRUE)
296 {
297
298 /* We return this characteristics. */
299 audio_sampling -> ux_host_class_audio_sampling_characteristics_channels = audio_interface_descriptor.bNrChannels;
300 audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution = audio_interface_descriptor.bBitResolution;
301 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low = lower_frequency;
302 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high = lower_frequency;
303
304 /* Unprotect thread reentry to this instance. */
305 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
306
307 /* Return successful completion. */
308 return(UX_SUCCESS);
309 }
310 }
311 }
312 }
313 }
314 else
315 {
316
317 /* We come here when the current characteristics does not match
318 the one given by the application. We need to check if we had found a match
319 before in which case, this is the one we need to return. */
320 if (previous_match_found == UX_TRUE)
321 {
322
323 /* We return this characteristics. */
324 audio_sampling -> ux_host_class_audio_sampling_characteristics_channels = audio_interface_descriptor.bNrChannels;
325 audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution = audio_interface_descriptor.bBitResolution;
326
327 if (audio_interface_descriptor.bSamFreqType == 0)
328 {
329
330 /* The declaration of frequency is contiguous, so get the minimum and maximum. */
331 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
332 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
333 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
334
335 higher_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
336 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
337 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
338
339 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low = lower_frequency;
340 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high = higher_frequency;
341
342 /* Unprotect thread reentry to this instance. */
343 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
344
345 /* Return successful completion. */
346 return(UX_SUCCESS);
347 }
348 else
349 {
350
351 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
352 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
353 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
354
355 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low = lower_frequency;
356 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high = lower_frequency;
357
358 /* Unprotect thread reentry to this instance. */
359 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
360
361 /* Return successful completion. */
362 return(UX_SUCCESS);
363 }
364 }
365 }
366 }
367 }
368 }
369
370 /* Verify the descriptor is still valid. */
371 if (descriptor_length > total_descriptor_length)
372 {
373
374 /* Error trap. */
375 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
376
377 /* If trace is enabled, insert this event into the trace buffer. */
378 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
379
380 /* Unprotect thread reentry to this instance. */
381 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
382
383 return(UX_DESCRIPTOR_CORRUPTED);
384 }
385
386 /* Jump to the next descriptor if we have not reached the end. */
387 descriptor += descriptor_length;
388
389 /* And adjust the length left to parse in the descriptor. */
390 total_descriptor_length -= descriptor_length;
391 }
392
393 /* Unprotect thread reentry to this instance. */
394 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
395
396 /* Error trap. */
397 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_NO_ALTERNATE_SETTING);
398
399 /* If trace is enabled, insert this event into the trace buffer. */
400 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_ALTERNATE_SETTING, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
401
402 /* We get here when either the report descriptor has a problem or we could
403 not find the right audio device. */
404 return(UX_NO_ALTERNATE_SETTING);
405 }
406
407