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