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 /** USBX Component */
14 /** */
15 /** Device Audio Class */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19
20 #define UX_SOURCE_CODE
21
22
23 /* Include necessary system files. */
24
25 #include "ux_api.h"
26 #include "ux_device_class_audio.h"
27 #include "ux_device_stack.h"
28
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _ux_device_class_audio_initialize PORTABLE C */
35 /* 6.3.0 */
36 /* AUTHOR */
37 /* */
38 /* Chaoqiong Xiao, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function initializes the USB Audio device. */
43 /* */
44 /* INPUT */
45 /* */
46 /* command Pointer to audio command */
47 /* */
48 /* OUTPUT */
49 /* */
50 /* Completion Status */
51 /* */
52 /* CALLS */
53 /* */
54 /* _ux_utility_memory_allocate Allocate memory */
55 /* _ux_utility_memory_copy Copy memory */
56 /* _ux_utility_memory_free Free memory */
57 /* _ux_device_thread_create Create thread to use */
58 /* _ux_device_thread_delete Delete thread */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* Device Audio Class */
63 /* */
64 /* RELEASE HISTORY */
65 /* */
66 /* DATE NAME DESCRIPTION */
67 /* */
68 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
69 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
70 /* verified memset and memcpy */
71 /* cases, used UX prefix to */
72 /* refer to TX symbols instead */
73 /* of using them directly, */
74 /* resulting in version 6.1 */
75 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
76 /* refined macros names, */
77 /* added feedback support, */
78 /* resulting in version 6.1.10 */
79 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
80 /* fixed standalone compile, */
81 /* resulting in version 6.1.11 */
82 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
83 /* added interrupt support, */
84 /* refined internal logic, */
85 /* resulting in version 6.1.12 */
86 /* 10-31-2022 Yajun Xia Modified comment(s), */
87 /* added standalone support, */
88 /* resulting in version 6.2.0 */
89 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
90 /* added a new mode to manage */
91 /* endpoint buffer in classes */
92 /* with zero copy enabled, */
93 /* resulting in version 6.3.0 */
94 /* */
95 /**************************************************************************/
_ux_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND * command)96 UINT _ux_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND *command)
97 {
98
99 UINT status = UX_SUCCESS;
100 UX_DEVICE_CLASS_AUDIO *audio;
101 UX_DEVICE_CLASS_AUDIO_PARAMETER *audio_parameter;
102 UX_DEVICE_CLASS_AUDIO_STREAM *stream;
103 UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER *stream_parameter;
104 UX_SLAVE_CLASS *audio_class;
105 ULONG memory_size;
106 ULONG streams_size;
107 ULONG i;
108
109
110 /* Get the class container. */
111 audio_class = command -> ux_slave_class_command_class_ptr;
112
113 /* Get the pointer to the application parameters for the audio class. */
114 audio_parameter = (UX_DEVICE_CLASS_AUDIO_PARAMETER *)command -> ux_slave_class_command_parameter;
115
116 /* Create an instance of the device audio class, with additional streams and controls instances. */
117 memory_size = sizeof(UX_DEVICE_CLASS_AUDIO);
118
119 /* Put 0 to default result. */
120 streams_size = 0;
121
122 /* Confirm there is no overflow on multiply. */
123 UX_UTILITY_MULC_SAFE(audio_parameter -> ux_device_class_audio_parameter_streams_nb, (ULONG)sizeof(UX_DEVICE_CLASS_AUDIO_STREAM), streams_size, status);
124 if (status != UX_SUCCESS)
125 return(status);
126
127 /* Confirm there is no overflow on add. */
128 UX_UTILITY_ADD_SAFE(memory_size, streams_size, memory_size, status);
129 if (status != UX_SUCCESS)
130 return(status);
131
132 /* Create buffer for audio and controls. */
133 audio = (UX_DEVICE_CLASS_AUDIO *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
134
135 /* Check for successful allocation. */
136 if (audio == UX_NULL)
137 return(UX_MEMORY_INSUFFICIENT);
138
139 #if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT)
140
141 /* Create resources for interrupt endpoint support. */
142
143 /* Get status data size. */
144 audio -> ux_device_class_audio_status_size =
145 audio_parameter -> ux_device_class_audio_parameter_status_size;
146
147 /* Calculate queue size in bytes. */
148 if (UX_OVERFLOW_CHECK_MULV_ULONG(
149 audio_parameter -> ux_device_class_audio_parameter_status_queue_size,
150 audio_parameter -> ux_device_class_audio_parameter_status_size))
151 {
152 _ux_utility_memory_free(audio);
153 return(UX_MATH_OVERFLOW);
154 }
155 memory_size = audio_parameter -> ux_device_class_audio_parameter_status_queue_size *
156 audio_parameter -> ux_device_class_audio_parameter_status_size;
157 audio -> ux_device_class_audio_status_queue_bytes = memory_size;
158
159 #if !defined(UX_DEVICE_STANDALONE)
160 if (UX_OVERFLOW_CHECK_ADD_ULONG(memory_size, UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE))
161 {
162 _ux_utility_memory_free(audio);
163 return(UX_MATH_OVERFLOW);
164 }
165 memory_size += UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE;
166
167 audio_class -> ux_slave_class_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
168 if (audio_class -> ux_slave_class_thread_stack == UX_NULL)
169 status = UX_MEMORY_INSUFFICIENT;
170
171 if (status == UX_SUCCESS)
172 {
173 status = _ux_device_thread_create(&audio_class -> ux_slave_class_thread,
174 "ux_device_class_audio_status_thread",
175 _ux_device_class_audio_interrupt_thread_entry, (ULONG)(ALIGN_TYPE)audio,
176 audio_class -> ux_slave_class_thread_stack,
177 UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE,
178 UX_THREAD_PRIORITY_CLASS, UX_THREAD_PRIORITY_CLASS,
179 UX_NO_TIME_SLICE, UX_DONT_START);
180 if (status == UX_SUCCESS)
181 {
182 UX_THREAD_EXTENSION_PTR_SET(&(audio_class -> ux_slave_class_thread), audio)
183
184 status = _ux_device_semaphore_create(&audio -> ux_device_class_audio_status_semaphore,
185 "ux_device_class_audio_status_semaphore", 0);
186 if (status == UX_SUCCESS)
187 {
188 status = _ux_device_mutex_create(&audio -> ux_device_class_audio_status_mutex,
189 "ux_device_class_audio_status_mutex");
190 if (status != UX_SUCCESS)
191 status = UX_MUTEX_ERROR;
192
193 if (status != UX_SUCCESS)
194 _ux_device_semaphore_delete(&audio -> ux_device_class_audio_status_semaphore);
195 }
196 else
197 status = UX_SEMAPHORE_ERROR;
198
199 if (status != UX_SUCCESS)
200 _ux_device_thread_delete(&audio_class -> ux_slave_class_thread);
201 }
202 else
203 status = UX_THREAD_ERROR;
204
205 if (status != UX_SUCCESS)
206 {
207 _ux_utility_memory_free(audio_class -> ux_slave_class_thread_stack);
208 audio_class -> ux_slave_class_thread_stack = UX_NULL;
209 }
210 }
211
212 if (status != UX_SUCCESS)
213 {
214 _ux_utility_memory_free(audio);
215 return(status);
216 }
217
218 /* Status queue locates right after status stack. */
219 audio -> ux_device_class_audio_status_queue =
220 (UCHAR *)audio_class -> ux_slave_class_thread_stack +
221 UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE;
222 #else
223 audio -> ux_device_class_audio_status_queue = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
224
225 /* Check for successful allocation. */
226 if (audio -> ux_device_class_audio_status_queue == UX_NULL)
227 {
228 _ux_utility_memory_free(audio);
229 return(UX_MEMORY_INSUFFICIENT);
230 }
231 #endif
232
233 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
234
235 /* Allocate memory for interrupt endpoint buffer. */
236 audio -> ux_device_class_audio_interrupt_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY,
237 audio_parameter -> ux_device_class_audio_parameter_status_size);
238 if (audio -> ux_device_class_audio_interrupt_buffer == UX_NULL)
239 {
240 _ux_utility_memory_free(audio -> ux_device_class_audio_status_queue);
241 _ux_utility_memory_free(audio);
242 return(UX_MEMORY_INSUFFICIENT);
243 }
244 #endif
245
246 #endif
247
248 /* Save streams. */
249 if (streams_size)
250 {
251 audio -> ux_device_class_audio_streams = (UX_DEVICE_CLASS_AUDIO_STREAM *)((UCHAR *)audio + sizeof(UX_DEVICE_CLASS_AUDIO));
252 audio -> ux_device_class_audio_streams_nb = audio_parameter -> ux_device_class_audio_parameter_streams_nb;
253 }
254
255 /* Allocate resources for streams. */
256 stream = audio -> ux_device_class_audio_streams;
257 stream_parameter = audio_parameter -> ux_device_class_audio_parameter_streams;
258 for (i = 0; i < audio -> ux_device_class_audio_streams_nb; i ++)
259 {
260
261 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
262 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
263
264 /* Allocate memory for feedback endpoint buffer. */
265 stream -> ux_device_class_audio_stream_feedback_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY,
266 UX_DEVICE_CLASS_AUDIO_FEEDBACK_BUFFER_SIZE);
267 if (stream -> ux_device_class_audio_stream_feedback_buffer == UX_NULL)
268 {
269 status = UX_MEMORY_INSUFFICIENT;
270 break;
271 }
272 #endif
273 #endif
274
275 /* Create memory block based on max frame buffer size and max number of frames buffered.
276 Each frame require some additional header memory (8 bytes). */
277 stream -> ux_device_class_audio_stream_frame_buffer_size = stream_parameter -> ux_device_class_audio_stream_parameter_max_frame_buffer_size;
278
279 if (UX_OVERFLOW_CHECK_ADD_USHORT(stream -> ux_device_class_audio_stream_frame_buffer_size, 8))
280 {
281 status = UX_ERROR;
282 break;
283 }
284 stream -> ux_device_class_audio_stream_frame_buffer_size += 8;
285
286 if (UX_OVERFLOW_CHECK_MULV_ULONG(stream -> ux_device_class_audio_stream_frame_buffer_size,
287 stream_parameter -> ux_device_class_audio_stream_parameter_max_frame_buffer_nb))
288 {
289 status = UX_ERROR;
290 break;
291 }
292 memory_size = stream -> ux_device_class_audio_stream_frame_buffer_size *
293 stream_parameter -> ux_device_class_audio_stream_parameter_max_frame_buffer_nb;
294
295 /* Create block of buffer buffer is cache safe for USB transfer. */
296 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
297 stream -> ux_device_class_audio_stream_buffer = (UCHAR *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, memory_size);
298 #else
299 stream -> ux_device_class_audio_stream_buffer = (UCHAR *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
300 #endif
301
302 /* Check for successful allocation. */
303 if (stream -> ux_device_class_audio_stream_buffer == UX_NULL)
304 {
305 status = UX_MEMORY_INSUFFICIENT;
306 break;
307 }
308
309 stream -> ux_device_class_audio_stream_buffer_size = memory_size;
310 stream -> ux_device_class_audio_stream_transfer_pos = (UX_DEVICE_CLASS_AUDIO_FRAME *)stream -> ux_device_class_audio_stream_buffer;
311 stream -> ux_device_class_audio_stream_access_pos = stream -> ux_device_class_audio_stream_transfer_pos;
312
313 #if !defined(UX_DEVICE_STANDALONE)
314
315 /* Create memory block for streaming thread stack in addition. */
316 if (stream_parameter -> ux_device_class_audio_stream_parameter_thread_stack_size == 0)
317 memory_size = UX_DEVICE_CLASS_AUDIO_FEEDBACK_THREAD_STACK_SIZE;
318 else
319 memory_size = stream_parameter -> ux_device_class_audio_stream_parameter_thread_stack_size;
320 stream -> ux_device_class_audio_stream_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
321
322 /* Check for successful allocation. */
323 if (stream -> ux_device_class_audio_stream_thread_stack == UX_NULL)
324 {
325 status = UX_MEMORY_INSUFFICIENT;
326 break;
327 }
328
329 /* Create streaming thread. */
330 status = _ux_device_thread_create(&stream -> ux_device_class_audio_stream_thread , "ux_device_class_audio_stream_thread",
331 stream_parameter -> ux_device_class_audio_stream_parameter_thread_entry,
332 (ULONG)(ALIGN_TYPE)stream, (VOID *) stream -> ux_device_class_audio_stream_thread_stack,
333 memory_size, UX_THREAD_PRIORITY_CLASS,
334 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
335
336 /* Check for successful allocation. */
337 if (status != UX_SUCCESS)
338 {
339 _ux_utility_memory_free(stream -> ux_device_class_audio_stream_thread_stack);
340 stream -> ux_device_class_audio_stream_thread_stack = UX_NULL;
341 break;
342 }
343
344 UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_audio_stream_thread), stream)
345 #else
346
347 /* Save task function for streaming. */
348 stream -> ux_device_class_audio_stream_task_function = stream_parameter -> ux_device_class_audio_stream_parameter_task_function;
349 #endif
350
351 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
352
353 #if !defined(UX_DEVICE_STANDALONE)
354
355 /* Check entry to confirm feedback is supported. */
356 if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_entry)
357 {
358 /* Create memory block for streaming thread stack in addition. */
359 if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_stack_size == 0)
360 memory_size = UX_THREAD_STACK_SIZE;
361 else
362 memory_size = stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_stack_size;
363 stream -> ux_device_class_audio_stream_feedback_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
364
365 /* Check for successful allocation. */
366 if (stream -> ux_device_class_audio_stream_feedback_thread_stack == UX_NULL)
367 {
368 status = UX_MEMORY_INSUFFICIENT;
369 break;
370 }
371
372 /* Create streaming thread. */
373 status = _ux_utility_thread_create(&stream -> ux_device_class_audio_stream_feedback_thread , "ux_device_class_audio_stream_feedback_thread",
374 stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_entry,
375 (ULONG)(ALIGN_TYPE)stream, (VOID *) stream -> ux_device_class_audio_stream_feedback_thread_stack,
376 memory_size, UX_THREAD_PRIORITY_CLASS,
377 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
378
379 /* Check for successful allocation. */
380 if (status != UX_SUCCESS)
381 {
382 _ux_utility_memory_free(stream -> ux_device_class_audio_stream_feedback_thread_stack);
383 stream -> ux_device_class_audio_stream_feedback_thread_stack = UX_NULL;
384 break;
385 }
386
387 UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_audio_stream_feedback_thread), stream)
388 }
389 #else
390 if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_task_function)
391 {
392
393 /* Save task function for streaming. */
394 stream -> ux_device_class_audio_stream_feedback_task_function = stream_parameter -> ux_device_class_audio_stream_parameter_feedback_task_function;
395 }
396 #endif
397 #endif
398
399 /* Save callbacks. */
400 _ux_utility_memory_copy(&stream -> ux_device_class_audio_stream_callbacks,
401 &stream_parameter -> ux_device_class_audio_stream_parameter_callbacks,
402 sizeof(UX_DEVICE_CLASS_AUDIO_STREAM_CALLBACKS)); /* Use case of memcpy is verified. */
403
404 /* Save audio instance. */
405 stream -> ux_device_class_audio_stream_audio = audio;
406
407 stream ++;
408 stream_parameter ++;
409 }
410
411 /* Check for successful creation. */
412 if (status == UX_SUCCESS)
413 {
414
415 /* Save the address of the Audio instance inside the Audio container. */
416 audio_class -> ux_slave_class_instance = (VOID *) audio;
417
418 /* Link to class instance. */
419 audio -> ux_device_class_audio_class = audio_class;
420
421 /* Save callbacks. */
422 _ux_utility_memory_copy(&audio -> ux_device_class_audio_callbacks,
423 &audio_parameter -> ux_device_class_audio_parameter_callbacks,
424 sizeof(UX_DEVICE_CLASS_AUDIO_CALLBACKS)); /* Use case of memcpy is verified. */
425
426 #if defined(UX_DEVICE_STANDALONE)
427
428 /* Link task function. */
429 audio_class -> ux_slave_class_task_function = _ux_device_class_audio_tasks_run;
430 #endif
431
432 /* Return completion status. */
433 return(UX_SUCCESS);
434 }
435
436 /* Error trap! */
437 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
438
439 /* Free allocated resources. */
440 stream = audio -> ux_device_class_audio_streams;
441 for (i = 0; i < audio -> ux_device_class_audio_streams_nb; i ++)
442 {
443 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
444 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
445 if (stream -> ux_device_class_audio_stream_feedback_buffer)
446 _ux_utility_memory_free(stream -> ux_device_class_audio_stream_feedback_buffer);
447 #endif
448 #if !defined(UX_DEVICE_STANDALONE)
449 if (stream -> ux_device_class_audio_stream_feedback_thread_stack)
450 {
451 _ux_device_thread_delete(&stream -> ux_device_class_audio_stream_feedback_thread);
452 _ux_utility_memory_free(stream -> ux_device_class_audio_stream_feedback_thread_stack);
453 }
454 #endif
455 #endif
456 #if !defined(UX_DEVICE_STANDALONE)
457 if (stream -> ux_device_class_audio_stream_thread_stack)
458 {
459 _ux_device_thread_delete(&stream -> ux_device_class_audio_stream_thread);
460 _ux_utility_memory_free(stream -> ux_device_class_audio_stream_thread_stack);
461 }
462 #endif
463 if (stream -> ux_device_class_audio_stream_buffer)
464 _ux_utility_memory_free(stream -> ux_device_class_audio_stream_buffer);
465 stream ++;
466 }
467 #if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT)
468 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
469 if (audio -> ux_device_class_audio_interrupt_buffer)
470 _ux_utility_memory_free(audio -> ux_device_class_audio_interrupt_buffer);
471 #endif
472 #if !defined(UX_DEVICE_STANDALONE)
473 if (audio_class -> ux_slave_class_thread_stack)
474 {
475 _ux_device_thread_delete(&audio_class -> ux_slave_class_thread);
476 _ux_utility_memory_free(audio_class -> ux_slave_class_thread_stack);
477
478 _ux_device_semaphore_delete(&audio -> ux_device_class_audio_status_semaphore);
479 _ux_device_mutex_delete(&audio -> ux_device_class_audio_status_mutex);
480 }
481 #else
482 if (audio -> ux_device_class_audio_status_queue)
483 {
484 _ux_utility_memory_free(audio -> ux_device_class_audio_status_queue);
485 }
486 #endif
487 #endif
488 _ux_utility_memory_free(audio);
489
490 return(status);
491 }
492
493 /**************************************************************************/
494 /* */
495 /* FUNCTION RELEASE */
496 /* */
497 /* _uxe_device_class_audio_initialize PORTABLE C */
498 /* 6.3.0 */
499 /* AUTHOR */
500 /* */
501 /* Chaoqiong Xiao, Microsoft Corporation */
502 /* */
503 /* DESCRIPTION */
504 /* */
505 /* This function checks errors in audio initialization function call. */
506 /* */
507 /* INPUT */
508 /* */
509 /* command Pointer to audio command */
510 /* */
511 /* OUTPUT */
512 /* */
513 /* Completion Status */
514 /* */
515 /* CALLS */
516 /* */
517 /* _ux_device_class_audio_initialize Initialize audio instance */
518 /* */
519 /* CALLED BY */
520 /* */
521 /* Device Audio Class */
522 /* */
523 /* RELEASE HISTORY */
524 /* */
525 /* DATE NAME DESCRIPTION */
526 /* */
527 /* 03-08-2023 Chaoqiong Xiao Initial Version 6.2.1 */
528 /* 10-31-2023 Yajun Xia Modified comment(s), */
529 /* fixed error checking issue, */
530 /* resulting in version 6.3.0 */
531 /* */
532 /**************************************************************************/
_uxe_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND * command)533 UINT _uxe_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND *command)
534 {
535
536 UX_DEVICE_CLASS_AUDIO_PARAMETER *audio_parameter;
537 ULONG i;
538
539 /* Get the pointer to the application parameters for the audio class. */
540 audio_parameter = (UX_DEVICE_CLASS_AUDIO_PARAMETER *)command -> ux_slave_class_command_parameter;
541
542 /* Sanity checks. */
543 if (audio_parameter == UX_NULL)
544 return(UX_INVALID_PARAMETER);
545
546 /* There must be at least one stream. */
547 if (audio_parameter -> ux_device_class_audio_parameter_streams == UX_NULL ||
548 audio_parameter -> ux_device_class_audio_parameter_streams_nb < 1)
549 return(UX_INVALID_PARAMETER);
550
551 for (i = 0; i < audio_parameter -> ux_device_class_audio_parameter_streams_nb; i ++)
552 {
553 if ((audio_parameter -> ux_device_class_audio_parameter_streams[i].ux_device_class_audio_stream_parameter_max_frame_buffer_size == 0) ||
554 (audio_parameter -> ux_device_class_audio_parameter_streams[i].ux_device_class_audio_stream_parameter_max_frame_buffer_nb == 0))
555 return(UX_INVALID_PARAMETER);
556 }
557
558 #if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT)
559
560 /* There must be status setting for event queue. */
561 if (audio_parameter -> ux_device_class_audio_parameter_status_queue_size == 0 ||
562 audio_parameter -> ux_device_class_audio_parameter_status_size == 0)
563 return(UX_INVALID_PARAMETER);
564 #endif
565
566 /* Do initialize. */
567 return(_ux_device_class_audio_initialize(command));
568 }
569