int testEnumFormats(struct node *node)
{
	static const __u32 buftype2cap[] = {
		0,
		V4L2_CAP_VIDEO_CAPTURE,
		V4L2_CAP_VIDEO_OUTPUT,
		V4L2_CAP_VIDEO_OVERLAY,
		V4L2_CAP_VBI_CAPTURE,
		V4L2_CAP_VBI_OUTPUT,
		V4L2_CAP_SLICED_VBI_CAPTURE,
		V4L2_CAP_SLICED_VBI_OUTPUT,
		V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
		V4L2_CAP_VIDEO_CAPTURE_MPLANE,
		V4L2_CAP_VIDEO_OUTPUT_MPLANE,
	};
	int type;
	int ret;

	for (type = 0; type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; type++) {
		ret = testEnumFormatsType(node, (enum v4l2_buf_type)type);
		if (ret > 0)
			return ret;
		switch (type) {
		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
			if (ret < 0 && (node->caps & buftype2cap[type]))
				return fail("%s cap set, but no %s formats defined\n",
						buftype2s(type).c_str(), buftype2s(type).c_str());
			if (!ret && !(node->caps & buftype2cap[type]))
				return fail("%s cap not set, but %s formats defined\n",
						buftype2s(type).c_str(), buftype2s(type).c_str());
			break;
		default:
			if (!ret)
				return fail("Buffer type %s not allowed!\n", buftype2s(type).c_str());
			break;
		}
	}

	ret = testEnumFormatsType(node, V4L2_BUF_TYPE_PRIVATE);
	if (ret > 0)
		return ret;
	if (!ret)
		warn("Buffer type PRIVATE allowed!\n");
		
	ret = testEnumFrameSizes(node, 0x20202020);
	if (ret >= 0)
		return fail("Accepted framesize for invalid format\n");
	ret = testEnumFrameIntervals(node, 0x20202020, 640, 480, false);
	if (ret >= 0)
		return fail("Accepted frameinterval for invalid format\n");
	return 0;
}
static int testEnumFormatsType(struct node *node, unsigned type)
{
	pixfmt_set &set = node->buftype_pixfmts[type];
	struct v4l2_fmtdesc fmtdesc;
	unsigned f = 0;
	int ret;

	for (;;) {
		memset(&fmtdesc, 0xff, sizeof(fmtdesc));
		fmtdesc.type = type;
		fmtdesc.index = f;

		ret = doioctl(node, VIDIOC_ENUM_FMT, &fmtdesc);
		if (ret == ENOTTY)
			return ret;
		if (f == 0 && ret == EINVAL)
			return ENOTTY;
		if (ret == EINVAL)
			break;
		if (ret)
			return fail("expected EINVAL, but got %d when enumerating buftype %d\n", ret, type);
		ret = check_0(fmtdesc.reserved, sizeof(fmtdesc.reserved));
		if (ret)
			return fail("fmtdesc.reserved not zeroed\n");
		if (fmtdesc.index != f)
			return fail("fmtdesc.index was modified\n");
		if (fmtdesc.type != type)
			return fail("fmtdesc.type was modified\n");
		ret = check_ustring(fmtdesc.description, sizeof(fmtdesc.description));
		if (ret)
			return fail("fmtdesc.description not set\n");
		if (!fmtdesc.pixelformat)
			return fail("fmtdesc.pixelformat not set\n");
		if (!wrapper && (fmtdesc.flags & V4L2_FMT_FLAG_EMULATED))
			return fail("drivers must never set the emulated flag\n");
		if (fmtdesc.flags & ~(V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_EMULATED))
			return fail("unknown flag %08x returned\n", fmtdesc.flags);
		ret = testEnumFrameSizes(node, fmtdesc.pixelformat);
		if (ret && ret != ENOTTY)
			return ret;
		if (ret == 0 && !(node->caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)))
			return fail("found framesizes when no video capture is supported\n");
		f++;
		if (type == V4L2_BUF_TYPE_PRIVATE)
			continue;
		// Update array in v4l2-compliance.h if new buffer types are added
		assert(type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
		if (set.find(fmtdesc.pixelformat) != set.end())
			return fail("duplicate format %08x\n", fmtdesc.pixelformat);
		set.insert(fmtdesc.pixelformat);
	}
	info("found %d formats for buftype %d\n", f, type);
	return 0;
}
int testEnumFormats(struct node *node)
{
	bool supported = false;
	unsigned type;
	int ret;

	for (type = 0; type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; type++) {
		ret = testEnumFormatsType(node, type);
		if (ret && ret != ENOTTY)
			return ret;
		if (!ret)
			supported = true;
		switch (type) {
		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
			if (ret && (node->caps & buftype2cap[type]))
				return fail("%s cap set, but no %s formats defined\n",
						buftype2s(type).c_str(), buftype2s(type).c_str());
			if (!ret && !(node->caps & buftype2cap[type]))
				return fail("%s cap not set, but %s formats defined\n",
						buftype2s(type).c_str(), buftype2s(type).c_str());
			break;
		default:
			if (!ret)
				return fail("Buffer type %s not allowed!\n", buftype2s(type).c_str());
			break;
		}
	}

	ret = testEnumFormatsType(node, V4L2_BUF_TYPE_PRIVATE);
	if (ret && ret != ENOTTY)
		return ret;
	if (!ret) {
		supported = true;
		warn("Buffer type PRIVATE allowed!\n");
	}

	ret = testEnumFrameSizes(node, 0x20202020);
	if (ret != ENOTTY)
		return fail("Accepted framesize for invalid format\n");
	ret = testEnumFrameIntervals(node, 0x20202020, 640, 480, false);
	if (ret != ENOTTY)
		return fail("Accepted frameinterval for invalid format\n");
	return supported ? 0 : ENOTTY;
}