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