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