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 Video 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_video.h"
27 #include "ux_device_stack.h"
28
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _ux_device_class_video_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 Video device. */
43 /* */
44 /* INPUT */
45 /* */
46 /* command Pointer to video 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_utility_thread_create Create thread to use */
58 /* _ux_utility_thread_delete Delete thread */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* Device Video Class */
63 /* */
64 /* RELEASE HISTORY */
65 /* */
66 /* DATE NAME DESCRIPTION */
67 /* */
68 /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */
69 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
70 /* added standalone support, */
71 /* resulting in version 6.2.0 */
72 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
73 /* added a new mode to manage */
74 /* endpoint buffer in classes */
75 /* with zero copy enabled, */
76 /* resulting in version 6.3.0 */
77 /* */
78 /**************************************************************************/
_ux_device_class_video_initialize(UX_SLAVE_CLASS_COMMAND * command)79 UINT _ux_device_class_video_initialize(UX_SLAVE_CLASS_COMMAND *command)
80 {
81
82 UINT status = UX_SUCCESS;
83 UX_DEVICE_CLASS_VIDEO *video;
84 UX_DEVICE_CLASS_VIDEO_PARAMETER *video_parameter;
85 UX_DEVICE_CLASS_VIDEO_STREAM *stream;
86 UX_DEVICE_CLASS_VIDEO_STREAM_PARAMETER *stream_parameter;
87 UX_SLAVE_CLASS *class_inst;
88 ULONG memory_size;
89 ULONG streams_size;
90 ULONG i;
91
92
93 /* Get the class container. */
94 class_inst = command -> ux_slave_class_command_class_ptr;
95
96 /* Get the pointer to the application parameters for the video class. */
97 video_parameter = (UX_DEVICE_CLASS_VIDEO_PARAMETER *)command -> ux_slave_class_command_parameter;
98
99 /* Create an instance of the device video class, with additional streams and controls instances. */
100 memory_size = sizeof(UX_DEVICE_CLASS_VIDEO);
101
102 /* Put 0 to default result. */
103 streams_size = 0;
104
105 /* Confirm there is no overflow on multiply. */
106 UX_UTILITY_MULC_SAFE(video_parameter -> ux_device_class_video_parameter_streams_nb, (ULONG)sizeof(UX_DEVICE_CLASS_VIDEO_STREAM), streams_size, status);
107 if (status != UX_SUCCESS)
108 return(status);
109
110 /* Confirm there is no overflow on add. */
111 UX_UTILITY_ADD_SAFE(memory_size, streams_size, memory_size, status);
112 if (status != UX_SUCCESS)
113 return(status);
114
115 /* Create buffer for video and controls. */
116 video = (UX_DEVICE_CLASS_VIDEO *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
117
118 /* Check for successful allocation. */
119 if (video == UX_NULL)
120 return(UX_MEMORY_INSUFFICIENT);
121
122 /* Save streams. */
123 if (streams_size)
124 {
125 video -> ux_device_class_video_streams = (UX_DEVICE_CLASS_VIDEO_STREAM *)((UCHAR *)video + sizeof(UX_DEVICE_CLASS_VIDEO));
126 video -> ux_device_class_video_streams_nb = video_parameter -> ux_device_class_video_parameter_streams_nb;
127 }
128
129 /* Allocate resources for streams. */
130 stream = video -> ux_device_class_video_streams;
131 stream_parameter = video_parameter -> ux_device_class_video_parameter_streams;
132 for (i = 0; i < video -> ux_device_class_video_streams_nb; i ++)
133 {
134
135 /* Create memory block based on max payload buffer size and max number of payloads buffered.
136 Each payload require some additional header memory (8 bytes). */
137 stream -> ux_device_class_video_stream_payload_buffer_size = stream_parameter -> ux_device_class_video_stream_parameter_max_payload_buffer_size;
138
139 if (UX_OVERFLOW_CHECK_ADD_USHORT(stream -> ux_device_class_video_stream_payload_buffer_size, 4))
140 {
141 status = UX_ERROR;
142 break;
143 }
144 stream -> ux_device_class_video_stream_payload_buffer_size += 4;
145
146 if (UX_OVERFLOW_CHECK_MULV_ULONG(stream -> ux_device_class_video_stream_payload_buffer_size,
147 stream_parameter -> ux_device_class_video_stream_parameter_max_payload_buffer_nb))
148 {
149 status = UX_ERROR;
150 break;
151 }
152 memory_size = stream -> ux_device_class_video_stream_payload_buffer_size *
153 stream_parameter -> ux_device_class_video_stream_parameter_max_payload_buffer_nb;
154
155 /* Create block of buffer buffer is cache safe for USB transfer. */
156 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
157 stream -> ux_device_class_video_stream_buffer = (UCHAR *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, memory_size);
158 #else
159 stream -> ux_device_class_video_stream_buffer = (UCHAR *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
160 #endif
161
162 /* Check for successful allocation. */
163 if (stream -> ux_device_class_video_stream_buffer == UX_NULL)
164 {
165 status = UX_MEMORY_INSUFFICIENT;
166 break;
167 }
168
169 stream -> ux_device_class_video_stream_buffer_size = memory_size;
170 stream -> ux_device_class_video_stream_transfer_pos = (UX_DEVICE_CLASS_VIDEO_PAYLOAD *)stream -> ux_device_class_video_stream_buffer;
171 stream -> ux_device_class_video_stream_access_pos = stream -> ux_device_class_video_stream_transfer_pos;
172
173 #if !defined(UX_DEVICE_STANDALONE)
174
175 /* Create memory block for streaming thread stack in addition. */
176 if (stream_parameter -> ux_device_class_video_stream_parameter_thread_stack_size == 0)
177 memory_size = UX_DEVICE_CLASS_VIDEO_THREAD_STACK_SIZE;
178 else
179 memory_size = stream_parameter -> ux_device_class_video_stream_parameter_thread_stack_size;
180 stream -> ux_device_class_video_stream_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
181
182 /* Check for successful allocation. */
183 if (stream -> ux_device_class_video_stream_thread_stack == UX_NULL)
184 {
185 status = UX_MEMORY_INSUFFICIENT;
186 break;
187 }
188
189 /* Create streaming thread. */
190 status = _ux_utility_thread_create(&stream -> ux_device_class_video_stream_thread , "ux_device_class_video_stream_thread",
191 stream_parameter -> ux_device_class_video_stream_parameter_thread_entry,
192 (ULONG)(ALIGN_TYPE)stream, (VOID *) stream -> ux_device_class_video_stream_thread_stack,
193 memory_size, UX_THREAD_PRIORITY_CLASS,
194 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
195
196 /* Check for successful allocation. */
197 if (status != UX_SUCCESS)
198 break;
199
200 UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_video_stream_thread), stream)
201 #else
202
203 /* Save task function for streaming. */
204 stream -> ux_device_class_video_stream_task_function = stream_parameter -> ux_device_class_video_stream_parameter_task_function;
205 #endif
206
207 /* Save callbacks. */
208 _ux_utility_memory_copy(&stream -> ux_device_class_video_stream_callbacks,
209 &stream_parameter -> ux_device_class_video_stream_parameter_callbacks,
210 sizeof(UX_DEVICE_CLASS_VIDEO_STREAM_CALLBACKS)); /* Use case of memcpy is verified. */
211
212 /* Save video instance. */
213 stream -> ux_device_class_video_stream_video = video;
214
215 stream ++;
216 stream_parameter ++;
217 }
218
219 /* Check for successful creation. */
220 if (status == UX_SUCCESS)
221 {
222
223 /* Save the address of the Video instance inside the Video container. */
224 class_inst -> ux_slave_class_instance = (VOID *) video;
225
226 /* Link to class instance. */
227 video -> ux_device_class_video_class = class_inst;
228
229 /* Save callbacks. */
230 _ux_utility_memory_copy(&video -> ux_device_class_video_callbacks,
231 &video_parameter -> ux_device_class_video_parameter_callbacks,
232 sizeof(UX_DEVICE_CLASS_VIDEO_CALLBACKS)); /* Use case of memcpy is verified. */
233
234 #if defined(UX_DEVICE_STANDALONE)
235
236 /* Link task function. */
237 class_inst -> ux_slave_class_task_function = _ux_device_class_video_tasks_run;
238 #endif
239
240 /* Return completion status. */
241 return(UX_SUCCESS);
242 }
243
244 /* Error trap! */
245 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
246
247 /* Free allocated resources. */
248 stream = video -> ux_device_class_video_streams;
249 for (i = 0; i < video -> ux_device_class_video_streams_nb; i ++)
250 {
251
252 #if !defined(UX_DEVICE_STANDALONE)
253 if (stream -> ux_device_class_video_stream_thread.tx_thread_id)
254 _ux_utility_thread_delete(&stream -> ux_device_class_video_stream_thread);
255 if (stream -> ux_device_class_video_stream_thread_stack)
256 _ux_utility_memory_free(stream -> ux_device_class_video_stream_thread_stack);
257 #endif
258 if (stream -> ux_device_class_video_stream_buffer)
259 _ux_utility_memory_free(stream -> ux_device_class_video_stream_buffer);
260 stream ++;
261 }
262 _ux_utility_memory_free(video);
263
264 return(status);
265 }
266
267 /**************************************************************************/
268 /* */
269 /* FUNCTION RELEASE */
270 /* */
271 /* _uxe_device_class_video_initialize PORTABLE C */
272 /* 6.3.0 */
273 /* AUTHOR */
274 /* */
275 /* Yajun Xia, Microsoft Corporation */
276 /* */
277 /* DESCRIPTION */
278 /* */
279 /* This function checks errors in video initialization function call. */
280 /* */
281 /* INPUT */
282 /* */
283 /* command Pointer to video command */
284 /* */
285 /* OUTPUT */
286 /* */
287 /* Completion Status */
288 /* */
289 /* CALLS */
290 /* */
291 /* _ux_device_class_video_initialize Initialize video instance */
292 /* */
293 /* CALLED BY */
294 /* */
295 /* Device Video Class */
296 /* */
297 /* RELEASE HISTORY */
298 /* */
299 /* DATE NAME DESCRIPTION */
300 /* */
301 /* 10-31-2023 Yajun Xia Initial Version 6.3.0 */
302 /* */
303 /**************************************************************************/
_uxe_device_class_video_initialize(UX_SLAVE_CLASS_COMMAND * command)304 UINT _uxe_device_class_video_initialize(UX_SLAVE_CLASS_COMMAND *command)
305 {
306 UX_DEVICE_CLASS_VIDEO_PARAMETER *video_parameter;
307 ULONG i;
308
309 /* Get the pointer to the application parameters for the video class. */
310 video_parameter = (UX_DEVICE_CLASS_VIDEO_PARAMETER *)command -> ux_slave_class_command_parameter;
311
312 /* Sanity checks. */
313 if (video_parameter == UX_NULL)
314 return(UX_INVALID_PARAMETER);
315
316 /* There must be at least one stream. */
317 if ((video_parameter -> ux_device_class_video_parameter_streams_nb == 0) ||
318 (video_parameter -> ux_device_class_video_parameter_streams == UX_NULL))
319 return(UX_INVALID_PARAMETER);
320
321 for (i = 0; i < video_parameter -> ux_device_class_video_parameter_streams_nb; i ++)
322 {
323 if ((video_parameter -> ux_device_class_video_parameter_streams[i].ux_device_class_video_stream_parameter_max_payload_buffer_size == 0) ||
324 (video_parameter -> ux_device_class_video_parameter_streams[i].ux_device_class_video_stream_parameter_max_payload_buffer_nb == 0))
325 return(UX_INVALID_PARAMETER);
326 }
327
328 /* Do initialize. */
329 return(_ux_device_class_video_initialize(command));
330 }