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_control_get PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function obtains the static feature values for a single audio */
46 /* control on either the master channel or a specific channel. */
47 /* */
48 /* Note only control value of BYTE, WORD and DWORD (<4) is supported. */
49 /* E.g., Graphic Equalizer Control is not supported. */
50 /* */
51 /* Note only first RANGE of a list is returned. */
52 /* */
53 /* Note it's not recommended for supporting audio device with complex */
54 /* pinout scheme, where ux_host_class_audio_descriptors_parse can be */
55 /* used to build audio pinout scheme, and settings can be changed by */
56 /* ux_host_class_audio_control_request or ux_host_class_audio_feature */
57 /* functions. */
58 /* */
59 /* INPUT */
60 /* */
61 /* audio Pointer to audio class */
62 /* audio_control Pointer to audio control */
63 /* */
64 /* OUTPUT */
65 /* */
66 /* Completion Status */
67 /* */
68 /* CALLS */
69 /* */
70 /* _ux_host_stack_class_instance_verify Verify instance is valid */
71 /* _ux_host_stack_transfer_request Process transfer request */
72 /* _ux_host_semaphore_get Get semaphore */
73 /* _ux_host_semaphore_put Release semaphore */
74 /* _ux_host_mutex_on Get mutex */
75 /* _ux_host_mutex_off Release mutex */
76 /* _ux_utility_memory_allocate Allocate memory block */
77 /* _ux_utility_memory_free Release memory block */
78 /* _ux_utility_short_get Read 16-bit value */
79 /* */
80 /* CALLED BY */
81 /* */
82 /* Application */
83 /* Audio Class */
84 /* */
85 /* RELEASE HISTORY */
86 /* */
87 /* DATE NAME DESCRIPTION */
88 /* */
89 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
90 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
91 /* resulting in version 6.1 */
92 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
93 /* refined macros names, */
94 /* resulting in version 6.1.10 */
95 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
96 /* fixed standalone compile, */
97 /* resulting in version 6.1.11 */
98 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
99 /* added audio 2.0 support, */
100 /* protect reentry with mutex, */
101 /* resulting in version 6.1.12 */
102 /* */
103 /**************************************************************************/
_ux_host_class_audio_control_get(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_CONTROL * audio_control)104 UINT _ux_host_class_audio_control_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_CONTROL *audio_control)
105 {
106 #if defined(UX_HOST_CLASS_AUDIO_DISABLE_CONTROLS)
107 UX_PARAMETER_NOT_USED(audio);
108 UX_PARAMETER_NOT_USED(audio_control);
109 return(UX_FUNCTION_NOT_SUPPORTED);
110 #else
111
112 UX_ENDPOINT *control_endpoint;
113 UX_TRANSFER *transfer_request;
114 UINT status;
115 UCHAR * control_buffer;
116
117
118 /* Ensure the instance is valid. */
119 if (_ux_host_stack_class_instance_verify(_ux_system_host_class_audio_name, (VOID *) audio) != UX_SUCCESS)
120 {
121
122 /* Error trap. */
123 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
124
125 /* If trace is enabled, insert this event into the trace buffer. */
126 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
127
128 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
129 }
130
131 /* Protect thread reentry to this instance. */
132 _ux_host_mutex_on(&audio -> ux_host_class_audio_mutex);
133
134 /* We need to get the default control endpoint transfer request pointer. */
135 control_endpoint = &audio -> ux_host_class_audio_device -> ux_device_control_endpoint;
136 transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
137
138 /* Protect the control endpoint semaphore here. It will be unprotected in the
139 transfer request function. */
140 status = _ux_host_semaphore_get(&audio -> ux_host_class_audio_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
141
142 /* Check for status. */
143 if (status != UX_SUCCESS)
144 {
145
146 /* Something went wrong. */
147 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
148 return(status);
149 }
150
151 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
152 if (_ux_host_class_audio_protocol_get(audio) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_02_00)
153 {
154 /* Size RANGE Size
155 D1..0: Mute 1 2+1*3=5
156 D3..2: Volume 2 2+2*3=8
157 D5..4: Bass 1
158 D7..6: Mid 1
159 D9..8: Treble 1
160 D11..10: Graphic Equalizer 4+NrBits
161 D13..12: Automatic Gain 1
162 D15..14: Delay 4 2+4*3=14
163 D17..16: Bass Boost 1
164 D19..18: Loudness 1
165 D21..20: Input Gain 2
166 D23..22: Input Gain Pad 2
167 D25..24: Phase Inverter 1
168 D27..26: Underflow 1
169 D29..28: Overflow 1
170 */
171
172 /* Need to allocate enough memory for the control buffer. */
173 control_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 16);
174 if (control_buffer == UX_NULL)
175 {
176
177 /* Return an error. */
178 _ux_host_semaphore_put(&audio -> ux_host_class_audio_device -> ux_device_protection_semaphore);
179 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
180 return(UX_MEMORY_INSUFFICIENT);
181 }
182
183 /* Create a transfer request for the GET RANGE request. */
184 transfer_request -> ux_transfer_request_data_pointer = control_buffer;
185 transfer_request -> ux_transfer_request_requested_length = 16;
186 transfer_request -> ux_transfer_request_function = UX_CLASS_AUDIO20_RANGE;
187 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
188 transfer_request -> ux_transfer_request_value = audio_control -> ux_host_class_audio_control_channel | (audio_control -> ux_host_class_audio_control << 8);
189 transfer_request -> ux_transfer_request_index = audio -> ux_host_class_audio_control_interface_number | (audio -> ux_host_class_audio_feature_unit_id << 8);
190
191 /* Send request to HCD layer. */
192 status = _ux_host_stack_transfer_request(transfer_request);
193
194 /* Check request status code. */
195 if (status == UX_SUCCESS)
196 {
197
198 /* Check returned length for parameter layouts. */
199 switch(transfer_request -> ux_transfer_request_actual_length)
200 {
201
202 /* Layout 3: wNumSubranges, dMIN, dMAX, dRES. */
203 case 14:
204 audio_control -> ux_host_class_audio_control_min = _ux_utility_long_get(control_buffer + 2);
205 audio_control -> ux_host_class_audio_control_max = _ux_utility_long_get(control_buffer + 6);
206 audio_control -> ux_host_class_audio_control_res = _ux_utility_long_get(control_buffer + 10);
207 break;
208
209 /* Layout 2: wNumSubranges, wMIN, wMAX, wRES. */
210 case 8:
211 audio_control -> ux_host_class_audio_control_min = _ux_utility_short_get(control_buffer + 2);
212 audio_control -> ux_host_class_audio_control_max = _ux_utility_short_get(control_buffer + 4);
213 audio_control -> ux_host_class_audio_control_res = _ux_utility_short_get(control_buffer + 6);
214 break;
215
216 /* Layout 1: wNumSubranges, bMIN, bMAX, bRES. */
217 case 5:
218 audio_control -> ux_host_class_audio_control_min = *(control_buffer + 2);
219 audio_control -> ux_host_class_audio_control_max = *(control_buffer + 3);
220 audio_control -> ux_host_class_audio_control_res = *(control_buffer + 4);
221 break;
222
223 /* Invalid data. */
224 default:
225 status = UX_ERROR;
226 break;
227 }
228 }
229 }
230 else
231 #endif
232 {
233
234 /* Size
235 D0: Mute 1
236 D1: Volume 2
237 D2: Bass 1
238 D3: Mid 1
239 D4: Treble 1
240 D5: Graphic Equalizer 4+NrBits
241 D6: Automatic Gain 1
242 D7: Delay 2
243 D8: Bass Boost 1
244 D9: Loudness 1
245 */
246
247 /* Need to allocate memory for the control buffer. */
248 control_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 4);
249 if (control_buffer == UX_NULL)
250 {
251
252 /* Return an error. */
253 _ux_host_semaphore_put(&audio -> ux_host_class_audio_device -> ux_device_protection_semaphore);
254 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
255 return(UX_MEMORY_INSUFFICIENT);
256 }
257
258 /* The buffer should be aligned. Returned data is little endian so DWord can be used
259 to copy any returned data of BYTE/WORD/DWORD. */
260
261 /* Create a transfer request for the GET_MIN request. */
262 transfer_request -> ux_transfer_request_data_pointer = control_buffer;
263 transfer_request -> ux_transfer_request_requested_length = 4;
264 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
265 transfer_request -> ux_transfer_request_value = audio_control -> ux_host_class_audio_control_channel | (audio_control -> ux_host_class_audio_control << 8);
266 transfer_request -> ux_transfer_request_index = audio -> ux_host_class_audio_control_interface_number | (audio -> ux_host_class_audio_feature_unit_id << 8);
267 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_AUDIO_GET_MIN;
268
269 /* Send request to HCD layer. */
270 * (ULONG *)control_buffer = 0;
271 status = _ux_host_stack_transfer_request(transfer_request);
272
273 /* Check for correct transfer and entire control buffer returned.
274 * Start GET_MAX request. */
275 if (status == UX_SUCCESS)
276 {
277
278 /* Update the MIN static value for the caller. */
279 audio_control -> ux_host_class_audio_control_min = _ux_utility_long_get(control_buffer);
280
281 /* Protect the control endpoint semaphore here. It will be unprotected in the
282 transfer request function. */
283 status = _ux_host_semaphore_get(&audio -> ux_host_class_audio_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
284 if (status != UX_SUCCESS)
285 {
286 _ux_utility_memory_free(control_buffer);
287 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
288 return(status);
289 }
290
291 /* Create a transfer request for the GET_MAX request. */
292 transfer_request -> ux_transfer_request_data_pointer = control_buffer;
293 transfer_request -> ux_transfer_request_requested_length = 4;
294 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
295 transfer_request -> ux_transfer_request_value = audio_control -> ux_host_class_audio_control_channel | (audio_control -> ux_host_class_audio_control << 8);
296 transfer_request -> ux_transfer_request_index = audio -> ux_host_class_audio_control_interface_number | (audio -> ux_host_class_audio_feature_unit_id << 8);
297 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_AUDIO_GET_MAX;
298
299 /* Send request to HCD layer. */
300 * (ULONG *)control_buffer = 0;
301 status = _ux_host_stack_transfer_request(transfer_request);
302 }
303
304 /* Check for correct transfer and entire control buffer returned.
305 * Start GET_RES request. */
306 if (status == UX_SUCCESS)
307 {
308
309 /* Update the MAX static value for the caller. */
310 audio_control -> ux_host_class_audio_control_max = _ux_utility_long_get(control_buffer);
311
312 /* Protect the control endpoint semaphore here. It will be unprotected in the
313 transfer request function. */
314 status = _ux_host_semaphore_get(&audio -> ux_host_class_audio_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
315 if (status != UX_SUCCESS)
316 {
317 _ux_utility_memory_free(control_buffer);
318 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
319 return(status);
320 }
321
322 /* Create a transfer request for the GET_RES request. */
323 transfer_request -> ux_transfer_request_data_pointer = control_buffer;
324 transfer_request -> ux_transfer_request_requested_length = 4;
325 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
326 transfer_request -> ux_transfer_request_value = audio_control -> ux_host_class_audio_control_channel | (audio_control -> ux_host_class_audio_control << 8);
327 transfer_request -> ux_transfer_request_index = audio -> ux_host_class_audio_control_interface_number | (audio -> ux_host_class_audio_feature_unit_id << 8);
328 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_AUDIO_GET_RES;
329
330 /* Send request to HCD layer. */
331 * (ULONG *)control_buffer = 0;
332 status = _ux_host_stack_transfer_request(transfer_request);
333 }
334
335 /* Check for correct transfer and entire control buffer returned. */
336 if (status == UX_SUCCESS)
337 {
338
339 /* Update the RES static value for the caller. */
340 audio_control -> ux_host_class_audio_control_res = _ux_utility_long_get(control_buffer);
341 }
342 }
343
344 /* Free all used resources. */
345 _ux_utility_memory_free(control_buffer);
346
347 /* Unprotect thread reentry to this instance. */
348 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
349
350 /* Return completion status. */
351 return(status);
352 #endif
353 }
354