printf("]\n");
}
+static const char *v4l2_dv_type_to_string(unsigned int type)
+{
+ static const struct {
+ __u32 type;
+ const char *name;
+ } types[] = {
+ { V4L2_DV_BT_656_1120, "BT.656/1120" },
+ };
+
+ static char unknown[20];
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (types[i].type == type)
+ return types[i].name;
+ }
+
+ sprintf(unknown, "Unknown (%u)", type);
+ return unknown;
+}
+
+static const struct flag_name bt_standards[] = {
+ { V4L2_DV_BT_STD_CEA861, "CEA-861" },
+ { V4L2_DV_BT_STD_DMT, "DMT" },
+ { V4L2_DV_BT_STD_CVT, "CVT" },
+ { V4L2_DV_BT_STD_GTF, "GTF" },
+};
+
+static const struct flag_name bt_capabilities[] = {
+ { V4L2_DV_BT_CAP_INTERLACED, "interlaced" },
+ { V4L2_DV_BT_CAP_PROGRESSIVE, "progressive" },
+ { V4L2_DV_BT_CAP_REDUCED_BLANKING, "reduced-blanking" },
+ { V4L2_DV_BT_CAP_CUSTOM, "custom" },
+};
+
+static const struct flag_name bt_flags[] = {
+ { V4L2_DV_FL_REDUCED_BLANKING, "reduced-blanking" },
+ { V4L2_DV_FL_CAN_REDUCE_FPS, "can-reduce-fps" },
+ { V4L2_DV_FL_REDUCED_FPS, "reduced-fps" },
+ { V4L2_DV_FL_HALF_LINE, "half-line" },
+};
+
+static void v4l2_subdev_print_dv_timings(const struct v4l2_dv_timings *timings,
+ const char *name)
+{
+ printf("\t\t[dv.%s:%s", name, v4l2_dv_type_to_string(timings->type));
+
+ switch (timings->type) {
+ case V4L2_DV_BT_656_1120: {
+ const struct v4l2_bt_timings *bt = &timings->bt;
+ unsigned int htotal, vtotal;
+
+ htotal = V4L2_DV_BT_FRAME_WIDTH(bt);
+ vtotal = V4L2_DV_BT_FRAME_HEIGHT(bt);
+
+ printf(" %ux%u%s%llu (%ux%u)",
+ bt->width, bt->height, bt->interlaced ? "i" : "p",
+ (htotal * vtotal) > 0 ? (bt->pixelclock / (htotal * vtotal)) : 0,
+ htotal, vtotal);
+
+ printf(" stds:");
+ print_flags(bt_standards, ARRAY_SIZE(bt_standards),
+ bt->standards);
+ printf(" flags:");
+ print_flags(bt_flags, ARRAY_SIZE(bt_flags),
+ bt->flags);
+
+ break;
+ }
+ }
+
+ printf("]\n");
+}
+
+static void v4l2_subdev_print_pad_dv(struct media_entity *entity,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ struct v4l2_dv_timings_cap caps;
+ int ret;
+
+ caps.pad = pad;
+ ret = v4l2_subdev_get_dv_timings_caps(entity, &caps);
+ if (ret != 0)
+ return;
+
+ printf("\t\t[dv.caps:%s", v4l2_dv_type_to_string(caps.type));
+
+ switch (caps.type) {
+ case V4L2_DV_BT_656_1120:
+ printf(" min:%ux%u@%llu max:%ux%u@%llu",
+ caps.bt.min_width, caps.bt.min_height, caps.bt.min_pixelclock,
+ caps.bt.max_width, caps.bt.max_height, caps.bt.max_pixelclock);
+
+ printf(" stds:");
+ print_flags(bt_standards, ARRAY_SIZE(bt_standards),
+ caps.bt.standards);
+ printf(" caps:");
+ print_flags(bt_capabilities, ARRAY_SIZE(bt_capabilities),
+ caps.bt.capabilities);
+
+ break;
+ }
+
+ printf("]\n");
+}
+
+static void v4l2_subdev_print_subdev_dv(struct media_entity *entity)
+{
+ struct v4l2_dv_timings timings;
+ int ret;
+
+ ret = v4l2_subdev_query_dv_timings(entity, &timings);
+ switch (ret) {
+ case -ENOLINK:
+ printf("\t\t[dv.query:no-link]\n");
+ break;
+ case -ENOLCK:
+ printf("\t\t[dv.query:no-lock]\n");
+ break;
+ case -ERANGE:
+ printf("\t\t[dv.query:out-of-range]\n");
+ break;
+ case 0:
+ v4l2_subdev_print_dv_timings(&timings, "detect");
+ break;
+ default:
+ return;
+ }
+
+ ret = v4l2_subdev_get_dv_timings(entity, &timings);
+ if (ret == 0)
+ v4l2_subdev_print_dv_timings(&timings, "current");
+}
+
static const char *media_entity_type_to_string(unsigned type)
{
static const struct {
printf("}\n");
}
+static void media_print_pad_text(struct media_entity *entity,
+ const struct media_pad *pad)
+{
+ if (media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ return;
+
+ v4l2_subdev_print_format(entity, pad->index, V4L2_SUBDEV_FORMAT_ACTIVE);
+ v4l2_subdev_print_pad_dv(entity, pad->index, V4L2_SUBDEV_FORMAT_ACTIVE);
+
+ if (pad->flags & MEDIA_PAD_FL_SOURCE)
+ v4l2_subdev_print_subdev_dv(entity);
+}
+
static void media_print_topology_text(struct media_device *media)
{
static const struct flag_name link_flags[] = {
printf("\tpad%u: %s\n", j, media_pad_type_to_string(pad->flags));
- if (media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV)
- v4l2_subdev_print_format(entity, j, V4L2_SUBDEV_FORMAT_ACTIVE);
+ media_print_pad_text(entity, pad);
for (k = 0; k < num_links; k++) {
const struct media_link *link = media_entity_get_link(entity, k);
printf("%s\n", media_entity_get_devname(entity));
}
- if (media_opts.pad) {
+ if (media_opts.fmt_pad) {
struct media_pad *pad;
- pad = media_parse_pad(media, media_opts.pad, NULL);
+ pad = media_parse_pad(media, media_opts.fmt_pad, NULL);
if (pad == NULL) {
- printf("Pad '%s' not found\n", media_opts.pad);
+ printf("Pad '%s' not found\n", media_opts.fmt_pad);
goto out;
}
V4L2_SUBDEV_FORMAT_ACTIVE);
}
+ if (media_opts.dv_pad) {
+ struct v4l2_dv_timings timings;
+ struct media_pad *pad;
+
+ pad = media_parse_pad(media, media_opts.dv_pad, NULL);
+ if (pad == NULL) {
+ printf("Pad '%s' not found\n", media_opts.dv_pad);
+ goto out;
+ }
+
+ ret = v4l2_subdev_query_dv_timings(pad->entity, &timings);
+ if (ret < 0) {
+ printf("Failed to query DV timings: %s\n", strerror(ret));
+ goto out;
+ }
+
+ ret = v4l2_subdev_set_dv_timings(pad->entity, &timings);
+ if (ret < 0) {
+ printf("Failed to set DV timings: %s\n", strerror(ret));
+ goto out;
+ }
+ }
+
if (media_opts.print || media_opts.print_dot) {
media_print_topology(media, media_opts.print_dot);
printf("\n");
printf("-e, --entity name Print the device name associated with the given entity\n");
printf("-V, --set-v4l2 v4l2 Comma-separated list of formats to setup\n");
printf(" --get-v4l2 pad Print the active format on a given pad\n");
+ printf(" --set-dv pad Configure DV timings on a given pad\n");
printf("-h, --help Show verbose help and exit\n");
printf("-i, --interactive Modify links interactively\n");
printf("-l, --links links Comma-separated list of link descriptors to setup\n");
#define OPT_PRINT_DOT 256
#define OPT_GET_FORMAT 257
+#define OPT_SET_DV 258
static struct option opts[] = {
{"device", 1, 0, 'd'},
{"set-v4l2", 1, 0, 'V'},
{"get-format", 1, 0, OPT_GET_FORMAT},
{"get-v4l2", 1, 0, OPT_GET_FORMAT},
+ {"set-dv", 1, 0, OPT_SET_DV},
{"help", 0, 0, 'h'},
{"interactive", 0, 0, 'i'},
{"links", 1, 0, 'l'},
break;
case OPT_GET_FORMAT:
- media_opts.pad = optarg;
+ media_opts.fmt_pad = optarg;
+ break;
+
+ case OPT_SET_DV:
+ media_opts.dv_pad = optarg;
break;
default: