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_v4l2.c
19 * \brief     source file for libv4l2
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 <errno.h>
32#include <stdarg.h>
33#include <fcntl.h>
34#include <string.h>
35#include <sys/types.h>
36#include <sys/ioctl.h>
37#include <sys/stat.h>
38
39#include "exynos_v4l2.h"
40
41//#define LOG_NDEBUG 0
42#define LOG_TAG "libexynosv4l2"
43#include <utils/Log.h>
44#include "Exynos_log.h"
45
46#define VIDEODEV_MINOR_MAX 63
47
48//#define EXYNOS_V4L2_TRACE 0
49#ifdef EXYNOS_V4L2_TRACE
50#define Exynos_v4l2_In() Exynos_Log(EXYNOS_DEV_LOG_DEBUG, LOG_TAG, "%s In , Line: %d", __FUNCTION__, __LINE__)
51#define Exynos_v4l2_Out() Exynos_Log(EXYNOS_DEV_LOG_DEBUG, LOG_TAG, "%s Out , Line: %d", __FUNCTION__, __LINE__)
52#else
53#define Exynos_v4l2_In() ((void *)0)
54#define Exynos_v4l2_Out() ((void *)0)
55#endif
56
57static bool __v4l2_check_buf_type(enum v4l2_buf_type type)
58{
59    bool supported;
60
61    switch (type) {
62    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
63    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
64    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
65    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
66    case V4L2_BUF_TYPE_VIDEO_OVERLAY:
67        supported = true;
68        break;
69
70    default:
71        supported = (type >= V4L2_BUF_TYPE_PRIVATE) ? true : false;
72        break;
73    }
74
75    return supported;
76}
77
78static int __v4l2_open(const char *filename, int oflag, va_list ap)
79{
80    mode_t mode = 0;
81    int fd;
82
83    if (oflag & O_CREAT)
84        mode = va_arg(ap, int);
85
86    fd = open(filename, oflag, mode);
87
88    return fd;
89}
90
91int exynos_v4l2_open(const char *filename, int oflag, ...)
92{
93    va_list ap;
94    int fd;
95
96    Exynos_v4l2_In();
97
98    va_start(ap, oflag);
99    fd = __v4l2_open(filename, oflag, ap);
100    va_end(ap);
101
102    Exynos_v4l2_Out();
103
104    return fd;
105}
106
107int exynos_v4l2_open_devname(const char *devname, int oflag, ...)
108{
109    bool found = false;
110    int fd = -1;
111    struct stat s;
112    va_list ap;
113    FILE *stream_fd;
114    char filename[64], name[64];
115    int minor, size, i = 0;
116
117    Exynos_v4l2_In();
118
119    do {
120        if (i > VIDEODEV_MINOR_MAX)
121            break;
122
123        /* video device node */
124        sprintf(filename, "/dev/video%d", i++);
125
126        /* if the node is video device */
127        if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) &&
128                ((int)((unsigned short)(s.st_rdev) >> 8) == 81)) {
129            minor = (int)((unsigned short)(s.st_rdev & 0x3f));
130            ALOGD("try node: %s, minor: %d", filename, minor);
131            /* open sysfs entry */
132            sprintf(filename, "/sys/class/video4linux/video%d/name", minor);
133            stream_fd = fopen(filename, "r");
134            if (stream_fd == NULL) {
135                ALOGE("failed to open sysfs entry for videodev");
136                continue;   /* try next */
137            }
138
139            /* read sysfs entry for device name */
140            size = (int)fgets(name, sizeof(name), stream_fd);
141            fclose(stream_fd);
142
143            /* check read size */
144            if (size == 0) {
145                ALOGE("failed to read sysfs entry for videodev");
146            } else {
147                /* matched */
148                if (strncmp(name, devname, strlen(devname)) == 0) {
149                    ALOGI("node found for device %s: /dev/video%d", devname, minor);
150                    found = true;
151                }
152            }
153        }
154    } while (found == false);
155
156    if (found) {
157        sprintf(filename, "/dev/video%d", minor);
158        va_start(ap, oflag);
159        fd = __v4l2_open(filename, oflag, ap);
160        va_end(ap);
161
162        if (fd > 0)
163            ALOGI("open video device %s", filename);
164        else
165            ALOGE("failed to open video device %s", filename);
166    } else {
167        ALOGE("no video device found");
168    }
169
170    Exynos_v4l2_Out();
171
172    return fd;
173}
174
175int exynos_v4l2_close(int fd)
176{
177    int ret = -1;
178
179    Exynos_v4l2_In();
180
181    if (fd < 0)
182        ALOGE("%s: invalid fd: %d", __func__, fd);
183    else
184        ret = close(fd);
185
186    Exynos_v4l2_Out();
187
188    return ret;
189}
190
191bool exynos_v4l2_enuminput(int fd, int index, char *input_name_buf)
192{
193    int ret = -1;
194    struct v4l2_input input;
195
196    Exynos_v4l2_In();
197
198    if (fd < 0) {
199        ALOGE("%s: invalid fd: %d", __func__, fd);
200        return NULL;
201    }
202
203    input.index = index;
204    ret = ioctl(fd, VIDIOC_ENUMINPUT, &input);
205    if (ret) {
206        ALOGE("%s: no matching index founds", __func__);
207        return false;
208    }
209
210    ALOGI("Name of input channel[%d] is %s", input.index, input.name);
211
212    strcpy(input_name_buf, (const char *)input.name);
213
214    Exynos_v4l2_Out();
215
216    return true;
217}
218
219int exynos_v4l2_s_input(int fd, int index)
220{
221    int ret = -1;
222    struct v4l2_input input;
223
224    Exynos_v4l2_In();
225
226    if (fd < 0) {
227        ALOGE("%s: invalid fd: %d", __func__, fd);
228        return ret;
229    }
230
231    input.index = index;
232
233    ret = ioctl(fd, VIDIOC_S_INPUT, &input);
234    if (ret){
235        ALOGE("failed to ioctl: VIDIOC_S_INPUT (%d - %s)", errno, strerror(errno));
236        return ret;
237    }
238
239    Exynos_v4l2_Out();
240
241    return ret;
242}
243
244bool exynos_v4l2_querycap(int fd, unsigned int need_caps)
245{
246    struct v4l2_capability cap;
247    int ret;
248
249    Exynos_v4l2_In();
250
251    if (fd < 0) {
252        ALOGE("%s: invalid fd: %d", __func__, fd);
253        return false;
254    }
255
256    if (!(need_caps & V4L2_CAP_VIDEO_CAPTURE) &&
257            !(need_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) &&
258            !(need_caps & V4L2_CAP_VIDEO_OUTPUT) &&
259            !(need_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE) &&
260            !(need_caps & V4L2_CAP_VIDEO_OVERLAY)) {
261        ALOGE("%s: unsupported capabilities", __func__);
262        return false;
263    }
264
265    memset(&cap, 0, sizeof(cap));
266
267    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
268    if (ret) {
269        ALOGE("failed to ioctl: VIDIOC_QUERYCAP (%d - %s)", errno, strerror(errno));
270        return false;
271    }
272
273    if ((need_caps & cap.capabilities) != need_caps) {
274        ALOGE("%s: unsupported capabilities", __func__);
275        return false;
276    }
277
278    Exynos_v4l2_Out();
279
280    return true;
281}
282
283bool exynos_v4l2_enum_fmt(int fd, enum v4l2_buf_type type, unsigned int fmt)
284{
285    struct v4l2_fmtdesc fmtdesc;
286    int found = 0;
287
288    Exynos_v4l2_In();
289
290    fmtdesc.type = type;
291    fmtdesc.index = 0;
292
293    while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
294        if (fmtdesc.pixelformat == fmt) {
295            ALOGE("Passed fmt = %#x found pixel format[%d]: %s", fmt, fmtdesc.index, fmtdesc.description);
296            found = 1;
297            break;
298        }
299
300        fmtdesc.index++;
301    }
302
303    if (!found) {
304        ALOGE("%s: unsupported pixel format", __func__);
305        return false;
306    }
307
308    Exynos_v4l2_Out();
309
310    return true;
311}
312
313int exynos_v4l2_g_fmt(int fd, struct v4l2_format *fmt)
314{
315    int ret = -1;
316
317    Exynos_v4l2_In();
318
319    if (fd < 0) {
320        ALOGE("%s: invalid fd: %d", __func__, fd);
321        return ret;
322    }
323
324    if (!fmt) {
325        ALOGE("%s: fmt is NULL", __func__);
326        return ret;
327    }
328
329    if (__v4l2_check_buf_type(fmt->type) == false) {
330        ALOGE("%s: unsupported buffer type", __func__);
331        return ret;
332    }
333
334    ret = ioctl(fd, VIDIOC_G_FMT, fmt);
335    if (ret) {
336        ALOGE("failed to ioctl: VIDIOC_G_FMT (%d - %s)", errno, strerror(errno));
337        return ret;
338    }
339
340    Exynos_v4l2_Out();
341
342    return ret;
343}
344
345static int __v4l2_s_fmt(int fd, unsigned int request, struct v4l2_format *fmt)
346{
347    int ret = -1;
348
349    Exynos_v4l2_In();
350
351    if (fd < 0) {
352        ALOGE("%s: invalid fd: %d", __func__, fd);
353        return ret;
354    }
355
356    if (!fmt) {
357        ALOGE("%s: fmt is NULL", __func__);
358        return ret;
359    }
360
361    if (__v4l2_check_buf_type(fmt->type) == false) {
362        ALOGE("%s: unsupported buffer type", __func__);
363        return ret;
364    } else {
365        ret = ioctl(fd, request, fmt);
366        if (ret) {
367            if (request == VIDIOC_TRY_FMT)
368                ALOGE("failed to ioctl: VIDIOC_TRY_FMT (%d - %s)", errno, strerror(errno));
369            else
370                ALOGE("failed to ioctl: VIDIOC_S_FMT (%d - %s)", errno, strerror(errno));
371
372            return ret;
373        }
374    }
375
376    Exynos_v4l2_Out();
377
378    return ret;
379}
380
381int exynos_v4l2_try_fmt(int fd, struct v4l2_format *fmt)
382{
383    return __v4l2_s_fmt(fd, VIDIOC_TRY_FMT, fmt);
384}
385
386int exynos_v4l2_s_fmt(int fd, struct v4l2_format *fmt)
387{
388    return __v4l2_s_fmt(fd, VIDIOC_S_FMT, fmt);
389}
390
391int exynos_v4l2_reqbufs(int fd, struct v4l2_requestbuffers *req)
392{
393    int ret = -1;
394    unsigned int count;
395
396    Exynos_v4l2_In();
397
398    if (fd < 0) {
399        ALOGE("%s: invalid fd: %d", __func__, fd);
400        return ret;
401    }
402
403    if (!req) {
404        ALOGE("%s: req is NULL", __func__);
405        return ret;
406    }
407
408    if ((req->memory != V4L2_MEMORY_MMAP) &&
409	(req->memory != V4L2_MEMORY_USERPTR) &&
410	(req->memory != V4L2_MEMORY_DMABUF)) {
411        ALOGE("%s: unsupported memory type", __func__);
412        return ret;
413    }
414
415    if (__v4l2_check_buf_type(req->type) == false) {
416        ALOGE("%s: unsupported buffer type", __func__);
417        return ret;
418    }
419
420    count = req->count;
421
422    ret = ioctl(fd, VIDIOC_REQBUFS, req);
423    if (ret) {
424        ALOGE("failed to ioctl: VIDIOC_REQBUFS (%d - %s)", ret, strerror(errno));
425        return ret;
426    }
427
428    if (count != req->count) {
429        ALOGW("number of buffers had been changed: %d => %d", count, req->count);
430    }
431
432    Exynos_v4l2_Out();
433
434    return ret;
435}
436
437int exynos_v4l2_querybuf(int fd, struct v4l2_buffer *buf)
438{
439    int ret = -1;
440
441    Exynos_v4l2_In();
442
443    if (fd < 0) {
444        ALOGE("%s: invalid fd: %d", __func__, fd);
445        return ret;
446    }
447
448    if (!buf) {
449        ALOGE("%s: buf is NULL", __func__);
450        return ret;
451    }
452
453    if ((buf->memory != V4L2_MEMORY_MMAP) &&
454	(buf->memory != V4L2_MEMORY_DMABUF)) {
455        ALOGE("%s: unsupported memory type", __func__);
456        return ret;
457    }
458
459    if (__v4l2_check_buf_type(buf->type) == false) {
460        ALOGE("%s: unsupported buffer type", __func__);
461        return ret;
462    }
463
464    ret = ioctl(fd, VIDIOC_QUERYBUF, buf);
465    if (ret) {
466        ALOGE("failed to ioctl: VIDIOC_QUERYBUF (%d - %s)", errno, strerror(errno));
467        return ret;
468    }
469
470    Exynos_v4l2_Out();
471
472    return ret;
473}
474
475int exynos_v4l2_qbuf(int fd, struct v4l2_buffer *buf)
476{
477    int ret = -1;
478
479    Exynos_v4l2_In();
480
481    if (fd < 0) {
482        ALOGE("%s: invalid fd: %d", __func__, fd);
483        return ret;
484    }
485
486    if (!buf) {
487        ALOGE("%s: buf is NULL", __func__);
488        return ret;
489    }
490
491    if ((buf->memory != V4L2_MEMORY_MMAP) &&
492	(buf->memory != V4L2_MEMORY_USERPTR) &&
493	(buf->memory != V4L2_MEMORY_DMABUF)) {
494        ALOGE("%s: unsupported memory type", __func__);
495        return ret;
496    }
497
498    if (__v4l2_check_buf_type(buf->type) == false) {
499        ALOGE("%s: unsupported buffer type", __func__);
500        return ret;
501    }
502
503    ret = ioctl(fd, VIDIOC_QBUF, buf);
504    if (ret) {
505        ALOGE("failed to ioctl: VIDIOC_QBUF (%d - %s)", errno, strerror(errno));
506        return ret;
507    }
508
509    Exynos_v4l2_Out();
510
511    return ret;
512}
513
514int exynos_v4l2_dqbuf(int fd, struct v4l2_buffer *buf)
515{
516    int ret = -1;
517
518    Exynos_v4l2_In();
519
520    if (fd < 0) {
521        ALOGE("%s: invalid fd: %d", __func__, fd);
522        return ret;
523    }
524
525    if (!buf) {
526        ALOGE("%s: buf is NULL", __func__);
527        return ret;
528    }
529
530    if ((buf->memory != V4L2_MEMORY_MMAP) &&
531	(buf->memory != V4L2_MEMORY_USERPTR) &&
532	(buf->memory != V4L2_MEMORY_DMABUF)) {
533        ALOGE("%s: unsupported memory type", __func__);
534        return ret;
535    }
536
537    if (__v4l2_check_buf_type(buf->type) == false) {
538        ALOGE("%s: unsupported buffer type", __func__);
539        return ret;
540    }
541
542    ret = ioctl(fd, VIDIOC_DQBUF, buf);
543    if (ret) {
544        ALOGE("failed to ioctl: VIDIOC_DQBUF (%d - %s)", errno, strerror(errno));
545        return ret;
546    }
547
548    Exynos_v4l2_Out();
549
550    return ret;
551}
552
553int exynos_v4l2_streamon(int fd, enum v4l2_buf_type type)
554{
555    int ret = -1;
556
557    Exynos_v4l2_In();
558
559    if (fd < 0) {
560        ALOGE("%s: invalid fd: %d", __func__, fd);
561        return ret;
562    }
563
564    if (__v4l2_check_buf_type(type) == false) {
565        ALOGE("%s: unsupported buffer type", __func__);
566        return ret;
567    }
568
569    ret = ioctl(fd, VIDIOC_STREAMON, &type);
570    if (ret) {
571        ALOGE("failed to ioctl: VIDIOC_STREAMON (%d - %s)", errno, strerror(errno));
572        return ret;
573    }
574
575    Exynos_v4l2_Out();
576
577    return ret;
578}
579
580int exynos_v4l2_streamoff(int fd, enum v4l2_buf_type type)
581{
582    int ret = -1;
583
584    Exynos_v4l2_In();
585
586    if (fd < 0) {
587        ALOGE("%s: invalid fd: %d", __func__, fd);
588        return ret;
589    }
590
591    if (__v4l2_check_buf_type(type) == false) {
592        ALOGE("%s: unsupported buffer type", __func__);
593        return ret;
594    }
595
596    ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
597    if (ret) {
598        ALOGE("failed to ioctl: VIDIOC_STREAMOFF (%d - %s)", errno, strerror(errno));
599        return ret;
600    }
601
602    Exynos_v4l2_Out();
603
604    return ret;
605}
606
607int exynos_v4l2_cropcap(int fd, struct v4l2_cropcap *crop)
608{
609    int ret = -1;
610
611    Exynos_v4l2_In();
612
613    if (fd < 0) {
614        ALOGE("%s: invalid fd: %d", __func__, fd);
615        return ret;
616    }
617
618    if (!crop) {
619        ALOGE("%s: crop is NULL", __func__);
620        return ret;
621    }
622
623    if (__v4l2_check_buf_type(crop->type) == false) {
624        ALOGE("%s: unsupported buffer type", __func__);
625        return ret;
626    }
627
628    ret = ioctl(fd, VIDIOC_CROPCAP, crop);
629    if (ret) {
630        ALOGE("failed to ioctl: VIDIOC_CROPCAP (%d - %s)", errno, strerror(errno));
631        return ret;
632    }
633
634    Exynos_v4l2_Out();
635
636    return ret;
637}
638
639int exynos_v4l2_g_crop(int fd, struct v4l2_crop *crop)
640{
641    int ret = -1;
642
643    Exynos_v4l2_In();
644
645    if (fd < 0) {
646        ALOGE("%s: invalid fd: %d", __func__, fd);
647        return ret;
648    }
649
650    if (!crop) {
651        ALOGE("%s: crop is NULL", __func__);
652        return ret;
653    }
654
655    if (__v4l2_check_buf_type(crop->type) == false) {
656        ALOGE("%s: unsupported buffer type", __func__);
657        return ret;
658    }
659
660    ret = ioctl(fd, VIDIOC_G_CROP, crop);
661    if (ret) {
662        ALOGE("failed to ioctl: VIDIOC_G_CROP (%d - %s)", errno, strerror(errno));
663        return ret;
664    }
665
666    Exynos_v4l2_Out();
667
668    return ret;
669}
670
671int exynos_v4l2_s_crop(int fd, struct v4l2_crop *crop)
672{
673    int ret = -1;
674
675    Exynos_v4l2_In();
676
677    if (fd < 0) {
678        ALOGE("%s: invalid fd: %d", __func__, fd);
679        return ret;
680    }
681
682    if (!crop) {
683        ALOGE("%s: crop is NULL", __func__);
684        return ret;
685    }
686
687    if (__v4l2_check_buf_type(crop->type) == false) {
688        ALOGE("%s: unsupported buffer type", __func__);
689        return ret;
690    }
691
692    ret = ioctl(fd, VIDIOC_S_CROP, crop);
693    if (ret) {
694        ALOGE("failed to ioctl: VIDIOC_S_CROP (%d - %s)", errno, strerror(errno));
695        return ret;
696    }
697
698    Exynos_v4l2_Out();
699
700    return ret;
701}
702
703int exynos_v4l2_g_ctrl(int fd, unsigned int id, int *value)
704{
705    int ret = -1;
706    struct v4l2_control ctrl;
707
708    Exynos_v4l2_In();
709
710    ctrl.id = id;
711
712    if (fd < 0) {
713        ALOGE("%s: invalid fd: %d", __func__, fd);
714        return ret;
715    }
716
717    ret = ioctl(fd, VIDIOC_G_CTRL, &ctrl);
718    if (ret) {
719        ALOGE("failed to ioctl: VIDIOC_G_CTRL (%d - %s)", errno, strerror(errno));
720        return ret;
721    }
722
723    *value = ctrl.value;
724
725    Exynos_v4l2_Out();
726
727    return ret;
728}
729
730int exynos_v4l2_s_ctrl(int fd, unsigned int id, int value)
731{
732    int ret = -1;
733    struct v4l2_control ctrl;
734
735    Exynos_v4l2_In();
736
737    ctrl.id = id;
738    ctrl.value = value;
739
740    if (fd < 0) {
741        ALOGE("%s: invalid fd: %d", __func__, fd);
742        return ret;
743    }
744
745    ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
746    if (ret) {
747        ALOGE("failed to ioctl: VIDIOC_S_CTRL (%d)", errno);
748        return ret;
749    }
750
751    Exynos_v4l2_Out();
752
753    return ret;
754}
755
756int exynos_v4l2_g_parm(int fd, struct v4l2_streamparm *streamparm)
757{
758    int ret = -1;
759
760    Exynos_v4l2_In();
761
762    if (fd < 0) {
763        ALOGE("%s: invalid fd: %d", __func__, fd);
764        return ret;
765    }
766
767    if (__v4l2_check_buf_type(streamparm->type) == false) {
768        ALOGE("%s: unsupported buffer type", __func__);
769        return ret;
770    }
771
772    ret = ioctl(fd, VIDIOC_G_PARM, streamparm);
773    if (ret) {
774        ALOGE("failed to ioctl: VIDIOC_G_PARM (%d - %s)", errno, strerror(errno));
775        return ret;
776    }
777
778    Exynos_v4l2_Out();
779
780    return ret;
781}
782
783int exynos_v4l2_s_parm(int fd, struct v4l2_streamparm *streamparm)
784{
785    int ret = -1;
786
787    Exynos_v4l2_In();
788
789    if (fd < 0) {
790        ALOGE("%s: invalid fd: %d", __func__, fd);
791        return ret;
792    }
793
794    if (__v4l2_check_buf_type(streamparm->type) == false) {
795        ALOGE("%s: unsupported buffer type", __func__);
796        return ret;
797    }
798
799    ret = ioctl(fd, VIDIOC_S_PARM, streamparm);
800    if (ret) {
801        ALOGE("failed to ioctl: VIDIOC_S_PARM (%d - %s)", errno, strerror(errno));
802        return ret;
803    }
804
805    Exynos_v4l2_Out();
806
807    return ret;
808}
809
810int exynos_v4l2_g_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl)
811{
812    int ret = -1;
813
814    Exynos_v4l2_In();
815
816    if (fd < 0) {
817        ALOGE("%s: invalid fd: %d", __func__, fd);
818        return ret;
819    }
820
821    if (ctrl == NULL) {
822        ALOGE("%s: ctrl is NULL", __func__);
823        return ret;
824    }
825
826    ret = ioctl(fd, VIDIOC_G_EXT_CTRLS, ctrl);
827    if (ret)
828        ALOGE("failed to ioctl: VIDIOC_G_EXT_CTRLS (%d - %s)", errno, strerror(errno));
829
830    Exynos_v4l2_Out();
831
832    return ret;
833}
834
835int exynos_v4l2_s_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl)
836{
837    int ret = -1;
838
839    Exynos_v4l2_In();
840
841    if (fd < 0) {
842        ALOGE("%s: invalid fd: %d", __func__, fd);
843        return ret;
844    }
845
846    if (ctrl == NULL) {
847        ALOGE("%s: ctrl is NULL", __func__);
848        return ret;
849    }
850
851    ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, ctrl);
852    if (ret)
853        ALOGE("failed to ioctl: VIDIOC_S_EXT_CTRLS (%d - %s)", errno, strerror(errno));
854
855    Exynos_v4l2_Out();
856
857    return ret;
858}
859