Commit | Line | Data |
---|---|---|
e5931c34 JC |
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_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)); | |
7642c64b | 91 | ALOGD("try node: %s, minor: %d", filename, minor); |
e5931c34 JC |
92 | /* open sysfs entry */ |
93 | sprintf(filename, "/sys/class/video4linux/v4l-subdev%d/name", minor); | |
94 | stream_fd = fopen(filename, "r"); | |
d970bdc0 | 95 | if (stream_fd == NULL) { |
7642c64b | 96 | ALOGE("failed to open sysfs entry for subdev"); |
e5931c34 JC |
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) { | |
7642c64b | 106 | ALOGE("failed to read sysfs entry for subdev"); |
e5931c34 JC |
107 | } else { |
108 | /* matched */ | |
109 | if (strncmp(name, devname, strlen(devname)) == 0) { | |
7642c64b | 110 | ALOGI("node found for device %s: /dev/v4l-subdev%d", devname, minor); |
e5931c34 JC |
111 | 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) | |
7642c64b | 124 | ALOGI("open subdev device %s", filename); |
e5931c34 | 125 | else |
7642c64b | 126 | ALOGE("failed to open subdev device %s", filename); |
e5931c34 | 127 | } else { |
7642c64b | 128 | ALOGE("no subdev device found"); |
e5931c34 JC |
129 | } |
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 | */ | |
138 | int 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) { | |
7642c64b | 143 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
144 | return ret; |
145 | } | |
146 | ||
147 | if (!frame_size_enum) { | |
7642c64b | 148 | ALOGE("%s: frame_size_enum is NULL", __func__); |
e5931c34 JC |
149 | return ret; |
150 | } | |
151 | ||
152 | ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, frame_size_enum); | |
153 | if (ret) { | |
7642c64b | 154 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE"); |
e5931c34 JC |
155 | 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 | */ | |
165 | int exynos_subdev_g_fmt(int fd, struct v4l2_subdev_format *fmt) | |
166 | { | |
167 | int ret = -1; | |
168 | ||
169 | if (fd < 0) { | |
7642c64b | 170 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
171 | return ret; |
172 | } | |
173 | ||
174 | if (!fmt) { | |
7642c64b | 175 | ALOGE("%s: fmt is NULL", __func__); |
e5931c34 JC |
176 | return ret; |
177 | } | |
178 | ||
179 | ret = ioctl(fd, VIDIOC_SUBDEV_G_FMT, fmt); | |
180 | if (ret) { | |
7642c64b | 181 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FMT"); |
e5931c34 JC |
182 | 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 | */ | |
192 | int exynos_subdev_s_fmt(int fd, struct v4l2_subdev_format *fmt) | |
193 | { | |
194 | int ret = -1; | |
195 | ||
196 | if (fd < 0) { | |
7642c64b | 197 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
198 | return ret; |
199 | } | |
200 | ||
201 | if (!fmt) { | |
7642c64b | 202 | ALOGE("%s: fmt is NULL", __func__); |
e5931c34 JC |
203 | return ret; |
204 | } | |
205 | ||
206 | ret = ioctl(fd, VIDIOC_SUBDEV_S_FMT, fmt); | |
207 | if (ret) { | |
7642c64b | 208 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FMT"); |
e5931c34 JC |
209 | 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 | */ | |
219 | int exynos_subdev_g_crop(int fd, struct v4l2_subdev_crop *crop) | |
220 | { | |
221 | int ret = -1; | |
222 | ||
223 | if (fd < 0) { | |
7642c64b | 224 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
225 | return ret; |
226 | } | |
227 | ||
228 | if (!crop) { | |
7642c64b | 229 | ALOGE("%s: crop is NULL", __func__); |
e5931c34 JC |
230 | return ret; |
231 | } | |
232 | ||
233 | ret = ioctl(fd, VIDIOC_SUBDEV_G_CROP, crop); | |
234 | if (ret) { | |
7642c64b | 235 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_CROP"); |
e5931c34 JC |
236 | 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 | */ | |
246 | int exynos_subdev_s_crop(int fd, struct v4l2_subdev_crop *crop) | |
247 | { | |
248 | int ret = -1; | |
249 | ||
250 | if (fd < 0) { | |
7642c64b | 251 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
252 | return ret; |
253 | } | |
254 | ||
255 | if (!crop) { | |
7642c64b | 256 | ALOGE("%s: crop is NULL", __func__); |
e5931c34 JC |
257 | return ret; |
258 | } | |
259 | ||
260 | ret = ioctl(fd, VIDIOC_SUBDEV_S_CROP, crop); | |
261 | if (ret) { | |
7642c64b | 262 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_CROP"); |
e5931c34 JC |
263 | 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 | */ | |
273 | int 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) { | |
7642c64b | 278 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
279 | return ret; |
280 | } | |
281 | ||
282 | if (!frame_internval_enum) { | |
7642c64b | 283 | ALOGE("%s: frame_internval_enum is NULL", __func__); |
e5931c34 JC |
284 | return ret; |
285 | } | |
286 | ||
287 | ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, frame_internval_enum); | |
288 | if (ret) { | |
7642c64b | 289 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL"); |
e5931c34 JC |
290 | 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 | */ | |
300 | int exynos_subdev_g_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval) | |
301 | { | |
302 | int ret = -1; | |
303 | ||
304 | if (fd < 0) { | |
7642c64b | 305 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
306 | return ret; |
307 | } | |
308 | ||
309 | if (!frame_internval) { | |
7642c64b | 310 | ALOGE("%s: frame_internval is NULL", __func__); |
e5931c34 JC |
311 | return ret; |
312 | } | |
313 | ||
314 | ret = ioctl(fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, frame_internval); | |
315 | if (ret) { | |
7642c64b | 316 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL"); |
e5931c34 JC |
317 | 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 | */ | |
327 | int exynos_subdev_s_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval) | |
328 | { | |
329 | int ret = -1; | |
330 | ||
331 | if (fd < 0) { | |
7642c64b | 332 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
333 | return ret; |
334 | } | |
335 | ||
336 | if (!frame_internval) { | |
7642c64b | 337 | ALOGE("%s: frame_internval is NULL", __func__); |
e5931c34 JC |
338 | return ret; |
339 | } | |
340 | ||
341 | ret = ioctl(fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, frame_internval); | |
342 | if (ret) { | |
7642c64b | 343 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL"); |
e5931c34 JC |
344 | 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 | */ | |
354 | int 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) { | |
7642c64b | 359 | ALOGE("%s: invalid fd: %d", __func__, fd); |
e5931c34 JC |
360 | return ret; |
361 | } | |
362 | ||
363 | if (!mbus_code_enum) { | |
7642c64b | 364 | ALOGE("%s: mbus_code_enum is NULL", __func__); |
e5931c34 JC |
365 | return ret; |
366 | } | |
367 | ||
368 | ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, mbus_code_enum); | |
369 | if (ret) { | |
7642c64b | 370 | ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE"); |
e5931c34 JC |
371 | return ret; |
372 | } | |
373 | ||
374 | return ret; | |
375 | } |