Commit 5489c8f2 authored by Josuah Demangeon's avatar Josuah Demangeon Committed by github-actions[bot]
Browse files

usb: uvc: allow the host to use short probe/commit messages



Some OSes like MacOS use shorter UVC 1.1 probe/commit messages even when
UVC 1.5 is supported, without bUsage, bBitDepthLuma, bmSettings,
bMaxNumberOfRefFramesPlus1, bmRateControlModes bmLayoutPerStream.
Accept messages of arbitrary size to safely be processed, ignoring all
missing fields, improving standard compliance.

Signed-off-by: default avatarJosuah Demangeon <me@josuah.net>
(cherry picked from commit ed9327de)
parent 413b789d
Loading
Loading
Loading
Loading
+20 −28
Original line number Diff line number Diff line
@@ -694,7 +694,8 @@ static int uvc_get_vs_probe(const struct device *dev, struct net_buf *const buf,
			    const struct usb_setup_packet *const setup)
{
	struct uvc_data *data = dev->data;
	size_t size = MIN(sizeof(struct uvc_probe), net_buf_tailroom(buf));
	const size_t size = MIN(sizeof(struct uvc_probe), net_buf_tailroom(buf));
	struct uvc_probe probe = {0};
	int ret;

	switch (setup->bRequest) {
@@ -702,19 +703,18 @@ static int uvc_get_vs_probe(const struct device *dev, struct net_buf *const buf,
		if (size < 1) {
			return -ENOTSUP;
		}

		net_buf_add_u8(buf, UVC_INFO_SUPPORTS_GET);
		return 0;
	case UVC_GET_LEN:
		if (size < 2) {
			return -ENOTSUP;
		}

		net_buf_add_le16(buf, sizeof(struct uvc_probe));
		return 0;
	case UVC_GET_DEF:
		if (size < sizeof(struct uvc_probe)) {
			return -ENOTSUP;
		}
		net_buf_add_mem(buf, &data->default_probe, sizeof(data->default_probe));
		net_buf_add_mem(buf, &data->default_probe, size);
		return 0;
	case UVC_GET_MIN:
		__fallthrough;
@@ -723,16 +723,12 @@ static int uvc_get_vs_probe(const struct device *dev, struct net_buf *const buf,
	case UVC_GET_MAX:
		__fallthrough;
	case UVC_GET_CUR:
		if (size < sizeof(struct uvc_probe)) {
			return -ENOTSUP;
		}

		ret = uvc_get_vs_probe_struct(dev, (struct uvc_probe *)buf->data, setup->bRequest);
		ret = uvc_get_vs_probe_struct(dev, &probe, setup->bRequest);
		if (ret != 0) {
			return ret;
		}

		net_buf_add(buf, sizeof(struct uvc_probe));
		net_buf_add_mem(buf, &probe, size);
		return 0;
	default:
		return -EINVAL;
@@ -742,45 +738,41 @@ static int uvc_get_vs_probe(const struct device *dev, struct net_buf *const buf,
static int uvc_set_vs_probe(const struct device *dev, const struct net_buf *const buf)
{
	struct uvc_data *data = dev->data;
	struct uvc_probe *probe;
	const size_t size = MIN(sizeof(struct uvc_probe), buf->len);
	struct uvc_probe probe = {0};
	struct uvc_probe max = {0};
	int ret;

	if (buf->len != sizeof(*probe)) {
		LOG_ERR("Expected probe message of %u bytes got %u", sizeof(*probe), buf->len);
		return -EINVAL;
	}

	probe = (struct uvc_probe *)buf->data;
	memcpy(&probe, buf->data, size);

	ret = uvc_get_vs_probe_struct(dev, &max, UVC_GET_MAX);
	if (ret != 0) {
		return ret;
	}

	if (probe->bFrameIndex > max.bFrameIndex) {
	if (probe.bFrameIndex > max.bFrameIndex) {
		LOG_WRN("The bFrameIndex %u requested is beyond the max %u",
			probe->bFrameIndex, max.bFrameIndex);
			probe.bFrameIndex, max.bFrameIndex);
		return -ERANGE;
	}

	if (probe->bFormatIndex > max.bFormatIndex) {
	if (probe.bFormatIndex > max.bFormatIndex) {
		LOG_WRN("The bFormatIndex %u requested is beyond the max %u",
			probe->bFormatIndex, max.bFormatIndex);
			probe.bFormatIndex, max.bFormatIndex);
		return -ERANGE;
	}

	if (probe->dwFrameInterval != 0) {
		data->video_frmival.numerator = sys_le32_to_cpu(probe->dwFrameInterval);
	if (probe.dwFrameInterval != 0) {
		data->video_frmival.numerator = sys_le32_to_cpu(probe.dwFrameInterval);
		data->video_frmival.denominator = USEC_PER_SEC * 100;
	}

	if (probe->bFrameIndex != 0) {
		data->frame_id = probe->bFrameIndex;
	if (probe.bFrameIndex != 0) {
		data->frame_id = probe.bFrameIndex;
	}

	if (probe->bFormatIndex != 0) {
		data->format_id = probe->bFormatIndex;
	if (probe.bFormatIndex != 0) {
		data->format_id = probe.bFormatIndex;
	}

	return 0;