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