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_mc.c
19 * \brief source file for libexynosv4l2
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 <stdlib.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <sys/stat.h>
40 #include <media.h>
41 #include <linux/kdev_t.h>
42 #include <linux/types.h>
43 #include <unistd.h>
44
45 #include "exynos_v4l2.h"
46
47 //#define LOG_NDEBUG 0
48 #define LOG_TAG "libexynosv4l2-mc"
49 #include <log/log.h>
50
__media_entity_type(struct media_entity * entity)51 static inline unsigned int __media_entity_type(struct media_entity *entity)
52 {
53 return entity->info.type & MEDIA_ENT_TYPE_MASK;
54 }
55
__media_debug_default(void * ptr,...)56 static void __media_debug_default(void *ptr, ...)
57 {
58 va_list argptr;
59 va_start(argptr, ptr);
60 vprintf((const char*)ptr, argptr);
61 va_end(argptr);
62 }
63
__media_debug_set_handler(struct media_device * media,void (* debug_handler)(void *,...),void * debug_priv)64 static void __media_debug_set_handler(
65 struct media_device *media,
66 void (*debug_handler)(void *, ...),
67 void *debug_priv)
68 {
69 if (debug_handler) {
70 media->debug_handler = debug_handler;
71 media->debug_priv = debug_priv;
72 } else {
73 media->debug_handler = __media_debug_default;
74 media->debug_priv = NULL;
75 }
76 }
77
__media_entity_add_link(struct media_entity * entity)78 static struct media_link *__media_entity_add_link(struct media_entity *entity)
79 {
80 return NULL;
81 }
82
83
__media_enum_links(struct media_device * media)84 static int __media_enum_links(struct media_device *media)
85 {
86 return 0;
87 }
88
__media_get_devname_sysfs(struct media_entity * entity)89 static int __media_get_devname_sysfs(struct media_entity *entity)
90 {
91 //struct stat devstat;
92 char devname[32];
93 char sysname[32];
94 char target[1024];
95 char *p;
96 int ret;
97
98 snprintf(sysname, sizeof(sysname), "/sys/dev/char/%u:%u", entity->info.v4l.major,
99 entity->info.v4l.minor);
100
101 ret = readlink(sysname, target, sizeof(target));
102 if (ret < 0 || ret >= (int)sizeof(target))
103 return -errno;
104
105 target[ret] = '\0';
106 p = strrchr(target, '/');
107 if (p == NULL)
108 return -EINVAL;
109
110 snprintf(devname, sizeof(devname), "/tmp/%s", p + 1);
111
112 ret = mknod(devname, 0666 | S_IFCHR, MKDEV(81, entity->info.v4l.minor));
113 strncpy(entity->devname, devname, sizeof(devname) - 1);
114
115 return 0;
116 }
117
__media_get_media_fd(const char * filename,struct media_device * media)118 static int __media_get_media_fd(const char *filename, struct media_device *media)
119 {
120 ssize_t num;
121 int media_node;
122 char *ptr;
123
124 ALOGD("%s: %s", __func__, filename);
125
126 media->fd = open(filename, O_RDWR, 0);
127 if (media->fd < 0) {
128 ALOGE("Open sysfs media device failed, media->fd: %d", media->fd);
129 return -1;
130 }
131
132 ALOGD("%s: media->fd: %d", __func__, media->fd);
133
134 return media->fd;
135
136 }
137
__media_enum_entities(struct media_device * media)138 static int __media_enum_entities(struct media_device *media)
139 {
140 return 0;
141 }
142
__media_open_debug(const char * filename,void (* debug_handler)(void *,...),void * debug_priv)143 static struct media_device *__media_open_debug(
144 const char *filename,
145 void (*debug_handler)(void *, ...),
146 void *debug_priv)
147 {
148 struct media_device *media;
149 int ret;
150
151 media = (struct media_device *)calloc(1, sizeof(struct media_device));
152 if (media == NULL) {
153 ALOGE("media: %p", media);
154 return NULL;
155 }
156
157 __media_debug_set_handler(media, debug_handler, debug_priv);
158
159 ALOGD("%s: Opening media device %s", __func__, filename);
160 ALOGD("%s: media: %p", __func__, media);
161
162 media->fd = __media_get_media_fd(filename, media);
163 if (media->fd < 0) {
164 exynos_media_close(media);
165 ALOGE("failed __media_get_media_fd %s", filename);
166 return NULL;
167 }
168
169 ALOGD("%s: media->fd: %d", __func__, media->fd);
170 ret = __media_enum_entities(media);
171
172 if (ret < 0) {
173 ALOGE("Unable to enumerate entities for device %s (%s)", filename, strerror(-ret));
174 exynos_media_close(media);
175 return NULL;
176 }
177
178 ALOGD("%s: Found %u entities", __func__, media->entities_count);
179 ALOGD("%s: Enumerating pads and links", __func__);
180
181 ret = __media_enum_links(media);
182 if (ret < 0) {
183 ALOGE("Unable to enumerate pads and links for device %s", filename);
184 exynos_media_close(media);
185 return NULL;
186 }
187
188 return media;
189 }
190
191 /**
192 * @brief Open a media device.
193 * @param filename - name (including path) of the device node.
194 *
195 * Open the media device referenced by @a filename and enumerate entities, pads and
196 * links.
197 *
198 * @return A pointer to a newly allocated media_device structure instance on
199 * success and NULL on failure. The returned pointer must be freed with
200 * exynos_media_close when the device isn't needed anymore.
201 */
exynos_media_open(const char * filename)202 struct media_device *exynos_media_open(const char *filename)
203 {
204 return __media_open_debug(filename, (void (*)(void *, ...))fprintf, stdout);
205 }
206
207 /**
208 * @brief Close a media device.
209 * @param media - device instance.
210 *
211 * Close the @a media device instance and free allocated resources. Access to the
212 * device instance is forbidden after this function returns.
213 */
exynos_media_close(struct media_device * media)214 void exynos_media_close(struct media_device *media)
215 {
216 unsigned int i;
217
218 if (media->fd != -1)
219 close(media->fd);
220
221 for (i = 0; i < media->entities_count; ++i) {
222 struct media_entity *entity = &media->entities[i];
223
224 free(entity->pads);
225 free(entity->links);
226 if (entity->fd != -1)
227 close(entity->fd);
228 }
229
230 free(media->entities);
231 free(media);
232 }
233
234 /**
235 * @brief Locate the pad at the other end of a link.
236 * @param pad - sink pad at one end of the link.
237 *
238 * Locate the source pad connected to @a pad through an enabled link. As only one
239 * link connected to a sink pad can be enabled at a time, the connected source
240 * pad is guaranteed to be unique.
241 *
242 * @return A pointer to the connected source pad, or NULL if all links connected
243 * to @a pad are disabled. Return NULL also if @a pad is not a sink pad.
244 */
exynos_media_entity_remote_source(struct media_pad * pad)245 struct media_pad *exynos_media_entity_remote_source(struct media_pad *pad)
246 {
247 return NULL;
248 }
249
250 /**
251 * @brief Find an entity by its name.
252 * @param media - media device.
253 * @param name - entity name.
254 * @param length - size of @a name.
255 *
256 * Search for an entity with a name equal to @a name.
257 *
258 * @return A pointer to the entity if found, or NULL otherwise.
259 */
exynos_media_get_entity_by_name(struct media_device * media,const char * name,size_t length)260 struct media_entity *exynos_media_get_entity_by_name(struct media_device *media,
261 const char *name, size_t length)
262 {
263 unsigned int i;
264 struct media_entity *entity;
265
266 for (i = 0; i < media->entities_count; ++i) {
267 entity = &media->entities[i];
268
269 if (strncmp(entity->info.name, name, length) == 0)
270 return entity;
271 }
272
273 return NULL;
274 }
275
276 /**
277 * @brief Find an entity by its ID.
278 * @param media - media device.
279 * @param id - entity ID.
280 *
281 * Search for an entity with an ID equal to @a id.
282 *
283 * @return A pointer to the entity if found, or NULL otherwise.
284 */
exynos_media_get_entity_by_id(struct media_device * media,__u32 id)285 struct media_entity *exynos_media_get_entity_by_id(struct media_device *media,
286 __u32 id)
287 {
288 unsigned int i;
289
290 for (i = 0; i < media->entities_count; ++i) {
291 struct media_entity *entity = &media->entities[i];
292
293 if (entity->info.id == id)
294 return entity;
295 }
296
297 return NULL;
298 }
299
300 /**
301 * @brief Configure a link.
302 * @param media - media device.
303 * @param source - source pad at the link origin.
304 * @param sink - sink pad at the link target.
305 * @param flags - configuration flags.
306 *
307 * Locate the link between @a source and @a sink, and configure it by applying
308 * the new @a flags.
309 *
310 * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
311 *
312 * @return 0 on success, -1 on failure:
313 * -ENOENT: link not found
314 * - other error codes returned by MEDIA_IOC_SETUP_LINK
315 */
exynos_media_setup_link(struct media_device * media,struct media_pad * source,struct media_pad * sink,__u32 flags)316 int exynos_media_setup_link(struct media_device *media,
317 struct media_pad *source,
318 struct media_pad *sink,
319 __u32 flags)
320 {
321 return 0;
322 }
323
324 /**
325 * @brief Reset all links to the disabled state.
326 * @param media - media device.
327 *
328 * Disable all links in the media device. This function is usually used after
329 * opening a media device to reset all links to a known state.
330 *
331 * @return 0 on success, or a negative error code on failure.
332 */
exynos_media_reset_links(struct media_device * media)333 int exynos_media_reset_links(struct media_device *media)
334 {
335 return 0;
336 }
337
338 #ifdef HAVE_LIBUDEV
339
340 #include <libudev.h>
341
__media_udev_open(struct udev ** udev)342 static inline int __media_udev_open(struct udev **udev)
343 {
344 *udev = udev_new();
345 if (*udev == NULL)
346 return -ENOMEM;
347 return 0;
348 }
349
__media_udev_close(struct udev * udev)350 static inline void __media_udev_close(struct udev *udev)
351 {
352 if (udev != NULL)
353 udev_unref(udev);
354 }
355
__media_get_devname_udev(struct udev * udev,struct media_entity * entity)356 static int __media_get_devname_udev(struct udev *udev,
357 struct media_entity *entity)
358 {
359 struct udev_device *device;
360 dev_t devnum;
361 const char *p;
362 int ret = -ENODEV;
363
364 if (udev == NULL)
365 return -EINVAL;
366
367 devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
368 ALOGE("looking up device: %u:%u",
369 major(devnum), minor(devnum));
370 device = udev_device_new_from_devnum(udev, 'c', devnum);
371 if (device) {
372 p = udev_device_get_devnode(device);
373 if (p) {
374 strncpy(entity->devname, p, sizeof(entity->devname));
375 entity->devname[sizeof(entity->devname) - 1] = '\0';
376 }
377 ret = 0;
378 }
379
380 udev_device_unref(device);
381
382 return ret;
383 }
384
385 #else /* HAVE_LIBUDEV */
386
387 struct udev;
388
__media_udev_open(struct udev ** udev)389 static inline int __media_udev_open(struct udev **udev) { return 0; }
390
__media_udev_close(struct udev * udev)391 static inline void __media_udev_close(struct udev *udev) { }
392
__media_get_devname_udev(struct udev * udev,struct media_entity * entity)393 static inline int __media_get_devname_udev(struct udev *udev,
394 struct media_entity *entity)
395 {
396 return -ENOTSUP;
397 }
398
399 #endif /* HAVE_LIBUDEV */
400
401 /**
402 * @brief Parse string to a pad on the media device.
403 * @param media - media device.
404 * @param p - input string
405 * @param endp - pointer to string where parsing ended
406 *
407 * Parse NULL terminated string describing a pad and return its struct
408 * media_pad instance.
409 *
410 * @return Pointer to struct media_pad on success, NULL on failure.
411 */
exynos_media_parse_pad(struct media_device * media,const char * p,char ** endp)412 struct media_pad *exynos_media_parse_pad(struct media_device *media,
413 const char *p, char **endp)
414 {
415 return NULL;
416 }
417
418 /**
419 * @brief Parse string to a link on the media device.
420 * @param media - media device.
421 * @param p - input string
422 * @param endp - pointer to p where parsing ended
423 *
424 * Parse NULL terminated string p describing a link and return its struct
425 * media_link instance.
426 *
427 * @return Pointer to struct media_link on success, NULL on failure.
428 */
exynos_media_parse_link(struct media_device * media,const char * p,char ** endp)429 struct media_link *exynos_media_parse_link(
430 struct media_device *media,
431 const char *p,
432 char **endp)
433 {
434 struct media_link *link;
435 struct media_pad *source;
436 struct media_pad *sink;
437 unsigned int i;
438 char *end;
439
440 source = exynos_media_parse_pad(media, p, &end);
441 if (source == NULL)
442 return NULL;
443
444 if (end[0] != '-' || end[1] != '>')
445 return NULL;
446 p = end + 2;
447
448 sink = exynos_media_parse_pad(media, p, &end);
449 if (sink == NULL)
450 return NULL;
451
452 *endp = end;
453
454 for (i = 0; i < source->entity->num_links; i++) {
455 link = &source->entity->links[i];
456
457 if (link->source == source && link->sink == sink)
458 return link;
459 }
460
461 return NULL;
462 }
463
464 /**
465 * @brief Parse string to a link on the media device and set it up.
466 * @param media - media device.
467 * @param p - input string
468 *
469 * Parse NULL terminated string p describing a link and its configuration
470 * and configure the link.
471 *
472 * @return 0 on success, or a negative error code on failure.
473 */
exynos_media_parse_setup_link(struct media_device * media,const char * p,char ** endp)474 int exynos_media_parse_setup_link(
475 struct media_device *media,
476 const char *p,
477 char **endp)
478 {
479 return 0;
480 }
481
482 /**
483 * @brief Parse string to link(s) on the media device and set it up.
484 * @param media - media device.
485 * @param p - input string
486 *
487 * Parse NULL terminated string p describing link(s) separated by
488 * commas (,) and configure the link(s).
489 *
490 * @return 0 on success, or a negative error code on failure.
491 */
exynos_media_parse_setup_links(struct media_device * media,const char * p)492 int exynos_media_parse_setup_links(struct media_device *media, const char *p)
493 {
494 return 0;
495 }
496