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:
parent
50d2d1446f
commit
3b345568bc
@ -640,6 +640,8 @@ gst_uvc_sink_init (GstUvcSink * self)
|
|||||||
gst_pad_set_query_function (self->sinkpad, gst_uvc_sink_query);
|
gst_pad_set_query_function (self->sinkpad, gst_uvc_sink_query);
|
||||||
gst_pad_set_event_function (self->sinkpad, gst_uvc_sink_event);
|
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 ();
|
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:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
gst_element_sync_state_with_parent (GST_ELEMENT (self->fakesink));
|
gst_element_sync_state_with_parent (GST_ELEMENT (self->fakesink));
|
||||||
gst_uvc_sink_remove_idle_probe (self);
|
gst_uvc_sink_remove_idle_probe (self);
|
||||||
|
self->request_error_code = REQUEST_ERROR_CODE_NO_ERROR;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
if (!gst_uvc_sink_unwatch (self))
|
if (!gst_uvc_sink_unwatch (self))
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS GST_DEBUG_CATEGORY_EXTERN (uvcsink_debug);
|
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())
|
#define GST_TYPE_UVCSINK (gst_uvc_sink_get_type())
|
||||||
G_DECLARE_FINAL_TYPE (GstUvcSink, gst_uvc_sink, GST, UVCSINK, GstBin)
|
G_DECLARE_FINAL_TYPE (GstUvcSink, gst_uvc_sink, GST, UVCSINK, GstBin)
|
||||||
|
|
||||||
@ -54,6 +57,8 @@ struct _GstUvcSink
|
|||||||
|
|
||||||
int control;
|
int control;
|
||||||
|
|
||||||
|
int request_error_code;
|
||||||
|
|
||||||
/* probes */
|
/* probes */
|
||||||
int buffer_peer_probe_id;
|
int buffer_peer_probe_id;
|
||||||
int idle_probe_id;
|
int idle_probe_id;
|
||||||
|
@ -343,7 +343,7 @@ uvc_events_process_streaming (GstUvcSink * self, uint8_t req, uint8_t cs,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
uvc_events_parse_control (GstUvcSink * self, uint8_t req,
|
uvc_events_parse_control (GstUvcSink * self, uint8_t req,
|
||||||
uint8_t cs, uint8_t entity_id, uint8_t len, struct uvc_request_data *resp)
|
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:
|
case 0:
|
||||||
GST_DEBUG_OBJECT (self, "%s",
|
GST_DEBUG_OBJECT (self, "%s",
|
||||||
uvc_video_control_interface_control_selector_name (cs));
|
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:
|
case 1:
|
||||||
GST_DEBUG_OBJECT (self, "%s: %s",
|
GST_DEBUG_OBJECT (self, "%s: %s",
|
||||||
uvc_camera_terminal_control_selector_name (cs),
|
uvc_camera_terminal_control_selector_name (cs),
|
||||||
uvc_request_name (req));
|
uvc_request_name (req));
|
||||||
break;
|
goto error;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
GST_DEBUG_OBJECT (self, "%s: %s",
|
GST_DEBUG_OBJECT (self, "%s: %s",
|
||||||
uvc_processing_unit_control_selector_name (cs),
|
uvc_processing_unit_control_selector_name (cs),
|
||||||
uvc_request_name (req));
|
uvc_request_name (req));
|
||||||
break;
|
goto error;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GST_DEBUG_OBJECT (self,
|
GST_DEBUG_OBJECT (self,
|
||||||
"Unknown entity ID (0x%02x), CS: 0x%02x, Request %s (0x%02x)",
|
"Unknown entity ID (0x%02x), CS: 0x%02x, Request %s (0x%02x)",
|
||||||
entity_id, cs, uvc_request_name (req), req);
|
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
|
static int
|
||||||
@ -389,9 +413,8 @@ uvc_events_process_class (GstUvcSink * self,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (interface == UVC_STRING_CONTROL_IDX) {
|
if (interface == UVC_STRING_CONTROL_IDX) {
|
||||||
uvc_events_parse_control (self, ctrl->bRequest, ctrl->wValue >> 8,
|
return uvc_events_parse_control (self, ctrl->bRequest,
|
||||||
ctrl->wIndex >> 8, ctrl->wLength, resp);
|
ctrl->wValue >> 8, ctrl->wIndex >> 8, ctrl->wLength, resp);
|
||||||
return -EOPNOTSUPP;
|
|
||||||
} else if (interface == UVC_STRING_STREAMING_IDX) {
|
} else if (interface == UVC_STRING_STREAMING_IDX) {
|
||||||
return uvc_events_process_streaming (self, ctrl->bRequest,
|
return uvc_events_process_streaming (self, ctrl->bRequest,
|
||||||
le16toh (ctrl->wValue) >> 8, resp);
|
le16toh (ctrl->wValue) >> 8, resp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user