uvcsink: Respond to control requests with proper error handling

The complete handling on the control interface is currently dead.
We return with EOPNOTSUPP for the caller to know that a response
to such requests is not valid. The host however may ask
control interface why these control requests were not available.

For this the UVC_VC_REQUEST_ERROR_CODE_CONTROL is used. As an overall
exception for the control interface we just always return 0x06 as
an response which is representing "not implemented".

This patch is a necessary feature to properly pass the UVC Functionality
Test of the USB3CV Compliance Software.

Fixes: 69c17461392d ('uvcgadget: Properly implement GET_INFO control responses')
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7524>
This commit is contained in:
Michael Grzeschik 2024-09-10 01:13:25 +02:00 committed by GStreamer Marge Bot
parent 50d2d1446f
commit 3b345568bc
3 changed files with 39 additions and 8 deletions

View File

@ -640,6 +640,8 @@ gst_uvc_sink_init (GstUvcSink * self)
gst_pad_set_query_function (self->sinkpad, gst_uvc_sink_query);
gst_pad_set_event_function (self->sinkpad, gst_uvc_sink_event);
self->request_error_code = REQUEST_ERROR_CODE_NO_ERROR;
self->cur_caps = gst_caps_new_empty ();
}
@ -985,6 +987,7 @@ gst_uvc_sink_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_element_sync_state_with_parent (GST_ELEMENT (self->fakesink));
gst_uvc_sink_remove_idle_probe (self);
self->request_error_code = REQUEST_ERROR_CODE_NO_ERROR;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
if (!gst_uvc_sink_unwatch (self))

View File

@ -17,6 +17,9 @@
G_BEGIN_DECLS GST_DEBUG_CATEGORY_EXTERN (uvcsink_debug);
#define REQUEST_ERROR_CODE_NO_ERROR 0x0
#define REQUEST_ERROR_CODE_INVALID_REQUEST 0x6
#define GST_TYPE_UVCSINK (gst_uvc_sink_get_type())
G_DECLARE_FINAL_TYPE (GstUvcSink, gst_uvc_sink, GST, UVCSINK, GstBin)
@ -54,6 +57,8 @@ struct _GstUvcSink
int control;
int request_error_code;
/* probes */
int buffer_peer_probe_id;
int idle_probe_id;

View File

@ -343,7 +343,7 @@ uvc_events_process_streaming (GstUvcSink * self, uint8_t req, uint8_t cs,
return 0;
}
static void
static int
uvc_events_parse_control (GstUvcSink * self, uint8_t req,
uint8_t cs, uint8_t entity_id, uint8_t len, struct uvc_request_data *resp)
{
@ -357,26 +357,50 @@ uvc_events_parse_control (GstUvcSink * self, uint8_t req,
case 0:
GST_DEBUG_OBJECT (self, "%s",
uvc_video_control_interface_control_selector_name (cs));
break;
/*
* For ERROR_CODE_CONTROL requests we have to return not implemented so
* bail out gracefully here to properly send control is not
* currently implemented. (0x06) (4.2.1.2 Request Error Code Control)
*/
if (cs == UVC_VC_REQUEST_ERROR_CODE_CONTROL) {
resp->data[0] = self->request_error_code;
resp->length = 1;
break;
}
goto error;
case 1:
GST_DEBUG_OBJECT (self, "%s: %s",
uvc_camera_terminal_control_selector_name (cs),
uvc_request_name (req));
break;
goto error;
case 2:
GST_DEBUG_OBJECT (self, "%s: %s",
uvc_processing_unit_control_selector_name (cs),
uvc_request_name (req));
break;
goto error;
default:
GST_DEBUG_OBJECT (self,
"Unknown entity ID (0x%02x), CS: 0x%02x, Request %s (0x%02x)",
entity_id, cs, uvc_request_name (req), req);
break;
goto error;
}
self->request_error_code = REQUEST_ERROR_CODE_NO_ERROR;
return 0;
error:
self->request_error_code = REQUEST_ERROR_CODE_INVALID_REQUEST;
/*
* Stall and don't response the control requests that are
* actually not implemented
*/
return -EOPNOTSUPP;
}
static int
@ -389,9 +413,8 @@ uvc_events_process_class (GstUvcSink * self,
return -EINVAL;
if (interface == UVC_STRING_CONTROL_IDX) {
uvc_events_parse_control (self, ctrl->bRequest, ctrl->wValue >> 8,
ctrl->wIndex >> 8, ctrl->wLength, resp);
return -EOPNOTSUPP;
return uvc_events_parse_control (self, ctrl->bRequest,
ctrl->wValue >> 8, ctrl->wIndex >> 8, ctrl->wLength, resp);
} else if (interface == UVC_STRING_STREAMING_IDX) {
return uvc_events_process_streaming (self, ctrl->bRequest,
le16toh (ctrl->wValue) >> 8, resp);