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 struct UX_HOST_CLASS_AUDIO10_SAM_PARSER {
33     UINT    (*parse_function)(VOID  *arg,
34                               UCHAR *packed_interface_descriptor,
35                               UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr
36                             );
37     UCHAR   *arg;
38     UX_HOST_CLASS_AUDIO
39             *audio;
40 };
41 struct UX_HOST_CLASS_AUDIO20_SAM_PARSER {
42     UINT    (*parse_function)(VOID  *arg,
43                               UCHAR *packed_interface_descriptor,
44                               UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr
45                             );
46     UCHAR   *arg;
47     UX_HOST_CLASS_AUDIO
48             *audio;
49     UCHAR   *as_header;
50     UINT    status;
51 };
52 
53 
54 static UINT _ux_host_class_audio10_sam_parse_func(VOID *arg,
55                             UCHAR *packed_interface_descriptor,
56                             UCHAR *packed_endpoint_descriptor,
57                             UCHAR *packed_audio_descriptor);
58 static inline UINT _ux_host_class_audio10_sampling_parse(UX_HOST_CLASS_AUDIO *audio,
59         UINT(*parse_function)(VOID  *arg,
60                               UCHAR *packed_interface_descriptor,
61                               UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr),
62         VOID* arg);
63 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
64 static UINT _ux_host_class_audio20_sam_parse_func(VOID *arg,
65                             UCHAR *packed_interface_descriptor,
66                             UCHAR *packed_endpoint_descriptor,
67                             UCHAR *packed_audio_descriptor);
68 
69 static inline UINT _ux_host_class_audio20_sampling_parse(UX_HOST_CLASS_AUDIO *audio,
70         UINT(*parse_function)(VOID  *arg,
71                               UCHAR *packed_interface_descriptor,
72                               UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr),
73         VOID* arg);
74 #endif
75 
76 
77 /**************************************************************************/
78 /*                                                                        */
79 /*  FUNCTION                                               RELEASE        */
80 /*                                                                        */
81 /*    _ux_host_class_audio_raw_sampling_parse             PORTABLE C      */
82 /*                                                           6.1.12       */
83 /*  AUTHOR                                                                */
84 /*                                                                        */
85 /*    Chaoqiong Xiao, Microsoft Corporation                               */
86 /*                                                                        */
87 /*  DESCRIPTION                                                           */
88 /*                                                                        */
89 /*    This function parses all possible RAW (PCM like) sampling           */
90 /*    characteristics for current clock source and clock selector         */
91 /*    settings.                                                           */
92 /*                                                                        */
93 /*    For sampling characteristics of different clock settings,           */
94 /*    use ux_host_class_audio_descriptors_parse to get their IDs and      */
95 /*    use _ux_host_class_audio_control_request to change settings.        */
96 /*                                                                        */
97 /*  INPUT                                                                 */
98 /*                                                                        */
99 /*    audio                                 Pointer to audio class        */
100 /*    parse_function                        Pointer to parse function,    */
101 /*                                          returns 0 to continue parse,  */
102 /*                                          others to terminate parse.    */
103 /*    arg                                   Pointer to parse arguments    */
104 /*                                                                        */
105 /*  OUTPUT                                                                */
106 /*                                                                        */
107 /*    Completion Status                                                   */
108 /*                                                                        */
109 /*  CALLS                                                                 */
110 /*                                                                        */
111 /*    _ux_host_stack_class_instance_verify  Verify instance is valid      */
112 /*    _ux_host_semaphore_get                Get semaphore                 */
113 /*    _ux_host_semaphore_put                Put semaphore                 */
114 /*                                                                        */
115 /*  CALLED BY                                                             */
116 /*                                                                        */
117 /*    Application                                                         */
118 /*    Audio Class                                                         */
119 /*                                                                        */
120 /*  RELEASE HISTORY                                                       */
121 /*                                                                        */
122 /*    DATE              NAME                      DESCRIPTION             */
123 /*                                                                        */
124 /*  07-29-2022     Chaoqiong Xiao           Initial Version 6.1.12        */
125 /*                                                                        */
126 /**************************************************************************/
_ux_host_class_audio_raw_sampling_parse(UX_HOST_CLASS_AUDIO * audio,UINT (* parse_function)(VOID * arg,UCHAR * packed_interface_descriptor,UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS * sam_attr),VOID * arg)127 UINT _ux_host_class_audio_raw_sampling_parse(UX_HOST_CLASS_AUDIO *audio,
128         UINT(*parse_function)(VOID  *arg,
129                               UCHAR *packed_interface_descriptor,
130                               UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr),
131         VOID* arg)
132 {
133 
134     /* Ensure the instance is valid.  */
135     if (_ux_host_stack_class_instance_verify(_ux_system_host_class_audio_name, (VOID *) audio) != UX_SUCCESS)
136     {
137 
138         /* Error trap. */
139         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
140 
141         /* If trace is enabled, insert this event into the trace buffer.  */
142         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
143 
144         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
145     }
146 
147 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
148     if (_ux_host_class_audio_protocol_get(audio) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_02_00)
149         return(_ux_host_class_audio20_sampling_parse(audio, parse_function, arg));
150 #endif
151 
152     return(_ux_host_class_audio10_sampling_parse(audio, parse_function, arg));
153 }
154 
_ux_host_class_audio10_sam_parse_func(VOID * arg,UCHAR * packed_interface_descriptor,UCHAR * packed_endpoint_descriptor,UCHAR * packed_audio_descriptor)155 static UINT _ux_host_class_audio10_sam_parse_func(VOID *arg,
156                             UCHAR *packed_interface_descriptor,
157                             UCHAR *packed_endpoint_descriptor,
158                             UCHAR *packed_audio_descriptor)
159 {
160 struct UX_HOST_CLASS_AUDIO10_SAM_PARSER           *parser = (struct UX_HOST_CLASS_AUDIO10_SAM_PARSER *)arg;
161 UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS    sam_attr;
162 ULONG                                           n, offset;
163 UINT                                            status;
164 
165     UX_PARAMETER_NOT_USED(packed_endpoint_descriptor);
166 
167     /* Check bInterfaceNumber @ 2.  */
168     if (packed_interface_descriptor[2] !=
169         parser -> audio -> ux_host_class_audio_streaming_interface ->
170                             ux_interface_descriptor.bInterfaceNumber)
171         return(0);
172 
173     /* Check bDescriptorType @ 1.  */
174     if (packed_audio_descriptor[1] != UX_HOST_CLASS_AUDIO_CS_INTERFACE)
175         return(0);
176 
177     /* Check bDescriptorSubType @ 2.  */
178     if (packed_audio_descriptor[2] != UX_HOST_CLASS_AUDIO_CS_FORMAT_TYPE)
179         return(0);
180 
181     /* Check bFormatType @ 3.  */
182     if (packed_audio_descriptor[3] != UX_HOST_CLASS_AUDIO_FORMAT_TYPE_I)
183         return(0);
184 
185     /* Get bNrChannels @ 4.  */
186     sam_attr.ux_host_class_audio_sampling_characteristics_channels = packed_audio_descriptor[4];
187 
188     /* Get bBitResolution @ 6.  */
189     sam_attr.ux_host_class_audio_sampling_characteristics_resolution = packed_audio_descriptor[6];
190 
191     /* No clock ID (set to 0), no mul, div (set to 1).  */
192     sam_attr.ux_host_class_audio_sampling_characteristics_descriptor = packed_audio_descriptor;
193     sam_attr.ux_host_class_audio_sampling_characteristics_clock_mul = 1;
194     sam_attr.ux_host_class_audio_sampling_characteristics_clock_div = 1;
195 
196     /* Check bSamFreqType @ 7.  */
197     if (packed_audio_descriptor[7] == 0)
198     {
199 
200         /* Continuous, get dLowSamFreq and dHighSamFreq.  */
201         sam_attr.ux_host_class_audio_sampling_characteristics_frequency_low =
202                                     ((ULONG)packed_audio_descriptor[8]) +
203                                     ((ULONG)packed_audio_descriptor[9]  << 8) +
204                                     ((ULONG)packed_audio_descriptor[10] << 16);
205         sam_attr.ux_host_class_audio_sampling_characteristics_frequency_high =
206                                     ((ULONG)packed_audio_descriptor[11]) +
207                                     ((ULONG)packed_audio_descriptor[12]  << 8) +
208                                     ((ULONG)packed_audio_descriptor[13] << 16);
209 
210         /* Parse this sampling characteristic.  */
211         status = parser->parse_function(parser->arg, packed_interface_descriptor, &sam_attr);
212         return(status);
213     }
214     else
215     {
216 
217         /* Parse list of sampling characteristics.  */
218         for (n = 0, offset = 8;
219              n < packed_audio_descriptor[7];
220              n ++, offset += 3)
221         {
222             sam_attr.ux_host_class_audio_sampling_characteristics_frequency_low =
223                                     ((ULONG)packed_audio_descriptor[offset]) +
224                                     ((ULONG)packed_audio_descriptor[offset+1]  << 8) +
225                                     ((ULONG)packed_audio_descriptor[offset+2] << 16);
226 
227             /* Not range, frequency high = low.  */
228             sam_attr.ux_host_class_audio_sampling_characteristics_frequency_high =
229                 sam_attr.ux_host_class_audio_sampling_characteristics_frequency_low;
230 
231             /* Parse this sampling characteristic.  */
232             status = parser->parse_function(parser->arg, packed_interface_descriptor, &sam_attr);
233 
234             /* If status is not 0, it terminate parsing.  */
235             if (status != 0)
236                 return(status);
237         }
238     }
239     return(0);
240 }
241 
_ux_host_class_audio10_sampling_parse(UX_HOST_CLASS_AUDIO * audio,UINT (* parse_function)(VOID * arg,UCHAR * packed_interface_descriptor,UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS * sam_attr),VOID * arg)242 static inline UINT _ux_host_class_audio10_sampling_parse(UX_HOST_CLASS_AUDIO *audio,
243         UINT(*parse_function)(VOID  *arg,
244                               UCHAR *packed_interface_descriptor,
245                               UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr),
246         VOID* arg)
247 {
248 
249 struct UX_HOST_CLASS_AUDIO10_SAM_PARSER     parser;
250 
251     /* No need to protect thread reentry to this instance (no requests).  */
252 
253     parser.parse_function = parse_function;
254     parser.arg = arg;
255     parser.audio = audio;
256     return(_ux_host_class_audio_descriptors_parse(audio,
257                     _ux_host_class_audio10_sam_parse_func, (VOID *)&parser));
258 }
259 
260 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
261 struct UX_HOST_CLASS_AUDIO_AC_DESCR_FINDER_STRUCT
262 {
263     UCHAR   *descriptor;
264     UCHAR   interface_num;
265     UCHAR   subtype;
266     UCHAR   id;
267 };
_ux_host_class_audio_ac_find_parse(VOID * arg,UCHAR * packed_interface_descriptor,UCHAR * packed_endpoint_descriptor,UCHAR * packed_audio_descriptor)268 static UINT  _ux_host_class_audio_ac_find_parse(VOID  *arg,
269                               UCHAR *packed_interface_descriptor,
270                               UCHAR *packed_endpoint_descriptor,
271                               UCHAR *packed_audio_descriptor)
272 {
273 struct UX_HOST_CLASS_AUDIO_AC_DESCR_FINDER_STRUCT *finder = (struct UX_HOST_CLASS_AUDIO_AC_DESCR_FINDER_STRUCT *)arg;
274 
275     UX_PARAMETER_NOT_USED(packed_endpoint_descriptor);
276 
277     /* Check interface number (bInterfaceNumber @ 2).  */
278     if (packed_interface_descriptor[2] != finder -> interface_num)
279         return(0);
280 
281     /* Check bDescriptorType @ 1.  */
282     if (packed_audio_descriptor[1] != UX_HOST_CLASS_AUDIO_CS_INTERFACE)
283         return(0);
284 
285     /* Get finding data.  */
286     finder = (struct UX_HOST_CLASS_AUDIO_AC_DESCR_FINDER_STRUCT *)arg;
287 
288     /* Check bDescriptorSubType @ 2.  */
289     if (packed_audio_descriptor[2] != finder -> subtype)
290         return(0);
291 
292     /* Check bEntityID @ 3.  */
293     if (packed_audio_descriptor[3] != finder -> id)
294         return(0);
295 
296     /* Found it, break parsing loop.  */
297     finder -> descriptor = packed_audio_descriptor;
298     return(1);
299 }
_ux_host_class_audio_ac_find(UX_HOST_CLASS_AUDIO * audio,UCHAR subtype,UCHAR id)300 static UCHAR *_ux_host_class_audio_ac_find(UX_HOST_CLASS_AUDIO *audio, UCHAR subtype, UCHAR id)
301 {
302 
303 struct UX_HOST_CLASS_AUDIO_AC_DESCR_FINDER_STRUCT   finder;
304 UINT                                                status;
305 
306     finder.descriptor    = UX_NULL;
307     finder.interface_num = (UCHAR)audio -> ux_host_class_audio_control_interface_number;
308     finder.subtype       = subtype;
309     finder.id            = id;
310     status = _ux_host_class_audio_descriptors_parse(audio,
311                             _ux_host_class_audio_ac_find_parse,
312                             &finder);
313     if (status != UX_SUCCESS)
314         return(UX_NULL);
315     return(finder.descriptor);
316 }
317 
_ux_host_class_audio20_clock_get(UX_HOST_CLASS_AUDIO * audio,UCHAR terminal_link,UCHAR ** csd,ULONG * clk_numerator,ULONG * clk_denominator)318 static inline UINT _ux_host_class_audio20_clock_get(UX_HOST_CLASS_AUDIO *audio,
319                     UCHAR terminal_link,
320                     UCHAR **csd, ULONG *clk_numerator, ULONG *clk_denominator)
321 {
322 
323 UX_DEVICE       *device;
324 UX_ENDPOINT     *endpoint;
325 UX_TRANSFER     *request;
326 UCHAR           *control_buffer = UX_NULL;
327 UCHAR           *descriptor;
328 UCHAR           id;
329 ULONG           numerator = 1, denominator = 1;
330 UCHAR           scan_round = 0;
331 UINT            status;
332 
333     if (audio -> ux_host_class_audio_type == UX_HOST_CLASS_AUDIO_INPUT)
334     {
335 
336         /* If audio input, streaming is from output terminal (OT).  */
337         descriptor = _ux_host_class_audio_ac_find(audio,
338                                         UX_CLASS_AUDIO20_AC_OUTPUT_TERMINAL,
339                                         (UCHAR)terminal_link);
340         if (descriptor == UX_NULL)
341             return(UX_DESCRIPTOR_CORRUPTED);
342 
343         /* Get OTD::bCSourceID @ 8.  */
344         id = descriptor[8];
345     }
346     else
347     {
348 
349         /* If audio output, streaming is to input terminal (IT).  */
350         descriptor = _ux_host_class_audio_ac_find(audio,
351                                         UX_CLASS_AUDIO20_AC_INPUT_TERMINAL,
352                                         (UCHAR)terminal_link);
353         if (descriptor == UX_NULL)
354             return(UX_DESCRIPTOR_CORRUPTED);
355 
356         /* Get ITD::bCSourceID @ 7.  */
357         id = descriptor[7];
358     }
359 
360     /* Get control endpoint and request, for possible control requests.  */
361     device = audio -> ux_host_class_audio_device;
362     endpoint = &device -> ux_device_control_endpoint;
363     request = &endpoint -> ux_endpoint_transfer_request;
364 
365     /* Get clock source descriptor.  */
366     do
367     {
368 
369         /* Try to find ClockSource CSD.  */
370         descriptor = _ux_host_class_audio_ac_find(audio,
371                                     UX_CLASS_AUDIO20_AC_CLOCK_SOURCE, id);
372         if (descriptor != UX_NULL)
373         {
374 
375             /* Finally we get clock source.  */
376             *csd = descriptor;
377             *clk_numerator = numerator;
378             *clk_denominator = denominator;
379             status = UX_SUCCESS;
380             break;
381         }
382 
383         /* Try to find ClockMultiplier CMD.  */
384         descriptor = _ux_host_class_audio_ac_find(audio,
385                                     UX_CLASS_AUDIO20_AC_CLOCK_MULTIPLIER, id);
386         if (descriptor != UX_NULL)
387         {
388 
389             /* Get numerator, denominator.  */
390 
391             /* Allocate buffer for requests.  */
392             control_buffer =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 4);
393             if (control_buffer == UX_NULL)
394             {
395 
396                 /* Unprotect device control.  */
397                 status = UX_MEMORY_INSUFFICIENT;
398                 break;
399             }
400 
401             /* Protect device control endpoint.  */
402             status = _ux_host_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
403             if (status != UX_SUCCESS)
404             {
405                 status = UX_SEMAPHORE_ERROR;
406                 break;
407             }
408 
409             /* Create a transfer request for the GET_CUR LAYOUT 2 request.  */
410             request -> ux_transfer_request_data_pointer =      control_buffer;
411             request -> ux_transfer_request_requested_length =  2;
412             request -> ux_transfer_request_function =          UX_CLASS_AUDIO20_CUR;
413             request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
414             request -> ux_transfer_request_value =             0 | (UX_CLASS_AUDIO20_CM_NUMERATOR_CONTROL << 8);
415             request -> ux_transfer_request_index =             audio -> ux_host_class_audio_control_interface_number | ((ULONG)id << 8);
416             *(ULONG *)control_buffer = 0;
417             status = _ux_host_stack_transfer_request(request);
418             if ((status != UX_SUCCESS) ||
419                 (request -> ux_transfer_request_actual_length != 2) ||
420                 (*(ULONG *)control_buffer == 0))
421             {
422                 status = UX_TRANSFER_ERROR;
423                 break;
424             }
425 
426             /* Update numerator.  */
427             numerator *= *(ULONG *)control_buffer;
428 
429             /* Protect device control endpoint.  */
430             status = _ux_host_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
431             if (status != UX_SUCCESS)
432             {
433                 status = UX_SEMAPHORE_ERROR;
434                 break;
435             }
436 
437             /* Create a transfer request for the GET_CUR request.  */
438             request -> ux_transfer_request_data_pointer =      control_buffer;
439             request -> ux_transfer_request_requested_length =  2;
440             request -> ux_transfer_request_function =          UX_CLASS_AUDIO20_CUR;
441             request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
442             request -> ux_transfer_request_value =             0 | (UX_CLASS_AUDIO20_CM_DENOMINATOR_CONTROL << 8);
443             request -> ux_transfer_request_index =             audio -> ux_host_class_audio_control_interface_number | ((ULONG)id << 8);
444             *(ULONG *)control_buffer = 0;
445             status = _ux_host_stack_transfer_request(request);
446             if ((status != UX_SUCCESS) ||
447                 (request -> ux_transfer_request_actual_length != 2) ||
448                 (*(ULONG *)control_buffer == 0))
449             {
450                 status = UX_TRANSFER_ERROR;
451                 break;
452             }
453 
454             /* Update denominator.  */
455             denominator *= *(ULONG *)control_buffer;
456 
457             /* Get CMD::bCSourceID @ 4.  */
458             id = descriptor[4];
459 
460             /* Next round of scan.  */
461             scan_round ++;
462             continue;
463         }
464 
465         /* Try to find ClockSelector CSD.  */
466         descriptor = _ux_host_class_audio_ac_find(audio,
467                                     UX_CLASS_AUDIO20_AC_CLOCK_SELECTOR, id);
468         if (descriptor != UX_NULL)
469         {
470 
471             /* Get current selected InPin.  */
472 
473             /* Allocate buffer for requests.  */
474             if (control_buffer == UX_NULL)
475             {
476                 control_buffer =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 4);
477                 if (control_buffer == UX_NULL)
478                 {
479 
480                     /* Unprotect device control.  */
481                     status = UX_MEMORY_INSUFFICIENT;
482                     break;
483                 }
484             }
485 
486             /* Protect device control endpoint.  */
487             status = _ux_host_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
488             if (status != UX_SUCCESS)
489             {
490                 status = UX_SEMAPHORE_ERROR;
491                 break;
492             }
493 
494             /* Create a transfer request for the GET_CUR LAYOUT 1 request.  */
495             request -> ux_transfer_request_data_pointer =      control_buffer;
496             request -> ux_transfer_request_requested_length =  1;
497             request -> ux_transfer_request_function =          UX_CLASS_AUDIO20_CUR;
498             request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
499             request -> ux_transfer_request_value =             0 | (UX_CLASS_AUDIO20_CX_CLOCK_SELECTOR_CONTROL << 8);
500             request -> ux_transfer_request_index =             audio -> ux_host_class_audio_control_interface_number | ((ULONG)id << 8);
501             *(ULONG *)control_buffer = 0;
502             status = _ux_host_stack_transfer_request(request);
503             if ((status != UX_SUCCESS) ||
504                 (request -> ux_transfer_request_actual_length != 1) ||
505                 (*(ULONG *)control_buffer == 0))
506             {
507                 status = UX_TRANSFER_ERROR;
508                 break;
509             }
510 
511             /* Update id from CSD::baCSourceID @ 5.  */
512             id = descriptor[5 + *(ULONG *)control_buffer - 1];
513 
514             /* Next round of scan.  */
515             scan_round ++;
516             continue;
517         }
518 
519         /* Nothing found!!!  */
520         status = UX_DESCRIPTOR_CORRUPTED;
521     } while(status == UX_SUCCESS);
522 
523     /* Free allocated resources.  */
524     if (control_buffer)
525         _ux_utility_memory_free(control_buffer);
526 
527     /* Return with status.  */
528     return(status);
529 }
530 
_ux_host_class_audio20_sam_parse_func(VOID * arg,UCHAR * packed_interface_descriptor,UCHAR * packed_endpoint_descriptor,UCHAR * packed_audio_descriptor)531 static UINT _ux_host_class_audio20_sam_parse_func(VOID *arg,
532                             UCHAR *packed_interface_descriptor,
533                             UCHAR *packed_endpoint_descriptor,
534                             UCHAR *packed_audio_descriptor)
535 {
536 
537 struct UX_HOST_CLASS_AUDIO20_SAM_PARSER         *parser = (struct UX_HOST_CLASS_AUDIO20_SAM_PARSER *)arg;
538 UX_HOST_CLASS_AUDIO                             *audio = parser -> audio;
539 
540 UCHAR                                           *csd;
541 ULONG                                           clk_id, clk_mul = 1, clk_div = 1;
542 UINT                                            status;
543 UX_DEVICE                                       *device;
544 UX_ENDPOINT                                     *endpoint;
545 UX_TRANSFER                                     *transfer;
546 UCHAR                                           *buffer;
547 ULONG                                           n_sub, param_len, offset;
548 UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS    sam_attr;
549 
550     UX_PARAMETER_NOT_USED(packed_endpoint_descriptor);
551 
552     /* Check bInterfaceNumber @ 2 to confirm inside AS.  */
553     if (packed_interface_descriptor[2] !=
554         audio -> ux_host_class_audio_streaming_interface ->
555                     ux_interface_descriptor.bInterfaceNumber)
556         return(0);
557 
558     /* Check bDescriptorType @ 1 to confirm AS CS descriptor.  */
559     if (packed_audio_descriptor[1] != UX_CLASS_AUDIO20_CS_INTERFACE)
560         return(0);
561 
562     /* Check bDescriptorSubType@2 to confirm AS_HEADER.  */
563     if (packed_audio_descriptor[2] == UX_CLASS_AUDIO20_AS_GENERAL)
564     {
565 
566         /* Save AS_HEADER for future use.  */
567         parser -> as_header = packed_audio_descriptor;
568         return(0);
569     }
570 
571     /* Check bDescriptorSubType@2, bFormatType@3 to confirm FORMAT_TYPE_I.  */
572     if (packed_audio_descriptor[2] != UX_CLASS_AUDIO20_AS_FORMAT_TYPE)
573         return(0);
574     if (packed_audio_descriptor[3] != UX_CLASS_AUDIO20_FORMAT_TYPE_I)
575         return(0);
576 
577     /* Save FORMAT_TYPE_I::bBitResolution@5.  */
578     sam_attr.ux_host_class_audio_sampling_characteristics_resolution = packed_audio_descriptor[5];
579 
580     /* If AS_HEADER is not ready, fail.  */
581     if (parser -> as_header == UX_NULL)
582     {
583         parser -> status = UX_DESCRIPTOR_CORRUPTED;
584         return(1);
585     }
586 
587     /* Check AS_HEADER::bTerminalLink@3 to find frequencies.  */
588     status = _ux_host_class_audio20_clock_get(audio, parser -> as_header[3],
589                                                 &csd, &clk_mul, &clk_div);
590     if (status != UX_SUCCESS)
591     {
592         parser -> status = status;
593         return(1);
594     }
595 
596     /* Get CSD::bClockID@3.  */
597     clk_id = csd[3];
598 
599     /* Issue GET_RANGE to get sampling frequency.  */
600 
601     /* Get device, endpoint, transfer.  */
602     device = audio -> ux_host_class_audio_device;
603     endpoint = &device -> ux_device_control_endpoint;
604     transfer = &endpoint -> ux_endpoint_transfer_request;
605 
606     /* Allocate buffer for GET_RANGE.  */
607     buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, 2);
608     if (buffer == UX_NULL)
609     {
610         parser -> status = UX_MEMORY_INSUFFICIENT;
611         return(1);
612     }
613 
614     /* Protect control transfer.  */
615     parser -> status = _ux_host_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
616     if (parser -> status != UX_SUCCESS)
617     {
618         _ux_utility_memory_free(buffer);
619         return(1);
620     }
621 
622     /* Issue GET_RANGE request.  */
623     transfer -> ux_transfer_request_data_pointer =     buffer;
624     transfer -> ux_transfer_request_requested_length = 2;
625     transfer -> ux_transfer_request_function =         UX_CLASS_AUDIO20_RANGE;
626     transfer -> ux_transfer_request_type =             UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
627     transfer -> ux_transfer_request_value =            0 | (UX_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8);
628     transfer -> ux_transfer_request_index =            audio -> ux_host_class_audio_control_interface_number | (clk_id << 8);
629     parser -> status = _ux_host_stack_transfer_request(transfer);
630 
631     /* Get wNumSubRanges.  */
632     n_sub = (ULONG)(*(USHORT *)buffer);
633     _ux_utility_memory_free(buffer);
634 
635     /* Check errors.  */
636     if (parser -> status != UX_SUCCESS)
637         return(1);
638     if (n_sub == 0)
639     {
640         parser -> status = UX_TRANSFER_ERROR;
641         return(1);
642     }
643 
644     /* Calculate parameter length, with overflow check.  */
645     param_len = n_sub * (4 * 3);
646     if (param_len > 0xFFFF)
647     {
648         parser -> status = UX_MATH_OVERFLOW;
649         return(1);
650     }
651     param_len += 2;
652     if (param_len > 0xFFFF)
653     {
654         parser -> status = UX_MATH_OVERFLOW;
655         return(1);
656     }
657 
658     /* Allocate buffer for GET_RANGE.  */
659     buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, param_len);
660     if (buffer == UX_NULL)
661     {
662         parser -> status = UX_MEMORY_INSUFFICIENT;
663         return(1);
664     }
665 
666     /* Protect control transfer.  */
667     parser -> status = _ux_host_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
668     if (parser -> status != UX_SUCCESS)
669     {
670         _ux_utility_memory_free(buffer);
671         return(1);
672     }
673 
674     /* Issue GET_RANGE request.  */
675     transfer -> ux_transfer_request_data_pointer =     buffer;
676     transfer -> ux_transfer_request_requested_length = param_len;
677     transfer -> ux_transfer_request_function =         UX_CLASS_AUDIO20_RANGE;
678     transfer -> ux_transfer_request_type =             UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
679     transfer -> ux_transfer_request_value =            0 | (UX_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8);
680     transfer -> ux_transfer_request_index =            audio -> ux_host_class_audio_control_interface_number | (clk_id << 8);
681     parser -> status = _ux_host_stack_transfer_request(transfer);
682     if (parser -> status != UX_SUCCESS)
683     {
684         _ux_utility_memory_free(buffer);
685         return(1);
686     }
687 
688     /* Save AS_HEADER::bNrChannels@10.  */
689     sam_attr.ux_host_class_audio_sampling_characteristics_channels = parser -> as_header[10];
690 
691     /* Save CSD.  */
692     sam_attr.ux_host_class_audio_sampling_characteristics_descriptor = csd;
693 
694     /* Parse ranges.  */
695     for (offset = 2; offset < param_len; offset += (4*3))
696     {
697 
698         /* Save dMIN, dMAX.  */
699         sam_attr.ux_host_class_audio_sampling_characteristics_frequency_low =
700                                     _ux_utility_long_get(buffer + offset);
701         sam_attr.ux_host_class_audio_sampling_characteristics_frequency_high =
702                                     _ux_utility_long_get(buffer + offset + 4);
703 
704         /* Save MUL, DIV.  */
705         sam_attr.ux_host_class_audio_sampling_characteristics_clock_mul = clk_mul;
706         sam_attr.ux_host_class_audio_sampling_characteristics_clock_div = clk_div;
707 
708         /* Parse frequency.  */
709         status = parser -> parse_function(parser -> arg, packed_interface_descriptor, &sam_attr);
710         if (status)
711         {
712             _ux_utility_memory_free(buffer);
713             return(status);
714         }
715     }
716     _ux_utility_memory_free(buffer);
717 
718     /* Continue parsing.  */
719     return(0);
720 }
_ux_host_class_audio20_sampling_parse(UX_HOST_CLASS_AUDIO * audio,UINT (* parse_function)(VOID * arg,UCHAR * packed_interface_descriptor,UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS * sam_attr),VOID * arg)721 static inline UINT _ux_host_class_audio20_sampling_parse(UX_HOST_CLASS_AUDIO *audio,
722         UINT(*parse_function)(VOID  *arg,
723                               UCHAR *packed_interface_descriptor,
724                               UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr),
725         VOID* arg)
726 {
727 struct UX_HOST_CLASS_AUDIO20_SAM_PARSER parser;
728 UINT                                    status;
729 
730     /* Run parse process.  */
731     parser.parse_function = parse_function;
732     parser.arg = arg;
733     parser.audio = audio;
734     parser.as_header = UX_NULL;
735     parser.status = UX_SUCCESS;
736     status = _ux_host_class_audio_descriptors_parse(audio,
737                     _ux_host_class_audio20_sam_parse_func, (VOID *)&parser);
738 
739     /* Return parser status.  */
740     if (status == UX_SUCCESS)
741         return(parser.status);
742 
743     /* Return parsing error status.  */
744     return(status);
745 }
746 #endif /* defined(UX_HOST_CLASS_AUDIO_2_SUPPORT) */
747 
748 
749 /**************************************************************************/
750 /*                                                                        */
751 /*  FUNCTION                                               RELEASE        */
752 /*                                                                        */
753 /*    _uxe_host_class_audio_raw_sampling_parse            PORTABLE C      */
754 /*                                                           6.3.0        */
755 /*  AUTHOR                                                                */
756 /*                                                                        */
757 /*    Chaoqiong Xiao, Microsoft Corporation                               */
758 /*                                                                        */
759 /*  DESCRIPTION                                                           */
760 /*                                                                        */
761 /*    This function checks errors in audio RAW sampling parse function    */
762 /*    call.                                                               */
763 /*                                                                        */
764 /*  INPUT                                                                 */
765 /*                                                                        */
766 /*    audio                                 Pointer to audio control (AC) */
767 /*                                          instance                      */
768 /*    callback_function                     Callback function invoked on  */
769 /*                                          interrupt message reception   */
770 /*    arg                                   Callback argument passed to   */
771 /*                                          callback function             */
772 /*                                                                        */
773 /*  OUTPUT                                                                */
774 /*                                                                        */
775 /*    Status                                                              */
776 /*                                                                        */
777 /*  CALLS                                                                 */
778 /*                                                                        */
779 /*    _ux_host_class_audio_raw_sampling_parse                             */
780 /*                                          Parse RAW sampling properties */
781 /*                                                                        */
782 /*  CALLED BY                                                             */
783 /*                                                                        */
784 /*    Application                                                         */
785 /*                                                                        */
786 /*  RELEASE HISTORY                                                       */
787 /*                                                                        */
788 /*    DATE              NAME                      DESCRIPTION             */
789 /*                                                                        */
790 /*  10-31-2023     Chaoqiong Xiao           Initial Version 6.3.0         */
791 /*                                                                        */
792 /**************************************************************************/
_uxe_host_class_audio_raw_sampling_parse(UX_HOST_CLASS_AUDIO * audio,UINT (* parse_function)(VOID * arg,UCHAR * packed_interface_descriptor,UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS * sam_attr),VOID * arg)793 UINT _uxe_host_class_audio_raw_sampling_parse(UX_HOST_CLASS_AUDIO *audio,
794         UINT(*parse_function)(VOID  *arg,
795                               UCHAR *packed_interface_descriptor,
796                               UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr),
797         VOID* arg)
798 {
799 
800     /* Sanity checks.  */
801     if ((audio == UX_NULL) || (parse_function == UX_NULL))
802         return(UX_INVALID_PARAMETER);
803 
804     /* Invoke sampling characteristics parse function.  */
805     return(_ux_host_class_audio_raw_sampling_parse(audio, parse_function, arg));
806 }
807