Home | History | Annotate | Download | only in libv4l2
      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 (at) samsung.com)
     21  * \author    Sangwoo Park (sw5771.park (at) samsung.com)
     22  * \date      2012/01/17
     23  *
     24  * <b>Revision History: </b>
     25  * - 2012/01/17: Jinsung Yang (jsgood.yang (at) 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 
     50 static inline unsigned int __media_entity_type(struct media_entity *entity)
     51 {
     52     return entity->info.type & MEDIA_ENT_TYPE_MASK;
     53 }
     54 
     55 static 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 
     63 static 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 
     77 static 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 
     99 static 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 
    165 static 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 
    194 static 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 
    215 static 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 
    270 static 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  */
    329 struct 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  */
    341 void 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  */
    372 struct 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  */
    402 struct 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  */
    427 struct 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  */
    458 int 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  */
    515 int 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 
    544 static 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 
    552 static inline void __media_udev_close(struct udev *udev)
    553 {
    554     if (udev != NULL)
    555         udev_unref(udev);
    556 }
    557 
    558 static 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 
    589 struct udev;
    590 
    591 static inline int __media_udev_open(struct udev **udev) { return 0; }
    592 
    593 static inline void __media_udev_close(struct udev *udev) { }
    594 
    595 static 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  */
    614 struct 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  */
    669 struct 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  */
    714 int 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  */
    763 int 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