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 /** 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_control_request PORTABLE C */
36 /* 6.1.11 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function manages the based sent by the host on the control */
44 /* endpoints with a CLASS or VENDOR SPECIFIC type. */
45 /* */
46 /* INPUT */
47 /* */
48 /* command Pointer to class command */
49 /* */
50 /* OUTPUT */
51 /* */
52 /* Completion Status */
53 /* */
54 /* CALLS */
55 /* */
56 /* _ux_device_stack_endpoint_stall Endpoint stall */
57 /* */
58 /* CALLED BY */
59 /* */
60 /* Device Video Class */
61 /* */
62 /* RELEASE HISTORY */
63 /* */
64 /* DATE NAME DESCRIPTION */
65 /* */
66 /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */
67 /* */
68 /**************************************************************************/
_ux_device_class_video_control_request(UX_SLAVE_CLASS_COMMAND * command)69 UINT _ux_device_class_video_control_request(UX_SLAVE_CLASS_COMMAND *command)
70 {
71
72 UX_SLAVE_TRANSFER *transfer_request;
73 UX_SLAVE_DEVICE *device;
74 UX_SLAVE_CLASS *class_inst;
75 UX_DEVICE_CLASS_VIDEO *video;
76 UX_DEVICE_CLASS_VIDEO_STREAM *stream;
77 ULONG stream_index;
78 UCHAR request_type;
79 UCHAR request;
80 UCHAR index_low;
81 ULONG value_cs;
82 UCHAR *buffer;
83 UINT status;
84
85
86 /* Get the class container. */
87 class_inst = command -> ux_slave_class_command_class_ptr;
88
89 /* Get the video instance from this class container. */
90 video = (UX_DEVICE_CLASS_VIDEO *) class_inst -> ux_slave_class_instance;
91
92 /* Get the pointer to the device. */
93 device = &_ux_system_slave -> ux_system_slave_device;
94
95 /* Get the pointer to the transfer request associated with the control endpoint. */
96 transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
97
98 /* Get bmRequestType, wValue and wIndex low byte. */
99 request_type = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_REQUEST_TYPE];
100 request = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_REQUEST];
101 value_cs = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_VALUE + 1];
102 index_low = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_INDEX];
103 buffer = transfer_request -> ux_slave_transfer_request_data_pointer;
104
105 /* Check request target (only target interface is supported now). */
106 if ((request_type & UX_REQUEST_TARGET) != UX_REQUEST_TARGET_INTERFACE)
107 return(UX_ERROR);
108
109 /* Check request interface (wIndex low) of control. */
110 if (index_low == video -> ux_device_class_video_interface -> ux_slave_interface_descriptor.bInterfaceNumber)
111 {
112
113 /* Check control selector. */
114 switch(value_cs)
115 {
116 case UX_DEVICE_CLASS_VIDEO_VC_REQUEST_ERROR_CODE_CONTROL:
117
118 /* Must have at least 1 byte buffer. */
119 if (transfer_request->ux_slave_transfer_request_requested_length < 1)
120 return(UX_ERROR);
121
122 /* GET_CUR. */
123 if (request == UX_DEVICE_CLASS_VIDEO_GET_CUR)
124 {
125
126 /* Fill bRequestErrorCode. */
127 *buffer = (UCHAR)video -> ux_device_class_video_error;
128
129 /* Send data. */
130 status = _ux_device_stack_transfer_request(transfer_request, 1, 1);
131 return(status);
132 }
133
134 /* GET_INFO. */
135 if (request == UX_DEVICE_CLASS_VIDEO_GET_INFO)
136 {
137
138 /* Support GET_CUR | GET_INFO. */
139 *buffer = UX_DEVICE_CLASS_VIDEO_INFO_GET_REQUEST_SUPPORT;
140
141 /* Send data. */
142 status = _ux_device_stack_transfer_request(transfer_request, 1, 1);
143 return(status);
144 }
145
146 /* Request not expected. */
147 return(UX_ERROR);
148
149 default:
150 break;
151 }
152
153 /* By default it's not handled. */
154 status = UX_ERROR;
155
156 /* Invoke callback. */
157 if (video -> ux_device_class_video_callbacks.ux_device_class_video_request != UX_NULL)
158 {
159
160 /* Handled by callback. */
161 status = video -> ux_device_class_video_callbacks.ux_device_class_video_request(video, transfer_request);
162 }
163 return(status);
164 }
165
166 /* Check request index of stream. */
167 stream = video -> ux_device_class_video_streams;
168 for (stream_index = 0; stream_index < video -> ux_device_class_video_streams_nb; stream_index ++)
169 {
170
171 /* No stream. */
172 if (stream -> ux_device_class_video_stream_interface == UX_NULL)
173 break;
174
175 /* Check interface number. */
176 if (index_low == stream -> ux_device_class_video_stream_interface ->
177 ux_slave_interface_descriptor.bInterfaceNumber)
178 {
179
180 /* Check control selector. */
181 switch(value_cs)
182 {
183 case UX_DEVICE_CLASS_VIDEO_VS_STREAM_ERROR_CODE_CONTROL:
184
185 /* Must have at least 1 byte buffer. */
186 if (transfer_request->ux_slave_transfer_request_requested_length < 1)
187 return(UX_ERROR);
188
189 /* GET_CUR. */
190 if (request == UX_DEVICE_CLASS_VIDEO_GET_CUR)
191 {
192
193 /* Fill bRequestErrorCode. */
194 *buffer = (UCHAR)stream -> ux_device_class_video_stream_error;
195
196 /* Send data. */
197 status = _ux_device_stack_transfer_request(transfer_request, 1, 1);
198 return(status);
199 }
200
201 /* GET_INFO. */
202 if (request == UX_DEVICE_CLASS_VIDEO_GET_INFO)
203 {
204
205 /* Support GET_CUR | GET_INFO. */
206 *buffer = UX_DEVICE_CLASS_VIDEO_INFO_GET_REQUEST_SUPPORT;
207
208 /* Send data. */
209 status = _ux_device_stack_transfer_request(transfer_request, 1, 1);
210 return(status);
211 }
212
213 /* Request not expected. */
214 return(UX_ERROR);
215
216 default:
217 break;
218 }
219
220 /* By default it's not handled. */
221 status = UX_ERROR;
222
223 /* Invoke callback. */
224 if (stream -> ux_device_class_video_stream_callbacks.ux_device_class_video_stream_request != UX_NULL)
225 {
226
227 /* Handled by callback. */
228 status = stream -> ux_device_class_video_stream_callbacks.ux_device_class_video_stream_request(stream, transfer_request);
229 }
230 return(status);
231 }
232
233 /* Next stream. */
234 stream ++;
235 }
236
237 /* Not handled. */
238 return(UX_ERROR);
239 }
240