Remove extra verbosity
[media-ctl.git] / src / main.c
1 /*
2  * Media controller test application
3  *
4  * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  */
19
20 #include <sys/mman.h>
21 #include <sys/ioctl.h>
22 #include <sys/time.h>
23 #include <sys/stat.h>
24
25 #include <ctype.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include <linux/types.h>
34 #include <linux/media.h>
35 #include <linux/v4l2-mediabus.h>
36 #include <linux/v4l2-subdev.h>
37 #include <linux/videodev2.h>
38
39 #include "mediactl.h"
40 #include "options.h"
41 #include "v4l2subdev.h"
42 #include "tools.h"
43
44 /* -----------------------------------------------------------------------------
45  * Printing
46  */
47
48 static void v4l2_subdev_print_format(struct media_entity *entity,
49         unsigned int pad, enum v4l2_subdev_format_whence which)
50 {
51         struct v4l2_mbus_framefmt format;
52         struct v4l2_rect rect;
53         int ret;
54
55         ret = v4l2_subdev_get_format(entity, &format, pad, which);
56         if (ret != 0)
57                 return;
58
59         printf("[%s %ux%u", v4l2_subdev_pixelcode_to_string(format.code),
60                format.width, format.height);
61
62         ret = v4l2_subdev_get_crop(entity, &rect, pad, which);
63         if (ret == 0)
64                 printf(" (%u,%u)/%ux%u", rect.left, rect.top,
65                        rect.width, rect.height);
66         printf("]");
67 }
68
69 static const char *media_entity_type_to_string(unsigned type)
70 {
71         static const struct {
72                 __u32 type;
73                 const char *name;
74         } types[] = {
75                 { MEDIA_ENT_T_DEVNODE, "Node" },
76                 { MEDIA_ENT_T_V4L2_SUBDEV, "V4L2 subdev" },
77         };
78
79         unsigned int i;
80
81         type &= MEDIA_ENT_TYPE_MASK;
82
83         for (i = 0; i < ARRAY_SIZE(types); i++) {
84                 if (types[i].type == type)
85                         return types[i].name;
86         }
87
88         return "Unknown";
89 }
90
91 static const char *media_entity_subtype_to_string(unsigned type)
92 {
93         static const char *node_types[] = {
94                 "Unknown",
95                 "V4L",
96                 "FB",
97                 "ALSA",
98                 "DVB",
99         };
100         static const char *subdev_types[] = {
101                 "Unknown",
102                 "Sensor",
103                 "Flash",
104                 "Lens",
105         };
106
107         unsigned int subtype = type & MEDIA_ENT_SUBTYPE_MASK;
108
109         switch (type & MEDIA_ENT_TYPE_MASK) {
110         case MEDIA_ENT_T_DEVNODE:
111                 if (subtype >= ARRAY_SIZE(node_types))
112                         subtype = 0;
113                 return node_types[subtype];
114
115         case MEDIA_ENT_T_V4L2_SUBDEV:
116                 if (subtype >= ARRAY_SIZE(subdev_types))
117                         subtype = 0;
118                 return subdev_types[subtype];
119         default:
120                 return node_types[0];
121         }
122 }
123
124 static const char *media_pad_type_to_string(unsigned flag)
125 {
126         static const struct {
127                 __u32 flag;
128                 const char *name;
129         } flags[] = {
130                 { MEDIA_PAD_FL_SINK, "Input" },
131                 { MEDIA_PAD_FL_SOURCE, "Output" },
132         };
133
134         unsigned int i;
135
136         for (i = 0; i < ARRAY_SIZE(flags); i++) {
137                 if (flags[i].flag & flag)
138                         return flags[i].name;
139         }
140
141         return "Unknown";
142 }
143
144 static void media_print_topology_dot(struct media_device *media)
145 {
146         unsigned int i, j;
147
148         printf("digraph board {\n");
149         printf("\trankdir=TB\n");
150
151         for (i = 0; i < media->entities_count; ++i) {
152                 struct media_entity *entity = &media->entities[i];
153                 unsigned int npads;
154
155                 switch (media_entity_type(entity)) {
156                 case MEDIA_ENT_T_DEVNODE:
157                         printf("\tn%08x [label=\"%s\\n%s\", shape=box, style=filled, "
158                                "fillcolor=yellow]\n",
159                                entity->info.id, entity->info.name, entity->devname);
160                         break;
161
162                 case MEDIA_ENT_T_V4L2_SUBDEV:
163                         printf("\tn%08x [label=\"{{", entity->info.id);
164
165                         for (j = 0, npads = 0; j < entity->info.pads; ++j) {
166                                 if (!(entity->pads[j].flags & MEDIA_PAD_FL_SINK))
167                                         continue;
168
169                                 printf("%s<port%u> %u", npads ? " | " : "", j, j);
170                                 npads++;
171                         }
172
173                         printf("} | %s", entity->info.name);
174                         if (entity->devname)
175                                 printf("\\n%s", entity->devname);
176                         printf(" | {");
177
178                         for (j = 0, npads = 0; j < entity->info.pads; ++j) {
179                                 if (!(entity->pads[j].flags & MEDIA_PAD_FL_SOURCE))
180                                         continue;
181
182                                 printf("%s<port%u> %u", npads ? " | " : "", j, j);
183                                 npads++;
184                         }
185
186                         printf("}}\", shape=Mrecord, style=filled, fillcolor=green]\n");
187                         break;
188
189                 default:
190                         continue;
191                 }
192
193                 for (j = 0; j < entity->num_links; j++) {
194                         struct media_link *link = &entity->links[j];
195
196                         if (link->source->entity != entity)
197                                 continue;
198
199                         printf("\tn%08x", link->source->entity->info.id);
200                         if (media_entity_type(link->source->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
201                                 printf(":port%u", link->source->index);
202                         printf(" -> ");
203                         printf("n%08x", link->sink->entity->info.id);
204                         if (media_entity_type(link->sink->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
205                                 printf(":port%u", link->sink->index);
206
207                         if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
208                                 printf(" [style=bold]");
209                         else if (!(link->flags & MEDIA_LNK_FL_ENABLED))
210                                 printf(" [style=dashed]");
211                         printf("\n");
212                 }
213         }
214
215         printf("}\n");
216 }
217
218 static void media_print_topology_text(struct media_device *media)
219 {
220         unsigned int i, j, k;
221         unsigned int padding;
222
223         printf("Device topology\n");
224
225         for (i = 0; i < media->entities_count; ++i) {
226                 struct media_entity *entity = &media->entities[i];
227
228                 padding = printf("- entity %u: ", entity->info.id);
229                 printf("%s (%u pad%s, %u link%s)\n", entity->info.name,
230                         entity->info.pads, entity->info.pads > 1 ? "s" : "",
231                         entity->num_links, entity->num_links > 1 ? "s" : "");
232                 printf("%*ctype %s subtype %s\n", padding, ' ',
233                         media_entity_type_to_string(entity->info.type),
234                         media_entity_subtype_to_string(entity->info.type));
235                 if (entity->devname[0])
236                         printf("%*cdevice node name %s\n", padding, ' ', entity->devname);
237
238                 for (j = 0; j < entity->info.pads; j++) {
239                         struct media_pad *pad = &entity->pads[j];
240
241                         printf("\tpad%u: %s ", j, media_pad_type_to_string(pad->flags));
242
243                         if (media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV)
244                                 v4l2_subdev_print_format(entity, j, V4L2_SUBDEV_FORMAT_ACTIVE);
245
246                         printf("\n");
247
248                         for (k = 0; k < entity->num_links; k++) {
249                                 struct media_link *link = &entity->links[k];
250                                 struct media_pad *source = link->source;
251                                 struct media_pad *sink = link->sink;
252
253                                 if (source->entity == entity && source->index == j)
254                                         printf("\t\t-> '%s':pad%u [",
255                                                 sink->entity->info.name, sink->index);
256                                 else if (sink->entity == entity && sink->index == j)
257                                         printf("\t\t<- '%s':pad%u [",
258                                                 source->entity->info.name, source->index);
259                                 else
260                                         continue;
261
262                                 if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
263                                         printf("IMMUTABLE,");
264                                 if (link->flags & MEDIA_LNK_FL_ENABLED)
265                                         printf("ACTIVE");
266
267                                 printf("]\n");
268                         }
269                 }
270                 printf("\n");
271         }
272 }
273
274 void media_print_topology(struct media_device *media, int dot)
275 {
276         if (dot)
277                 media_print_topology_dot(media);
278         else
279                 media_print_topology_text(media);
280 }
281
282 int main(int argc, char **argv)
283 {
284         struct media_device *media;
285         int ret = -1;
286
287         if (parse_cmdline(argc, argv))
288                 return EXIT_FAILURE;
289
290         /* Open the media device and enumerate entities, pads and links. */
291         if (media_opts.verbose)
292                 media = media_open_debug(
293                         media_opts.devname,
294                         (void (*)(void *, ...))fprintf, stdout);
295         else
296                 media = media_open(media_opts.devname);
297         if (media == NULL) {
298                 printf("Failed to open %s\n", media_opts.devname);
299                 goto out;
300         }
301
302         if (media_opts.entity) {
303                 struct media_entity *entity;
304
305                 entity = media_get_entity_by_name(media, media_opts.entity,
306                                                   strlen(media_opts.entity));
307                 if (entity == NULL) {
308                         printf("Entity '%s' not found\n", media_opts.entity);
309                         goto out;
310                 }
311
312                 printf("%s\n", entity->devname);
313         }
314
315         if (media_opts.pad) {
316                 struct media_pad *pad;
317
318                 pad = media_parse_pad(media, media_opts.pad, NULL);
319                 if (pad == NULL) {
320                         printf("Pad '%s' not found\n", media_opts.pad);
321                         goto out;
322                 }
323
324                 v4l2_subdev_print_format(pad->entity, pad->index,
325                                          V4L2_SUBDEV_FORMAT_ACTIVE);
326                 printf("\n");
327         }
328
329         if (media_opts.print || media_opts.print_dot) {
330                 media_print_topology(media, media_opts.print_dot);
331                 printf("\n");
332         }
333
334         if (media_opts.reset) {
335                 if (media_opts.verbose)
336                         printf("Resetting all links to inactive\n");
337                 ret = media_reset_links(media);
338                 if (ret) {
339                         printf("Unable to reset links: %s (%d)\n",
340                                strerror(-ret), -ret);
341                         goto out;
342                 }
343         }
344
345         if (media_opts.links) {
346                 ret = media_parse_setup_links(media, media_opts.links);
347                 if (ret) {
348                         printf("Unable to parse link: %s (%d)\n",
349                                strerror(-ret), -ret);
350                         goto out;
351                 }
352         }
353
354         if (media_opts.formats) {
355                 ret = v4l2_subdev_parse_setup_formats(media,
356                                                       media_opts.formats);
357                 if (ret) {
358                         printf("Unable to parse format: %s (%d)\n",
359                                strerror(-ret), -ret);
360                         goto out;
361                 }
362         }
363
364         if (media_opts.interactive) {
365                 while (1) {
366                         char buffer[32];
367                         char *end;
368
369                         printf("Enter a link to modify or enter to stop\n");
370                         if (fgets(buffer, sizeof buffer, stdin) == NULL)
371                                 break;
372
373                         if (buffer[0] == '\n')
374                                 break;
375
376                         ret = media_parse_setup_link(media, buffer, &end);
377                         if (ret)
378                                 printf("Unable to parse link: %s (%d)\n",
379                                        strerror(-ret), -ret);
380                 }
381         }
382
383         ret = 0;
384
385 out:
386         if (media)
387                 media_close(media);
388
389         return ret ? EXIT_FAILURE : EXIT_SUCCESS;
390 }
391