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