blob: 54b6e74a30d4007e6a1fc81ec8e0430711fdfd70 [file] [log] [blame]
Jiho Change5931c32012-03-24 05:59:38 +09001/*
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@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 <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
45static 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
58int 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
70int 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));
Dima Zavin7642c642012-04-02 23:45:46 -070091 ALOGD("try node: %s, minor: %d", filename, minor);
Jiho Change5931c32012-03-24 05:59:38 +090092 /* open sysfs entry */
93 sprintf(filename, "/sys/class/video4linux/v4l-subdev%d/name", minor);
94 stream_fd = fopen(filename, "r");
Jiho Changd970bdc2012-04-26 15:55:33 -070095 if (stream_fd == NULL) {
Dima Zavin7642c642012-04-02 23:45:46 -070096 ALOGE("failed to open sysfs entry for subdev");
Jiho Change5931c32012-03-24 05:59:38 +090097 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) {
Dima Zavin7642c642012-04-02 23:45:46 -0700106 ALOGE("failed to read sysfs entry for subdev");
Jiho Change5931c32012-03-24 05:59:38 +0900107 } else {
108 /* matched */
109 if (strncmp(name, devname, strlen(devname)) == 0) {
Dima Zavin7642c642012-04-02 23:45:46 -0700110 ALOGI("node found for device %s: /dev/v4l-subdev%d", devname, minor);
Jiho Change5931c32012-03-24 05:59:38 +0900111 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)
Dima Zavin7642c642012-04-02 23:45:46 -0700124 ALOGI("open subdev device %s", filename);
Jiho Change5931c32012-03-24 05:59:38 +0900125 else
Dima Zavin7642c642012-04-02 23:45:46 -0700126 ALOGE("failed to open subdev device %s", filename);
Jiho Change5931c32012-03-24 05:59:38 +0900127 } else {
Dima Zavin7642c642012-04-02 23:45:46 -0700128 ALOGE("no subdev device found");
Jiho Change5931c32012-03-24 05:59:38 +0900129 }
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 */
138int 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) {
Dima Zavin7642c642012-04-02 23:45:46 -0700143 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900144 return ret;
145 }
146
147 if (!frame_size_enum) {
Dima Zavin7642c642012-04-02 23:45:46 -0700148 ALOGE("%s: frame_size_enum is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900149 return ret;
150 }
151
152 ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, frame_size_enum);
153 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700154 ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
Jiho Change5931c32012-03-24 05:59:38 +0900155 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 */
165int exynos_subdev_g_fmt(int fd, struct v4l2_subdev_format *fmt)
166{
167 int ret = -1;
168
169 if (fd < 0) {
Dima Zavin7642c642012-04-02 23:45:46 -0700170 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900171 return ret;
172 }
173
174 if (!fmt) {
Dima Zavin7642c642012-04-02 23:45:46 -0700175 ALOGE("%s: fmt is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900176 return ret;
177 }
178
179 ret = ioctl(fd, VIDIOC_SUBDEV_G_FMT, fmt);
180 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700181 ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FMT");
Jiho Change5931c32012-03-24 05:59:38 +0900182 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 */
192int exynos_subdev_s_fmt(int fd, struct v4l2_subdev_format *fmt)
193{
194 int ret = -1;
195
196 if (fd < 0) {
Dima Zavin7642c642012-04-02 23:45:46 -0700197 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900198 return ret;
199 }
200
201 if (!fmt) {
Dima Zavin7642c642012-04-02 23:45:46 -0700202 ALOGE("%s: fmt is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900203 return ret;
204 }
205
206 ret = ioctl(fd, VIDIOC_SUBDEV_S_FMT, fmt);
207 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700208 ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FMT");
Jiho Change5931c32012-03-24 05:59:38 +0900209 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 */
219int exynos_subdev_g_crop(int fd, struct v4l2_subdev_crop *crop)
220{
221 int ret = -1;
222
223 if (fd < 0) {
Dima Zavin7642c642012-04-02 23:45:46 -0700224 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900225 return ret;
226 }
227
228 if (!crop) {
Dima Zavin7642c642012-04-02 23:45:46 -0700229 ALOGE("%s: crop is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900230 return ret;
231 }
232
233 ret = ioctl(fd, VIDIOC_SUBDEV_G_CROP, crop);
234 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700235 ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_CROP");
Jiho Change5931c32012-03-24 05:59:38 +0900236 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 */
246int exynos_subdev_s_crop(int fd, struct v4l2_subdev_crop *crop)
247{
248 int ret = -1;
249
250 if (fd < 0) {
Dima Zavin7642c642012-04-02 23:45:46 -0700251 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900252 return ret;
253 }
254
255 if (!crop) {
Dima Zavin7642c642012-04-02 23:45:46 -0700256 ALOGE("%s: crop is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900257 return ret;
258 }
259
260 ret = ioctl(fd, VIDIOC_SUBDEV_S_CROP, crop);
261 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700262 ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_CROP");
Jiho Change5931c32012-03-24 05:59:38 +0900263 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 */
273int 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) {
Dima Zavin7642c642012-04-02 23:45:46 -0700278 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900279 return ret;
280 }
281
282 if (!frame_internval_enum) {
Dima Zavin7642c642012-04-02 23:45:46 -0700283 ALOGE("%s: frame_internval_enum is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900284 return ret;
285 }
286
287 ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, frame_internval_enum);
288 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700289 ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
Jiho Change5931c32012-03-24 05:59:38 +0900290 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 */
300int exynos_subdev_g_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval)
301{
302 int ret = -1;
303
304 if (fd < 0) {
Dima Zavin7642c642012-04-02 23:45:46 -0700305 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900306 return ret;
307 }
308
309 if (!frame_internval) {
Dima Zavin7642c642012-04-02 23:45:46 -0700310 ALOGE("%s: frame_internval is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900311 return ret;
312 }
313
314 ret = ioctl(fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, frame_internval);
315 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700316 ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL");
Jiho Change5931c32012-03-24 05:59:38 +0900317 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 */
327int exynos_subdev_s_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval)
328{
329 int ret = -1;
330
331 if (fd < 0) {
Dima Zavin7642c642012-04-02 23:45:46 -0700332 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900333 return ret;
334 }
335
336 if (!frame_internval) {
Dima Zavin7642c642012-04-02 23:45:46 -0700337 ALOGE("%s: frame_internval is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900338 return ret;
339 }
340
341 ret = ioctl(fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, frame_internval);
342 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700343 ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL");
Jiho Change5931c32012-03-24 05:59:38 +0900344 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 */
354int 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) {
Dima Zavin7642c642012-04-02 23:45:46 -0700359 ALOGE("%s: invalid fd: %d", __func__, fd);
Jiho Change5931c32012-03-24 05:59:38 +0900360 return ret;
361 }
362
363 if (!mbus_code_enum) {
Dima Zavin7642c642012-04-02 23:45:46 -0700364 ALOGE("%s: mbus_code_enum is NULL", __func__);
Jiho Change5931c32012-03-24 05:59:38 +0900365 return ret;
366 }
367
368 ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, mbus_code_enum);
369 if (ret) {
Dima Zavin7642c642012-04-02 23:45:46 -0700370 ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE");
Jiho Change5931c32012-03-24 05:59:38 +0900371 return ret;
372 }
373
374 return ret;
375}