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 /** */
16 /** USBX Component */
17 /** */
18 /** Video Class */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_host_class_video.h"
30 #include "ux_host_stack.h"
31
32 UCHAR _ux_system_class_video_interface_descriptor_structure[] = {1,1,1,1,1,1,1,1};
33 UCHAR _ux_system_class_video_input_terminal_descriptor_structure[] = {1,1,1,1,2,1,1};
34 UCHAR _ux_system_class_video_input_header_descriptor_structure[] = {1,1,1,1,2,1,1,1,1,1,1,1};
35 UCHAR _ux_system_class_video_processing_unit_descriptor_structure[] = {1,1,1,1,1,2,1,1};
36 UCHAR _ux_system_class_video_streaming_interface_descriptor_structure[] = {1,1,1,1,1,1};
37 UCHAR _ux_system_class_video_streaming_endpoint_descriptor_structure[] = {1,1,1,1,1,1};
38 UCHAR _ux_system_class_video_frame_descriptor_structure[] = {1,1,1,1,1,2,2,4,4,4,4,1};
39
40 UCHAR _ux_system_host_class_video_name[] = "ux_host_class_video";
41
42 typedef struct UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_STRUCT
43 {
44 UX_HOST_CLASS_VIDEO *video;
45 ULONG parsed_flags;
46 } UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER;
47 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_HEADER 1
48 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_IT 2
49 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_PU 4
50 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VS_HEADER 8
51 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_DONE (1|2|4|8)
52
53
_ux_host_class_video_descriptors_parser(VOID * arg,UCHAR * packed_interface_descriptor,UCHAR * packed_entity_descriptor)54 static UINT _ux_host_class_video_descriptors_parser(VOID *arg,
55 UCHAR *packed_interface_descriptor,
56 UCHAR *packed_entity_descriptor)
57 {
58
59 UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER *parser;
60 UX_HOST_CLASS_VIDEO *video;
61 UX_INTERFACE *streaming_interface;
62 UCHAR bInCollection;
63 UCHAR *baInterfaceNr;
64
65 /* Get parse data. */
66 parser = (UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER *)arg;
67
68 /* Get video instance. */
69 video = parser -> video;
70
71 if (packed_interface_descriptor[6] == UX_HOST_CLASS_VIDEO_SUBCLASS_CONTROL)
72 {
73
74 /* Parse VC descriptors. */
75
76 /* Locate control interface. */
77 if (video -> ux_host_class_video_control_interface_number == 0xFF)
78 {
79
80 /* Parse header. */
81 if (packed_entity_descriptor[2] == UX_HOST_CLASS_VIDEO_VC_HEADER)
82 {
83
84 /* Get streaming interface. */
85 streaming_interface = video -> ux_host_class_video_streaming_interface;
86
87 /* Check if this the VC interface is expected. */
88 bInCollection = packed_entity_descriptor[11];
89 baInterfaceNr = packed_entity_descriptor + 12;
90
91 /* Validation:
92 * baInterfaceNr not exceeding current descriptor.
93 */
94 if (packed_entity_descriptor[0] + packed_entity_descriptor < baInterfaceNr + bInCollection)
95 return(1);
96
97 while(bInCollection)
98 {
99
100 /* Streaming interface belongs to this control interface. */
101 if (*baInterfaceNr == streaming_interface -> ux_interface_descriptor.bInterfaceNumber)
102 {
103 video -> ux_host_class_video_control_interface_number = packed_interface_descriptor[2];
104 parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_HEADER;
105 return(0);
106 }
107
108 /* Next interface number in descriptor. */
109 baInterfaceNr ++;
110 bInCollection --;
111 }
112 }
113
114 /* Not expected interface, just try next descriptor. */
115 return(0);
116 }
117 else if (packed_interface_descriptor[2] == video -> ux_host_class_video_control_interface_number)
118 {
119
120 /* It's the expected VC interface. */
121
122 /* Parse UX_HOST_CLASS_VIDEO_VC_PROCESSING_UNIT as feature_unit_id. */
123 if (packed_entity_descriptor[2] == UX_HOST_CLASS_VIDEO_VC_PROCESSING_UNIT &&
124 video -> ux_host_class_video_feature_unit_id == 0)
125 {
126 parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_PU;
127
128 /* Save as feature unit ID. */
129 video -> ux_host_class_video_feature_unit_id = packed_entity_descriptor[3];
130 }
131
132 /* Parse UX_HOST_CLASS_VIDEO_VC_INPUT_TERMINAL and type (first only). */
133 if (packed_entity_descriptor[2] == UX_HOST_CLASS_VIDEO_VC_INPUT_TERMINAL &&
134 video -> ux_host_class_video_terminal_id == 0)
135 {
136 parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_IT;
137
138 /* Save the video terminal ID. */
139 video -> ux_host_class_video_terminal_id = packed_entity_descriptor[3];
140
141 /* Save the video terminal type. */
142 video -> ux_host_class_video_terminal_type = _ux_utility_short_get(packed_entity_descriptor + 4);
143 }
144 }
145 }
146 else
147 {
148
149 /* Parse VS descriptors. */
150 if (packed_entity_descriptor[2] == UX_HOST_CLASS_VIDEO_VS_INPUT_HEADER)
151 {
152 parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VS_HEADER;
153
154 /* Get the number of formats. */
155 video -> ux_host_class_video_number_formats = packed_entity_descriptor[3];
156
157 /* Get the length of formats. */
158 video -> ux_host_class_video_length_formats = _ux_utility_short_get(packed_entity_descriptor + 4);
159
160 /* Save the descriptor where the formats reside. */
161 video -> ux_host_class_video_format_address = packed_entity_descriptor;
162 }
163 }
164 return(0);
165 }
166
167
168 /**************************************************************************/
169 /* */
170 /* FUNCTION RELEASE */
171 /* */
172 /* _ux_host_class_video_activate PORTABLE C */
173 /* 6.2.0 */
174 /* AUTHOR */
175 /* */
176 /* Chaoqiong Xiao, Microsoft Corporation */
177 /* */
178 /* DESCRIPTION */
179 /* */
180 /* This function activates the video class. It may be called twice by */
181 /* the same device if there is a video control interface to this */
182 /* device. */
183 /* */
184 /* INPUT */
185 /* */
186 /* command Pointer to command */
187 /* */
188 /* OUTPUT */
189 /* */
190 /* Completion Status */
191 /* */
192 /* CALLS */
193 /* */
194 /* _ux_host_class_video_configure Configure the video class */
195 /* _ux_host_class_video_descriptor_get Get video descriptor */
196 /* _ux_host_class_video_input_terminal_get */
197 /* Get input terminal */
198 /* _ux_host_class_video_input_format_get Get input format */
199 /* _ux_host_class_video_control_list_get Get controls */
200 /* _ux_host_stack_class_instance_create Create class instance */
201 /* _ux_host_stack_class_instance_destroy Destroy class instance */
202 /* _ux_utility_memory_allocate Allocate a memory block */
203 /* _ux_utility_memory_free Free a memory block */
204 /* _ux_host_semaphore_create Create protection semaphore */
205 /* */
206 /* CALLED BY */
207 /* */
208 /* Video Class */
209 /* */
210 /* RELEASE HISTORY */
211 /* */
212 /* DATE NAME DESCRIPTION */
213 /* */
214 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
215 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
216 /* used entities parsing API, */
217 /* created new semaphore to */
218 /* protect control requests, */
219 /* resulting in version 6.1 */
220 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
221 /* refined macros names, */
222 /* resulting in version 6.1.10 */
223 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
224 /* internal clean up, */
225 /* fixed standalone compile, */
226 /* resulting in version 6.1.11 */
227 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
228 /* fixed parameter/variable */
229 /* names conflict C++ keyword, */
230 /* resulting in version 6.1.12 */
231 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
232 /* improved VC header check, */
233 /* resulting in version 6.2.0 */
234 /* */
235 /**************************************************************************/
_ux_host_class_video_activate(UX_HOST_CLASS_COMMAND * command)236 UINT _ux_host_class_video_activate(UX_HOST_CLASS_COMMAND *command)
237 {
238
239 UX_INTERFACE *interface_ptr;
240 UX_HOST_CLASS_VIDEO *video;
241 UINT status;
242 UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER parser;
243
244
245 /* The video is always activated by the interface descriptor and not the
246 device descriptor. */
247 interface_ptr = (UX_INTERFACE *) command -> ux_host_class_command_container;
248
249 /* Check the subclass of the new device. If it is a Video Control Interface,
250 we don't need to create an instance of this function. When we get the streaming interface,
251 we will search the video control interface for the device. */
252 if (interface_ptr -> ux_interface_descriptor.bInterfaceSubClass == UX_HOST_CLASS_VIDEO_SUBCLASS_CONTROL)
253 return(UX_SUCCESS);
254
255 /* Obtain memory for this class instance. */
256 video = (UX_HOST_CLASS_VIDEO *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_VIDEO));
257 if (video == UX_NULL)
258 return(UX_MEMORY_INSUFFICIENT);
259
260 /* Store the class container into this instance. */
261 video -> ux_host_class_video_class = command -> ux_host_class_command_class_ptr;
262
263 /* Store the interface container into the video class instance. */
264 video -> ux_host_class_video_streaming_interface = interface_ptr;
265
266 /* Store the device container into the video class instance. */
267 video -> ux_host_class_video_device = interface_ptr -> ux_interface_configuration -> ux_configuration_device;
268
269 /* This instance of the device must also be stored in the interface container. */
270 interface_ptr -> ux_interface_class_instance = (VOID *) video;
271
272 /* Create this class instance. */
273 _ux_host_stack_class_instance_create(video -> ux_host_class_video_class, (VOID *) video);
274
275 /* Configure the video. */
276 status = _ux_host_class_video_configure(video);
277
278 /* Get the video descriptor (all the class specific stuff) and memorize them
279 as we will need these descriptors to change settings. */
280 if (status == UX_SUCCESS)
281 status = _ux_host_class_video_descriptor_get(video);
282
283 /* Use parser to locate streaming terminal, formats and video controls. */
284 if (status == UX_SUCCESS)
285 {
286 parser.video = video;
287 parser.parsed_flags = 0;
288 video -> ux_host_class_video_control_interface_number = 0xFF;
289 status = _ux_host_class_video_entities_parse(video,
290 _ux_host_class_video_descriptors_parser, (VOID *)&parser);
291 if (parser.parsed_flags != UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_DONE)
292
293 /* Some of expected descriptors not found. */
294 status = UX_HOST_CLASS_VIDEO_WRONG_TYPE;
295 }
296
297 /* Create the semaphore to protect multiple threads from accessing the same
298 video instance. */
299 if (status == UX_SUCCESS)
300 {
301 status = _ux_host_semaphore_create(&video -> ux_host_class_video_semaphore, "ux_video_semaphore", 1);
302 if (status != UX_SUCCESS)
303 status = UX_SEMAPHORE_ERROR;
304 }
305
306 /* Create the semaphore to protect multiple threads from issuing the control
307 request at the same time. */
308 if (status == UX_SUCCESS)
309 {
310 status = _ux_host_semaphore_create(&video -> ux_host_class_video_semaphore_control_request, "ux_video_semaphore_control", 1);
311 if (status != UX_SUCCESS)
312 status = UX_SEMAPHORE_ERROR;
313 }
314
315 if (status == UX_SUCCESS)
316 {
317
318 /* Mark the video as live now. */
319 video -> ux_host_class_video_state = UX_HOST_CLASS_INSTANCE_LIVE;
320
321 /* If all is fine and the device is mounted, we may need to inform the application
322 if a function has been programmed in the system structure. */
323 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
324 {
325
326 /* Call system change function. */
327 _ux_system_host -> ux_system_host_change_function(UX_DEVICE_INSERTION, video -> ux_host_class_video_class, (VOID *) video);
328 }
329
330 /* If trace is enabled, insert this event into the trace buffer. */
331 //UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_VIDEO_ACTIVATE, video, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
332
333 /* If trace is enabled, register this object. */
334 UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, video, 0, 0, 0)
335
336 /* Return success. */
337 return(UX_SUCCESS);
338 }
339
340 /* There was error, free resources. */
341
342 /* The last resource, video -> ux_host_class_video_semaphore_control_request is not created or created error,
343 no need to free. */
344
345 /* Destroy the semaphore. */
346 if (_ux_host_semaphore_created(&video -> ux_host_class_video_semaphore))
347 _ux_host_semaphore_delete(&video -> ux_host_class_video_semaphore);
348
349 /* Destroy the class instance. */
350 _ux_host_stack_class_instance_destroy(video -> ux_host_class_video_class, (VOID *) video);
351
352 /* This instance of the device must also be cleared in the interface container. */
353 interface_ptr -> ux_interface_class_instance = UX_NULL;
354
355 /* Free instance memory. */
356 _ux_utility_memory_free(video);
357
358 /* Return completion status. */
359 return(status);
360 }
361
362