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 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_audio_descriptors_parse PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function parsees all interface descriptors and their audio */
46 /* class specific descriptors relates to current audio instance. */
47 /* */
48 /* The function scans the device configuration descriptor. Once the */
49 /* interface descriptors of the audio instance are found, each audio */
50 /* class descriptors belong to the interface are passed to parse */
51 /* function for caller one by one to parse. The interface descriptor */
52 /* is also passed to provide more information. Another pointer to */
53 /* arguments is also available as parse function parameter for caller */
54 /* to pass necessary caller specific data to process in parse function.*/
55 /* */
56 /* The descriptor parsing can be terminated by returning non-zero */
57 /* code in parse function. */
58 /* */
59 /* INPUT */
60 /* */
61 /* audio Pointer to audio instance */
62 /* parse_function Parse function for each */
63 /* audio class descriptor */
64 /* arg Parse function argument */
65 /* */
66 /* OUTPUT */
67 /* */
68 /* Completion Status */
69 /* */
70 /* CALLS */
71 /* */
72 /* CALLED BY */
73 /* */
74 /* Audio Class */
75 /* Application */
76 /* */
77 /* RELEASE HISTORY */
78 /* */
79 /* DATE NAME DESCRIPTION */
80 /* */
81 /* 07-29-2022 Chaoqiong Xiao Initial Version 6.1.12 */
82 /* */
83 /**************************************************************************/
_ux_host_class_audio_descriptors_parse(UX_HOST_CLASS_AUDIO * audio,UINT (* parse_function)(VOID * arg,UCHAR * packed_interface_descriptor,UCHAR * packed_endpoint_descriptor,UCHAR * packed_audio_descriptor),VOID * arg)84 UINT _ux_host_class_audio_descriptors_parse(UX_HOST_CLASS_AUDIO *audio,
85 UINT(*parse_function)(VOID *arg,
86 UCHAR *packed_interface_descriptor,
87 UCHAR *packed_endpoint_descriptor,
88 UCHAR *packed_audio_descriptor),
89 VOID* arg)
90 {
91
92 UCHAR *descriptor;
93 UCHAR *interface_descriptor;
94 UCHAR *endpoint_descriptor;
95 ULONG ac_interface, as_interface;
96 ULONG total_descriptor_length;
97 ULONG descriptor_length;
98 ULONG descriptor_type;
99 UINT status;
100
101
102 /* Ensure the instance is valid. */
103 if (_ux_host_stack_class_instance_verify(_ux_system_host_class_audio_name, (VOID *) audio) != UX_SUCCESS)
104 {
105
106 /* Error trap. */
107 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
108
109 /* If trace is enabled, insert this event into the trace buffer. */
110 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
111 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
112 }
113
114 /* Device state check. */
115 if (audio -> ux_host_class_audio_device -> ux_device_state != UX_DEVICE_CONFIGURED)
116 return(UX_INVALID_STATE);
117
118 /* Get the descriptor to the selected format. */
119 descriptor = audio -> ux_host_class_audio_configuration_descriptor;
120 total_descriptor_length = audio -> ux_host_class_audio_configuration_descriptor_length;
121
122 /* Get target interface number of control/streaming. */
123 ac_interface = audio -> ux_host_class_audio_control_interface_number;
124 as_interface = audio -> ux_host_class_audio_streaming_interface -> ux_interface_descriptor.bInterfaceNumber;
125
126 /* Haven't found interface, endpoint yet. */
127 interface_descriptor = UX_NULL;
128 endpoint_descriptor = UX_NULL;
129
130 /* Scan the descriptor for the Audio Control/Streaming interface. */
131 while (total_descriptor_length)
132 {
133
134 /* Gather the length, type and subtype of the descriptor. */
135 descriptor_length = *descriptor;
136 descriptor_type = *(descriptor + 1);
137
138 /* Make sure this descriptor has at least the minimum length. */
139 if (descriptor_length < 3)
140 return(UX_DESCRIPTOR_CORRUPTED);
141
142 /* Process relative to descriptor type. */
143 switch (descriptor_type)
144 {
145
146 case UX_INTERFACE_DESCRIPTOR_ITEM:
147
148 /* Ensure we have the correct interface for Audio Control/Streaming. */
149 if (descriptor[2] == ac_interface || descriptor[2] == as_interface)
150 {
151
152 /* Mark we have found it. */
153 interface_descriptor = descriptor;
154 }
155 else
156 {
157
158 /* Haven't found it. */
159 interface_descriptor = UX_NULL;
160 }
161 break;
162
163 case UX_ENDPOINT_DESCRIPTOR_ITEM:
164
165 /* Log endpoint descriptor for following CS_ENDPOINT. */
166 endpoint_descriptor = descriptor;
167 break;
168
169 case UX_HOST_CLASS_AUDIO_CS_ENDPOINT:
170 case UX_HOST_CLASS_AUDIO_CS_INTERFACE:
171
172 /* Have we found the audio interface yet? */
173 if (interface_descriptor != UX_NULL)
174 {
175
176 /* Yes, parse the audio specific descriptor. */
177 status = parse_function(arg, interface_descriptor, endpoint_descriptor, descriptor);
178
179 /* Terminate the parsing if status is not 0. */
180 if (status)
181 {
182
183 /* Parsing terminated by user, it's OK. */
184 return(UX_SUCCESS);
185 }
186 }
187 break;
188
189 default:
190 break;
191 }
192
193 /* Verify if the descriptor is still valid. */
194 if (descriptor_length > total_descriptor_length)
195 return(UX_DESCRIPTOR_CORRUPTED);
196
197 /* Jump to the next descriptor if we have not reached the end. */
198 descriptor += descriptor_length;
199
200 /* And adjust the length left to parse in the descriptor. */
201 total_descriptor_length -= descriptor_length;
202 }
203
204 /* We get here when all descriptors scanned. */
205 return(UX_SUCCESS);
206 }
207