Support selections API for crop
[media-ctl.git] / src / main.c
1 /*
2  * Media controller test application
3  *
4  * Copyright (C) 2010-2011 Ideas on board SPRL
5  *
6  * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
7  *
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.
12  *
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.
17  *
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/>.
20  */
21
22 #include <sys/mman.h>
23 #include <sys/ioctl.h>
24 #include <sys/time.h>
25 #include <sys/stat.h>
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35
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>
41
42 #include "mediactl.h"
43 #include "options.h"
44 #include "v4l2subdev.h"
45 #include "tools.h"
46
47 /* -----------------------------------------------------------------------------
48  * Printing
49  */
50
51 static void v4l2_subdev_print_format(struct media_entity *entity,
52         unsigned int pad, enum v4l2_subdev_format_whence which)
53 {
54         struct v4l2_mbus_framefmt format;
55         struct v4l2_rect rect;
56         int ret;
57
58         ret = v4l2_subdev_get_format(entity, &format, pad, which);
59         if (ret != 0)
60                 return;
61
62         printf("[%s %ux%u", v4l2_subdev_pixelcode_to_string(format.code),
63                format.width, format.height);
64
65         ret = v4l2_subdev_get_selection(entity, &rect, pad,
66                                         V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL,
67                                         which);
68         if (ret == 0)
69                 printf(" (%u,%u)/%ux%u", rect.left, rect.top,
70                        rect.width, rect.height);
71         printf("]");
72 }
73
74 static const char *media_entity_type_to_string(unsigned type)
75 {
76         static const struct {
77                 __u32 type;
78                 const char *name;
79         } types[] = {
80                 { MEDIA_ENT_T_DEVNODE, "Node" },
81                 { MEDIA_ENT_T_V4L2_SUBDEV, "V4L2 subdev" },
82         };
83
84         unsigned int i;
85
86         type &= MEDIA_ENT_TYPE_MASK;
87
88         for (i = 0; i < ARRAY_SIZE(types); i++) {
89                 if (types[i].type == type)
90                         return types[i].name;
91         }
92
93         return "Unknown";
94 }
95
96 static const char *media_entity_subtype_to_string(unsigned type)
97 {
98         static const char *node_types[] = {
99                 "Unknown",
100                 "V4L",
101                 "FB",
102                 "ALSA",
103                 "DVB",
104         };
105         static const char *subdev_types[] = {
106                 "Unknown",
107                 "Sensor",
108                 "Flash",
109                 "Lens",
110         };
111
112         unsigned int subtype = type & MEDIA_ENT_SUBTYPE_MASK;
113
114         switch (type & MEDIA_ENT_TYPE_MASK) {
115         case MEDIA_ENT_T_DEVNODE:
116                 if (subtype >= ARRAY_SIZE(node_types))
117                         subtype = 0;
118                 return node_types[subtype];
119
120         case MEDIA_ENT_T_V4L2_SUBDEV:
121                 if (subtype >= ARRAY_SIZE(subdev_types))
122                         subtype = 0;
123                 return subdev_types[subtype];
124         default:
125                 return node_types[0];
126         }
127 }
128
129 static const char *media_pad_type_to_string(unsigned flag)
130 {
131         static const struct {
132                 __u32 flag;
133                 const char *name;
134         } flags[] = {
135                 { MEDIA_PAD_FL_SINK, "Sink" },
136                 { MEDIA_PAD_FL_SOURCE, "Source" },
137         };
138
139         unsigned int i;
140
141         for (i = 0; i < ARRAY_SIZE(flags); i++) {
142                 if (flags[i].flag & flag)
143                         return flags[i].name;
144         }
145
146         return "Unknown";
147 }
148
149 static void media_print_topology_dot(struct media_device *media)
150 {
151         unsigned int i, j;
152
153         printf("digraph board {\n");
154         printf("\trankdir=TB\n");
155
156         for (i = 0; i < media->entities_count; ++i) {
157                 struct media_entity *entity = &media->entities[i];
158                 unsigned int npads;
159
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);
165                         break;
166
167                 case MEDIA_ENT_T_V4L2_SUBDEV:
168                         printf("\tn%08x [label=\"{{", entity->info.id);
169
170                         for (j = 0, npads = 0; j < entity->info.pads; ++j) {
171                                 if (!(entity->pads[j].flags & MEDIA_PAD_FL_SINK))
172                                         continue;
173
174                                 printf("%s<port%u> %u", npads ? " | " : "", j, j);
175                                 npads++;
176                         }
177
178                         printf("} | %s", entity->info.name);
179                         if (entity->devname)
180                                 printf("\\n%s", entity->devname);
181                         printf(" | {");
182
183                         for (j = 0, npads = 0; j < entity->info.pads; ++j) {
184                                 if (!(entity->pads[j].flags & MEDIA_PAD_FL_SOURCE))
185                                         continue;
186
187                                 printf("%s<port%u> %u", npads ? " | " : "", j, j);
188                                 npads++;
189                         }
190
191                         printf("}}\", shape=Mrecord, style=filled, fillcolor=green]\n");
192                         break;
193
194                 default:
195                         continue;
196                 }
197
198                 for (j = 0; j < entity->num_links; j++) {
199                         struct media_link *link = &entity->links[j];
200
201                         if (link->source->entity != entity)
202                                 continue;
203
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);
207                         printf(" -> ");
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);
211
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]");
216                         printf("\n");
217                 }
218         }
219
220         printf("}\n");
221 }
222
223 static void media_print_topology_text(struct media_device *media)
224 {
225         static const struct {
226                 __u32 flag;
227                 char *name;
228         } link_flags[] = {
229                 { MEDIA_LNK_FL_ENABLED, "ENABLED" },
230                 { MEDIA_LNK_FL_IMMUTABLE, "IMMUTABLE" },
231                 { MEDIA_LNK_FL_DYNAMIC, "DYNAMIC" },
232         };
233
234         unsigned int i, j, k;
235         unsigned int padding;
236
237         printf("Device topology\n");
238
239         for (i = 0; i < media->entities_count; ++i) {
240                 struct media_entity *entity = &media->entities[i];
241
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);
251
252                 for (j = 0; j < entity->info.pads; j++) {
253                         struct media_pad *pad = &entity->pads[j];
254
255                         printf("\tpad%u: %s ", j, media_pad_type_to_string(pad->flags));
256
257                         if (media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV)
258                                 v4l2_subdev_print_format(entity, j, V4L2_SUBDEV_FORMAT_ACTIVE);
259
260                         printf("\n");
261
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;
266                                 bool first = true;
267                                 unsigned int i;
268
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);
275                                 else
276                                         continue;
277
278                                 for (i = 0; i < ARRAY_SIZE(link_flags); i++) {
279                                         if (!(link->flags & link_flags[i].flag))
280                                                 continue;
281                                         if (!first)
282                                                 printf(",");
283                                         printf("%s", link_flags[i].name);
284                                         first = false;
285                                 }
286
287                                 printf("]\n");
288                         }
289                 }
290                 printf("\n");
291         }
292 }
293
294 void media_print_topology(struct media_device *media, int dot)
295 {
296         if (dot)
297                 media_print_topology_dot(media);
298         else
299                 media_print_topology_text(media);
300 }
301
302 int main(int argc, char **argv)
303 {
304         struct media_device *media;
305         int ret = -1;
306
307         if (parse_cmdline(argc, argv))
308                 return EXIT_FAILURE;
309
310         /* Open the media device and enumerate entities, pads and links. */
311         if (media_opts.verbose)
312                 media = media_open_debug(
313                         media_opts.devname,
314                         (void (*)(void *, ...))fprintf, stdout);
315         else
316                 media = media_open(media_opts.devname);
317         if (media == NULL) {
318                 printf("Failed to open %s\n", media_opts.devname);
319                 goto out;
320         }
321
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"
329                        "driver          %s\n"
330                        "model           %s\n"
331                        "serial          %s\n"
332                        "bus info        %s\n"
333                        "hw revision     0x%x\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);
341         }
342
343         if (media_opts.entity) {
344                 struct media_entity *entity;
345
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);
350                         goto out;
351                 }
352
353                 printf("%s\n", entity->devname);
354         }
355
356         if (media_opts.pad) {
357                 struct media_pad *pad;
358
359                 pad = media_parse_pad(media, media_opts.pad, NULL);
360                 if (pad == NULL) {
361                         printf("Pad '%s' not found\n", media_opts.pad);
362                         goto out;
363                 }
364
365                 v4l2_subdev_print_format(pad->entity, pad->index,
366                                          V4L2_SUBDEV_FORMAT_ACTIVE);
367                 printf("\n");
368         }
369
370         if (media_opts.print || media_opts.print_dot) {
371                 media_print_topology(media, media_opts.print_dot);
372                 printf("\n");
373         }
374
375         if (media_opts.reset) {
376                 if (media_opts.verbose)
377                         printf("Resetting all links to inactive\n");
378                 ret = media_reset_links(media);
379                 if (ret) {
380                         printf("Unable to reset links: %s (%d)\n",
381                                strerror(-ret), -ret);
382                         goto out;
383                 }
384         }
385
386         if (media_opts.links) {
387                 ret = media_parse_setup_links(media, media_opts.links);
388                 if (ret) {
389                         printf("Unable to parse link: %s (%d)\n",
390                                strerror(-ret), -ret);
391                         goto out;
392                 }
393         }
394
395         if (media_opts.formats) {
396                 ret = v4l2_subdev_parse_setup_formats(media,
397                                                       media_opts.formats);
398                 if (ret) {
399                         printf("Unable to parse format: %s (%d)\n",
400                                strerror(-ret), -ret);
401                         goto out;
402                 }
403         }
404
405         if (media_opts.interactive) {
406                 while (1) {
407                         char buffer[32];
408                         char *end;
409
410                         printf("Enter a link to modify or enter to stop\n");
411                         if (fgets(buffer, sizeof buffer, stdin) == NULL)
412                                 break;
413
414                         if (buffer[0] == '\n')
415                                 break;
416
417                         ret = media_parse_setup_link(media, buffer, &end);
418                         if (ret)
419                                 printf("Unable to parse link: %s (%d)\n",
420                                        strerror(-ret), -ret);
421                 }
422         }
423
424         ret = 0;
425
426 out:
427         if (media)
428                 media_close(media);
429
430         return ret ? EXIT_FAILURE : EXIT_SUCCESS;
431 }
432