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