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