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