Initial version of libomxil-e3250-v4l2
[platform/adaptation/ap_samsung/libomxil-e3250-v4l2.git] / exynos / libv4l2 / exynos_mc.c
1 /*
2  * Copyright 2012 Samsung Electronics S.LSI Co. LTD
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*!
18  * \file      exynos_mc.c
19  * \brief     source file for libexynosv4l2
20  * \author    Jinsung Yang (jsgood.yang@samsung.com)
21  * \author    Sangwoo Park (sw5771.park@samsung.com)
22  * \date      2012/01/17
23  *
24  * <b>Revision History: </b>
25  * - 2012/01/17: Jinsung Yang (jsgood.yang@samsung.com) \n
26  *   Initial version
27  *
28  */
29
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <sys/stat.h>
40 #ifndef SLP_PLATFORM /* build env */
41 #include <media.h>
42 #else
43
44 //#include <linux/compiler.h>
45 #include <linux/media.h>
46
47 #endif
48 #include <linux/kdev_t.h>
49 #include <linux/types.h>
50
51 #include "exynos_v4l2.h"
52
53 //#define LOG_NDEBUG 0
54 #define LOG_TAG "libexynosv4l2-mc"
55 #ifndef SLP_PLATFORM /* build env */
56 #include <utils/Log.h>
57 #else
58 #include "Exynos_OSAL_Log.h"
59 #endif
60
61 static inline unsigned int __media_entity_type(struct media_entity *entity)
62 {
63     return entity->info.type & MEDIA_ENT_TYPE_MASK;
64 }
65
66 static void __media_debug_default(void *ptr, ...)
67 {
68     va_list argptr;
69     va_start(argptr, ptr);
70     vprintf((const char*)ptr, argptr);
71     va_end(argptr);
72 }
73
74 static void __media_debug_set_handler(
75                 struct media_device *media,
76                 void (*debug_handler)(void *, ...),
77                 void *debug_priv)
78 {
79     if (debug_handler) {
80         media->debug_handler = debug_handler;
81         media->debug_priv = debug_priv;
82     } else {
83         media->debug_handler = __media_debug_default;
84         media->debug_priv = NULL;
85     }
86 }
87
88 static struct media_link *__media_entity_add_link(struct media_entity *entity)
89 {
90     if (entity->num_links >= entity->max_links) {
91         struct media_link *links = entity->links;
92         unsigned int max_links = entity->max_links * 2;
93         unsigned int i;
94
95         links = (struct media_link*)realloc(links, max_links * sizeof *links);
96         if (links == NULL)
97             return NULL;
98
99         for (i = 0; i < entity->num_links; ++i)
100             links[i].twin->twin = &links[i];
101
102         entity->max_links = max_links;
103         entity->links = links;
104     }
105
106     return &entity->links[entity->num_links++];
107 }
108
109
110 static int __media_enum_links(struct media_device *media)
111 {
112     ALOGD("%s: start", __func__);
113     __u32 id;
114     int ret = 0;
115
116     for (id = 1; id <= media->entities_count; id++) {
117         struct media_entity *entity = &media->entities[id - 1];
118         struct media_links_enum links;
119         unsigned int i;
120
121         links.entity = entity->info.id;
122         links.pads = (struct media_pad_desc*)malloc(entity->info.pads * sizeof(struct media_pad_desc));
123         links.links = (struct media_link_desc*)malloc(entity->info.links * sizeof(struct media_link_desc));
124
125         if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
126             ALOGE("Unable to enumerate pads and links (%s)", strerror(errno));
127             free(links.pads);
128             free(links.links);
129             return -errno;
130         }
131
132         for (i = 0; i < entity->info.pads; ++i) {
133             entity->pads[i].entity = entity;
134             entity->pads[i].index = links.pads[i].index;
135             entity->pads[i].flags = links.pads[i].flags;
136         }
137
138         for (i = 0; i < entity->info.links; ++i) {
139             struct media_link_desc *link = &links.links[i];
140             struct media_link *fwdlink;
141             struct media_link *backlink;
142             struct media_entity *source;
143             struct media_entity *sink;
144
145             source = exynos_media_get_entity_by_id(media, link->source.entity);
146             sink = exynos_media_get_entity_by_id(media, link->sink.entity);
147             if (source == NULL || sink == NULL) {
148                 ALOGE("WARNING entity %u link %u from %u/%u to %u/%u is invalid!",
149                       id, i, link->source.entity,
150                       link->source.index,
151                       link->sink.entity,
152                       link->sink.index);
153                 ret = -EINVAL;
154             } else {
155                 fwdlink = __media_entity_add_link(source);
156                 fwdlink->source = &source->pads[link->source.index];
157                 fwdlink->sink = &sink->pads[link->sink.index];
158                 fwdlink->flags = link->flags;
159
160                 backlink = __media_entity_add_link(sink);
161                 backlink->source = &source->pads[link->source.index];
162                 backlink->sink = &sink->pads[link->sink.index];
163                 backlink->flags = link->flags;
164
165                 fwdlink->twin = backlink;
166                 backlink->twin = fwdlink;
167             }
168         }
169
170         free(links.pads);
171         free(links.links);
172     }
173     return ret;
174 }
175
176 static int __media_get_devname_sysfs(struct media_entity *entity)
177 {
178     //struct stat devstat;
179     char devname[32];
180     char sysname[32];
181     char target[1024];
182     char *p;
183     int ret;
184
185     sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
186         entity->info.v4l.minor);
187
188     ret = readlink(sysname, target, sizeof(target));
189     if (ret < 0)
190         return -errno;
191
192     target[ret] = '\0';
193     p = strrchr(target, '/');
194     if (p == NULL)
195         return -EINVAL;
196
197     sprintf(devname, "/tmp/%s", p + 1);
198
199     ret = mknod(devname, 0666 | S_IFCHR, MKDEV(81, entity->info.v4l.minor));
200     strcpy(entity->devname, devname);
201
202     return 0;
203 }
204
205 static int __media_get_media_fd(const char *filename, struct media_device *media)
206 {
207     ssize_t num;
208     int media_node;
209     char *ptr;
210     char media_buf[6];
211
212     ALOGD("%s: %s", __func__, filename);
213
214     media->fd = open(filename, O_RDWR, 0);
215     if (media->fd < 0) {
216         ALOGE("Open sysfs media device failed, media->fd: %d", media->fd);
217         return -1;
218     }
219
220     ALOGD("%s: media->fd: %d", __func__, media->fd);
221
222     return media->fd;
223
224 }
225
226 static int __media_enum_entities(struct media_device *media)
227 {
228     struct media_entity *entity, *temp_entity;
229     unsigned int size;
230     __u32 id;
231     int ret;
232
233     temp_entity = entity = (struct media_entity*)calloc(1,  sizeof(struct media_entity));
234     for (id = 0, ret = 0; ; id = entity->info.id) {
235         size = (media->entities_count + 1) * sizeof(*media->entities);
236         media->entities = (struct media_entity*)realloc(media->entities, size);
237
238         entity = &media->entities[media->entities_count];
239         memset(entity, 0, sizeof(*entity));
240         entity->fd = -1;
241         entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
242         entity->media = media;
243
244         ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
245
246         if (ret < 0) {
247             ret = errno != EINVAL ? -errno : 0;
248             break;
249         }
250
251         /* Number of links (for outbound links) plus number of pads (for
252          * inbound links) is a good safe initial estimate of the total
253          * number of links.
254          */
255         entity->max_links = entity->info.pads + entity->info.links;
256
257         entity->pads = (struct media_pad*)malloc(entity->info.pads * sizeof(*entity->pads));
258         entity->links = (struct media_link*)malloc(entity->max_links * sizeof(*entity->links));
259         if (entity->pads == NULL || entity->links == NULL) {
260             ret = -ENOMEM;
261             break;
262         }
263
264         media->entities_count++;
265
266         /* Find the corresponding device name. */
267         if (__media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
268             __media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
269             continue;
270
271         /* Fall back to get the device name via sysfs */
272         __media_get_devname_sysfs(entity);
273         if (ret < 0)
274             ALOGE("media_get_devname failed");
275     }
276     free(temp_entity);
277
278     return ret;
279 }
280
281 static struct media_device *__media_open_debug(
282         const char *filename,
283         void (*debug_handler)(void *, ...),
284         void *debug_priv)
285 {
286     struct media_device *media;
287     int ret;
288
289     media = (struct media_device *)calloc(1, sizeof(struct media_device));
290     if (media == NULL) {
291         ALOGE("media: %p", media);
292         return NULL;
293     }
294
295     __media_debug_set_handler(media, debug_handler, debug_priv);
296
297     ALOGD("%s: Opening media device %s", __func__, filename);
298     ALOGD("%s: media: %p", __func__, media);
299
300     media->fd = __media_get_media_fd(filename, media);
301     if (media->fd < 0) {
302         exynos_media_close(media);
303         ALOGE("failed __media_get_media_fd %s", filename);
304         return NULL;
305     }
306
307     ALOGD("%s: media->fd: %d", __func__, media->fd);
308     ret = __media_enum_entities(media);
309
310     if (ret < 0) {
311         ALOGE("Unable to enumerate entities for device %s (%s)", filename, strerror(-ret));
312         exynos_media_close(media);
313         return NULL;
314     }
315
316     ALOGD("%s: Found %u entities", __func__, media->entities_count);
317     ALOGD("%s: Enumerating pads and links", __func__);
318
319     ret = __media_enum_links(media);
320     if (ret < 0) {
321         ALOGE("Unable to enumerate pads and links for device %s", filename);
322         exynos_media_close(media);
323         return NULL;
324     }
325
326     return media;
327 }
328
329 /**
330  * @brief Open a media device.
331  * @param filename - name (including path) of the device node.
332  *
333  * Open the media device referenced by @a filename and enumerate entities, pads and
334  * links.
335  *
336  * @return A pointer to a newly allocated media_device structure instance on
337  * success and NULL on failure. The returned pointer must be freed with
338  * exynos_media_close when the device isn't needed anymore.
339  */
340 struct media_device *exynos_media_open(const char *filename)
341 {
342     return __media_open_debug(filename, (void (*)(void *, ...))fprintf, stdout);
343 }
344
345 /**
346  * @brief Close a media device.
347  * @param media - device instance.
348  *
349  * Close the @a media device instance and free allocated resources. Access to the
350  * device instance is forbidden after this function returns.
351  */
352 void exynos_media_close(struct media_device *media)
353 {
354     unsigned int i;
355
356     if (media->fd != -1)
357         close(media->fd);
358
359     for (i = 0; i < media->entities_count; ++i) {
360         struct media_entity *entity = &media->entities[i];
361
362         free(entity->pads);
363         free(entity->links);
364         if (entity->fd != -1)
365             close(entity->fd);
366     }
367
368     free(media->entities);
369     free(media);
370 }
371
372 /**
373  * @brief Locate the pad at the other end of a link.
374  * @param pad - sink pad at one end of the link.
375  *
376  * Locate the source pad connected to @a pad through an enabled link. As only one
377  * link connected to a sink pad can be enabled at a time, the connected source
378  * pad is guaranteed to be unique.
379  *
380  * @return A pointer to the connected source pad, or NULL if all links connected
381  * to @a pad are disabled. Return NULL also if @a pad is not a sink pad.
382  */
383 struct media_pad *exynos_media_entity_remote_source(struct media_pad *pad)
384 {
385     unsigned int i;
386
387     if (!(pad->flags & MEDIA_PAD_FL_SINK))
388         return NULL;
389
390     for (i = 0; i < pad->entity->num_links; ++i) {
391         struct media_link *link = &pad->entity->links[i];
392
393         if (!(link->flags & MEDIA_LNK_FL_ENABLED))
394             continue;
395
396         if (link->sink == pad)
397             return link->source;
398     }
399
400     return NULL;
401 }
402
403 /**
404  * @brief Find an entity by its name.
405  * @param media - media device.
406  * @param name - entity name.
407  * @param length - size of @a name.
408  *
409  * Search for an entity with a name equal to @a name.
410  *
411  * @return A pointer to the entity if found, or NULL otherwise.
412  */
413 struct media_entity *exynos_media_get_entity_by_name(struct media_device *media,
414                           const char *name, size_t length)
415 {
416     unsigned int i;
417     struct media_entity *entity;
418
419     for (i = 0; i < media->entities_count; ++i) {
420         entity = &media->entities[i];
421
422         if (strncmp(entity->info.name, name, length) == 0)
423             return entity;
424     }
425
426     return NULL;
427 }
428
429 /**
430  * @brief Find an entity by its ID.
431  * @param media - media device.
432  * @param id - entity ID.
433  *
434  * Search for an entity with an ID equal to @a id.
435  *
436  * @return A pointer to the entity if found, or NULL otherwise.
437  */
438 struct media_entity *exynos_media_get_entity_by_id(struct media_device *media,
439                         __u32 id)
440 {
441     unsigned int i;
442
443     for (i = 0; i < media->entities_count; ++i) {
444         struct media_entity *entity = &media->entities[i];
445
446         if (entity->info.id == id)
447             return entity;
448     }
449
450     return NULL;
451 }
452
453 /**
454  * @brief Configure a link.
455  * @param media - media device.
456  * @param source - source pad at the link origin.
457  * @param sink - sink pad at the link target.
458  * @param flags - configuration flags.
459  *
460  * Locate the link between @a source and @a sink, and configure it by applying
461  * the new @a flags.
462  *
463  * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
464  *
465  * @return 0 on success, -1 on failure:
466  *       -ENOENT: link not found
467  *       - other error codes returned by MEDIA_IOC_SETUP_LINK
468  */
469 int exynos_media_setup_link(struct media_device *media,
470              struct media_pad *source,
471              struct media_pad *sink,
472              __u32 flags)
473 {
474     struct media_link *link;
475     struct media_link_desc ulink;
476     unsigned int i;
477     int ret;
478
479     for (i = 0; i < source->entity->num_links; i++) {
480         link = &source->entity->links[i];
481
482         if (link->source->entity == source->entity &&
483             link->source->index == source->index &&
484             link->sink->entity == sink->entity &&
485             link->sink->index == sink->index)
486             break;
487     }
488
489     if (i == source->entity->num_links) {
490         ALOGE("Link not found");
491         return -ENOENT;
492     }
493
494     /* source pad */
495     ulink.source.entity = source->entity->info.id;
496     ulink.source.index = source->index;
497     ulink.source.flags = MEDIA_PAD_FL_SOURCE;
498
499     /* sink pad */
500     ulink.sink.entity = sink->entity->info.id;
501     ulink.sink.index = sink->index;
502     ulink.sink.flags = MEDIA_PAD_FL_SINK;
503
504     ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
505
506     ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
507     if (ret == -1) {
508         ALOGE("Unable to setup link (%s)", strerror(errno));
509         return -errno;
510     }
511
512     link->flags = ulink.flags;
513     link->twin->flags = ulink.flags;
514     return 0;
515 }
516
517 /**
518  * @brief Reset all links to the disabled state.
519  * @param media - media device.
520  *
521  * Disable all links in the media device. This function is usually used after
522  * opening a media device to reset all links to a known state.
523  *
524  * @return 0 on success, or a negative error code on failure.
525  */
526 int exynos_media_reset_links(struct media_device *media)
527 {
528     unsigned int i, j;
529     int ret;
530
531     for (i = 0; i < media->entities_count; ++i) {
532         struct media_entity *entity = &media->entities[i];
533
534         for (j = 0; j < entity->num_links; j++) {
535             struct media_link *link = &entity->links[j];
536
537             if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
538                 link->source->entity != entity)
539                 continue;
540
541             ret = exynos_media_setup_link(media, link->source, link->sink,
542                            link->flags & ~MEDIA_LNK_FL_ENABLED);
543             if (ret < 0)
544                 return ret;
545         }
546     }
547
548     return 0;
549 }
550
551 #ifdef HAVE_LIBUDEV
552
553 #include <libudev.h>
554
555 static inline int __media_udev_open(struct udev **udev)
556 {
557     *udev = udev_new();
558     if (*udev == NULL)
559         return -ENOMEM;
560     return 0;
561 }
562
563 static inline void __media_udev_close(struct udev *udev)
564 {
565     if (udev != NULL)
566         udev_unref(udev);
567 }
568
569 static int __media_get_devname_udev(struct udev *udev,
570         struct media_entity *entity)
571 {
572     struct udev_device *device;
573     dev_t devnum;
574     const char *p;
575     int ret = -ENODEV;
576
577     if (udev == NULL)
578         return -EINVAL;
579
580     devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
581     ALOGE("looking up device: %u:%u",
582           major(devnum), minor(devnum));
583     device = udev_device_new_from_devnum(udev, 'c', devnum);
584     if (device) {
585         p = udev_device_get_devnode(device);
586         if (p) {
587             strncpy(entity->devname, p, sizeof(entity->devname));
588             entity->devname[sizeof(entity->devname) - 1] = '\0';
589         }
590         ret = 0;
591     }
592
593     udev_device_unref(device);
594
595     return ret;
596 }
597
598 #else    /* HAVE_LIBUDEV */
599
600 struct udev;
601
602 static inline int __media_udev_open(struct udev **udev) { return 0; }
603
604 static inline void __media_udev_close(struct udev *udev) { }
605
606 static inline int __media_get_devname_udev(struct udev *udev,
607         struct media_entity *entity)
608 {
609     return -ENOTSUP;
610 }
611
612 #endif    /* HAVE_LIBUDEV */
613
614 /**
615  * @brief Parse string to a pad on the media device.
616  * @param media - media device.
617  * @param p - input string
618  * @param endp - pointer to string where parsing ended
619  *
620  * Parse NULL terminated string describing a pad and return its struct
621  * media_pad instance.
622  *
623  * @return Pointer to struct media_pad on success, NULL on failure.
624  */
625 struct media_pad *exynos_media_parse_pad(struct media_device *media,
626                   const char *p, char **endp)
627 {
628     unsigned int entity_id, pad;
629     struct media_entity *entity;
630     char *end;
631
632     for (; isspace(*p); ++p);
633
634     if (*p == '"') {
635         for (end = (char *)p + 1; *end && *end != '"'; ++end);
636         if (*end != '"')
637             return NULL;
638
639         entity = exynos_media_get_entity_by_name(media, p + 1, end - p - 1);
640         if (entity == NULL)
641             return NULL;
642
643         ++end;
644     } else {
645         entity_id = strtoul(p, &end, 10);
646         entity = exynos_media_get_entity_by_id(media, entity_id);
647         if (entity == NULL)
648             return NULL;
649     }
650     for (; isspace(*end); ++end);
651
652     if (*end != ':')
653         return NULL;
654     for (p = end + 1; isspace(*p); ++p);
655
656     pad = strtoul(p, &end, 10);
657     for (p = end; isspace(*p); ++p);
658
659     if (pad >= entity->info.pads)
660         return NULL;
661
662     for (p = end; isspace(*p); ++p);
663     if (endp)
664         *endp = (char *)p;
665
666     return &entity->pads[pad];
667 }
668
669 /**
670  * @brief Parse string to a link on the media device.
671  * @param media - media device.
672  * @param p - input string
673  * @param endp - pointer to p where parsing ended
674  *
675  * Parse NULL terminated string p describing a link and return its struct
676  * media_link instance.
677  *
678  * @return Pointer to struct media_link on success, NULL on failure.
679  */
680 struct media_link *exynos_media_parse_link(
681         struct media_device *media,
682         const char *p,
683         char **endp)
684 {
685     struct media_link *link;
686     struct media_pad *source;
687     struct media_pad *sink;
688     unsigned int i;
689     char *end;
690
691     source = exynos_media_parse_pad(media, p, &end);
692     if (source == NULL)
693         return NULL;
694
695     if (end[0] != '-' || end[1] != '>')
696         return NULL;
697     p = end + 2;
698
699     sink = exynos_media_parse_pad(media, p, &end);
700     if (sink == NULL)
701         return NULL;
702
703     *endp = end;
704
705     for (i = 0; i < source->entity->num_links; i++) {
706         link = &source->entity->links[i];
707
708         if (link->source == source && link->sink == sink)
709             return link;
710     }
711
712     return NULL;
713 }
714
715 /**
716  * @brief Parse string to a link on the media device and set it up.
717  * @param media - media device.
718  * @param p - input string
719  *
720  * Parse NULL terminated string p describing a link and its configuration
721  * and configure the link.
722  *
723  * @return 0 on success, or a negative error code on failure.
724  */
725 int exynos_media_parse_setup_link(
726         struct media_device *media,
727         const char *p,
728         char **endp)
729 {
730     struct media_link *link;
731     __u32 flags;
732     char *end;
733
734     link = exynos_media_parse_link(media, p, &end);
735     if (link == NULL) {
736         ALOGE("Unable to parse link");
737         return -EINVAL;
738     }
739
740     p = end;
741     if (*p++ != '[') {
742         ALOGE("Unable to parse link flags");
743         return -EINVAL;
744     }
745
746     flags = strtoul(p, &end, 10);
747     for (p = end; isspace(*p); p++);
748     if (*p++ != ']') {
749         ALOGE("Unable to parse link flags");
750         return -EINVAL;
751     }
752
753     for (; isspace(*p); p++);
754     *endp = (char *)p;
755
756     ALOGD("%s: Setting up link %u:%u -> %u:%u [%u]", __func__,
757           link->source->entity->info.id, link->source->index,
758           link->sink->entity->info.id, link->sink->index,
759           flags);
760
761     return exynos_media_setup_link(media, link->source, link->sink, flags);
762 }
763
764 /**
765  * @brief Parse string to link(s) on the media device and set it up.
766  * @param media - media device.
767  * @param p - input string
768  *
769  * Parse NULL terminated string p describing link(s) separated by
770  * commas (,) and configure the link(s).
771  *
772  * @return 0 on success, or a negative error code on failure.
773  */
774 int exynos_media_parse_setup_links(struct media_device *media, const char *p)
775 {
776     char *end;
777     int ret;
778
779     do {
780         ret = exynos_media_parse_setup_link(media, p, &end);
781         if (ret < 0)
782             return ret;
783
784         p = end + 1;
785     } while (*end == ',');
786
787     return *end ? -EINVAL : 0;
788 }