Several printout fixes.
[media-ctl.git] / src / mediactl.c
1 /*
2  * Media controller interface library
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 "config.h"
23
24 #include <sys/ioctl.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <errno.h>
34
35 #include <linux/videodev2.h>
36 #include <linux/media.h>
37
38 #include "mediactl.h"
39 #include "tools.h"
40
41 struct media_pad *media_entity_remote_source(struct media_pad *pad)
42 {
43         unsigned int i;
44
45         if (!(pad->flags & MEDIA_PAD_FL_SINK))
46                 return NULL;
47
48         for (i = 0; i < pad->entity->num_links; ++i) {
49                 struct media_link *link = &pad->entity->links[i];
50
51                 if (!(link->flags & MEDIA_LNK_FL_ENABLED))
52                         continue;
53
54                 if (link->sink == pad)
55                         return link->source;
56         }
57
58         return NULL;
59 }
60
61 struct media_entity *media_get_entity_by_name(struct media_device *media,
62                                               const char *name, size_t length)
63 {
64         unsigned int i;
65
66         for (i = 0; i < media->entities_count; ++i) {
67                 struct media_entity *entity = &media->entities[i];
68
69                 if (strncmp(entity->info.name, name, length) == 0)
70                         return entity;
71         }
72
73         return NULL;
74 }
75
76 struct media_entity *media_get_entity_by_id(struct media_device *media,
77                                             __u32 id)
78 {
79         unsigned int i;
80
81         for (i = 0; i < media->entities_count; ++i) {
82                 struct media_entity *entity = &media->entities[i];
83
84                 if (entity->info.id == id)
85                         return entity;
86         }
87
88         return NULL;
89 }
90
91 int media_setup_link(struct media_device *media,
92                      struct media_pad *source,
93                      struct media_pad *sink,
94                      __u32 flags)
95 {
96         struct media_link *link;
97         struct media_link_desc ulink;
98         unsigned int i;
99         int ret;
100
101         for (i = 0; i < source->entity->num_links; i++) {
102                 link = &source->entity->links[i];
103
104                 if (link->source->entity == source->entity &&
105                     link->source->index == source->index &&
106                     link->sink->entity == sink->entity &&
107                     link->sink->index == sink->index)
108                         break;
109         }
110
111         if (i == source->entity->num_links) {
112                 media_dbg(media, "%s: Link not found\n", __func__);
113                 return -ENOENT;
114         }
115
116         /* source pad */
117         ulink.source.entity = source->entity->info.id;
118         ulink.source.index = source->index;
119         ulink.source.flags = MEDIA_PAD_FL_SOURCE;
120
121         /* sink pad */
122         ulink.sink.entity = sink->entity->info.id;
123         ulink.sink.index = sink->index;
124         ulink.sink.flags = MEDIA_PAD_FL_SINK;
125
126         ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
127
128         ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
129         if (ret == -1) {
130                 media_dbg(media, "%s: Unable to setup link (%s)\n",
131                           __func__, strerror(errno));
132                 return -errno;
133         }
134
135         link->flags = ulink.flags;
136         link->twin->flags = ulink.flags;
137         return 0;
138 }
139
140 int media_reset_links(struct media_device *media)
141 {
142         unsigned int i, j;
143         int ret;
144
145         for (i = 0; i < media->entities_count; ++i) {
146                 struct media_entity *entity = &media->entities[i];
147
148                 for (j = 0; j < entity->num_links; j++) {
149                         struct media_link *link = &entity->links[j];
150
151                         if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
152                             link->source->entity != entity)
153                                 continue;
154
155                         ret = media_setup_link(media, link->source, link->sink,
156                                                link->flags & ~MEDIA_LNK_FL_ENABLED);
157                         if (ret < 0)
158                                 return ret;
159                 }
160         }
161
162         return 0;
163 }
164
165 static struct media_link *media_entity_add_link(struct media_entity *entity)
166 {
167         if (entity->num_links >= entity->max_links) {
168                 struct media_link *links = entity->links;
169                 unsigned int max_links = entity->max_links * 2;
170                 unsigned int i;
171
172                 links = realloc(links, max_links * sizeof *links);
173                 if (links == NULL)
174                         return NULL;
175
176                 for (i = 0; i < entity->num_links; ++i)
177                         links[i].twin->twin = &links[i];
178
179                 entity->max_links = max_links;
180                 entity->links = links;
181         }
182
183         return &entity->links[entity->num_links++];
184 }
185
186 static int media_enum_links(struct media_device *media)
187 {
188         __u32 id;
189         int ret = 0;
190
191         for (id = 1; id <= media->entities_count; id++) {
192                 struct media_entity *entity = &media->entities[id - 1];
193                 struct media_links_enum links;
194                 unsigned int i;
195
196                 links.entity = entity->info.id;
197                 links.pads = malloc(entity->info.pads * sizeof(struct media_pad_desc));
198                 links.links = malloc(entity->info.links * sizeof(struct media_link_desc));
199
200                 if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
201                         media_dbg(media,
202                                   "%s: Unable to enumerate pads and links (%s).\n",
203                                   __func__, strerror(errno));
204                         free(links.pads);
205                         free(links.links);
206                         return -errno;
207                 }
208
209                 for (i = 0; i < entity->info.pads; ++i) {
210                         entity->pads[i].entity = entity;
211                         entity->pads[i].index = links.pads[i].index;
212                         entity->pads[i].flags = links.pads[i].flags;
213                 }
214
215                 for (i = 0; i < entity->info.links; ++i) {
216                         struct media_link_desc *link = &links.links[i];
217                         struct media_link *fwdlink;
218                         struct media_link *backlink;
219                         struct media_entity *source;
220                         struct media_entity *sink;
221
222                         source = media_get_entity_by_id(media, link->source.entity);
223                         sink = media_get_entity_by_id(media, link->sink.entity);
224
225                         if (source == NULL || sink == NULL) {
226                                 media_dbg(media,
227                                           "WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
228                                           id, i, link->source.entity,
229                                           link->source.index,
230                                           link->sink.entity,
231                                           link->sink.index);
232                                 ret = -EINVAL;
233                         } else {
234                                 fwdlink = media_entity_add_link(source);
235                                 fwdlink->source = &source->pads[link->source.index];
236                                 fwdlink->sink = &sink->pads[link->sink.index];
237                                 fwdlink->flags = link->flags;
238
239                                 backlink = media_entity_add_link(sink);
240                                 backlink->source = &source->pads[link->source.index];
241                                 backlink->sink = &sink->pads[link->sink.index];
242                                 backlink->flags = link->flags;
243
244                                 fwdlink->twin = backlink;
245                                 backlink->twin = fwdlink;
246                         }
247                 }
248
249                 free(links.pads);
250                 free(links.links);
251         }
252
253         return ret;
254 }
255
256 #ifdef HAVE_LIBUDEV
257
258 #include <libudev.h>
259
260 static inline int media_udev_open(struct udev **udev)
261 {
262         *udev = udev_new();
263         if (*udev == NULL)
264                 return -ENOMEM;
265         return 0;
266 }
267
268 static inline void media_udev_close(struct udev *udev)
269 {
270         if (udev != NULL)
271                 udev_unref(udev);
272 }
273
274 static int media_get_devname_udev(struct udev *udev,
275                 struct media_entity *entity)
276 {
277         struct udev_device *device;
278         dev_t devnum;
279         const char *p;
280         int ret = -ENODEV;
281
282         if (udev == NULL)
283                 return -EINVAL;
284
285         devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
286         media_dbg(entity->media, "looking up device: %u:%u\n",
287                   major(devnum), minor(devnum));
288         device = udev_device_new_from_devnum(udev, 'c', devnum);
289         if (device) {
290                 p = udev_device_get_devnode(device);
291                 if (p) {
292                         strncpy(entity->devname, p, sizeof(entity->devname));
293                         entity->devname[sizeof(entity->devname) - 1] = '\0';
294                 }
295                 ret = 0;
296         }
297
298         udev_device_unref(device);
299
300         return ret;
301 }
302
303 #else   /* HAVE_LIBUDEV */
304
305 struct udev;
306
307 static inline int media_udev_open(struct udev **udev) { return 0; }
308
309 static inline void media_udev_close(struct udev *udev) { }
310
311 static inline int media_get_devname_udev(struct udev *udev,
312                 struct media_entity *entity)
313 {
314         return -ENOTSUP;
315 }
316
317 #endif  /* HAVE_LIBUDEV */
318
319 static int media_get_devname_sysfs(struct media_entity *entity)
320 {
321         struct stat devstat;
322         char devname[32];
323         char sysname[32];
324         char target[1024];
325         char *p;
326         int ret;
327
328         sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
329                 entity->info.v4l.minor);
330         ret = readlink(sysname, target, sizeof(target));
331         if (ret < 0)
332                 return -errno;
333
334         target[ret] = '\0';
335         p = strrchr(target, '/');
336         if (p == NULL)
337                 return -EINVAL;
338
339         sprintf(devname, "/dev/%s", p + 1);
340         ret = stat(devname, &devstat);
341         if (ret < 0)
342                 return -errno;
343
344         /* Sanity check: udev might have reordered the device nodes.
345          * Make sure the major/minor match. We should really use
346          * libudev.
347          */
348         if (major(devstat.st_rdev) == entity->info.v4l.major &&
349             minor(devstat.st_rdev) == entity->info.v4l.minor)
350                 strcpy(entity->devname, devname);
351
352         return 0;
353 }
354
355 static int media_enum_entities(struct media_device *media)
356 {
357         struct media_entity *entity;
358         struct udev *udev;
359         unsigned int size;
360         __u32 id;
361         int ret;
362
363         ret = media_udev_open(&udev);
364         if (ret < 0)
365                 media_dbg(media, "Can't get udev context\n");
366
367         for (id = 0, ret = 0; ; id = entity->info.id) {
368                 size = (media->entities_count + 1) * sizeof(*media->entities);
369                 media->entities = realloc(media->entities, size);
370
371                 entity = &media->entities[media->entities_count];
372                 memset(entity, 0, sizeof(*entity));
373                 entity->fd = -1;
374                 entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
375                 entity->media = media;
376
377                 ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
378                 if (ret < 0) {
379                         ret = errno != EINVAL ? -errno : 0;
380                         break;
381                 }
382
383                 /* Number of links (for outbound links) plus number of pads (for
384                  * inbound links) is a good safe initial estimate of the total
385                  * number of links.
386                  */
387                 entity->max_links = entity->info.pads + entity->info.links;
388
389                 entity->pads = malloc(entity->info.pads * sizeof(*entity->pads));
390                 entity->links = malloc(entity->max_links * sizeof(*entity->links));
391                 if (entity->pads == NULL || entity->links == NULL) {
392                         ret = -ENOMEM;
393                         break;
394                 }
395
396                 media->entities_count++;
397
398                 /* Find the corresponding device name. */
399                 if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
400                     media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
401                         continue;
402
403                 /* Try to get the device name via udev */
404                 if (!media_get_devname_udev(udev, entity))
405                         continue;
406
407                 /* Fall back to get the device name via sysfs */
408                 media_get_devname_sysfs(entity);
409         }
410
411         media_udev_close(udev);
412         return ret;
413 }
414
415 static void media_debug_default(void *ptr, ...)
416 {
417 }
418
419 void media_debug_set_handler(struct media_device *media,
420                              void (*debug_handler)(void *, ...),
421                              void *debug_priv)
422 {
423         if (debug_handler) {
424                 media->debug_handler = debug_handler;
425                 media->debug_priv = debug_priv;
426         } else {
427                 media->debug_handler = media_debug_default;
428                 media->debug_priv = NULL;
429         }
430 }
431
432 struct media_device *media_open_debug(
433         const char *name, void (*debug_handler)(void *, ...),
434         void *debug_priv)
435 {
436         struct media_device *media;
437         int ret;
438
439         media = calloc(1, sizeof(*media));
440         if (media == NULL)
441                 return NULL;
442
443         media_debug_set_handler(media, debug_handler, debug_priv);
444
445         media_dbg(media, "Opening media device %s\n", name);
446
447         media->fd = open(name, O_RDWR);
448         if (media->fd < 0) {
449                 media_close(media);
450                 media_dbg(media, "%s: Can't open media device %s\n",
451                           __func__, name);
452                 return NULL;
453         }
454
455         ret = ioctl(media->fd, MEDIA_IOC_DEVICE_INFO, &media->info);
456         if (ret < 0) {
457                 media_dbg(media, "%s: Unable to retrieve media device "
458                           "information for device %s (%s)\n", __func__,
459                           name, strerror(errno));
460                 media_close(media);
461                 return NULL;
462         }
463
464         media_dbg(media, "Enumerating entities\n");
465
466         ret = media_enum_entities(media);
467
468         if (ret < 0) {
469                 media_dbg(media,
470                           "%s: Unable to enumerate entities for device %s (%s)\n",
471                           __func__, name, strerror(-ret));
472                 media_close(media);
473                 return NULL;
474         }
475
476         media_dbg(media, "Found %u entities\n", media->entities_count);
477         media_dbg(media, "Enumerating pads and links\n");
478
479         ret = media_enum_links(media);
480         if (ret < 0) {
481                 media_dbg(media,
482                           "%s: Unable to enumerate pads and linksfor device %s\n",
483                           __func__, name);
484                 media_close(media);
485                 return NULL;
486         }
487
488         return media;
489 }
490
491 struct media_device *media_open(const char *name)
492 {
493         return media_open_debug(name, NULL, NULL);
494 }
495
496 void media_close(struct media_device *media)
497 {
498         unsigned int i;
499
500         if (media->fd != -1)
501                 close(media->fd);
502
503         for (i = 0; i < media->entities_count; ++i) {
504                 struct media_entity *entity = &media->entities[i];
505
506                 free(entity->pads);
507                 free(entity->links);
508                 if (entity->fd != -1)
509                         close(entity->fd);
510         }
511
512         free(media->entities);
513         free(media);
514 }
515
516 struct media_pad *media_parse_pad(struct media_device *media,
517                                   const char *p, char **endp)
518 {
519         unsigned int entity_id, pad;
520         struct media_entity *entity;
521         char *end;
522
523         for (; isspace(*p); ++p);
524
525         if (*p == '"') {
526                 for (end = (char *)p + 1; *end && *end != '"'; ++end);
527                 if (*end != '"')
528                         return NULL;
529
530                 entity = media_get_entity_by_name(media, p + 1, end - p - 1);
531                 if (entity == NULL)
532                         return NULL;
533
534                 ++end;
535         } else {
536                 entity_id = strtoul(p, &end, 10);
537                 entity = media_get_entity_by_id(media, entity_id);
538                 if (entity == NULL)
539                         return NULL;
540         }
541         for (; isspace(*end); ++end);
542
543         if (*end != ':')
544                 return NULL;
545         for (p = end + 1; isspace(*p); ++p);
546
547         pad = strtoul(p, &end, 10);
548         for (p = end; isspace(*p); ++p);
549
550         if (pad >= entity->info.pads)
551                 return NULL;
552
553         for (p = end; isspace(*p); ++p);
554         if (endp)
555                 *endp = (char *)p;
556
557         return &entity->pads[pad];
558 }
559
560 struct media_link *media_parse_link(struct media_device *media,
561                                     const char *p, char **endp)
562 {
563         struct media_link *link;
564         struct media_pad *source;
565         struct media_pad *sink;
566         unsigned int i;
567         char *end;
568
569         source = media_parse_pad(media, p, &end);
570         if (source == NULL)
571                 return NULL;
572
573         if (end[0] != '-' || end[1] != '>')
574                 return NULL;
575         p = end + 2;
576
577         sink = media_parse_pad(media, p, &end);
578         if (sink == NULL)
579                 return NULL;
580
581         *endp = end;
582
583         for (i = 0; i < source->entity->num_links; i++) {
584                 link = &source->entity->links[i];
585
586                 if (link->source == source && link->sink == sink)
587                         return link;
588         }
589
590         return NULL;
591 }
592
593 int media_parse_setup_link(struct media_device *media,
594                            const char *p, char **endp)
595 {
596         struct media_link *link;
597         __u32 flags;
598         char *end;
599
600         link = media_parse_link(media, p, &end);
601         if (link == NULL) {
602                 media_dbg(media,
603                           "%s: Unable to parse link\n", __func__);
604                 return -EINVAL;
605         }
606
607         p = end;
608         if (*p++ != '[') {
609                 media_dbg(media, "Unable to parse link flags\n");
610                 return -EINVAL;
611         }
612
613         flags = strtoul(p, &end, 10);
614         for (p = end; isspace(*p); p++);
615         if (*p++ != ']') {
616                 media_dbg(media, "Unable to parse link flags\n");
617                 return -EINVAL;
618         }
619
620         for (; isspace(*p); p++);
621         *endp = (char *)p;
622
623         media_dbg(media,
624                   "Setting up link %u:%u -> %u:%u [%u]\n",
625                   link->source->entity->info.id, link->source->index,
626                   link->sink->entity->info.id, link->sink->index,
627                   flags);
628
629         return media_setup_link(media, link->source, link->sink, flags);
630 }
631
632 int media_parse_setup_links(struct media_device *media, const char *p)
633 {
634         char *end;
635         int ret;
636
637         do {
638                 ret = media_parse_setup_link(media, p, &end);
639                 if (ret < 0)
640                         return ret;
641
642                 p = end + 1;
643         } while (*end == ',');
644
645         return *end ? -EINVAL : 0;
646 }