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