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