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