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