Make the media_device structure private
[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 <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include <linux/media.h>
38 #include <linux/videodev2.h>
39
40 #include "mediactl.h"
41 #include "mediactl-priv.h"
42 #include "tools.h"
43
44 /* -----------------------------------------------------------------------------
45  * Graph access
46  */
47
48 struct media_pad *media_entity_remote_source(struct media_pad *pad)
49 {
50         unsigned int i;
51
52         if (!(pad->flags & MEDIA_PAD_FL_SINK))
53                 return NULL;
54
55         for (i = 0; i < pad->entity->num_links; ++i) {
56                 struct media_link *link = &pad->entity->links[i];
57
58                 if (!(link->flags & MEDIA_LNK_FL_ENABLED))
59                         continue;
60
61                 if (link->sink == pad)
62                         return link->source;
63         }
64
65         return NULL;
66 }
67
68 struct media_entity *media_get_entity_by_name(struct media_device *media,
69                                               const char *name, size_t length)
70 {
71         unsigned int i;
72
73         /* A match is impossible if the entity name is longer than the maximum
74          * size we can get from the kernel.
75          */
76         if (length >= FIELD_SIZEOF(struct media_entity_desc, name))
77                 return NULL;
78
79         for (i = 0; i < media->entities_count; ++i) {
80                 struct media_entity *entity = &media->entities[i];
81
82                 if (strncmp(entity->info.name, name, length) == 0 &&
83                     entity->info.name[length] == '\0')
84                         return entity;
85         }
86
87         return NULL;
88 }
89
90 struct media_entity *media_get_entity_by_id(struct media_device *media,
91                                             __u32 id)
92 {
93         bool next = id & MEDIA_ENT_ID_FLAG_NEXT;
94         unsigned int i;
95
96         id &= ~MEDIA_ENT_ID_FLAG_NEXT;
97
98         for (i = 0; i < media->entities_count; ++i) {
99                 struct media_entity *entity = &media->entities[i];
100
101                 if ((entity->info.id == id && !next) ||
102                     (entity->info.id > id && next))
103                         return entity;
104         }
105
106         return NULL;
107 }
108
109 unsigned int media_get_entities_count(struct media_device *media)
110 {
111         return media->entities_count;
112 }
113
114 struct media_entity *media_get_entities(struct media_device *media)
115 {
116         return media->entities;
117 }
118
119 const struct media_device_info *media_get_info(struct media_device *media)
120 {
121         return &media->info;
122 }
123
124 const char *media_get_devnode(struct media_device *media)
125 {
126         return media->devnode;
127 }
128
129 /* -----------------------------------------------------------------------------
130  * Open/close
131  */
132
133 static int media_device_open(struct media_device *media)
134 {
135         int ret;
136
137         if (media->fd != -1)
138                 return 0;
139
140         media_dbg(media, "Opening media device %s\n", media->devnode);
141
142         media->fd = open(media->devnode, O_RDWR);
143         if (media->fd < 0) {
144                 ret = -errno;
145                 media_dbg(media, "%s: Can't open media device %s\n",
146                           __func__, media->devnode);
147                 return ret;
148         }
149
150         return 0;
151 }
152
153 static void media_device_close(struct media_device *media)
154 {
155         if (media->fd != -1) {
156                 close(media->fd);
157                 media->fd = -1;
158         }
159 }
160
161 /* -----------------------------------------------------------------------------
162  * Link setup
163  */
164
165 int media_setup_link(struct media_device *media,
166                      struct media_pad *source,
167                      struct media_pad *sink,
168                      __u32 flags)
169 {
170         struct media_link *link;
171         struct media_link_desc ulink;
172         unsigned int i;
173         int ret;
174
175         ret = media_device_open(media);
176         if (ret < 0)
177                 goto done;
178
179         for (i = 0; i < source->entity->num_links; i++) {
180                 link = &source->entity->links[i];
181
182                 if (link->source->entity == source->entity &&
183                     link->source->index == source->index &&
184                     link->sink->entity == sink->entity &&
185                     link->sink->index == sink->index)
186                         break;
187         }
188
189         if (i == source->entity->num_links) {
190                 media_dbg(media, "%s: Link not found\n", __func__);
191                 ret = -ENOENT;
192                 goto done;
193         }
194
195         /* source pad */
196         ulink.source.entity = source->entity->info.id;
197         ulink.source.index = source->index;
198         ulink.source.flags = MEDIA_PAD_FL_SOURCE;
199
200         /* sink pad */
201         ulink.sink.entity = sink->entity->info.id;
202         ulink.sink.index = sink->index;
203         ulink.sink.flags = MEDIA_PAD_FL_SINK;
204
205         ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
206
207         ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
208         if (ret == -1) {
209                 ret = -errno;
210                 media_dbg(media, "%s: Unable to setup link (%s)\n",
211                           __func__, strerror(errno));
212                 goto done;
213         }
214
215         link->flags = ulink.flags;
216         link->twin->flags = ulink.flags;
217
218         ret = 0;
219
220 done:
221         media_device_close(media);
222         return ret;
223 }
224
225 int media_reset_links(struct media_device *media)
226 {
227         unsigned int i, j;
228         int ret;
229
230         for (i = 0; i < media->entities_count; ++i) {
231                 struct media_entity *entity = &media->entities[i];
232
233                 for (j = 0; j < entity->num_links; j++) {
234                         struct media_link *link = &entity->links[j];
235
236                         if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
237                             link->source->entity != entity)
238                                 continue;
239
240                         ret = media_setup_link(media, link->source, link->sink,
241                                                link->flags & ~MEDIA_LNK_FL_ENABLED);
242                         if (ret < 0)
243                                 return ret;
244                 }
245         }
246
247         return 0;
248 }
249
250 /* -----------------------------------------------------------------------------
251  * Entities, pads and links enumeration
252  */
253
254 static struct media_link *media_entity_add_link(struct media_entity *entity)
255 {
256         if (entity->num_links >= entity->max_links) {
257                 struct media_link *links = entity->links;
258                 unsigned int max_links = entity->max_links * 2;
259                 unsigned int i;
260
261                 links = realloc(links, max_links * sizeof *links);
262                 if (links == NULL)
263                         return NULL;
264
265                 for (i = 0; i < entity->num_links; ++i)
266                         links[i].twin->twin = &links[i];
267
268                 entity->max_links = max_links;
269                 entity->links = links;
270         }
271
272         return &entity->links[entity->num_links++];
273 }
274
275 static int media_enum_links(struct media_device *media)
276 {
277         __u32 id;
278         int ret = 0;
279
280         for (id = 1; id <= media->entities_count; id++) {
281                 struct media_entity *entity = &media->entities[id - 1];
282                 struct media_links_enum links;
283                 unsigned int i;
284
285                 links.entity = entity->info.id;
286                 links.pads = calloc(entity->info.pads, sizeof(struct media_pad_desc));
287                 links.links = calloc(entity->info.links, sizeof(struct media_link_desc));
288
289                 if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
290                         ret = -errno;
291                         media_dbg(media,
292                                   "%s: Unable to enumerate pads and links (%s).\n",
293                                   __func__, strerror(errno));
294                         free(links.pads);
295                         free(links.links);
296                         return ret;
297                 }
298
299                 for (i = 0; i < entity->info.pads; ++i) {
300                         entity->pads[i].entity = entity;
301                         entity->pads[i].index = links.pads[i].index;
302                         entity->pads[i].flags = links.pads[i].flags;
303                 }
304
305                 for (i = 0; i < entity->info.links; ++i) {
306                         struct media_link_desc *link = &links.links[i];
307                         struct media_link *fwdlink;
308                         struct media_link *backlink;
309                         struct media_entity *source;
310                         struct media_entity *sink;
311
312                         source = media_get_entity_by_id(media, link->source.entity);
313                         sink = media_get_entity_by_id(media, link->sink.entity);
314
315                         if (source == NULL || sink == NULL) {
316                                 media_dbg(media,
317                                           "WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
318                                           id, i, link->source.entity,
319                                           link->source.index,
320                                           link->sink.entity,
321                                           link->sink.index);
322                                 ret = -EINVAL;
323                         } else {
324                                 fwdlink = media_entity_add_link(source);
325                                 fwdlink->source = &source->pads[link->source.index];
326                                 fwdlink->sink = &sink->pads[link->sink.index];
327                                 fwdlink->flags = link->flags;
328
329                                 backlink = media_entity_add_link(sink);
330                                 backlink->source = &source->pads[link->source.index];
331                                 backlink->sink = &sink->pads[link->sink.index];
332                                 backlink->flags = link->flags;
333
334                                 fwdlink->twin = backlink;
335                                 backlink->twin = fwdlink;
336                         }
337                 }
338
339                 free(links.pads);
340                 free(links.links);
341         }
342
343         return ret;
344 }
345
346 #ifdef HAVE_LIBUDEV
347
348 #include <libudev.h>
349
350 static inline int media_udev_open(struct udev **udev)
351 {
352         *udev = udev_new();
353         if (*udev == NULL)
354                 return -ENOMEM;
355         return 0;
356 }
357
358 static inline void media_udev_close(struct udev *udev)
359 {
360         if (udev != NULL)
361                 udev_unref(udev);
362 }
363
364 static int media_get_devname_udev(struct udev *udev,
365                 struct media_entity *entity)
366 {
367         struct udev_device *device;
368         dev_t devnum;
369         const char *p;
370         int ret = -ENODEV;
371
372         if (udev == NULL)
373                 return -EINVAL;
374
375         devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
376         media_dbg(entity->media, "looking up device: %u:%u\n",
377                   major(devnum), minor(devnum));
378         device = udev_device_new_from_devnum(udev, 'c', devnum);
379         if (device) {
380                 p = udev_device_get_devnode(device);
381                 if (p) {
382                         strncpy(entity->devname, p, sizeof(entity->devname));
383                         entity->devname[sizeof(entity->devname) - 1] = '\0';
384                 }
385                 ret = 0;
386         }
387
388         udev_device_unref(device);
389
390         return ret;
391 }
392
393 #else   /* HAVE_LIBUDEV */
394
395 struct udev;
396
397 static inline int media_udev_open(struct udev **udev) { return 0; }
398
399 static inline void media_udev_close(struct udev *udev) { }
400
401 static inline int media_get_devname_udev(struct udev *udev,
402                 struct media_entity *entity)
403 {
404         return -ENOTSUP;
405 }
406
407 #endif  /* HAVE_LIBUDEV */
408
409 static int media_get_devname_sysfs(struct media_entity *entity)
410 {
411         struct stat devstat;
412         char devname[32];
413         char sysname[32];
414         char target[1024];
415         char *p;
416         int ret;
417
418         sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
419                 entity->info.v4l.minor);
420         ret = readlink(sysname, target, sizeof(target));
421         if (ret < 0)
422                 return -errno;
423
424         target[ret] = '\0';
425         p = strrchr(target, '/');
426         if (p == NULL)
427                 return -EINVAL;
428
429         sprintf(devname, "/dev/%s", p + 1);
430         ret = stat(devname, &devstat);
431         if (ret < 0)
432                 return -errno;
433
434         /* Sanity check: udev might have reordered the device nodes.
435          * Make sure the major/minor match. We should really use
436          * libudev.
437          */
438         if (major(devstat.st_rdev) == entity->info.v4l.major &&
439             minor(devstat.st_rdev) == entity->info.v4l.minor)
440                 strcpy(entity->devname, devname);
441
442         return 0;
443 }
444
445 static int media_enum_entities(struct media_device *media)
446 {
447         struct media_entity *entity;
448         struct udev *udev;
449         unsigned int size;
450         __u32 id;
451         int ret;
452
453         ret = media_udev_open(&udev);
454         if (ret < 0)
455                 media_dbg(media, "Can't get udev context\n");
456
457         for (id = 0, ret = 0; ; id = entity->info.id) {
458                 size = (media->entities_count + 1) * sizeof(*media->entities);
459                 media->entities = realloc(media->entities, size);
460
461                 entity = &media->entities[media->entities_count];
462                 memset(entity, 0, sizeof(*entity));
463                 entity->fd = -1;
464                 entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
465                 entity->media = media;
466
467                 ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
468                 if (ret < 0) {
469                         ret = errno != EINVAL ? -errno : 0;
470                         break;
471                 }
472
473                 /* Number of links (for outbound links) plus number of pads (for
474                  * inbound links) is a good safe initial estimate of the total
475                  * number of links.
476                  */
477                 entity->max_links = entity->info.pads + entity->info.links;
478
479                 entity->pads = malloc(entity->info.pads * sizeof(*entity->pads));
480                 entity->links = malloc(entity->max_links * sizeof(*entity->links));
481                 if (entity->pads == NULL || entity->links == NULL) {
482                         ret = -ENOMEM;
483                         break;
484                 }
485
486                 media->entities_count++;
487
488                 /* Find the corresponding device name. */
489                 if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
490                     media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
491                         continue;
492
493                 /* Try to get the device name via udev */
494                 if (!media_get_devname_udev(udev, entity))
495                         continue;
496
497                 /* Fall back to get the device name via sysfs */
498                 media_get_devname_sysfs(entity);
499         }
500
501         media_udev_close(udev);
502         return ret;
503 }
504
505 int media_device_enumerate(struct media_device *media)
506 {
507         int ret;
508
509         if (media->entities)
510                 return 0;
511
512         ret = media_device_open(media);
513         if (ret < 0)
514                 return ret;
515
516         ret = ioctl(media->fd, MEDIA_IOC_DEVICE_INFO, &media->info);
517         if (ret < 0) {
518                 ret = -errno;
519                 media_dbg(media, "%s: Unable to retrieve media device "
520                           "information for device %s (%s)\n", __func__,
521                           media->devnode, strerror(errno));
522                 goto done;
523         }
524
525         media_dbg(media, "Enumerating entities\n");
526
527         ret = media_enum_entities(media);
528         if (ret < 0) {
529                 media_dbg(media,
530                           "%s: Unable to enumerate entities for device %s (%s)\n",
531                           __func__, media->devnode, strerror(-ret));
532                 goto done;
533         }
534
535         media_dbg(media, "Found %u entities\n", media->entities_count);
536         media_dbg(media, "Enumerating pads and links\n");
537
538         ret = media_enum_links(media);
539         if (ret < 0) {
540                 media_dbg(media,
541                           "%s: Unable to enumerate pads and linksfor device %s\n",
542                           __func__, media->devnode);
543                 goto done;
544         }
545
546         ret = 0;
547
548 done:
549         media_device_close(media);
550         return ret;
551 }
552
553 /* -----------------------------------------------------------------------------
554  * Create/destroy
555  */
556
557 static void media_debug_default(void *ptr, ...)
558 {
559 }
560
561 void media_debug_set_handler(struct media_device *media,
562                              void (*debug_handler)(void *, ...),
563                              void *debug_priv)
564 {
565         if (debug_handler) {
566                 media->debug_handler = debug_handler;
567                 media->debug_priv = debug_priv;
568         } else {
569                 media->debug_handler = media_debug_default;
570                 media->debug_priv = NULL;
571         }
572 }
573
574 struct media_device *media_device_new(const char *devnode)
575 {
576         struct media_device *media;
577         int ret;
578
579         media = calloc(1, sizeof(*media));
580         if (media == NULL)
581                 return NULL;
582
583         media->fd = -1;
584         media->refcount = 1;
585
586         media_debug_set_handler(media, NULL, NULL);
587
588         media->devnode = strdup(devnode);
589         if (media->devnode == NULL) {
590                 media_device_unref(media);
591                 return NULL;
592         }
593
594         return media;
595 }
596
597 struct media_device *media_device_ref(struct media_device *media)
598 {
599         media->refcount++;
600         return media;
601 }
602
603 void media_device_unref(struct media_device *media)
604 {
605         unsigned int i;
606
607         media->refcount--;
608         if (media->refcount > 0)
609                 return;
610
611         for (i = 0; i < media->entities_count; ++i) {
612                 struct media_entity *entity = &media->entities[i];
613
614                 free(entity->pads);
615                 free(entity->links);
616                 if (entity->fd != -1)
617                         close(entity->fd);
618         }
619
620         free(media->entities);
621         free(media->devnode);
622         free(media);
623 }
624
625 /* -----------------------------------------------------------------------------
626  * Parsing
627  */
628
629 struct media_pad *media_parse_pad(struct media_device *media,
630                                   const char *p, char **endp)
631 {
632         unsigned int entity_id, pad;
633         struct media_entity *entity;
634         char *end;
635
636         /* endp can be NULL. To avoid spreading NULL checks across the function,
637          * set endp to &end in that case.
638          */
639         if (endp == NULL)
640                 endp = &end;
641
642         for (; isspace(*p); ++p);
643
644         if (*p == '"' || *p == '\'') {
645                 for (end = (char *)p + 1; *end && *end != '"' && *end != '\''; ++end);
646                 if (*end != '"' && *end != '\'') {
647                         media_dbg(media, "missing matching '\"'\n");
648                         *endp = end;
649                         return NULL;
650                 }
651
652                 entity = media_get_entity_by_name(media, p + 1, end - p - 1);
653                 if (entity == NULL) {
654                         media_dbg(media, "no such entity \"%.*s\"\n", end - p - 1, p + 1);
655                         *endp = (char *)p + 1;
656                         return NULL;
657                 }
658
659                 ++end;
660         } else {
661                 entity_id = strtoul(p, &end, 10);
662                 entity = media_get_entity_by_id(media, entity_id);
663                 if (entity == NULL) {
664                         media_dbg(media, "no such entity %d\n", entity_id);
665                         *endp = (char *)p;
666                         return NULL;
667                 }
668         }
669         for (; isspace(*end); ++end);
670
671         if (*end != ':') {
672                 media_dbg(media, "Expected ':'\n", *end);
673                 *endp = end;
674                 return NULL;
675         }
676
677         for (p = end + 1; isspace(*p); ++p);
678
679         pad = strtoul(p, &end, 10);
680
681         if (pad >= entity->info.pads) {
682                 media_dbg(media, "No pad '%d' on entity \"%s\". Maximum pad number is %d\n",
683                                 pad, entity->info.name, entity->info.pads - 1);
684                 *endp = (char *)p;
685                 return NULL;
686         }
687
688         for (p = end; isspace(*p); ++p);
689         *endp = (char *)p;
690
691         return &entity->pads[pad];
692 }
693
694 struct media_link *media_parse_link(struct media_device *media,
695                                     const char *p, char **endp)
696 {
697         struct media_link *link;
698         struct media_pad *source;
699         struct media_pad *sink;
700         unsigned int i;
701         char *end;
702
703         source = media_parse_pad(media, p, &end);
704         if (source == NULL) {
705                 *endp = end;
706                 return NULL;
707         }
708
709         if (end[0] != '-' || end[1] != '>') {
710                 *endp = end;
711                 media_dbg(media, "Expected '->'\n");
712                 return NULL;
713         }
714
715         p = end + 2;
716
717         sink = media_parse_pad(media, p, &end);
718         if (sink == NULL) {
719                 *endp = end;
720                 return NULL;
721         }
722
723         *endp = end;
724
725         for (i = 0; i < source->entity->num_links; i++) {
726                 link = &source->entity->links[i];
727
728                 if (link->source == source && link->sink == sink)
729                         return link;
730         }
731
732         media_dbg(media, "No link between \"%s\":%d and \"%s\":%d\n",
733                         source->entity->info.name, source->index,
734                         sink->entity->info.name, sink->index);
735         return NULL;
736 }
737
738 int media_parse_setup_link(struct media_device *media,
739                            const char *p, char **endp)
740 {
741         struct media_link *link;
742         __u32 flags;
743         char *end;
744
745         link = media_parse_link(media, p, &end);
746         if (link == NULL) {
747                 media_dbg(media,
748                           "%s: Unable to parse link\n", __func__);
749                 *endp = end;
750                 return -EINVAL;
751         }
752
753         p = end;
754         if (*p++ != '[') {
755                 media_dbg(media, "Unable to parse link flags: expected '['.\n");
756                 *endp = (char *)p - 1;
757                 return -EINVAL;
758         }
759
760         flags = strtoul(p, &end, 10);
761         for (p = end; isspace(*p); p++);
762         if (*p++ != ']') {
763                 media_dbg(media, "Unable to parse link flags: expected ']'.\n");
764                 *endp = (char *)p - 1;
765                 return -EINVAL;
766         }
767
768         for (; isspace(*p); p++);
769         *endp = (char *)p;
770
771         media_dbg(media,
772                   "Setting up link %u:%u -> %u:%u [%u]\n",
773                   link->source->entity->info.id, link->source->index,
774                   link->sink->entity->info.id, link->sink->index,
775                   flags);
776
777         return media_setup_link(media, link->source, link->sink, flags);
778 }
779
780 void media_print_streampos(struct media_device *media, const char *p,
781                            const char *end)
782 {
783         int pos;
784
785         pos = end - p + 1;
786
787         if (pos < 0)
788                 pos = 0;
789         if (pos > strlen(p))
790                 pos = strlen(p);
791
792         media_dbg(media, "\n");
793         media_dbg(media, " %s\n", p);
794         media_dbg(media, " %*s\n", pos, "^");
795 }
796
797 int media_parse_setup_links(struct media_device *media, const char *p)
798 {
799         char *end;
800         int ret;
801
802         do {
803                 ret = media_parse_setup_link(media, p, &end);
804                 if (ret < 0) {
805                         media_print_streampos(media, p, end);
806                         return ret;
807                 }
808
809                 p = end + 1;
810         } while (*end == ',');
811
812         return *end ? -EINVAL : 0;
813 }