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