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 /** USBX Component */
16 /** */
17 /** Device Audio Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define UX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "ux_api.h"
28 #include "ux_device_class_audio.h"
29 #include "ux_device_class_audio10.h"
30 #include "ux_device_stack.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_device_class_audio10_control_process PORTABLE C */
38 /* 6.2.1 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function manages the based sent by the host on the control */
46 /* endpoints with a CLASS or VENDOR SPECIFIC type. */
47 /* */
48 /* INPUT */
49 /* */
50 /* audio Address of audio class */
51 /* instance */
52 /* transfer Address of transfer request */
53 /* instance */
54 /* group Request process data */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* Completion Status */
59 /* */
60 /* CALLS */
61 /* */
62 /* _ux_utility_short_get Get 2-byte value from buffer */
63 /* _ux_utility_short_put Put 2-byte value to buffer */
64 /* _ux_device_stack_transfer_request Issue a transfer request */
65 /* _ux_device_stack_endpoint_stall Endpoint stall */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* Application */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
76 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
77 /* resulting in version 6.1 */
78 /* 04-02-2021 Chaoqiong Xiao Modified comment(s), */
79 /* added volume RES support, */
80 /* resulting in version 6.1.6 */
81 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
82 /* internal clean up, */
83 /* resulting in version 6.1.11 */
84 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
85 /* added sampling control, */
86 /* resulting in version 6.1.12 */
87 /* 03-08-2023 Chaoqiong Xiao Modified comment(s), */
88 /* fixed a macro name, */
89 /* resulting in version 6.2.1 */
90 /* */
91 /**************************************************************************/
_ux_device_class_audio10_control_process(UX_DEVICE_CLASS_AUDIO * audio,UX_SLAVE_TRANSFER * transfer,UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP * group)92 UINT _ux_device_class_audio10_control_process(UX_DEVICE_CLASS_AUDIO *audio,
93 UX_SLAVE_TRANSFER *transfer, UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP *group)
94 {
95
96 UX_SLAVE_ENDPOINT *endpoint;
97 UX_DEVICE_CLASS_AUDIO10_CONTROL *control;
98 UCHAR request;
99 UCHAR request_type;
100 UCHAR unit_id, ep_addr;
101 UCHAR control_selector;
102 UCHAR channel_number;
103 ULONG request_length;
104 UCHAR *desc;
105 ULONG sam, min, max, pos;
106 ULONG i;
107
108
109 /* Get instances. */
110 endpoint = &audio -> ux_device_class_audio_device -> ux_slave_device_control_endpoint;
111 transfer = &endpoint -> ux_slave_endpoint_transfer_request;
112
113 /* Extract all necessary fields of the request. */
114 request = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_REQUEST);
115 request_type = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_REQUEST_TYPE);
116 unit_id = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_ENEITY_ID);
117 ep_addr = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_ENDPOINT);
118 control_selector = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_CONTROL_SELECTOR);
119 channel_number = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_CHANNEL_NUMBER);
120 request_length = _ux_utility_short_get(transfer -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
121
122 /* Process controls one by one. */
123 for (i = 0; i < group -> ux_device_class_audio10_control_group_controls_nb; i ++)
124 {
125 control = &group -> ux_device_class_audio10_control_group_controls[i];
126
127 /* Reset change map. */
128 control -> ux_device_class_audio10_control_changed = 0;
129
130 /* We handle endpoint requests. */
131 if ((request_type & UX_REQUEST_TARGET) == UX_REQUEST_TARGET_ENDPOINT &&
132 ep_addr == control -> ux_device_class_audio10_control_ep_addr)
133 {
134
135 /* Handle the request. */
136 switch(request)
137 {
138 case UX_DEVICE_CLASS_AUDIO10_SET_CUR:
139
140 /* Only sampling frequency control is supported. */
141 if (control_selector != UX_DEVICE_CLASS_AUDIO10_EP_SAMPLING_FREQ_CONTROL)
142 break;
143
144 /* Length check. */
145 if (request_length != 3)
146 break;
147
148 /* If frequencies not specified, no modification accepted. */
149 if (control -> ux_device_class_audio10_control_sam_freq_types == UX_NULL)
150 return(UX_SUCCESS);
151
152 /* Check sampling frequency types (UAC 1.0 Format Type I : bSamFreqType ..) for MIN and MAX. */
153 desc = control -> ux_device_class_audio10_control_sam_freq_types;
154 if (desc[0] == 0)
155 {
156 min = ((ULONG)desc[1]) | ((ULONG)desc[2] << 8) | ((ULONG)desc[3] << 16);
157 max = ((ULONG)desc[4]) | ((ULONG)desc[5] << 8) | ((ULONG)desc[6] << 16);
158 }
159 else
160 {
161 min = 0xFFFFFFFF;
162 max = 0x00000000;
163 for (pos = 1;
164 pos < (ULONG)desc[0] * 3 + 1; /* Calculate from byte, no overflow. */
165 pos += 3)
166 {
167 sam = (ULONG)desc[pos + 0] | ((ULONG)desc[pos + 1] << 8) | ((ULONG)desc[pos + 2] << 16);
168 if (sam > max)
169 max = sam;
170 if (sam < min)
171 min = sam;
172 }
173 }
174
175 /* Accept frequency any way.
176 * If it's not in range, round to min or max.
177 * If it's in range it's not rounded, application should check and round it. */
178 sam = ((ULONG)transfer -> ux_slave_transfer_request_data_pointer[0] ) |
179 ((ULONG)transfer -> ux_slave_transfer_request_data_pointer[1] << 8) |
180 ((ULONG)transfer -> ux_slave_transfer_request_data_pointer[2] << 16);
181 if (sam < min)
182 sam = min;
183 if (sam > max)
184 sam = max;
185 control -> ux_device_class_audio10_control_sam_freq = sam;
186 control -> ux_device_class_audio10_control_changed = UX_DEVICE_CLASS_AUDIO10_CONTROL_FREQUENCY_CHANGED;
187 return(UX_SUCCESS);
188
189 case UX_DEVICE_CLASS_AUDIO10_GET_CUR:
190
191 /* Sampling frequency control is supported. */
192 if (control_selector != UX_DEVICE_CLASS_AUDIO10_EP_SAMPLING_FREQ_CONTROL)
193 break;
194
195 /* Check host buffer. */
196 if (request_length < 3)
197 break;
198
199 /* Put sample frequency. */
200 sam = control -> ux_device_class_audio10_control_sam_freq;
201 transfer -> ux_slave_transfer_request_data_pointer[0] = UX_DW0(sam);
202 transfer -> ux_slave_transfer_request_data_pointer[1] = UX_DW1(sam);
203 transfer -> ux_slave_transfer_request_data_pointer[2] = UX_DW2(sam);
204 _ux_device_stack_transfer_request(transfer, 3, request_length);
205 return(UX_SUCCESS);
206
207 default:
208 break;
209 }
210 }
211
212 /* We handle feature unit requests. */
213 if ((request_type & UX_REQUEST_TARGET) == UX_REQUEST_TARGET_INTERFACE &&
214 unit_id == control -> ux_device_class_audio10_control_fu_id)
215 {
216
217 /* Handle the request. */
218 switch(request)
219 {
220 case UX_DEVICE_CLASS_AUDIO10_SET_CUR:
221
222 /* We only support master channel, so channel number must be 0 or 0xFF. */
223 if (channel_number != 0 && channel_number != 0xFF)
224 break;
225
226 /* Set request. */
227 switch(control_selector)
228 {
229 case UX_DEVICE_CLASS_AUDIO10_FU_MUTE_CONTROL:
230
231 if (transfer -> ux_slave_transfer_request_actual_length < 1)
232
233 /* No change applied. */
234 break;
235
236 if (control -> ux_device_class_audio10_control_mute[0] != transfer -> ux_slave_transfer_request_data_pointer[0])
237 {
238 control -> ux_device_class_audio10_control_changed = UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED;
239 control -> ux_device_class_audio10_control_mute[0] = transfer -> ux_slave_transfer_request_data_pointer[0];
240
241 }
242
243 /* Done success. */
244 return(UX_SUCCESS);
245
246 case UX_DEVICE_CLASS_AUDIO10_FU_VOLUME_CONTROL:
247
248 if (transfer -> ux_slave_transfer_request_actual_length < 2)
249
250 /* No change applied. */
251 break;
252
253 if (control -> ux_device_class_audio10_control_volume[0] != (SHORT)_ux_utility_short_get(transfer -> ux_slave_transfer_request_data_pointer))
254 {
255 control -> ux_device_class_audio10_control_changed = UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED;
256 control -> ux_device_class_audio10_control_volume[0] = (SHORT)_ux_utility_short_get(transfer -> ux_slave_transfer_request_data_pointer);
257 }
258
259 /* Done success. */
260 return(UX_SUCCESS);
261
262
263 default:
264
265 /* No change applied. */
266 break;
267 }
268
269 /* Request or parameter problem. */
270 break;
271
272 case UX_DEVICE_CLASS_AUDIO10_GET_MIN:
273 case UX_DEVICE_CLASS_AUDIO10_GET_MAX:
274 case UX_DEVICE_CLASS_AUDIO10_GET_RES:
275 case UX_DEVICE_CLASS_AUDIO10_GET_CUR:
276
277 /* We only support master channel, so channel number must be 0 or 0xFF. */
278 if (channel_number != 0 && channel_number != 0xFF)
279 break;
280
281 /* Get request. */
282 switch(control_selector)
283 {
284 case UX_DEVICE_CLASS_AUDIO10_FU_MUTE_CONTROL:
285
286 /* We only support _CUR. */
287 if (request != UX_DEVICE_CLASS_AUDIO10_GET_CUR)
288 break;
289
290 /* Not enough buffer for data. */
291 if (request_length < 1)
292 break;
293
294 /* Send mute status. */
295 transfer -> ux_slave_transfer_request_data_pointer[0] = (UCHAR)control -> ux_device_class_audio10_control_mute[0];
296 _ux_device_stack_transfer_request(transfer, 1, request_length);
297
298 /* Done success. */
299 return(UX_SUCCESS);
300
301 case UX_DEVICE_CLASS_AUDIO10_FU_VOLUME_CONTROL:
302
303 /* Not enough buffer for data. */
304 if (request_length < 2)
305 break;
306
307 /* Send volume value. */
308 _ux_utility_short_put(transfer -> ux_slave_transfer_request_data_pointer, (USHORT)
309 (request == UX_DEVICE_CLASS_AUDIO10_GET_MIN ? control -> ux_device_class_audio10_control_volume_min[0] :
310 (request == UX_DEVICE_CLASS_AUDIO10_GET_MAX ? control -> ux_device_class_audio10_control_volume_max[0] :
311 (request == UX_DEVICE_CLASS_AUDIO10_GET_RES ? UX_MAX(1, control -> ux_device_class_audio10_control_volume_res[0]) :
312 control -> ux_device_class_audio10_control_volume[0]))));
313 _ux_device_stack_transfer_request(transfer, 2, request_length);
314
315 /* Done success. */
316 return(UX_SUCCESS);
317
318 default:
319 break;
320 }
321 break;
322
323 default:
324 break;
325 }
326
327 /* We are here when there is error, break the loop. */
328 break;
329 }
330
331 /* Now try next. */
332 }
333
334
335 /* Request or parameter not supported. */
336 _ux_device_stack_endpoint_stall(endpoint);
337
338 /* Done error. */
339 return(UX_ERROR);
340 }
341
342
343 /**************************************************************************/
344 /* */
345 /* FUNCTION RELEASE */
346 /* */
347 /* _uxe_device_class_audio10_control_process PORTABLE C */
348 /* 6.2.1 */
349 /* AUTHOR */
350 /* */
351 /* Chaoqiong Xiao, Microsoft Corporation */
352 /* */
353 /* DESCRIPTION */
354 /* */
355 /* This function checks errors in control processing function call. */
356 /* */
357 /* INPUT */
358 /* */
359 /* audio Address of audio class */
360 /* instance */
361 /* transfer Address of transfer request */
362 /* instance */
363 /* group Request process data */
364 /* */
365 /* OUTPUT */
366 /* */
367 /* Completion Status */
368 /* */
369 /* CALLS */
370 /* */
371 /* _ux_device_class_audio10_control_process */
372 /* Process control requests */
373 /* */
374 /* CALLED BY */
375 /* */
376 /* Application */
377 /* */
378 /* RELEASE HISTORY */
379 /* */
380 /* DATE NAME DESCRIPTION */
381 /* */
382 /* 03-08-2023 Chaoqiong Xiao Initial Version 6.2.1 */
383 /* */
384 /**************************************************************************/
_uxe_device_class_audio10_control_process(UX_DEVICE_CLASS_AUDIO * audio,UX_SLAVE_TRANSFER * transfer,UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP * group)385 UINT _uxe_device_class_audio10_control_process(UX_DEVICE_CLASS_AUDIO *audio,
386 UX_SLAVE_TRANSFER *transfer, UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP *group)
387 {
388
389 /* Sanity checks. */
390 if (audio == UX_NULL || transfer == UX_NULL || group == UX_NULL)
391 return(UX_INVALID_PARAMETER);
392
393 /* Process control request. */
394 return(_ux_device_class_audio10_control_process(audio, transfer, group));
395 }
396