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/>.
23 #include <sys/ioctl.h>
36 #include <linux/types.h>
37 #include <linux/media.h>
38 #include <linux/v4l2-mediabus.h>
39 #include <linux/v4l2-subdev.h>
40 #include <linux/videodev2.h>
44 #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("[%s %ux%u", v4l2_subdev_pixelcode_to_string(format.code),
63 format.width, format.height);
65 ret = v4l2_subdev_get_selection(entity, &rect, pad,
66 V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL,
69 printf(" (%u,%u)/%ux%u", rect.left, rect.top,
70 rect.width, rect.height);
74 static const char *media_entity_type_to_string(unsigned type)
80 { MEDIA_ENT_T_DEVNODE, "Node" },
81 { MEDIA_ENT_T_V4L2_SUBDEV, "V4L2 subdev" },
86 type &= MEDIA_ENT_TYPE_MASK;
88 for (i = 0; i < ARRAY_SIZE(types); i++) {
89 if (types[i].type == type)
96 static const char *media_entity_subtype_to_string(unsigned type)
98 static const char *node_types[] = {
105 static const char *subdev_types[] = {
112 unsigned int subtype = type & MEDIA_ENT_SUBTYPE_MASK;
114 switch (type & MEDIA_ENT_TYPE_MASK) {
115 case MEDIA_ENT_T_DEVNODE:
116 if (subtype >= ARRAY_SIZE(node_types))
118 return node_types[subtype];
120 case MEDIA_ENT_T_V4L2_SUBDEV:
121 if (subtype >= ARRAY_SIZE(subdev_types))
123 return subdev_types[subtype];
125 return node_types[0];
129 static const char *media_pad_type_to_string(unsigned flag)
131 static const struct {
135 { MEDIA_PAD_FL_SINK, "Sink" },
136 { MEDIA_PAD_FL_SOURCE, "Source" },
141 for (i = 0; i < ARRAY_SIZE(flags); i++) {
142 if (flags[i].flag & flag)
143 return flags[i].name;
149 static void media_print_topology_dot(struct media_device *media)
153 printf("digraph board {\n");
154 printf("\trankdir=TB\n");
156 for (i = 0; i < media->entities_count; ++i) {
157 struct media_entity *entity = &media->entities[i];
160 switch (media_entity_type(entity)) {
161 case MEDIA_ENT_T_DEVNODE:
162 printf("\tn%08x [label=\"%s\\n%s\", shape=box, style=filled, "
163 "fillcolor=yellow]\n",
164 entity->info.id, entity->info.name, entity->devname);
167 case MEDIA_ENT_T_V4L2_SUBDEV:
168 printf("\tn%08x [label=\"{{", entity->info.id);
170 for (j = 0, npads = 0; j < entity->info.pads; ++j) {
171 if (!(entity->pads[j].flags & MEDIA_PAD_FL_SINK))
174 printf("%s<port%u> %u", npads ? " | " : "", j, j);
178 printf("} | %s", entity->info.name);
180 printf("\\n%s", entity->devname);
183 for (j = 0, npads = 0; j < entity->info.pads; ++j) {
184 if (!(entity->pads[j].flags & MEDIA_PAD_FL_SOURCE))
187 printf("%s<port%u> %u", npads ? " | " : "", j, j);
191 printf("}}\", shape=Mrecord, style=filled, fillcolor=green]\n");
198 for (j = 0; j < entity->num_links; j++) {
199 struct media_link *link = &entity->links[j];
201 if (link->source->entity != entity)
204 printf("\tn%08x", link->source->entity->info.id);
205 if (media_entity_type(link->source->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
206 printf(":port%u", link->source->index);
208 printf("n%08x", link->sink->entity->info.id);
209 if (media_entity_type(link->sink->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
210 printf(":port%u", link->sink->index);
212 if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
213 printf(" [style=bold]");
214 else if (!(link->flags & MEDIA_LNK_FL_ENABLED))
215 printf(" [style=dashed]");
223 static void media_print_topology_text(struct media_device *media)
225 static const struct {
229 { MEDIA_LNK_FL_ENABLED, "ENABLED" },
230 { MEDIA_LNK_FL_IMMUTABLE, "IMMUTABLE" },
231 { MEDIA_LNK_FL_DYNAMIC, "DYNAMIC" },
234 unsigned int i, j, k;
235 unsigned int padding;
237 printf("Device topology\n");
239 for (i = 0; i < media->entities_count; ++i) {
240 struct media_entity *entity = &media->entities[i];
242 padding = printf("- entity %u: ", entity->info.id);
243 printf("%s (%u pad%s, %u link%s)\n", entity->info.name,
244 entity->info.pads, entity->info.pads > 1 ? "s" : "",
245 entity->num_links, entity->num_links > 1 ? "s" : "");
246 printf("%*ctype %s subtype %s\n", padding, ' ',
247 media_entity_type_to_string(entity->info.type),
248 media_entity_subtype_to_string(entity->info.type));
249 if (entity->devname[0])
250 printf("%*cdevice node name %s\n", padding, ' ', entity->devname);
252 for (j = 0; j < entity->info.pads; j++) {
253 struct media_pad *pad = &entity->pads[j];
255 printf("\tpad%u: %s ", j, media_pad_type_to_string(pad->flags));
257 if (media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV)
258 v4l2_subdev_print_format(entity, j, V4L2_SUBDEV_FORMAT_ACTIVE);
262 for (k = 0; k < entity->num_links; k++) {
263 struct media_link *link = &entity->links[k];
264 struct media_pad *source = link->source;
265 struct media_pad *sink = link->sink;
269 if (source->entity == entity && source->index == j)
270 printf("\t\t-> \"%s\":%u [",
271 sink->entity->info.name, sink->index);
272 else if (sink->entity == entity && sink->index == j)
273 printf("\t\t<- \"%s\":%u [",
274 source->entity->info.name, source->index);
278 for (i = 0; i < ARRAY_SIZE(link_flags); i++) {
279 if (!(link->flags & link_flags[i].flag))
283 printf("%s", link_flags[i].name);
294 void media_print_topology(struct media_device *media, int dot)
297 media_print_topology_dot(media);
299 media_print_topology_text(media);
302 int main(int argc, char **argv)
304 struct media_device *media;
307 if (parse_cmdline(argc, argv))
310 /* Open the media device and enumerate entities, pads and links. */
311 if (media_opts.verbose)
312 media = media_open_debug(
314 (void (*)(void *, ...))fprintf, stdout);
316 media = media_open(media_opts.devname);
318 printf("Failed to open %s\n", media_opts.devname);
322 if (media_opts.print) {
323 printf("Media controller API version %u.%u.%u\n\n",
324 (media->info.media_version << 16) & 0xff,
325 (media->info.media_version << 8) & 0xff,
326 (media->info.media_version << 0) & 0xff);
327 printf("Media device information\n"
328 "------------------------\n"
334 "driver version %u.%u.%u\n\n",
335 media->info.driver, media->info.model,
336 media->info.serial, media->info.bus_info,
337 media->info.hw_revision,
338 (media->info.driver_version << 16) & 0xff,
339 (media->info.driver_version << 8) & 0xff,
340 (media->info.driver_version << 0) & 0xff);
343 if (media_opts.entity) {
344 struct media_entity *entity;
346 entity = media_get_entity_by_name(media, media_opts.entity,
347 strlen(media_opts.entity));
348 if (entity == NULL) {
349 printf("Entity '%s' not found\n", media_opts.entity);
353 printf("%s\n", entity->devname);
356 if (media_opts.pad) {
357 struct media_pad *pad;
359 pad = media_parse_pad(media, media_opts.pad, NULL);
361 printf("Pad '%s' not found\n", media_opts.pad);
365 v4l2_subdev_print_format(pad->entity, pad->index,
366 V4L2_SUBDEV_FORMAT_ACTIVE);
370 if (media_opts.print || media_opts.print_dot) {
371 media_print_topology(media, media_opts.print_dot);
375 if (media_opts.reset) {
376 if (media_opts.verbose)
377 printf("Resetting all links to inactive\n");
378 ret = media_reset_links(media);
380 printf("Unable to reset links: %s (%d)\n",
381 strerror(-ret), -ret);
386 if (media_opts.links) {
387 ret = media_parse_setup_links(media, media_opts.links);
389 printf("Unable to parse link: %s (%d)\n",
390 strerror(-ret), -ret);
395 if (media_opts.formats) {
396 ret = v4l2_subdev_parse_setup_formats(media,
399 printf("Unable to parse format: %s (%d)\n",
400 strerror(-ret), -ret);
405 if (media_opts.interactive) {
410 printf("Enter a link to modify or enter to stop\n");
411 if (fgets(buffer, sizeof buffer, stdin) == NULL)
414 if (buffer[0] == '\n')
417 ret = media_parse_setup_link(media, buffer, &end);
419 printf("Unable to parse link: %s (%d)\n",
420 strerror(-ret), -ret);
430 return ret ? EXIT_FAILURE : EXIT_SUCCESS;