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.2.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 /* */
74 /**************************************************************************/
_ux_device_class_video_initialize(UX_SLAVE_CLASS_COMMAND * command)75 UINT _ux_device_class_video_initialize(UX_SLAVE_CLASS_COMMAND *command)
76 {
77
78 UINT status = UX_SUCCESS;
79 UX_DEVICE_CLASS_VIDEO *video;
80 UX_DEVICE_CLASS_VIDEO_PARAMETER *video_parameter;
81 UX_DEVICE_CLASS_VIDEO_STREAM *stream;
82 UX_DEVICE_CLASS_VIDEO_STREAM_PARAMETER *stream_parameter;
83 UX_SLAVE_CLASS *class_inst;
84 ULONG memory_size;
85 ULONG streams_size;
86 ULONG i;
87
88
89 /* Get the class container. */
90 class_inst = command -> ux_slave_class_command_class_ptr;
91
92 /* Get the pointer to the application parameters for the video class. */
93 video_parameter = (UX_DEVICE_CLASS_VIDEO_PARAMETER *)command -> ux_slave_class_command_parameter;
94
95 /* Create an instance of the device video class, with additional streams and controls instances. */
96 memory_size = sizeof(UX_DEVICE_CLASS_VIDEO);
97
98 /* Put 0 to default result. */
99 streams_size = 0;
100
101 /* Confirm there is no overflow on multiply. */
102 UX_UTILITY_MULC_SAFE(video_parameter -> ux_device_class_video_parameter_streams_nb, (ULONG)sizeof(UX_DEVICE_CLASS_VIDEO_STREAM), streams_size, status);
103 if (status != UX_SUCCESS)
104 return(status);
105
106 /* Confirm there is no overflow on add. */
107 UX_UTILITY_ADD_SAFE(memory_size, streams_size, memory_size, status);
108 if (status != UX_SUCCESS)
109 return(status);
110
111 /* Create buffer for video and controls. */
112 video = (UX_DEVICE_CLASS_VIDEO *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
113
114 /* Check for successful allocation. */
115 if (video == UX_NULL)
116 return(UX_MEMORY_INSUFFICIENT);
117
118 /* Save streams. */
119 if (streams_size)
120 {
121 video -> ux_device_class_video_streams = (UX_DEVICE_CLASS_VIDEO_STREAM *)((UCHAR *)video + sizeof(UX_DEVICE_CLASS_VIDEO));
122 video -> ux_device_class_video_streams_nb = video_parameter -> ux_device_class_video_parameter_streams_nb;
123 }
124
125 /* Allocate resources for streams. */
126 stream = video -> ux_device_class_video_streams;
127 stream_parameter = video_parameter -> ux_device_class_video_parameter_streams;
128 for (i = 0; i < video -> ux_device_class_video_streams_nb; i ++)
129 {
130
131 /* Create memory block based on max payload buffer size and max number of payloads buffered.
132 Each payload require some additional header memory (8 bytes). */
133 stream -> ux_device_class_video_stream_payload_buffer_size = stream_parameter -> ux_device_class_video_stream_parameter_max_payload_buffer_size;
134
135 if (UX_OVERFLOW_CHECK_ADD_USHORT(stream -> ux_device_class_video_stream_payload_buffer_size, 4))
136 {
137 status = UX_ERROR;
138 break;
139 }
140 stream -> ux_device_class_video_stream_payload_buffer_size += 4;
141
142 if (UX_OVERFLOW_CHECK_MULV_ULONG(stream -> ux_device_class_video_stream_payload_buffer_size,
143 stream_parameter -> ux_device_class_video_stream_parameter_max_payload_buffer_nb))
144 {
145 status = UX_ERROR;
146 break;
147 }
148 memory_size = stream -> ux_device_class_video_stream_payload_buffer_size *
149 stream_parameter -> ux_device_class_video_stream_parameter_max_payload_buffer_nb;
150
151 /* Create block of buffer buffer is cache safe for USB transfer. */
152 stream -> ux_device_class_video_stream_buffer = (UCHAR *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
153
154 /* Check for successful allocation. */
155 if (stream -> ux_device_class_video_stream_buffer == UX_NULL)
156 {
157 status = UX_MEMORY_INSUFFICIENT;
158 break;
159 }
160
161 stream -> ux_device_class_video_stream_buffer_size = memory_size;
162 stream -> ux_device_class_video_stream_transfer_pos = (UX_DEVICE_CLASS_VIDEO_PAYLOAD *)stream -> ux_device_class_video_stream_buffer;
163 stream -> ux_device_class_video_stream_access_pos = stream -> ux_device_class_video_stream_transfer_pos;
164
165
166 #if !defined(UX_DEVICE_STANDALONE)
167
168 /* Create memory block for streaming thread stack in addition. */
169 if (stream_parameter -> ux_device_class_video_stream_parameter_thread_stack_size == 0)
170 memory_size = UX_DEVICE_CLASS_VIDEO_THREAD_STACK_SIZE;
171 else
172 memory_size = stream_parameter -> ux_device_class_video_stream_parameter_thread_stack_size;
173 stream -> ux_device_class_video_stream_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
174
175 /* Check for successful allocation. */
176 if (stream -> ux_device_class_video_stream_thread_stack == UX_NULL)
177 {
178 status = UX_MEMORY_INSUFFICIENT;
179 break;
180 }
181
182 /* Create streaming thread. */
183 status = _ux_utility_thread_create(&stream -> ux_device_class_video_stream_thread , "ux_device_class_video_stream_thread",
184 stream_parameter -> ux_device_class_video_stream_parameter_thread_entry,
185 (ULONG)(ALIGN_TYPE)stream, (VOID *) stream -> ux_device_class_video_stream_thread_stack,
186 memory_size, UX_THREAD_PRIORITY_CLASS,
187 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
188
189 /* Check for successful allocation. */
190 if (status != UX_SUCCESS)
191 break;
192
193 UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_video_stream_thread), stream)
194 #else
195
196 /* Save task function for streaming. */
197 stream -> ux_device_class_video_stream_task_function = stream_parameter -> ux_device_class_video_stream_parameter_task_function;
198 #endif
199
200 /* Save callbacks. */
201 _ux_utility_memory_copy(&stream -> ux_device_class_video_stream_callbacks,
202 &stream_parameter -> ux_device_class_video_stream_parameter_callbacks,
203 sizeof(UX_DEVICE_CLASS_VIDEO_STREAM_CALLBACKS)); /* Use case of memcpy is verified. */
204
205 /* Save video instance. */
206 stream -> ux_device_class_video_stream_video = video;
207
208 stream ++;
209 stream_parameter ++;
210 }
211
212 /* Check for successful creation. */
213 if (status == UX_SUCCESS)
214 {
215
216 /* Save the address of the Video instance inside the Video container. */
217 class_inst -> ux_slave_class_instance = (VOID *) video;
218
219 /* Link to class instance. */
220 video -> ux_device_class_video_class = class_inst;
221
222 /* Save callbacks. */
223 _ux_utility_memory_copy(&video -> ux_device_class_video_callbacks,
224 &video_parameter -> ux_device_class_video_parameter_callbacks,
225 sizeof(UX_DEVICE_CLASS_VIDEO_CALLBACKS)); /* Use case of memcpy is verified. */
226
227 #if defined(UX_DEVICE_STANDALONE)
228
229 /* Link task function. */
230 class_inst -> ux_slave_class_task_function = _ux_device_class_video_tasks_run;
231 #endif
232
233 /* Return completion status. */
234 return(UX_SUCCESS);
235 }
236
237 /* Error trap! */
238 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
239
240 /* Free allocated resources. */
241 stream = video -> ux_device_class_video_streams;
242 for (i = 0; i < video -> ux_device_class_video_streams_nb; i ++)
243 {
244
245 #if !defined(UX_DEVICE_STANDALONE)
246 if (stream -> ux_device_class_video_stream_thread.tx_thread_id)
247 _ux_utility_thread_delete(&stream -> ux_device_class_video_stream_thread);
248 if (stream -> ux_device_class_video_stream_thread_stack)
249 _ux_utility_memory_free(stream -> ux_device_class_video_stream_thread_stack);
250 #endif
251
252 if (stream -> ux_device_class_video_stream_buffer)
253 _ux_utility_memory_free(stream -> ux_device_class_video_stream_buffer);
254 stream ++;
255 }
256 _ux_utility_memory_free(video);
257
258 return(status);
259 }
260