2 * Media controller test application
4 * Copyright (C) 2010-2011 Ideas on board SPRL
6 * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/ioctl.h>
36 #include <linux/media.h>
37 #include <linux/types.h>
38 #include <linux/v4l2-mediabus.h>
39 #include <linux/v4l2-subdev.h>
40 #include <linux/videodev2.h>
45 #include "v4l2subdev.h"
47 /* -----------------------------------------------------------------------------
51 static void v4l2_subdev_print_format(struct media_entity *entity,
52 unsigned int pad, enum v4l2_subdev_format_whence which)
54 struct v4l2_mbus_framefmt format;
55 struct v4l2_rect rect;
58 ret = v4l2_subdev_get_format(entity, &format, pad, which);
62 printf("\t\t[fmt:%s/%ux%u",
63 v4l2_subdev_pixelcode_to_string(format.code),
64 format.width, format.height);
67 printf(" field:%s", v4l2_subdev_field_to_string(format.field));
69 ret = v4l2_subdev_get_selection(entity, &rect, pad,
70 V4L2_SEL_TGT_CROP_BOUNDS,
73 printf("\n\t\t crop.bounds:(%u,%u)/%ux%u", rect.left, rect.top,
74 rect.width, rect.height);
76 ret = v4l2_subdev_get_selection(entity, &rect, pad,
80 printf("\n\t\t crop:(%u,%u)/%ux%u", rect.left, rect.top,
81 rect.width, rect.height);
83 ret = v4l2_subdev_get_selection(entity, &rect, pad,
84 V4L2_SEL_TGT_COMPOSE_BOUNDS,
87 printf("\n\t\t compose.bounds:(%u,%u)/%ux%u",
88 rect.left, rect.top, rect.width, rect.height);
90 ret = v4l2_subdev_get_selection(entity, &rect, pad,
94 printf("\n\t\t compose:(%u,%u)/%ux%u",
95 rect.left, rect.top, rect.width, rect.height);
100 static const char *media_entity_type_to_string(unsigned type)
102 static const struct {
106 { MEDIA_ENT_T_DEVNODE, "Node" },
107 { MEDIA_ENT_T_V4L2_SUBDEV, "V4L2 subdev" },
112 type &= MEDIA_ENT_TYPE_MASK;
114 for (i = 0; i < ARRAY_SIZE(types); i++) {
115 if (types[i].type == type)
116 return types[i].name;
122 static const char *media_entity_subtype_to_string(unsigned type)
124 static const char *node_types[] = {
131 static const char *subdev_types[] = {
138 unsigned int subtype = type & MEDIA_ENT_SUBTYPE_MASK;
140 switch (type & MEDIA_ENT_TYPE_MASK) {
141 case MEDIA_ENT_T_DEVNODE:
142 if (subtype >= ARRAY_SIZE(node_types))
144 return node_types[subtype];
146 case MEDIA_ENT_T_V4L2_SUBDEV:
147 if (subtype >= ARRAY_SIZE(subdev_types))
149 return subdev_types[subtype];
151 return node_types[0];
155 static const char *media_pad_type_to_string(unsigned flag)
157 static const struct {
161 { MEDIA_PAD_FL_SINK, "Sink" },
162 { MEDIA_PAD_FL_SOURCE, "Source" },
167 for (i = 0; i < ARRAY_SIZE(flags); i++) {
168 if (flags[i].flag & flag)
169 return flags[i].name;
175 static void media_print_topology_dot(struct media_device *media)
177 unsigned int nents = media_get_entities_count(media);
180 printf("digraph board {\n");
181 printf("\trankdir=TB\n");
183 for (i = 0; i < nents; ++i) {
184 struct media_entity *entity = media_get_entity(media, i);
185 const struct media_entity_desc *info = media_entity_get_info(entity);
186 const char *devname = media_entity_get_devname(entity);
187 unsigned int num_links = media_entity_get_links_count(entity);
190 switch (media_entity_type(entity)) {
191 case MEDIA_ENT_T_DEVNODE:
192 printf("\tn%08x [label=\"%s\\n%s\", shape=box, style=filled, "
193 "fillcolor=yellow]\n",
194 info->id, info->name, devname);
197 case MEDIA_ENT_T_V4L2_SUBDEV:
198 printf("\tn%08x [label=\"{{", info->id);
200 for (j = 0, npads = 0; j < info->pads; ++j) {
201 const struct media_pad *pad = media_entity_get_pad(entity, j);
203 if (!(pad->flags & MEDIA_PAD_FL_SINK))
206 printf("%s<port%u> %u", npads ? " | " : "", j, j);
210 printf("} | %s", info->name);
212 printf("\\n%s", devname);
215 for (j = 0, npads = 0; j < info->pads; ++j) {
216 const struct media_pad *pad = media_entity_get_pad(entity, j);
218 if (!(pad->flags & MEDIA_PAD_FL_SOURCE))
221 printf("%s<port%u> %u", npads ? " | " : "", j, j);
225 printf("}}\", shape=Mrecord, style=filled, fillcolor=green]\n");
232 for (j = 0; j < num_links; j++) {
233 const struct media_link *link = media_entity_get_link(entity, j);
234 const struct media_pad *source = link->source;
235 const struct media_pad *sink = link->sink;
237 if (source->entity != entity)
240 printf("\tn%08x", media_entity_get_info(source->entity)->id);
241 if (media_entity_type(source->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
242 printf(":port%u", source->index);
244 printf("n%08x", media_entity_get_info(sink->entity)->id);
245 if (media_entity_type(sink->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
246 printf(":port%u", sink->index);
248 if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
249 printf(" [style=bold]");
250 else if (!(link->flags & MEDIA_LNK_FL_ENABLED))
251 printf(" [style=dashed]");
259 static void media_print_topology_text(struct media_device *media)
261 static const struct {
265 { MEDIA_LNK_FL_ENABLED, "ENABLED" },
266 { MEDIA_LNK_FL_IMMUTABLE, "IMMUTABLE" },
267 { MEDIA_LNK_FL_DYNAMIC, "DYNAMIC" },
270 unsigned int nents = media_get_entities_count(media);
271 unsigned int i, j, k;
272 unsigned int padding;
274 printf("Device topology\n");
276 for (i = 0; i < nents; ++i) {
277 struct media_entity *entity = media_get_entity(media, i);
278 const struct media_entity_desc *info = media_entity_get_info(entity);
279 const char *devname = media_entity_get_devname(entity);
280 unsigned int num_links = media_entity_get_links_count(entity);
282 padding = printf("- entity %u: ", info->id);
283 printf("%s (%u pad%s, %u link%s)\n", info->name,
284 info->pads, info->pads > 1 ? "s" : "",
285 num_links, num_links > 1 ? "s" : "");
286 printf("%*ctype %s subtype %s flags %x\n", padding, ' ',
287 media_entity_type_to_string(info->type),
288 media_entity_subtype_to_string(info->type),
291 printf("%*cdevice node name %s\n", padding, ' ', devname);
293 for (j = 0; j < info->pads; j++) {
294 const struct media_pad *pad = media_entity_get_pad(entity, j);
296 printf("\tpad%u: %s\n", j, media_pad_type_to_string(pad->flags));
298 if (media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV)
299 v4l2_subdev_print_format(entity, j, V4L2_SUBDEV_FORMAT_ACTIVE);
301 for (k = 0; k < num_links; k++) {
302 const struct media_link *link = media_entity_get_link(entity, k);
303 const struct media_pad *source = link->source;
304 const struct media_pad *sink = link->sink;
308 if (source->entity == entity && source->index == j)
309 printf("\t\t-> \"%s\":%u [",
310 media_entity_get_info(sink->entity)->name,
312 else if (sink->entity == entity && sink->index == j)
313 printf("\t\t<- \"%s\":%u [",
314 media_entity_get_info(source->entity)->name,
319 for (i = 0; i < ARRAY_SIZE(link_flags); i++) {
320 if (!(link->flags & link_flags[i].flag))
324 printf("%s", link_flags[i].name);
335 void media_print_topology(struct media_device *media, int dot)
338 media_print_topology_dot(media);
340 media_print_topology_text(media);
343 int main(int argc, char **argv)
345 struct media_device *media;
348 if (parse_cmdline(argc, argv))
351 media = media_device_new(media_opts.devname);
353 printf("Failed to create media device\n");
357 if (media_opts.verbose)
358 media_debug_set_handler(media,
359 (void (*)(void *, ...))fprintf, stdout);
361 /* Enumerate entities, pads and links. */
362 ret = media_device_enumerate(media);
364 printf("Failed to enumerate %s (%d)\n", media_opts.devname, ret);
368 if (media_opts.print) {
369 const struct media_device_info *info = media_get_info(media);
371 printf("Media controller API version %u.%u.%u\n\n",
372 (info->media_version << 16) & 0xff,
373 (info->media_version << 8) & 0xff,
374 (info->media_version << 0) & 0xff);
375 printf("Media device information\n"
376 "------------------------\n"
382 "driver version %u.%u.%u\n\n",
383 info->driver, info->model,
384 info->serial, info->bus_info,
386 (info->driver_version << 16) & 0xff,
387 (info->driver_version << 8) & 0xff,
388 (info->driver_version << 0) & 0xff);
391 if (media_opts.entity) {
392 struct media_entity *entity;
394 entity = media_get_entity_by_name(media, media_opts.entity,
395 strlen(media_opts.entity));
396 if (entity == NULL) {
397 printf("Entity '%s' not found\n", media_opts.entity);
401 printf("%s\n", media_entity_get_devname(entity));
404 if (media_opts.pad) {
405 struct media_pad *pad;
407 pad = media_parse_pad(media, media_opts.pad, NULL);
409 printf("Pad '%s' not found\n", media_opts.pad);
413 v4l2_subdev_print_format(pad->entity, pad->index,
414 V4L2_SUBDEV_FORMAT_ACTIVE);
417 if (media_opts.print || media_opts.print_dot) {
418 media_print_topology(media, media_opts.print_dot);
422 if (media_opts.reset) {
423 if (media_opts.verbose)
424 printf("Resetting all links to inactive\n");
425 ret = media_reset_links(media);
427 printf("Unable to reset links: %s (%d)\n",
428 strerror(-ret), -ret);
433 if (media_opts.links) {
434 ret = media_parse_setup_links(media, media_opts.links);
436 printf("Unable to parse link: %s (%d)\n",
437 strerror(-ret), -ret);
442 if (media_opts.formats) {
443 ret = v4l2_subdev_parse_setup_formats(media,
446 printf("Unable to setup formats: %s (%d)\n",
447 strerror(-ret), -ret);
452 if (media_opts.interactive) {
457 printf("Enter a link to modify or enter to stop\n");
458 if (fgets(buffer, sizeof buffer, stdin) == NULL)
461 if (buffer[0] == '\n')
464 ret = media_parse_setup_link(media, buffer, &end);
466 printf("Unable to parse link: %s (%d)\n",
467 strerror(-ret), -ret);
475 media_device_unref(media);
477 return ret ? EXIT_FAILURE : EXIT_SUCCESS;