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