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