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