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