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_subdev.c
     19  * \brief     source file for libv4l2
     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 <fcntl.h>
     33 #include <sys/types.h>
     34 #include <sys/ioctl.h>
     35 #include <sys/stat.h>
     36 
     37 #include "exynos_v4l2.h"
     38 
     39 //#define LOG_NDEBUG 0
     40 #define LOG_TAG "libexynosv4l2-subdev"
     41 #include <utils/Log.h>
     42 
     43 #define SUBDEV_MINOR_MAX 191
     44 
     45 static int __subdev_open(const char *filename, int oflag, va_list ap)
     46 {
     47     mode_t mode = 0;
     48     int fd;
     49 
     50     if (oflag & O_CREAT)
     51         mode = va_arg(ap, int);
     52 
     53     fd = open(filename, oflag, mode);
     54 
     55     return fd;
     56 }
     57 
     58 int exynos_subdev_open(const char *filename, int oflag, ...)
     59 {
     60     va_list ap;
     61     int fd;
     62 
     63     va_start(ap, oflag);
     64     fd = __subdev_open(filename, oflag, ap);
     65     va_end(ap);
     66 
     67     return fd;
     68 }
     69 
     70 int exynos_subdev_open_devname(const char *devname, int oflag, ...)
     71 {
     72     bool found = false;
     73     int fd = -1;
     74     struct stat s;
     75     va_list ap;
     76     FILE *stream_fd;
     77     char filename[64], name[64];
     78     int minor, size, i = 0;
     79 
     80     do {
     81         if (i > (SUBDEV_MINOR_MAX - 128))
     82             break;
     83 
     84         /* video device node */
     85         sprintf(filename, "/dev/v4l-subdev%d", i++);
     86 
     87         /* if the node is video device */
     88         if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) &&
     89                 ((int)((unsigned short)(s.st_rdev) >> 8) == 81)) {
     90             minor = (int)((unsigned short)(s.st_rdev & 0x3f));
     91             ALOGD("try node: %s, minor: %d", filename, minor);
     92             /* open sysfs entry */
     93             sprintf(filename, "/sys/class/video4linux/v4l-subdev%d/name", minor);
     94             stream_fd = fopen(filename, "r");
     95             if (stream_fd == NULL) {
     96                 ALOGE("failed to open sysfs entry for subdev");
     97                 continue;   /* try next */
     98             }
     99 
    100             /* read sysfs entry for device name */
    101             size = (int)fgets(name, sizeof(name), stream_fd);
    102             fclose(stream_fd);
    103 
    104             /* check read size */
    105             if (size == 0) {
    106                 ALOGE("failed to read sysfs entry for subdev");
    107             } else {
    108                 /* matched */
    109                 if (strncmp(name, devname, strlen(devname)) == 0) {
    110                     ALOGI("node found for device %s: /dev/v4l-subdev%d", devname, minor);
    111                     found = true;
    112                 }
    113             }
    114         }
    115     } while (found == false);
    116 
    117     if (found) {
    118         sprintf(filename, "/dev/v4l-subdev%d", minor);
    119         va_start(ap, oflag);
    120         fd = __subdev_open(filename, oflag, ap);
    121         va_end(ap);
    122 
    123         if (fd > 0)
    124             ALOGI("open subdev device %s", filename);
    125         else
    126             ALOGE("failed to open subdev device %s", filename);
    127     } else {
    128         ALOGE("no subdev device found");
    129     }
    130 
    131     return fd;
    132 }
    133 
    134 /**
    135  * @brief enum frame size on a pad.
    136  * @return 0 on success, or a negative error code on failure.
    137  */
    138 int exynos_subdev_enum_frame_size(int fd, struct v4l2_subdev_frame_size_enum *frame_size_enum)
    139 {
    140     int ret = -1;
    141 
    142     if (fd < 0) {
    143         ALOGE("%s: invalid fd: %d", __func__, fd);
    144         return ret;
    145     }
    146 
    147     if (!frame_size_enum) {
    148         ALOGE("%s: frame_size_enum is NULL", __func__);
    149         return ret;
    150     }
    151 
    152     ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, frame_size_enum);
    153     if (ret) {
    154         ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
    155         return ret;
    156     }
    157 
    158     return ret;
    159 }
    160 
    161 /**
    162  * @brief Retrieve the format on a pad.
    163  * @return 0 on success, or a negative error code on failure.
    164  */
    165 int exynos_subdev_g_fmt(int fd, struct v4l2_subdev_format *fmt)
    166 {
    167     int ret = -1;
    168 
    169     if (fd < 0) {
    170         ALOGE("%s: invalid fd: %d", __func__, fd);
    171         return ret;
    172     }
    173 
    174     if (!fmt) {
    175         ALOGE("%s: fmt is NULL", __func__);
    176         return ret;
    177     }
    178 
    179     ret = ioctl(fd, VIDIOC_SUBDEV_G_FMT, fmt);
    180     if (ret) {
    181         ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FMT");
    182         return ret;
    183     }
    184 
    185     return ret;
    186 }
    187 
    188 /**
    189  * @brief Set the format on a pad.
    190  * @return 0 on success, or a negative error code on failure.
    191  */
    192 int exynos_subdev_s_fmt(int fd, struct v4l2_subdev_format *fmt)
    193 {
    194     int ret = -1;
    195 
    196     if (fd < 0) {
    197         ALOGE("%s: invalid fd: %d", __func__, fd);
    198         return ret;
    199     }
    200 
    201     if (!fmt) {
    202         ALOGE("%s: fmt is NULL", __func__);
    203         return ret;
    204     }
    205 
    206     ret = ioctl(fd, VIDIOC_SUBDEV_S_FMT, fmt);
    207     if (ret) {
    208         ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FMT");
    209         return ret;
    210     }
    211 
    212     return ret;
    213 }
    214 
    215 /**
    216  * @brief Retrieve the crop rectangle on a pad.
    217  * @return 0 on success, or a negative error code on failure.
    218  */
    219 int exynos_subdev_g_crop(int fd, struct v4l2_subdev_crop *crop)
    220 {
    221     int ret = -1;
    222 
    223     if (fd < 0) {
    224         ALOGE("%s: invalid fd: %d", __func__, fd);
    225         return ret;
    226     }
    227 
    228     if (!crop) {
    229         ALOGE("%s: crop is NULL", __func__);
    230         return ret;
    231     }
    232 
    233     ret = ioctl(fd, VIDIOC_SUBDEV_G_CROP, crop);
    234     if (ret) {
    235         ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_CROP");
    236         return ret;
    237     }
    238 
    239     return ret;
    240 }
    241 
    242 /**
    243  * @brief Set the crop rectangle on a pad.
    244  * @return 0 on success, or a negative error code on failure.
    245  */
    246 int exynos_subdev_s_crop(int fd, struct v4l2_subdev_crop *crop)
    247 {
    248     int ret = -1;
    249 
    250     if (fd < 0) {
    251         ALOGE("%s: invalid fd: %d", __func__, fd);
    252         return ret;
    253     }
    254 
    255     if (!crop) {
    256         ALOGE("%s: crop is NULL", __func__);
    257         return ret;
    258     }
    259 
    260     ret = ioctl(fd, VIDIOC_SUBDEV_S_CROP, crop);
    261     if (ret) {
    262         ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_CROP");
    263         return ret;
    264     }
    265 
    266     return ret;
    267 }
    268 
    269 /**
    270  * @brief Retrieve the frame interval on a sub-device.
    271  * @return 0 on success, or a negative error code on failure.
    272  */
    273 int exynos_subdev_enum_frame_interval(int fd, struct v4l2_subdev_frame_interval_enum *frame_internval_enum)
    274 {
    275     int ret = -1;
    276 
    277     if (fd < 0) {
    278         ALOGE("%s: invalid fd: %d", __func__, fd);
    279         return ret;
    280     }
    281 
    282     if (!frame_internval_enum) {
    283         ALOGE("%s: frame_internval_enum is NULL", __func__);
    284         return ret;
    285     }
    286 
    287     ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, frame_internval_enum);
    288     if (ret) {
    289         ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
    290         return ret;
    291     }
    292 
    293     return ret;
    294 }
    295 
    296 /**
    297  * @brief Retrieve the frame interval on a sub-device.
    298  * @return 0 on success, or a negative error code on failure.
    299  */
    300 int exynos_subdev_g_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval)
    301 {
    302     int ret = -1;
    303 
    304     if (fd < 0) {
    305         ALOGE("%s: invalid fd: %d", __func__, fd);
    306         return ret;
    307     }
    308 
    309     if (!frame_internval) {
    310         ALOGE("%s: frame_internval is NULL", __func__);
    311         return ret;
    312     }
    313 
    314     ret = ioctl(fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, frame_internval);
    315     if (ret) {
    316         ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL");
    317         return ret;
    318     }
    319 
    320     return ret;
    321 }
    322 
    323 /**
    324  * @brief Set the frame interval on a sub-device.
    325  * @return 0 on success, or a negative error code on failure.
    326  */
    327 int exynos_subdev_s_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval)
    328 {
    329     int ret = -1;
    330 
    331     if (fd < 0) {
    332         ALOGE("%s: invalid fd: %d", __func__, fd);
    333         return ret;
    334     }
    335 
    336     if (!frame_internval) {
    337         ALOGE("%s: frame_internval is NULL", __func__);
    338         return ret;
    339     }
    340 
    341     ret = ioctl(fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, frame_internval);
    342     if (ret) {
    343         ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL");
    344         return ret;
    345     }
    346 
    347     return ret;
    348 }
    349 
    350 /**
    351  * @brief enum mbus code
    352  * @return 0 on success, or a negative error code on failure.
    353  */
    354 int exynos_subdev_enum_mbus_code(int fd, struct v4l2_subdev_mbus_code_enum *mbus_code_enum)
    355 {
    356     int ret = -1;
    357 
    358     if (fd < 0) {
    359         ALOGE("%s: invalid fd: %d", __func__, fd);
    360         return ret;
    361     }
    362 
    363     if (!mbus_code_enum) {
    364         ALOGE("%s: mbus_code_enum is NULL", __func__);
    365         return ret;
    366     }
    367 
    368     ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, mbus_code_enum);
    369     if (ret) {
    370         ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE");
    371         return ret;
    372     }
    373 
    374     return ret;
    375 }
    376