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_get PORTABLE C */
37 /* 6.1.12 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function obtains 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_mutex_on Get mutex */
71 /* _ux_host_mutex_off Release mutex */
72 /* _ux_utility_memory_allocate Allocate memory block */
73 /* _ux_utility_memory_free Release memory block */
74 /* _ux_utility_short_get Read 16-bit value */
75 /* */
76 /* CALLED BY */
77 /* */
78 /* Audio Class */
79 /* */
80 /* RELEASE HISTORY */
81 /* */
82 /* DATE NAME DESCRIPTION */
83 /* */
84 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
85 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
86 /* resulting in version 6.1 */
87 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
88 /* refined macros names, */
89 /* resulting in version 6.1.10 */
90 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
91 /* fixed standalone compile, */
92 /* resulting in version 6.1.11 */
93 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
94 /* added audio 2.0 support, */
95 /* protect reentry with mutex, */
96 /* fixed error return code, */
97 /* fixed EP0 protection, */
98 /* supported more selectors, */
99 /* resulting in version 6.1.12 */
100 /* */
101 /**************************************************************************/
_ux_host_class_audio_control_value_get(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_CONTROL * audio_control)102 UINT _ux_host_class_audio_control_value_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_CONTROL *audio_control)
103 {
104 #if defined(UX_HOST_CLASS_AUDIO_DISABLE_CONTROLS)
105 UX_PARAMETER_NOT_USED(audio);
106 UX_PARAMETER_NOT_USED(audio_control);
107 return(UX_FUNCTION_NOT_SUPPORTED);
108 #else
109
110 UX_ENDPOINT *control_endpoint;
111 UX_TRANSFER *transfer_request;
112 UINT status;
113 UCHAR * control_buffer;
114
115 /* If trace is enabled, insert this event into the trace buffer. */
116 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_AUDIO_CONTROL_VALUE_GET, audio, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
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 /* Need to allocate memory for the control_buffer. */
139 control_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 4);
140 if (control_buffer == UX_NULL)
141 {
142
143 /* Unprotect thread reentry to this instance. */
144 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
145
146 /* Return error. */
147 return(UX_MEMORY_INSUFFICIENT);
148 }
149
150 /* Protect the control endpoint semaphore here. It will be unprotected in the
151 transfer request function. */
152 status = _ux_host_semaphore_get(&audio -> ux_host_class_audio_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
153
154 /* Check for status. */
155 if (status != UX_SUCCESS)
156 {
157
158 /* Something went wrong. */
159 _ux_utility_memory_free(control_buffer);
160 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
161 return(status);
162 }
163
164 /* The buffer should be aligned. Returned data is little endian so DWord can be used
165 to copy any returned data of BYTE/WORD/DWORD. */
166 * (ULONG *)control_buffer = 0;
167
168 /* Create a transfer request for the GET_CUR_buffer request. */
169 transfer_request -> ux_transfer_request_data_pointer = control_buffer;
170 transfer_request -> ux_transfer_request_requested_length = 4;
171 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
172 transfer_request -> ux_transfer_request_function = (_ux_host_class_audio_protocol_get(audio) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_02_00) ?
173 UX_CLASS_AUDIO20_CUR :
174 UX_HOST_CLASS_AUDIO_GET_CUR;
175 #else
176 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_AUDIO_GET_CUR;
177 #endif
178 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
179 transfer_request -> ux_transfer_request_value = audio_control -> ux_host_class_audio_control_channel | (audio_control -> ux_host_class_audio_control << 8);
180 transfer_request -> ux_transfer_request_index = audio -> ux_host_class_audio_control_interface_number | (audio -> ux_host_class_audio_feature_unit_id << 8);
181
182 /* Send request to HCD layer. */
183 status = _ux_host_stack_transfer_request(transfer_request);
184
185 /* Check for correct transfer and entire control buffer returned. */
186 if (status == UX_SUCCESS)
187 {
188
189 /* Update the CUR static value for the caller. */
190 audio_control -> ux_host_class_audio_control_cur = _ux_utility_long_get(control_buffer);
191 }
192
193 /* Free all used resources. */
194 _ux_utility_memory_free(control_buffer);
195
196 /* Unprotect thread reentry to this instance. */
197 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
198
199 /* Return completion status. */
200 return(status);
201 #endif
202 }
203
204
205 /**************************************************************************/
206 /* */
207 /* FUNCTION RELEASE */
208 /* */
209 /* _uxe_host_class_audio_control_value_get PORTABLE C */
210 /* 6.3.0 */
211 /* AUTHOR */
212 /* */
213 /* Chaoqiong Xiao, Microsoft Corporation */
214 /* */
215 /* DESCRIPTION */
216 /* */
217 /* This function checks errors in audio control value get function */
218 /* call. */
219 /* */
220 /* INPUT */
221 /* */
222 /* audio Pointer to audio class */
223 /* audio_control Pointer to audio control */
224 /* */
225 /* OUTPUT */
226 /* */
227 /* Status */
228 /* */
229 /* CALLS */
230 /* */
231 /* _uxe_host_class_audio_control_value_get */
232 /* Get audio control value */
233 /* */
234 /* CALLED BY */
235 /* */
236 /* Application */
237 /* */
238 /* RELEASE HISTORY */
239 /* */
240 /* DATE NAME DESCRIPTION */
241 /* */
242 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
243 /* */
244 /**************************************************************************/
_uxe_host_class_audio_control_value_get(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_CONTROL * audio_control)245 UINT _uxe_host_class_audio_control_value_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_CONTROL *audio_control)
246 {
247
248 if ((audio == UX_NULL) || (audio_control == UX_NULL))
249 return(UX_INVALID_PARAMETER);
250
251 /* Invoke audio control get function. */
252 return(_ux_host_class_audio_control_value_get(audio, audio_control));
253 }
254