manta: libcamera2: drain requests on empty request queue
[GitHub/LineageOS/android_hardware_samsung_slsi_exynos5.git] / libv4l2 / exynos_mc.c
CommitLineData
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_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
44#include "exynos_v4l2.h"
45
46//#define LOG_NDEBUG 0
47#define LOG_TAG "libexynosv4l2-mc"
48#include <utils/Log.h>
49
50static inline unsigned int __media_entity_type(struct media_entity *entity)
51{
52 return entity->info.type & MEDIA_ENT_TYPE_MASK;
53}
54
55static void __media_debug_default(void *ptr, ...)
56{
57 va_list argptr;
58 va_start(argptr, ptr);
59 vprintf((const char*)ptr, argptr);
60 va_end(argptr);
61}
62
63static void __media_debug_set_handler(
64 struct media_device *media,
65 void (*debug_handler)(void *, ...),
66 void *debug_priv)
67{
68 if (debug_handler) {
69 media->debug_handler = debug_handler;
70 media->debug_priv = debug_priv;
71 } else {
72 media->debug_handler = __media_debug_default;
73 media->debug_priv = NULL;
74 }
75}
76
77static struct media_link *__media_entity_add_link(struct media_entity *entity)
78{
79 if (entity->num_links >= entity->max_links) {
80 struct media_link *links = entity->links;
81 unsigned int max_links = entity->max_links * 2;
82 unsigned int i;
83
84 links = (struct media_link*)realloc(links, max_links * sizeof *links);
85 if (links == NULL)
86 return NULL;
87
88 for (i = 0; i < entity->num_links; ++i)
89 links[i].twin->twin = &links[i];
90
91 entity->max_links = max_links;
92 entity->links = links;
93 }
94
95 return &entity->links[entity->num_links++];
96}
97
98
99static int __media_enum_links(struct media_device *media)
100{
7642c64b 101 ALOGD("%s: start", __func__);
e5931c34
JC
102 __u32 id;
103 int ret = 0;
104
105 for (id = 1; id <= media->entities_count; id++) {
106 struct media_entity *entity = &media->entities[id - 1];
107 struct media_links_enum links;
108 unsigned int i;
109
110 links.entity = entity->info.id;
111 links.pads = (struct media_pad_desc*)malloc(entity->info.pads * sizeof(struct media_pad_desc));
112 links.links = (struct media_link_desc*)malloc(entity->info.links * sizeof(struct media_link_desc));
113
114 if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
7642c64b 115 ALOGE("Unable to enumerate pads and links (%s)", strerror(errno));
e5931c34
JC
116 free(links.pads);
117 free(links.links);
118 return -errno;
119 }
120
121 for (i = 0; i < entity->info.pads; ++i) {
122 entity->pads[i].entity = entity;
123 entity->pads[i].index = links.pads[i].index;
124 entity->pads[i].flags = links.pads[i].flags;
125 }
126
127 for (i = 0; i < entity->info.links; ++i) {
128 struct media_link_desc *link = &links.links[i];
129 struct media_link *fwdlink;
130 struct media_link *backlink;
131 struct media_entity *source;
132 struct media_entity *sink;
133
134 source = exynos_media_get_entity_by_id(media, link->source.entity);
135 sink = exynos_media_get_entity_by_id(media, link->sink.entity);
136 if (source == NULL || sink == NULL) {
7642c64b 137 ALOGE("WARNING entity %u link %u from %u/%u to %u/%u is invalid!",
e5931c34
JC
138 id, i, link->source.entity,
139 link->source.index,
140 link->sink.entity,
141 link->sink.index);
142 ret = -EINVAL;
143 } else {
144 fwdlink = __media_entity_add_link(source);
145 fwdlink->source = &source->pads[link->source.index];
146 fwdlink->sink = &sink->pads[link->sink.index];
147 fwdlink->flags = link->flags;
148
149 backlink = __media_entity_add_link(sink);
150 backlink->source = &source->pads[link->source.index];
151 backlink->sink = &sink->pads[link->sink.index];
152 backlink->flags = link->flags;
153
154 fwdlink->twin = backlink;
155 backlink->twin = fwdlink;
156 }
157 }
158
159 free(links.pads);
160 free(links.links);
161 }
162 return ret;
163}
164
165static int __media_get_devname_sysfs(struct media_entity *entity)
166{
167 //struct stat devstat;
168 char devname[32];
169 char sysname[32];
170 char target[1024];
171 char *p;
172 int ret;
173
174 sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
175 entity->info.v4l.minor);
176
177 ret = readlink(sysname, target, sizeof(target));
178 if (ret < 0)
179 return -errno;
180
181 target[ret] = '\0';
182 p = strrchr(target, '/');
183 if (p == NULL)
184 return -EINVAL;
185
186 sprintf(devname, "/tmp/%s", p + 1);
187
188 ret = mknod(devname, 0666 | S_IFCHR, MKDEV(81, entity->info.v4l.minor));
189 strcpy(entity->devname, devname);
190
191 return 0;
192}
193
194static int __media_get_media_fd(const char *filename, struct media_device *media)
195{
196 ssize_t num;
197 int media_node;
198 char *ptr;
199 char media_buf[6];
200
7642c64b 201 ALOGD("%s: %s", __func__, filename);
e5931c34
JC
202
203 media->fd = open(filename, O_RDWR, 0);
204 if (media->fd < 0) {
7642c64b 205 ALOGE("Open sysfs media device failed, media->fd: %d", media->fd);
e5931c34
JC
206 return -1;
207 }
208
7642c64b 209 ALOGD("%s: media->fd: %d", __func__, media->fd);
e5931c34
JC
210
211 return media->fd;
212
213}
214
215static int __media_enum_entities(struct media_device *media)
216{
d970bdc0 217 struct media_entity *entity, *temp_entity;
e5931c34
JC
218 unsigned int size;
219 __u32 id;
220 int ret;
d970bdc0
JC
221
222 temp_entity = entity = (struct media_entity*)calloc(1, sizeof(struct media_entity));
e5931c34
JC
223 for (id = 0, ret = 0; ; id = entity->info.id) {
224 size = (media->entities_count + 1) * sizeof(*media->entities);
225 media->entities = (struct media_entity*)realloc(media->entities, size);
226
227 entity = &media->entities[media->entities_count];
228 memset(entity, 0, sizeof(*entity));
229 entity->fd = -1;
230 entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
231 entity->media = media;
232
233 ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
234
235 if (ret < 0) {
236 ret = errno != EINVAL ? -errno : 0;
237 break;
238 }
239
240 /* Number of links (for outbound links) plus number of pads (for
241 * inbound links) is a good safe initial estimate of the total
242 * number of links.
243 */
244 entity->max_links = entity->info.pads + entity->info.links;
245
246 entity->pads = (struct media_pad*)malloc(entity->info.pads * sizeof(*entity->pads));
247 entity->links = (struct media_link*)malloc(entity->max_links * sizeof(*entity->links));
248 if (entity->pads == NULL || entity->links == NULL) {
249 ret = -ENOMEM;
250 break;
251 }
252
253 media->entities_count++;
254
255 /* Find the corresponding device name. */
256 if (__media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
257 __media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
258 continue;
259
260 /* Fall back to get the device name via sysfs */
261 __media_get_devname_sysfs(entity);
262 if (ret < 0)
7642c64b 263 ALOGE("media_get_devname failed");
e5931c34 264 }
d970bdc0 265 free(temp_entity);
e5931c34
JC
266
267 return ret;
268}
269
270static struct media_device *__media_open_debug(
271 const char *filename,
272 void (*debug_handler)(void *, ...),
273 void *debug_priv)
274{
275 struct media_device *media;
276 int ret;
277
278 media = (struct media_device *)calloc(1, sizeof(struct media_device));
279 if (media == NULL) {
7642c64b 280 ALOGE("media: %p", media);
e5931c34
JC
281 return NULL;
282 }
283
284 __media_debug_set_handler(media, debug_handler, debug_priv);
285
7642c64b
DZ
286 ALOGD("%s: Opening media device %s", __func__, filename);
287 ALOGD("%s: media: %p", __func__, media);
e5931c34
JC
288
289 media->fd = __media_get_media_fd(filename, media);
290 if (media->fd < 0) {
291 exynos_media_close(media);
7642c64b 292 ALOGE("failed __media_get_media_fd %s", filename);
e5931c34
JC
293 return NULL;
294 }
295
7642c64b 296 ALOGD("%s: media->fd: %d", __func__, media->fd);
e5931c34
JC
297 ret = __media_enum_entities(media);
298
299 if (ret < 0) {
7642c64b 300 ALOGE("Unable to enumerate entities for device %s (%s)", filename, strerror(-ret));
e5931c34
JC
301 exynos_media_close(media);
302 return NULL;
303 }
304
7642c64b
DZ
305 ALOGD("%s: Found %u entities", __func__, media->entities_count);
306 ALOGD("%s: Enumerating pads and links", __func__);
e5931c34
JC
307
308 ret = __media_enum_links(media);
309 if (ret < 0) {
7642c64b 310 ALOGE("Unable to enumerate pads and links for device %s", filename);
e5931c34
JC
311 exynos_media_close(media);
312 return NULL;
313 }
314
315 return media;
316}
317
318/**
319 * @brief Open a media device.
320 * @param filename - name (including path) of the device node.
321 *
322 * Open the media device referenced by @a filename and enumerate entities, pads and
323 * links.
324 *
325 * @return A pointer to a newly allocated media_device structure instance on
326 * success and NULL on failure. The returned pointer must be freed with
327 * exynos_media_close when the device isn't needed anymore.
328 */
329struct media_device *exynos_media_open(const char *filename)
330{
331 return __media_open_debug(filename, (void (*)(void *, ...))fprintf, stdout);
332}
333
334/**
335 * @brief Close a media device.
336 * @param media - device instance.
337 *
338 * Close the @a media device instance and free allocated resources. Access to the
339 * device instance is forbidden after this function returns.
340 */
341void exynos_media_close(struct media_device *media)
342{
343 unsigned int i;
344
345 if (media->fd != -1)
346 close(media->fd);
347
348 for (i = 0; i < media->entities_count; ++i) {
349 struct media_entity *entity = &media->entities[i];
350
351 free(entity->pads);
352 free(entity->links);
353 if (entity->fd != -1)
354 close(entity->fd);
355 }
356
357 free(media->entities);
358 free(media);
359}
360
361/**
362 * @brief Locate the pad at the other end of a link.
363 * @param pad - sink pad at one end of the link.
364 *
365 * Locate the source pad connected to @a pad through an enabled link. As only one
366 * link connected to a sink pad can be enabled at a time, the connected source
367 * pad is guaranteed to be unique.
368 *
369 * @return A pointer to the connected source pad, or NULL if all links connected
370 * to @a pad are disabled. Return NULL also if @a pad is not a sink pad.
371 */
372struct media_pad *exynos_media_entity_remote_source(struct media_pad *pad)
373{
374 unsigned int i;
375
376 if (!(pad->flags & MEDIA_PAD_FL_SINK))
377 return NULL;
378
379 for (i = 0; i < pad->entity->num_links; ++i) {
380 struct media_link *link = &pad->entity->links[i];
381
382 if (!(link->flags & MEDIA_LNK_FL_ENABLED))
383 continue;
384
385 if (link->sink == pad)
386 return link->source;
387 }
388
389 return NULL;
390}
391
392/**
393 * @brief Find an entity by its name.
394 * @param media - media device.
395 * @param name - entity name.
396 * @param length - size of @a name.
397 *
398 * Search for an entity with a name equal to @a name.
399 *
400 * @return A pointer to the entity if found, or NULL otherwise.
401 */
402struct media_entity *exynos_media_get_entity_by_name(struct media_device *media,
403 const char *name, size_t length)
404{
405 unsigned int i;
406 struct media_entity *entity;
407
e5931c34
JC
408 for (i = 0; i < media->entities_count; ++i) {
409 entity = &media->entities[i];
410
411 if (strncmp(entity->info.name, name, length) == 0)
412 return entity;
413 }
414
415 return NULL;
416}
417
418/**
419 * @brief Find an entity by its ID.
420 * @param media - media device.
421 * @param id - entity ID.
422 *
423 * Search for an entity with an ID equal to @a id.
424 *
425 * @return A pointer to the entity if found, or NULL otherwise.
426 */
427struct media_entity *exynos_media_get_entity_by_id(struct media_device *media,
428 __u32 id)
429{
430 unsigned int i;
431
432 for (i = 0; i < media->entities_count; ++i) {
433 struct media_entity *entity = &media->entities[i];
434
435 if (entity->info.id == id)
436 return entity;
437 }
438
439 return NULL;
440}
441
442/**
443 * @brief Configure a link.
444 * @param media - media device.
445 * @param source - source pad at the link origin.
446 * @param sink - sink pad at the link target.
447 * @param flags - configuration flags.
448 *
449 * Locate the link between @a source and @a sink, and configure it by applying
450 * the new @a flags.
451 *
452 * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
453 *
454 * @return 0 on success, -1 on failure:
455 * -ENOENT: link not found
456 * - other error codes returned by MEDIA_IOC_SETUP_LINK
457 */
458int exynos_media_setup_link(struct media_device *media,
459 struct media_pad *source,
460 struct media_pad *sink,
461 __u32 flags)
462{
463 struct media_link *link;
464 struct media_link_desc ulink;
465 unsigned int i;
466 int ret;
467
468 for (i = 0; i < source->entity->num_links; i++) {
469 link = &source->entity->links[i];
470
471 if (link->source->entity == source->entity &&
472 link->source->index == source->index &&
473 link->sink->entity == sink->entity &&
474 link->sink->index == sink->index)
475 break;
476 }
477
478 if (i == source->entity->num_links) {
7642c64b 479 ALOGE("Link not found");
e5931c34
JC
480 return -ENOENT;
481 }
482
483 /* source pad */
484 ulink.source.entity = source->entity->info.id;
485 ulink.source.index = source->index;
486 ulink.source.flags = MEDIA_PAD_FL_SOURCE;
487
488 /* sink pad */
489 ulink.sink.entity = sink->entity->info.id;
490 ulink.sink.index = sink->index;
491 ulink.sink.flags = MEDIA_PAD_FL_SINK;
492
493 ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
494
495 ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
496 if (ret == -1) {
7642c64b 497 ALOGE("Unable to setup link (%s)", strerror(errno));
e5931c34
JC
498 return -errno;
499 }
500
501 link->flags = ulink.flags;
502 link->twin->flags = ulink.flags;
503 return 0;
504}
505
506/**
507 * @brief Reset all links to the disabled state.
508 * @param media - media device.
509 *
510 * Disable all links in the media device. This function is usually used after
511 * opening a media device to reset all links to a known state.
512 *
513 * @return 0 on success, or a negative error code on failure.
514 */
515int exynos_media_reset_links(struct media_device *media)
516{
517 unsigned int i, j;
518 int ret;
519
520 for (i = 0; i < media->entities_count; ++i) {
521 struct media_entity *entity = &media->entities[i];
522
523 for (j = 0; j < entity->num_links; j++) {
524 struct media_link *link = &entity->links[j];
525
526 if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
527 link->source->entity != entity)
528 continue;
529
530 ret = exynos_media_setup_link(media, link->source, link->sink,
531 link->flags & ~MEDIA_LNK_FL_ENABLED);
532 if (ret < 0)
533 return ret;
534 }
535 }
536
537 return 0;
538}
539
540#ifdef HAVE_LIBUDEV
541
542#include <libudev.h>
543
544static inline int __media_udev_open(struct udev **udev)
545{
546 *udev = udev_new();
547 if (*udev == NULL)
548 return -ENOMEM;
549 return 0;
550}
551
552static inline void __media_udev_close(struct udev *udev)
553{
554 if (udev != NULL)
555 udev_unref(udev);
556}
557
558static int __media_get_devname_udev(struct udev *udev,
559 struct media_entity *entity)
560{
561 struct udev_device *device;
562 dev_t devnum;
563 const char *p;
564 int ret = -ENODEV;
565
566 if (udev == NULL)
567 return -EINVAL;
568
569 devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
7642c64b 570 ALOGE("looking up device: %u:%u",
e5931c34
JC
571 major(devnum), minor(devnum));
572 device = udev_device_new_from_devnum(udev, 'c', devnum);
573 if (device) {
574 p = udev_device_get_devnode(device);
575 if (p) {
576 strncpy(entity->devname, p, sizeof(entity->devname));
577 entity->devname[sizeof(entity->devname) - 1] = '\0';
578 }
579 ret = 0;
580 }
581
582 udev_device_unref(device);
583
584 return ret;
585}
586
587#else /* HAVE_LIBUDEV */
588
589struct udev;
590
591static inline int __media_udev_open(struct udev **udev) { return 0; }
592
593static inline void __media_udev_close(struct udev *udev) { }
594
595static inline int __media_get_devname_udev(struct udev *udev,
596 struct media_entity *entity)
597{
598 return -ENOTSUP;
599}
600
601#endif /* HAVE_LIBUDEV */
602
603/**
604 * @brief Parse string to a pad on the media device.
605 * @param media - media device.
606 * @param p - input string
607 * @param endp - pointer to string where parsing ended
608 *
609 * Parse NULL terminated string describing a pad and return its struct
610 * media_pad instance.
611 *
612 * @return Pointer to struct media_pad on success, NULL on failure.
613 */
614struct media_pad *exynos_media_parse_pad(struct media_device *media,
615 const char *p, char **endp)
616{
617 unsigned int entity_id, pad;
618 struct media_entity *entity;
619 char *end;
620
621 for (; isspace(*p); ++p);
622
623 if (*p == '"') {
624 for (end = (char *)p + 1; *end && *end != '"'; ++end);
625 if (*end != '"')
626 return NULL;
627
628 entity = exynos_media_get_entity_by_name(media, p + 1, end - p - 1);
629 if (entity == NULL)
630 return NULL;
631
632 ++end;
633 } else {
634 entity_id = strtoul(p, &end, 10);
635 entity = exynos_media_get_entity_by_id(media, entity_id);
636 if (entity == NULL)
637 return NULL;
638 }
639 for (; isspace(*end); ++end);
640
641 if (*end != ':')
642 return NULL;
643 for (p = end + 1; isspace(*p); ++p);
644
645 pad = strtoul(p, &end, 10);
646 for (p = end; isspace(*p); ++p);
647
648 if (pad >= entity->info.pads)
649 return NULL;
650
651 for (p = end; isspace(*p); ++p);
652 if (endp)
653 *endp = (char *)p;
654
655 return &entity->pads[pad];
656}
657
658/**
659 * @brief Parse string to a link on the media device.
660 * @param media - media device.
661 * @param p - input string
662 * @param endp - pointer to p where parsing ended
663 *
664 * Parse NULL terminated string p describing a link and return its struct
665 * media_link instance.
666 *
667 * @return Pointer to struct media_link on success, NULL on failure.
668 */
669struct media_link *exynos_media_parse_link(
670 struct media_device *media,
671 const char *p,
672 char **endp)
673{
674 struct media_link *link;
675 struct media_pad *source;
676 struct media_pad *sink;
677 unsigned int i;
678 char *end;
679
680 source = exynos_media_parse_pad(media, p, &end);
681 if (source == NULL)
682 return NULL;
683
684 if (end[0] != '-' || end[1] != '>')
685 return NULL;
686 p = end + 2;
687
688 sink = exynos_media_parse_pad(media, p, &end);
689 if (sink == NULL)
690 return NULL;
691
692 *endp = end;
693
694 for (i = 0; i < source->entity->num_links; i++) {
695 link = &source->entity->links[i];
696
697 if (link->source == source && link->sink == sink)
698 return link;
699 }
700
701 return NULL;
702}
703
704/**
705 * @brief Parse string to a link on the media device and set it up.
706 * @param media - media device.
707 * @param p - input string
708 *
709 * Parse NULL terminated string p describing a link and its configuration
710 * and configure the link.
711 *
712 * @return 0 on success, or a negative error code on failure.
713 */
714int exynos_media_parse_setup_link(
715 struct media_device *media,
716 const char *p,
717 char **endp)
718{
719 struct media_link *link;
720 __u32 flags;
721 char *end;
722
723 link = exynos_media_parse_link(media, p, &end);
724 if (link == NULL) {
7642c64b 725 ALOGE("Unable to parse link");
e5931c34
JC
726 return -EINVAL;
727 }
728
729 p = end;
730 if (*p++ != '[') {
7642c64b 731 ALOGE("Unable to parse link flags");
e5931c34
JC
732 return -EINVAL;
733 }
734
735 flags = strtoul(p, &end, 10);
736 for (p = end; isspace(*p); p++);
737 if (*p++ != ']') {
7642c64b 738 ALOGE("Unable to parse link flags");
e5931c34
JC
739 return -EINVAL;
740 }
741
742 for (; isspace(*p); p++);
743 *endp = (char *)p;
744
7642c64b 745 ALOGD("%s: Setting up link %u:%u -> %u:%u [%u]", __func__,
e5931c34
JC
746 link->source->entity->info.id, link->source->index,
747 link->sink->entity->info.id, link->sink->index,
748 flags);
749
750 return exynos_media_setup_link(media, link->source, link->sink, flags);
751}
752
753/**
754 * @brief Parse string to link(s) on the media device and set it up.
755 * @param media - media device.
756 * @param p - input string
757 *
758 * Parse NULL terminated string p describing link(s) separated by
759 * commas (,) and configure the link(s).
760 *
761 * @return 0 on success, or a negative error code on failure.
762 */
763int exynos_media_parse_setup_links(struct media_device *media, const char *p)
764{
765 char *end;
766 int ret;
767
768 do {
769 ret = exynos_media_parse_setup_link(media, p, &end);
770 if (ret < 0)
771 return ret;
772
773 p = end + 1;
774 } while (*end == ',');
775
776 return *end ? -EINVAL : 0;
777}