Hi, v5 can be found from: https://lore.kernel.org/all/20230529085003.47207-1-tomi.valkeinen@xxxxxxxxxxxxxxxx/ Changes in v6: - Use NUM_ROUTES_MAX all around - Improve the routing test (testSubDevRouting) - Improve the v4l2-ctl help text for subdev options Range diff against v5 can be found below. Tomi Tomi Valkeinen (8): v4l2-ctl: Improve sub-device options help text v4l2-ctl: Add routing and streams support media-ctl: Add support for routes and streams v4l2-ctl/compliance: Add routing and streams multiplexed streams v4l2-ctl/compliance: Add simple routing test media-ctl: Check for Streams API support utils/common: Set V4L2_SUBDEV_CLIENT_CAP_STREAMS for subdevs v4l2-ctl: Check for Streams API support utils/common/cv4l-helpers.h | 1 + utils/common/v4l-helpers.h | 18 + utils/common/v4l2-info.h | 6 + utils/media-ctl/libmediactl.c | 43 +++ utils/media-ctl/libv4l2subdev.c | 345 +++++++++++++++++-- utils/media-ctl/media-ctl.c | 113 +++++- utils/media-ctl/mediactl-priv.h | 1 + utils/media-ctl/mediactl.h | 16 + utils/media-ctl/options.c | 15 +- utils/media-ctl/options.h | 1 + utils/media-ctl/v4l2subdev.h | 66 +++- utils/v4l2-compliance/v4l2-compliance.cpp | 132 +++++-- utils/v4l2-compliance/v4l2-compliance.h | 9 +- utils/v4l2-compliance/v4l2-test-subdevs.cpp | 117 ++++++- utils/v4l2-ctl/v4l2-ctl-subdev.cpp | 364 ++++++++++++++++++-- utils/v4l2-ctl/v4l2-ctl.cpp | 2 + utils/v4l2-ctl/v4l2-ctl.h | 2 + 17 files changed, 1128 insertions(+), 123 deletions(-) Range-diff against v5: -: -------- > 1: 5b814067 v4l2-ctl: Improve sub-device options help text 1: 129c4dcd ! 2: 8e349ff0 v4l2-ctl: Add routing and streams support @@ Commit message Signed-off-by: Tomi Valkeinen <tomi.valkeinen@xxxxxxxxxxxxxxxx> - ## utils/v4l2-ctl/v4l2-ctl-subdev.cpp ## + ## utils/common/v4l2-info.h ## @@ - #include "v4l2-ctl.h" + #include <linux/videodev2.h> + #include <linux/v4l2-subdev.h> -+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) -+ +/* + * The max value comes from a check in the kernel source code + * drivers/media/v4l2-core/v4l2-ioctl.c check_array_args() + */ +#define NUM_ROUTES_MAX 256 ++ + struct flag_def { + unsigned flag; + const char *str; + + ## utils/v4l2-ctl/v4l2-ctl-subdev.cpp ## +@@ + #include "v4l2-ctl.h" + ++#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + struct mbus_name { const char *name; @@ utils/v4l2-ctl/v4l2-ctl-subdev.cpp: static const struct mbus_name mbus_names[] = void subdev_usage() { printf("\nSub-Device options:\n" + "Note: all parameters below (pad, code, etc.) are optional unless otherwise noted and default to 0\n" - " --list-subdev-mbus-codes <pad>\n" +- " display supported mediabus codes for this pad\n" + " --list-subdev-mbus-codes pad=<pad>,stream=<stream>\n" - " display supported mediabus codes for this pad (0 is default)\n" ++ " display supported mediabus codes for this pad and stream\n" " [VIDIOC_SUBDEV_ENUM_MBUS_CODE]\n" - " --list-subdev-framesizes pad=<pad>,code=<code>\n" +- " list supported framesizes for this pad and code\n" + " --list-subdev-framesizes pad=<pad>,stream=<stream>,code=<code>\n" - " list supported framesizes for this pad and code\n" ++ " list supported framesizes for this pad, stream and code\n" " [VIDIOC_SUBDEV_ENUM_FRAME_SIZE]\n" " <code> is the value of the mediabus code\n" - " --list-subdev-frameintervals pad=<pad>,width=<w>,height=<h>,code=<code>\n" +- " list supported frame intervals for this pad and code and\n" + " --list-subdev-frameintervals pad=<pad>,stream=<stream>,width=<w>,height=<h>,code=<code>\n" - " list supported frame intervals for this pad and code and\n" ++ " list supported frame intervals for this pad, stream, code and\n" " the given width and height [VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL]\n" " <code> is the value of the mediabus code\n" - " --get-subdev-fmt [<pad>]\n" - " query the frame format for the given pad [VIDIOC_SUBDEV_G_FMT]\n" - " --get-subdev-selection pad=<pad>,target=<target>\n" + " --get-subdev-fmt pad=<pad>,stream=<stream>\n" -+ " query the frame format for the given pad and optional stream [VIDIOC_SUBDEV_G_FMT]\n" -+ " <pad> the pad to get the format from\n" -+ " <stream> the stream to get the format from (0 if not specified)\n" ++ " query the frame format for the given pad and stream [VIDIOC_SUBDEV_G_FMT]\n" + " --get-subdev-selection pad=<pad>,stream=<stream>,target=<target>\n" " query the frame selection rectangle [VIDIOC_SUBDEV_G_SELECTION]\n" " See --set-subdev-selection command for the valid <target> values.\n" @@ utils/v4l2-ctl/v4l2-ctl-subdev.cpp: static const struct mbus_name mbus_names[] = + " --try-subdev-fmt pad=<pad>,stream=<stream>,width=<w>,height=<h>,code=<code>,field=<f>,colorspace=<c>,\n" " xfer=<xf>,ycbcr=<y>,hsv=<hsv>,quantization=<q>\n" - " set the frame format [VIDIOC_SUBDEV_S_FMT]\n" -+ " set the frame format for the given pad and optional stream [VIDIOC_SUBDEV_S_FMT]\n" ++ " set the frame format for the given pad and stream [VIDIOC_SUBDEV_S_FMT]\n" + " <pad> the pad to get the format from\n" -+ " <stream> the stream to get the format from (0 if not specified)\n" ++ " <stream> the stream to get the format\n" " <code> is the value of the mediabus code\n" " <f> can be one of the following field layouts:\n" " any, none, top, bottom, interlaced, seq_tb, seq_bt,\n" 2: 335faf8e ! 3: 5977db8f media-ctl: Add support for routes and streams @@ utils/media-ctl/libmediactl.c: struct media_pad *media_parse_pad(struct media_de { ## utils/media-ctl/libv4l2subdev.c ## +@@ + #include "tools.h" + #include "v4l2subdev.h" + ++/* ++ * The max value comes from a check in the kernel source code ++ * drivers/media/v4l2-core/v4l2-ioctl.c check_array_args() ++ */ ++#define NUM_ROUTES_MAX 256 ++ + int v4l2_subdev_open(struct media_entity *entity) + { + if (entity->fd != -1) @@ utils/media-ctl/libv4l2subdev.c: void v4l2_subdev_close(struct media_entity *entity) } @@ utils/media-ctl/libv4l2subdev.c: int v4l2_subdev_set_frame_interval(struct media + + p++; + -+ routes = calloc(256, sizeof(routes[0])); ++ routes = calloc(NUM_ROUTES_MAX, sizeof(routes[0])); + if (!routes) + return -ENOMEM; + 3: 1b4c8839 ! 4: 7af03ced v4l2-ctl/compliance: Add routing and streams multiplexed streams @@ utils/v4l2-compliance/v4l2-compliance.cpp: void testNode(struct node &node, stru bool has_source = false; bool has_sink = false; + struct v4l2_subdev_routing sd_routing[2] = {}; -+ struct v4l2_subdev_route sd_routes[2][256] = {}; ++ struct v4l2_subdev_route sd_routes[2][NUM_ROUTES_MAX] = {}; + bool has_routes = !!(subdevcap.capabilities & V4L2_SUBDEV_CAP_STREAMS); + int ret; @@ utils/v4l2-compliance/v4l2-compliance.cpp: void testNode(struct node &node, stru + + sd_routing[which].which = which; + sd_routing[which].routes = (__u64)sd_routes[which]; -+ sd_routing[which].num_routes = 256; ++ sd_routing[which].num_routes = NUM_ROUTES_MAX; + + ret = doioctl(&node, VIDIOC_SUBDEV_G_ROUTING, &sd_routing[which]); + if (ret) { 4: 833caa0b ! 5: abb2d296 v4l2-ctl/compliance: Add simple routing test @@ Metadata ## Commit message ## v4l2-ctl/compliance: Add simple routing test - Add a very simple test for - VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING. + Add a simple test for VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING. We can't (at least at the moment) really know here what kind of routings the driver would accept, but we can test a VIDIOC_SUBDEV_G_ROUTING call, followed by a VIDIOC_SUBDEV_S_ROUTING call with the routing we received. + Additionally, we can check that the returned pads and flags look fine, + and also that setting obviously invalid routing will fail. + Signed-off-by: Tomi Valkeinen <tomi.valkeinen@xxxxxxxxxxxxxxxx> - Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@xxxxxxxxxxxxxxxx> ## utils/v4l2-compliance/v4l2-compliance.cpp ## @@ utils/v4l2-compliance/v4l2-compliance.cpp: void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_ @@ utils/v4l2-compliance/v4l2-test-subdevs.cpp: int testSubDevSelection(struct node + +int testSubDevRouting(struct node *node, unsigned which) +{ ++ const uint32_t all_route_flags_mask = V4L2_SUBDEV_ROUTE_FL_ACTIVE; + struct v4l2_subdev_routing routing = {}; -+ struct v4l2_subdev_route routes[256] = {}; ++ struct v4l2_subdev_route routes[NUM_ROUTES_MAX] = {}; ++ unsigned int i; ++ int ret; + + routing.which = which; + routing.routes = (__u64)&routes; -+ routing.num_routes = 256; ++ routing.num_routes = 0; ++ memset(routing.reserved, 0xff, sizeof(routing.reserved)); ++ ++ /* ++ * First test that G_ROUTING either returns success, or ENOSPC and ++ * updates num_routes. ++ */ ++ ++ ret = doioctl(node, VIDIOC_SUBDEV_G_ROUTING, &routing); ++ fail_on_test(ret && ret != ENOSPC); ++ fail_on_test(ret == ENOSPC && routing.num_routes == 0); ++ fail_on_test(check_0(routing.reserved, sizeof(routing.reserved))); ++ ++ if (routing.num_routes) ++ return 0; + ++ /* Then get the actual routes */ ++ ++ routing.num_routes = NUM_ROUTES_MAX; + fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_ROUTING, &routing)); + ++ /* Check the validity of route pads and flags */ ++ ++ if (node->pads) { ++ for (i = 0; i < routing.num_routes; ++i) { ++ const struct v4l2_subdev_route *route = &routes[i]; ++ const struct media_pad_desc *sink; ++ const struct media_pad_desc *source; ++ ++ fail_on_test(route->sink_pad >= node->entity.pads); ++ fail_on_test(route->source_pad >= node->entity.pads); ++ ++ sink = &node->pads[route->sink_pad]; ++ source = &node->pads[route->source_pad]; ++ ++ fail_on_test(!(sink->flags & MEDIA_PAD_FL_SINK)); ++ fail_on_test(!(source->flags & MEDIA_PAD_FL_SOURCE)); ++ fail_on_test(route->flags & ~all_route_flags_mask); ++ } ++ } ++ ++ /* Set the same routes back, which should always succeed. */ ++ ++ memset(routing.reserved, 0xff, sizeof(routing.reserved)); + fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_ROUTING, &routing)); ++ fail_on_test(check_0(routing.reserved, sizeof(routing.reserved))); ++ ++ /* Test setting invalid pads */ ++ ++ if (node->pads) { ++ for (i = 0; i < routing.num_routes; ++i) { ++ struct v4l2_subdev_route *route = &routes[i]; ++ ++ route->sink_pad = node->entity.pads + 1; ++ } ++ ++ memset(routing.reserved, 0xff, sizeof(routing.reserved)); ++ fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_ROUTING, &routing) != EINVAL); ++ fail_on_test(check_0(routing.reserved, sizeof(routing.reserved))); ++ } + + return 0; +} 5: 25214f41 = 6: bedf5aa3 media-ctl: Check for Streams API support 6: c2d70033 = 7: 6e432bea utils/common: Set V4L2_SUBDEV_CLIENT_CAP_STREAMS for subdevs 7: eb47955d = 8: 05c3e4e6 v4l2-ctl: Check for Streams API support -- 2.34.1