exynos: Update from ODROID-XU 04212014 BSP
[GitHub/LineageOS/android_hardware_samsung_slsi_exynos.git] / libv4l2 / exynos_subdev.c
CommitLineData
1eb637c1
YK
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@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
14ec76c6
HC
70int exynos_subdev_get_node_num(const char *devname, int oflag, ...)
71{
72 bool found = false;
73 int ret = -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 */
380f6359 85 snprintf(filename, sizeof(filename), "/dev/v4l-subdev%d", i++);
14ec76c6
HC
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 */
380f6359 93 snprintf(filename, sizeof(filename), "/sys/class/video4linux/v4l-subdev%d/name", minor);
772716f5
EC
94 if (S_ISLNK(s.st_mode)) {
95 ALOGE("symbolic link detected");
96 return -1;
97 }
14ec76c6
HC
98 stream_fd = fopen(filename, "r");
99 if (stream_fd == NULL) {
100 ALOGE("failed to open sysfs entry for subdev");
101 continue; /* try next */
102 }
103
104 /* read sysfs entry for device name */
105 size = (int)fgets(name, sizeof(name), stream_fd);
106 fclose(stream_fd);
107
108 /* check read size */
109 if (size == 0) {
110 ALOGE("failed to read sysfs entry for subdev");
111 } else {
112 /* matched */
113 if (strncmp(name, devname, strlen(devname)) == 0) {
114 ALOGI("node found for device %s: /dev/v4l-subdev%d", devname, minor);
115 found = true;
116 }
117 }
118 }
119 } while (found == false);
120
121 if (found)
122 ret = minor;
123 else
124 ALOGE("no subdev device found");
125
126 return ret;
127}
128
1eb637c1
YK
129int exynos_subdev_open_devname(const char *devname, int oflag, ...)
130{
131 bool found = false;
132 int fd = -1;
133 struct stat s;
134 va_list ap;
135 FILE *stream_fd;
136 char filename[64], name[64];
137 int minor, size, i = 0;
138
139 do {
140 if (i > (SUBDEV_MINOR_MAX - 128))
141 break;
142
143 /* video device node */
380f6359 144 snprintf(filename, sizeof(filename), "/dev/v4l-subdev%d", i++);
1eb637c1
YK
145
146 /* if the node is video device */
147 if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) &&
148 ((int)((unsigned short)(s.st_rdev) >> 8) == 81)) {
149 minor = (int)((unsigned short)(s.st_rdev & 0x3f));
150 ALOGD("try node: %s, minor: %d", filename, minor);
151 /* open sysfs entry */
380f6359 152 snprintf(filename, sizeof(filename), "/sys/class/video4linux/v4l-subdev%d/name", minor);
772716f5
EC
153 if (S_ISLNK(s.st_mode)) {
154 ALOGE("symbolic link detected");
155 return -1;
156 }
1eb637c1
YK
157 stream_fd = fopen(filename, "r");
158 if (stream_fd == NULL) {
159 ALOGE("failed to open sysfs entry for subdev");
160 continue; /* try next */
161 }
162
163 /* read sysfs entry for device name */
164 size = (int)fgets(name, sizeof(name), stream_fd);
165 fclose(stream_fd);
166
167 /* check read size */
168 if (size == 0) {
169 ALOGE("failed to read sysfs entry for subdev");
170 } else {
171 /* matched */
172 if (strncmp(name, devname, strlen(devname)) == 0) {
173 ALOGI("node found for device %s: /dev/v4l-subdev%d", devname, minor);
174 found = true;
175 }
176 }
177 }
178 } while (found == false);
179
180 if (found) {
772716f5 181 snprintf(filename, sizeof(filename), "/dev/v4l-subdev%d", minor);
1eb637c1
YK
182 va_start(ap, oflag);
183 fd = __subdev_open(filename, oflag, ap);
184 va_end(ap);
185
186 if (fd > 0)
187 ALOGI("open subdev device %s", filename);
188 else
189 ALOGE("failed to open subdev device %s", filename);
190 } else {
191 ALOGE("no subdev device found");
192 }
193
194 return fd;
195}
196
19b03c8f
HC
197int exynos_subdev_close(int fd)
198{
199 int ret = -1;
200
19b03c8f
HC
201 if (fd < 0)
202 ALOGE("%s: invalid fd: %d", __func__, fd);
203 else
204 ret = close(fd);
205
206 return ret;
207}
208
1eb637c1
YK
209/**
210 * @brief enum frame size on a pad.
211 * @return 0 on success, or a negative error code on failure.
212 */
213int exynos_subdev_enum_frame_size(int fd, struct v4l2_subdev_frame_size_enum *frame_size_enum)
214{
215 int ret = -1;
216
217 if (fd < 0) {
218 ALOGE("%s: invalid fd: %d", __func__, fd);
219 return ret;
220 }
221
222 if (!frame_size_enum) {
223 ALOGE("%s: frame_size_enum is NULL", __func__);
224 return ret;
225 }
226
227 ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, frame_size_enum);
228 if (ret) {
229 ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
230 return ret;
231 }
232
233 return ret;
234}
235
236/**
237 * @brief Retrieve the format on a pad.
238 * @return 0 on success, or a negative error code on failure.
239 */
240int exynos_subdev_g_fmt(int fd, struct v4l2_subdev_format *fmt)
241{
242 int ret = -1;
243
244 if (fd < 0) {
245 ALOGE("%s: invalid fd: %d", __func__, fd);
246 return ret;
247 }
248
249 if (!fmt) {
250 ALOGE("%s: fmt is NULL", __func__);
251 return ret;
252 }
253
254 ret = ioctl(fd, VIDIOC_SUBDEV_G_FMT, fmt);
255 if (ret) {
256 ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FMT");
257 return ret;
258 }
259
260 return ret;
261}
262
263/**
264 * @brief Set the format on a pad.
265 * @return 0 on success, or a negative error code on failure.
266 */
267int exynos_subdev_s_fmt(int fd, struct v4l2_subdev_format *fmt)
268{
269 int ret = -1;
270
271 if (fd < 0) {
272 ALOGE("%s: invalid fd: %d", __func__, fd);
273 return ret;
274 }
275
276 if (!fmt) {
277 ALOGE("%s: fmt is NULL", __func__);
278 return ret;
279 }
280
281 ret = ioctl(fd, VIDIOC_SUBDEV_S_FMT, fmt);
282 if (ret) {
283 ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FMT");
284 return ret;
285 }
286
287 return ret;
288}
289
290/**
291 * @brief Retrieve the crop rectangle on a pad.
292 * @return 0 on success, or a negative error code on failure.
293 */
294int exynos_subdev_g_crop(int fd, struct v4l2_subdev_crop *crop)
295{
296 int ret = -1;
297
298 if (fd < 0) {
299 ALOGE("%s: invalid fd: %d", __func__, fd);
300 return ret;
301 }
302
303 if (!crop) {
304 ALOGE("%s: crop is NULL", __func__);
305 return ret;
306 }
307
308 ret = ioctl(fd, VIDIOC_SUBDEV_G_CROP, crop);
309 if (ret) {
310 ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_CROP");
311 return ret;
312 }
313
314 return ret;
315}
316
317/**
318 * @brief Set the crop rectangle on a pad.
319 * @return 0 on success, or a negative error code on failure.
320 */
321int exynos_subdev_s_crop(int fd, struct v4l2_subdev_crop *crop)
322{
323 int ret = -1;
324
325 if (fd < 0) {
326 ALOGE("%s: invalid fd: %d", __func__, fd);
327 return ret;
328 }
329
330 if (!crop) {
331 ALOGE("%s: crop is NULL", __func__);
332 return ret;
333 }
334
335 ret = ioctl(fd, VIDIOC_SUBDEV_S_CROP, crop);
336 if (ret) {
337 ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_CROP");
338 return ret;
339 }
340
341 return ret;
342}
343
344/**
345 * @brief Retrieve the frame interval on a sub-device.
346 * @return 0 on success, or a negative error code on failure.
347 */
348int exynos_subdev_enum_frame_interval(int fd, struct v4l2_subdev_frame_interval_enum *frame_internval_enum)
349{
350 int ret = -1;
351
352 if (fd < 0) {
353 ALOGE("%s: invalid fd: %d", __func__, fd);
354 return ret;
355 }
356
357 if (!frame_internval_enum) {
358 ALOGE("%s: frame_internval_enum is NULL", __func__);
359 return ret;
360 }
361
362 ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, frame_internval_enum);
363 if (ret) {
364 ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
365 return ret;
366 }
367
368 return ret;
369}
370
371/**
372 * @brief Retrieve the frame interval on a sub-device.
373 * @return 0 on success, or a negative error code on failure.
374 */
375int exynos_subdev_g_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval)
376{
377 int ret = -1;
378
379 if (fd < 0) {
380 ALOGE("%s: invalid fd: %d", __func__, fd);
381 return ret;
382 }
383
384 if (!frame_internval) {
385 ALOGE("%s: frame_internval is NULL", __func__);
386 return ret;
387 }
388
389 ret = ioctl(fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, frame_internval);
390 if (ret) {
391 ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL");
392 return ret;
393 }
394
395 return ret;
396}
397
398/**
399 * @brief Set the frame interval on a sub-device.
400 * @return 0 on success, or a negative error code on failure.
401 */
402int exynos_subdev_s_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval)
403{
404 int ret = -1;
405
406 if (fd < 0) {
407 ALOGE("%s: invalid fd: %d", __func__, fd);
408 return ret;
409 }
410
411 if (!frame_internval) {
412 ALOGE("%s: frame_internval is NULL", __func__);
413 return ret;
414 }
415
416 ret = ioctl(fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, frame_internval);
417 if (ret) {
418 ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL");
419 return ret;
420 }
421
422 return ret;
423}
424
425/**
426 * @brief enum mbus code
427 * @return 0 on success, or a negative error code on failure.
428 */
429int exynos_subdev_enum_mbus_code(int fd, struct v4l2_subdev_mbus_code_enum *mbus_code_enum)
430{
431 int ret = -1;
432
433 if (fd < 0) {
434 ALOGE("%s: invalid fd: %d", __func__, fd);
435 return ret;
436 }
437
438 if (!mbus_code_enum) {
439 ALOGE("%s: mbus_code_enum is NULL", __func__);
440 return ret;
441 }
442
443 ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, mbus_code_enum);
444 if (ret) {
445 ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE");
446 return ret;
447 }
448
449 return ret;
450}