new file mode 100644
@@ -0,0 +1,30 @@
+ARCH ?= arm
+KDIR ?= /usr/src/linux
+LIBV4LINCDIR ?= ../../v4l-utils/lib/include/
+LIBMEDIACTLDIR ?= /usr/local/lib
+CONF_INST_DIR := $(DESTDIR)/etc/libv4l2plugins
+PLUGIN_INST_DIR := $(DESTDIR)/usr/lib/libv4l/plugins
+
+KINC := -I$(KDIR)/include -I$(KDIR)/arch/$(ARCH)/include
+INC := -I$(LIBV4LINCDIR) $(KINC)
+CC := $(CROSS_COMPILE)gcc
+
+LDFLAGS += -L$(LIBMEDIACTLDIR) -lmediactl
+
+CFLAGS += -O2 -Wall -fpic -I. $(INC)
+OBJS = libv4l2plugin-omap3mc.o paths.o operations.o
+
+all: libv4l2plugin-omap3mc.so
+
+libv4l2plugin-omap3mc.so: $(OBJS)
+ $(CC) $(CFLAGS) -shared $(LDFLAGS) -o libv4l2plugin-omap3mc.so $(OBJS)
+clean:
+ rm -f $(OBJS) libv4l2plugin-omap3mc.so
+
+install: libv4l2plugin-omap3mc.so
+ test -z "$(CONF_INST_DIR)" || mkdir -p "$(CONF_INST_DIR)"
+ install -m 666 omap3-mc.conf "$(CONF_INST_DIR)"
+ test -z "$(PLUGIN_INST_DIR)" || mkdir -p "$(PLUGIN_INST_DIR)"
+ install -m 755 libv4l2plugin-omap3mc.so "$(PLUGIN_INST_DIR)"
+
+.PHONY: clean all
new file mode 100644
@@ -0,0 +1,82 @@
+# Configuration file for media controller plugin for libv4l
+#
+#
+# Format:
+#
+# [primary|secondary]_path
+# list of subdevice names
+# end
+#
+# [primary|secondary]_in_pixfmt
+# list of formats supported by input device
+# end
+#
+# [primary|secondary]_out_pixfmt
+# list of formats supported by output device
+# end
+#
+#
+#
+# Sensors:
+# jt8ev1, smiapp-001, smiapp-002, smiapp-003, smiapp-004, tcm8500md, vw6558
+#
+# Subdevices:
+# OMAP3 ISP CSI2a
+# OMAP3 ISP CSI2a output
+# OMAP3 ISP CCP2
+# OMAP3 ISP CCP2 input
+# OMAP3 ISP CCDC
+# OMAP3 ISP preview
+# OMAP3 ISP preview output
+# OMAP3 ISP resizer input
+# OMAP3 ISP resizer
+# OMAP3 ISP resizer output
+#
+#
+# Formats:
+# BAYER8_SBGGR, BAYER8_SGBRG, BAYER8_SGRBG, BAYER10_SGRBG, BAYER10_SRGGB,
+# BAYER10_SBGGR, BAYER10_SGBRG, BAYER10DPCM8_SGRBG, YUYV, UYVY
+#
+#
+
+
+
+primary_path
+ jt8ev1
+ OMAP3 ISP CSI2a
+ OMAP3 ISP CCDC
+ OMAP3 ISP preview
+ OMAP3 ISP resizer
+ OMAP3 ISP resizer output
+end
+
+primary_in_pixfmt
+ BAYER10DPCM8_SGRBG
+ BAYER10_SGRBG
+end
+
+primary_out_pixfmt
+ UYVY
+end
+
+
+
+secondary_path
+ vw6558
+ OMAP3 ISP CCP2
+ OMAP3 ISP CCDC
+ OMAP3 ISP preview
+ OMAP3 ISP resizer
+ OMAP3 ISP resizer output
+end
+
+secondary_in_pixfmt
+ BAYER10DPCM8_SGRBG
+ BAYER10_SGRBG
+end
+
+secondary_out_pixfmt
+ UYVY
+end
+
+
new file mode 100644
@@ -0,0 +1,959 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <linux/v4l2-subdev.h>
+
+#include "sl_list.h"
+#include "paths.h"
+
+#define CONFIG_FILE "/etc/libv4l2plugins/omap3-mc.conf"
+
+#define LINESIZE (256)
+#define CHOMP(x) \
+ do { \
+ char *p; \
+ int sz; \
+ p = (x); \
+ sz = strlen(p); \
+ p += sz - 1; \
+ if (sz) \
+ while (isspace(*p)) *p-- = 0; \
+ } while (0)
+
+/* Sections in configuration file */
+enum mc_plugin_config_sections {
+ CONFIG_SECTION_NONE,
+ CONFIG_SECTION_PRIMARY_PATH,
+ CONFIG_SECTION_PRIMARY_IN_PIXFMT,
+ CONFIG_SECTION_PRIMARY_OUT_PIXFMT,
+ CONFIG_SECTION_SECONDARY_PATH,
+ CONFIG_SECTION_SECONDARY_IN_PIXFMT,
+ CONFIG_SECTION_SECONDARY_OUT_PIXFMT
+};
+
+struct capture_pipeline pipe_sensor_yuv_path;
+
+int pixel_mc_plugin_to_subdev(enum mc_plugin_pixelformat pixfmt)
+{
+ switch (pixfmt) {
+ case MC_PLUGIN_PIX_FMT_BAYER10_SGRBG:
+ return V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ case MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG:
+ return V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8;
+
+ case MC_PLUGIN_PIX_FMT_YUYV:
+ return V4L2_MBUS_FMT_YUYV8_1X16;
+
+ case MC_PLUGIN_PIX_FMT_UYVY:
+ return V4L2_MBUS_FMT_UYVY8_1X16;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+enum mc_plugin_pixelformat pixel_subdev_to_mc_plugin(int pixfmt)
+{
+ switch (pixfmt) {
+ case V4L2_MBUS_FMT_SGRBG10_1X10:
+ return MC_PLUGIN_PIX_FMT_BAYER10_SGRBG;
+
+ case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+ return MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG;
+
+ case V4L2_MBUS_FMT_YUYV8_1X16:
+ return MC_PLUGIN_PIX_FMT_YUYV;
+
+ case V4L2_MBUS_FMT_UYVY8_1X16:
+ return MC_PLUGIN_PIX_FMT_UYVY;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int pixel_mc_plugin_to_v4l(enum mc_plugin_pixelformat pixfmt)
+{
+ switch (pixfmt) {
+ case MC_PLUGIN_PIX_FMT_BAYER10_SGRBG:
+ return V4L2_PIX_FMT_SGRBG10;
+
+#ifdef V4L2_PIX_FMT_SGRBG10DPCM8
+ case MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG:
+ return V4L2_PIX_FMT_SGRBG10DPCM8;
+#endif
+
+ case MC_PLUGIN_PIX_FMT_YUYV:
+ return V4L2_PIX_FMT_YUYV;
+
+ case MC_PLUGIN_PIX_FMT_UYVY:
+ return V4L2_PIX_FMT_UYVY;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+enum mc_plugin_pixelformat pixel_v4l_to_mc_plugin(int pixfmt)
+{
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_SGRBG10:
+ return MC_PLUGIN_PIX_FMT_BAYER10_SGRBG;
+
+#ifdef V4L2_PIX_FMT_SGRBG10DPCM8
+ case V4L2_PIX_FMT_SGRBG10DPCM8:
+ return MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG;
+#endif
+
+ case V4L2_PIX_FMT_YUYV:
+ return MC_PLUGIN_PIX_FMT_YUYV;
+
+ case V4L2_PIX_FMT_UYVY:
+ return MC_PLUGIN_PIX_FMT_UYVY;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+enum mc_plugin_pixelformat pixel_str_to_mc_plugin(char *strpix)
+{
+ if (strcmp(strpix, "BAYER8_SBGGR") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER8_SBGGR;
+ if (strcmp(strpix, "BAYER8_SGBRG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER8_SGBRG;
+ if (strcmp(strpix, "BAYER8_SGRBG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER8_SGRBG;
+ if (strcmp(strpix, "BAYER10_SGRBG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10_SGRBG;
+ if (strcmp(strpix, "BAYER10_SRGGB") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10_SRGGB;
+ if (strcmp(strpix, "BAYER10_SBGGR") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10_SBGGR;
+ if (strcmp(strpix, "BAYER10_SGBRG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10_SGBRG;
+ if (strcmp(strpix, "BAYER10DPCM8_SGRBG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG;
+ if (strcmp(strpix, "YUYV") == 0)
+ return MC_PLUGIN_PIX_FMT_YUYV;
+ if (strcmp(strpix, "UYVY") == 0)
+ return MC_PLUGIN_PIX_FMT_UYVY;
+
+ return MC_PLUGIN_PIX_FMT_INVALID;
+}
+
+const struct capture_pipeline *pipe_sensor_yuv(int primary)
+{
+ FILE *fp = NULL;
+ char buffer[LINESIZE], *begin;
+ int i = 0;
+ enum mc_plugin_config_sections conf_section = CONFIG_SECTION_NONE;
+
+ fp = fopen(CONFIG_FILE, "r");
+ if (!fp) {
+ MC_PLUGIN_PRINTF ("Opening file %s failed", CONFIG_FILE);
+ return NULL;
+ }
+
+ while (fgets(buffer, LINESIZE, fp)) {
+ /* skip initial whitespace */
+ begin = buffer + strspn(buffer, "\r\t ");
+
+ /* skip comments and empty lines */
+ if (*begin == '#')
+ continue;
+ if (*begin == '\n')
+ continue;
+
+ /* Remove LF */
+ CHOMP(begin);
+
+ /* Check if we enter a config section */
+ if (conf_section == CONFIG_SECTION_NONE) {
+ if (strcmp(begin, "primary_path") == 0)
+ conf_section = CONFIG_SECTION_PRIMARY_PATH;
+ else if (strcmp(begin, "primary_in_pixfmt") == 0)
+ conf_section = CONFIG_SECTION_PRIMARY_IN_PIXFMT;
+ else if (strcmp(begin, "primary_out_pixfmt") == 0)
+ conf_section = CONFIG_SECTION_PRIMARY_OUT_PIXFMT;
+ else if (strcmp(begin, "secondary_path") == 0)
+ conf_section = CONFIG_SECTION_SECONDARY_PATH;
+ else if (strcmp(begin, "secondary_in_pixfmt") == 0)
+ conf_section = CONFIG_SECTION_SECONDARY_IN_PIXFMT;
+ else if (strcmp(begin, "secondary_out_pixfmt") == 0)
+ conf_section = CONFIG_SECTION_SECONDARY_OUT_PIXFMT;
+
+ i = 0;
+ continue;
+ }
+
+ /* Check if we exit a config section */
+ if (strcmp(begin, "end") == 0) {
+ conf_section = CONFIG_SECTION_NONE;
+ continue;
+ }
+
+ if ((i + 1) > PIPELINE_MAX_ELEMENTS ||
+ strlen(begin) >= SUBDEVICE_MAX_NAME_LEN) {
+
+ fclose(fp);
+ return NULL;
+ }
+
+ switch (conf_section) {
+ case CONFIG_SECTION_PRIMARY_PATH:
+ if (!primary)
+ break;
+ strcpy(pipe_sensor_yuv_path.path[i], begin);
+ strcpy(pipe_sensor_yuv_path.path[i+1], "");
+ i++;
+ break;
+ case CONFIG_SECTION_PRIMARY_IN_PIXFMT:
+ if (!primary)
+ break;
+ pipe_sensor_yuv_path.in_pixfmt[i] = pixel_str_to_mc_plugin(begin);
+ pipe_sensor_yuv_path.in_pixfmt[i+1] = MC_PLUGIN_PIX_FMT_INVALID;
+ i++;
+ break;
+ case CONFIG_SECTION_PRIMARY_OUT_PIXFMT:
+ if (!primary)
+ break;
+ pipe_sensor_yuv_path.out_pixfmt[i] = pixel_str_to_mc_plugin(begin);
+ pipe_sensor_yuv_path.out_pixfmt[i+1] = MC_PLUGIN_PIX_FMT_INVALID;
+ i++;
+ break;
+ case CONFIG_SECTION_SECONDARY_PATH:
+ if (primary)
+ break;
+ strcpy(pipe_sensor_yuv_path.path[i], begin);
+ strcpy(pipe_sensor_yuv_path.path[i+1], "");
+ i++;
+ break;
+ case CONFIG_SECTION_SECONDARY_IN_PIXFMT:
+ if (primary)
+ break;
+ pipe_sensor_yuv_path.in_pixfmt[i] = pixel_str_to_mc_plugin(begin);
+ pipe_sensor_yuv_path.in_pixfmt[i+1] = MC_PLUGIN_PIX_FMT_INVALID;
+ i++;
+ break;
+ case CONFIG_SECTION_SECONDARY_OUT_PIXFMT:
+ if (primary)
+ break;
+ pipe_sensor_yuv_path.out_pixfmt[i] = pixel_str_to_mc_plugin(begin);
+ pipe_sensor_yuv_path.out_pixfmt[i+1] = MC_PLUGIN_PIX_FMT_INVALID;
+ i++;
+ break;
+ case CONFIG_SECTION_NONE:
+ break;
+ }
+
+ }
+
+ fclose(fp);
+
+ return &pipe_sensor_yuv_path;
+}
+
+struct media_link *media_find_link(struct media_device *media,
+ struct media_entity *source,
+ struct media_entity *sink)
+{
+ unsigned int l;
+
+ for (l = 0; l < source->num_links; l++) {
+ struct media_link *link = &source->links[l];
+
+ if (link->source->entity == source &&
+ link->sink->entity == sink)
+ return link;
+ }
+
+ return NULL;
+}
+
+struct ipipe_descriptor *path_allocate(struct media_device *media,
+ const struct capture_pipeline *pipe)
+{
+ struct ipipe_descriptor *image_path;
+ struct sub_module *sub;
+ struct media_entity *entity;
+ const char *entity_name;
+ int i;
+
+ if (!media || !pipe) {
+ MC_PLUGIN_PRINTF("NULL pointer\n");
+ return NULL;
+ }
+
+ image_path = malloc(sizeof(*image_path));
+ if (!image_path) {
+ perror("image path");
+ return NULL;
+ }
+
+ image_path->pipe = pipe;
+ INIT_LIST_HEAD(&image_path->container);
+
+ for (i = 0; ; i++) {
+ entity_name = (char *)pipe->path[i];
+ if (strlen(entity_name) == 0)
+ break;
+
+ entity = media_get_entity_by_name(media, entity_name, strlen(entity_name));
+ if (!entity) {
+ MC_PLUGIN_PRINTF("Can't find entity [%s]\n", entity_name);
+ continue;
+ }
+
+ sub = submodule_alloc();
+ if (sub) {
+ sub->entity = entity;
+ list_add_tail(&sub->list, &image_path->container);
+ }
+ }
+
+ return image_path;
+}
+
+struct sub_module *submodule_alloc()
+{
+ struct sub_module *sb = NULL;
+
+ sb = malloc(sizeof (*sb));
+ if (!sb) {
+ MC_PLUGIN_PRINTF("Can not allocate module\n");
+ return sb;
+ }
+
+ sb->entity = NULL;
+ INIT_LIST_HEAD(&sb->list);
+
+ return sb;
+}
+
+void submodule_free(struct sub_module *sb)
+{
+ free(sb);
+ sb = NULL;
+}
+
+struct sub_module *path_destination_submodule(struct ipipe_descriptor *path)
+{
+ struct sub_module *next, *last;
+
+ if (NULL == path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return NULL;
+ }
+
+ last = NULL;
+ list_for_each_entry(next, &path->container, list)
+ last = next;
+
+ return last;
+}
+
+int path_power_on(struct ipipe_descriptor *path, int fd)
+{
+ struct sub_module *sub_mod, *next_sub_mod;
+ int last_sm, err = 0;
+
+ if (NULL == path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ list_for_each_entry(sub_mod, &path->container, list) {
+ next_sub_mod = list_entry(sub_mod->list.next, typeof(*sub_mod), list);
+ last_sm = &next_sub_mod->list == &path->container;
+ err += submodule_open(sub_mod, fd, last_sm);
+ }
+
+ return err;
+}
+
+int submodule_open(struct sub_module *sb, int fd, int last_sm)
+{
+ int err = 0;
+
+ if (!sb) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ if (sb->entity->fd < 0)
+ sb->entity->fd = SYS_OPEN(sb->entity->devname, O_RDWR, 0);
+
+ if (sb->entity->fd < 0)
+ err = -1;
+
+ if (last_sm && err != -1) {
+ int dr;
+ dr = dup2(sb->entity->fd, fd);
+ close(sb->entity->fd);
+ sb->entity->fd = fd;
+ }
+
+ return err;
+}
+
+int path_connect_entities(struct media_device *media,
+ struct ipipe_descriptor *path)
+{
+ struct media_entity *source, *sink;
+ struct media_link *link;
+ const char *sink_name, *source_name;
+ int i, err = 0;
+
+ if (!media || !path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ source_name = (char *)path->pipe->path[0];
+ sink_name = (char *)path->pipe->path[1];
+ i = 1;
+
+ while (strlen(source_name) != 0) {
+
+ sink_name = (char *)path->pipe->path[i];
+ if (strlen(sink_name) == 0)
+ break;
+
+ source = media_get_entity_by_name(media, source_name, strlen(source_name));
+ sink = media_get_entity_by_name(media, sink_name, strlen(sink_name));
+
+ if ((NULL == sink) || (NULL == source)) {
+ MC_PLUGIN_PRINTF("Error finding entities\n");
+ err = -1;
+ break;
+ }
+
+ link = media_find_link(media, source, sink);
+
+ /* Do not explicitly setup immutable links */
+ if (!(link->flags & MEDIA_LINK_FLAG_IMMUTABLE)) {
+ err = media_setup_link(media, link->source, link->sink,
+ MEDIA_LINK_FLAG_ACTIVE);
+ } else {
+ if (!(link->flags & MEDIA_LINK_FLAG_ACTIVE)) {
+ MC_PLUGIN_PRINTF("Immutable link is not activated\n");
+ err = -1;
+ }
+ }
+
+ if (err < 0) {
+ MC_PLUGIN_PRINTF("Fail to connect %s->%s\n", source_name, sink_name);
+ break;
+ }
+
+ source_name = sink_name;
+ i++;
+ }
+
+ return err;
+}
+
+void path_power_off(struct ipipe_descriptor *path)
+{
+ struct sub_module *sub_mod, *next_sub_mod;
+ int last_sm;
+
+ if (NULL == path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return;
+ }
+
+ list_for_each_entry(sub_mod, &path->container, list) {
+ next_sub_mod = list_entry(sub_mod->list.next, typeof(*sub_mod), list);
+ last_sm = &next_sub_mod->list == &path->container;
+ submodule_power_off(sub_mod, last_sm);
+ }
+
+}
+
+int submodule_power_off(struct sub_module *sb, int last_sm)
+{
+ if (!sb) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ if (sb->entity->fd > 0 && !last_sm)
+ SYS_CLOSE(sb->entity->fd);
+
+ sb->entity->fd = -1;
+
+ return 0;
+}
+
+int path_disconnect_entities(struct media_device *media,
+ struct ipipe_descriptor *path)
+{
+ struct media_entity *source, *sink;
+ struct media_link *link;
+ const char *sink_name, *source_name;
+ int i, err = 0;
+
+ if (!media || !path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ source_name = (char *)path->pipe->path[0];
+ sink_name = (char *)path->pipe->path[1];
+ i = 1;
+
+ while (strlen(source_name) != 0) {
+
+ sink_name = (char *)path->pipe->path[i];
+ if (strlen(sink_name) == 0)
+ break;
+
+ source = media_get_entity_by_name(media, source_name, strlen(source_name));
+ sink = media_get_entity_by_name(media, sink_name, strlen(sink_name));
+
+ if ((NULL == sink) || (NULL == source)) {
+ MC_PLUGIN_PRINTF("Error finding entities\n");
+ err = -1;
+ break;
+ }
+
+ link = media_find_link(media, source, sink);
+
+ /* Do not explicitly setup immutable links */
+ if (!(link->flags & MEDIA_LINK_FLAG_IMMUTABLE))
+ err = media_setup_link(media, link->source, link->sink,
+ (link->flags & ~MEDIA_LINK_FLAG_ACTIVE));
+
+ source_name = sink_name;
+ i++;
+ }
+
+ return err;
+}
+
+int path_enum_src_framesizes(struct omap3mcplugin *plugin,
+ enum mc_plugin_pixelformat *pixfmt,
+ struct v4l2_rect *res, int max_rect)
+{
+ struct media_entity *source, *sink;
+ const char *sink_name, *source_name;
+ struct media_link *link;
+ int ret = -1;
+ struct v4l2_subdev_frame_size_enum size;
+
+ if (!plugin || !pixfmt || !res) {
+ MC_PLUGIN_PRINTF("NULL pointer");
+ return -1;
+ }
+
+ source_name = (char *)plugin->path->pipe->path[0];
+ sink_name = (char *)plugin->path->pipe->path[1];
+
+ source = media_get_entity_by_name(plugin->media, source_name, strlen(source_name));
+ sink = media_get_entity_by_name(plugin->media, sink_name, strlen(sink_name));
+
+ if ((NULL == sink) || (NULL == source)) {
+ MC_PLUGIN_PRINTF("Error finding entities\n");
+ errno = EBADF;
+ return -1;
+ }
+
+ link = media_find_link(plugin->media, source, sink);
+
+ if (NULL == link) {
+ MC_PLUGIN_PRINTF("No link present between source and sink\n");
+ errno = EBADF;
+ return -1;
+ }
+
+ memset(&size, 0, sizeof(size));
+
+ size.index = 0;
+ size.code = pixel_mc_plugin_to_subdev(*pixfmt);
+ size.pad = link->source->index;
+
+ while (0 == SYS_IOCTL(source->fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &size)) {
+ /* NOTE : min_width min_height and max_width max_height */
+ /* are equal for now so take just one of them */
+ ret = 0;
+ res[size.index].width = size.max_width;
+ res[size.index].height = size.max_height;
+
+ ++size.index;
+ if (size.index >= max_rect)
+ break;
+
+ }
+
+ return ret;
+}
+
+int path_set_resolution(struct omap3mcplugin *plugin,
+ struct v4l2_rect *src_res,
+ enum mc_plugin_pixelformat *src_pix,
+ struct v4l2_rect *dst_res,
+ enum mc_plugin_pixelformat *dst_pix)
+{
+ struct media_link *link = NULL;
+ struct sub_module *pos, *source = NULL, *sink = NULL;
+ struct v4l2_rect res;
+ struct v4l2_format format;
+ struct v4l2_subdev_format subdev_fmt;
+ enum mc_plugin_pixelformat source_pix, sink_pix;
+ int first_submodule, err = -1;
+
+ if (!plugin || !src_res || !src_pix ||
+ !dst_res || !dst_pix) {
+
+ MC_PLUGIN_PRINTF("NULL pointer\n");
+ return -1;
+ }
+
+ if (!src_res->width || !src_res->height || MC_PLUGIN_PIX_FMT_INVALID == *src_pix ||
+ !dst_res->width || !dst_res->height || MC_PLUGIN_PIX_FMT_INVALID == *dst_pix) {
+
+ MC_PLUGIN_PRINTF("Wrong input argumets\n");
+ return -1;
+ }
+
+ source_pix = *src_pix;
+ sink_pix = *src_pix;
+ res = *src_res;
+
+ first_submodule = 1;
+ list_for_each_entry(pos, &plugin->path->container, list) {
+
+ /* If first submodule just set source pixel format and resolution */
+ if (NULL == source) {
+ source = pos;
+ continue;
+ }
+
+ /* If we reach last submodule apply destination resolution */
+ if (media_entity_type(pos->entity) == MEDIA_ENTITY_TYPE_NODE && sink) {
+ res = *dst_res;
+
+ memset (&format, 0x0, sizeof (struct v4l2_format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = SYS_IOCTL(pos->entity->fd, VIDIOC_G_FMT, &format);
+ if (err < 0) {
+ perror("VIDIOC_G_FMT:");
+ break;
+ }
+
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ format.fmt.pix.width = dst_res->width;
+ format.fmt.pix.height = dst_res->height;
+ format.fmt.pix.pixelformat = pixel_mc_plugin_to_v4l(*dst_pix);
+ format.fmt.pix.field = V4L2_FIELD_ANY;
+
+ err = SYS_IOCTL(pos->entity->fd, VIDIOC_S_FMT, &format);
+ if (err < 0) {
+ perror("VIDIOC_S_FMT:");
+ break;
+ }
+ }
+
+ sink = pos;
+
+ link = media_find_link(plugin->media, source->entity, sink->entity);
+
+ if (link == NULL) {
+ MC_PLUGIN_PRINTF("No link present between source and sink\n");
+ err = -1;
+ break;
+ }
+
+ if (!(link->flags & MEDIA_LINK_FLAG_ACTIVE)) {
+ MC_PLUGIN_PRINTF("This link is not active\n");
+ err = -1;
+ break;
+ }
+
+ /* Set source format */
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(source_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->source->index;
+
+ err = SYS_IOCTL(source->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error set source format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ source_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ if (media_entity_type(pos->entity) == MEDIA_ENTITY_TYPE_NODE && sink)
+ break;
+
+ /* Set sink format */
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(sink_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->sink->index;
+
+ err = SYS_IOCTL(sink->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error set sink format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ sink_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ /* Sink pix is not supported modify source pixelformat also */
+ if (source_pix != sink_pix) {
+ source_pix = sink_pix;
+
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(source_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->source->index;
+
+ err = SYS_IOCTL(source->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error set source format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ source_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ err += (source_pix == sink_pix) ? 0 : -1;
+ }
+
+ if (err < 0) {
+ fprintf(stderr, "Error set source format for second time %s\n", source->entity->info.name);
+ break;
+ }
+
+ /* Store correct source pixel format and resolution */
+ if (first_submodule) {
+ *src_pix = source_pix;
+ *src_res = res;
+ first_submodule = 0;
+ }
+
+ /* Try to set destination pixel fmt */
+ source_pix = sink_pix = *dst_pix;
+ /* Continue with next element */
+ source = sink;
+ }
+
+ /* Set Destination resolution and pixel format */
+ if (0 == err) {
+ *dst_pix = sink_pix;
+ *dst_res = res;
+ }
+
+ return err;
+}
+
+int path_try_resolution(struct omap3mcplugin *plugin,
+ struct v4l2_rect *src_res,
+ enum mc_plugin_pixelformat *src_pix,
+ struct v4l2_rect *dst_res,
+ enum mc_plugin_pixelformat *dst_pix)
+{
+ struct media_link *link = NULL;
+ struct sub_module *pos, *source = NULL, *sink = NULL;
+ struct v4l2_rect res;
+ struct v4l2_subdev_format subdev_fmt;
+ enum mc_plugin_pixelformat source_pix, sink_pix;
+ int first_submodule, err = -1;
+
+ if (!plugin || !src_res || !src_pix ||
+ !dst_res || !dst_pix) {
+
+ MC_PLUGIN_PRINTF("NULL pointer\n"
+ " plugin=%p\n"
+ " src_res=%p, src_pix=%p\n"
+ " dst_res=%p, dst_pix=%p\n",
+ plugin,
+ src_res, src_pix,
+ dst_res, dst_pix);
+
+ return -1;
+ }
+
+ if (!src_res->width || !src_res->height || MC_PLUGIN_PIX_FMT_INVALID == *src_pix ||
+ !dst_res->width || !dst_res->height || MC_PLUGIN_PIX_FMT_INVALID == *dst_pix) {
+
+ MC_PLUGIN_PRINTF("Wrong input argumets\n"
+ " Source format: Width = %d, Height = %d, Format = %d\n"
+ " Destination format: Width = %d, Height = %d, Format = %d\n",
+ src_res->width, src_res->height, *src_pix,
+ dst_res->width, dst_res->height, *dst_pix);
+ return -1;
+ }
+
+ source_pix = *src_pix;
+ sink_pix = *src_pix;
+ res = *src_res;
+
+ first_submodule = 1;
+ list_for_each_entry(pos, &plugin->path->container, list) {
+
+ /* If first submodule just set source pixel format and resolution */
+ if (NULL == source) {
+ source = pos;
+ continue;
+ }
+
+ /* If we reach last submodule apply destination resolution */
+ if (media_entity_type(pos->entity) == MEDIA_ENTITY_TYPE_NODE && sink)
+ res = *dst_res;
+
+ sink = pos;
+
+ link = media_find_link(plugin->media, source->entity, sink->entity);
+
+ if (NULL == link) {
+ MC_PLUGIN_PRINTF("No link present between source and sink\n");
+ err = -1;
+ break;
+ }
+
+ if (!(link->flags & MEDIA_LINK_FLAG_ACTIVE)) {
+ MC_PLUGIN_PRINTF("This link is not active\n");
+ err = -1;
+ break;
+ }
+
+ /* Set source format */
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(source_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_TRY;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->source->index;
+
+ err = SYS_IOCTL(source->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error try source format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ source_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ if (media_entity_type(pos->entity) == MEDIA_ENTITY_TYPE_NODE && sink)
+ break;
+
+ /* Set sink format */
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(sink_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_TRY;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->sink->index;
+
+ err = SYS_IOCTL(sink->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ MC_PLUGIN_PRINTF("Error try sink format\n");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ sink_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ /* Sink pix is not supported modify source pixelformat also */
+ if (source_pix != sink_pix) {
+ source_pix = sink_pix;
+
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(source_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_TRY;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->source->index;
+
+ err = SYS_IOCTL(source->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error try source format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ source_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ err += (source_pix == sink_pix) ? 0 : -1;
+ }
+
+ if (err < 0) {
+ fprintf(stderr, "Error try source format for second time %s\n", source->entity->info.name);
+ break;
+ }
+
+ /* Store correct source pixel format and resolution */
+ if (first_submodule) {
+ *src_pix = source_pix;
+ *src_res = res;
+ first_submodule = 0;
+ }
+
+ /* Try to set destination pixel fmt */
+ source_pix = sink_pix = *dst_pix;
+ /* Continue with next element */
+ source = sink;
+ }
+
+ /* Set Destination resolution and pixel format */
+ if (0 == err) {
+ *dst_pix = sink_pix;
+ *dst_res = res;
+ }
+
+ return err;
+}
new file mode 100644
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifndef __PATHS_H__
+#define __PATHS_H__
+
+#include <linux/videodev2.h>
+#include <mediactl/media.h>
+
+#include "libv4l2plugin-omap3mc.h"
+
+struct media_link *media_find_link(struct media_device *media,
+ struct media_entity *source,
+ struct media_entity *sink);
+int pixel_mc_plugin_to_subdev(enum mc_plugin_pixelformat pixfmt);
+enum mc_plugin_pixelformat pixel_subdev_to_mc_plugin(int pixfmt);
+int pixel_mc_plugin_to_v4l(enum mc_plugin_pixelformat pixfmt);
+enum mc_plugin_pixelformat pixel_v4l_to_mc_plugin(int pixfmt);
+const struct capture_pipeline *pipe_sensor_yuv(int primary);
+struct ipipe_descriptor *path_allocate(struct media_device *media,
+ const struct capture_pipeline *pipe);
+struct sub_module *submodule_alloc();
+void submodule_free(struct sub_module *sb);
+struct sub_module *path_destination_submodule(struct ipipe_descriptor *path);
+int path_power_on(struct ipipe_descriptor *path, int fd);
+int submodule_open(struct sub_module *sb, int fd, int last_sb);
+int path_connect_entities(struct media_device *media,
+ struct ipipe_descriptor *path);
+void path_power_off(struct ipipe_descriptor *path);
+int submodule_power_off(struct sub_module *sb, int last_sb);
+int path_disconnect_entities(struct media_device *media,
+ struct ipipe_descriptor *path);
+int path_enum_src_framesizes(struct omap3mcplugin *plugin,
+ enum mc_plugin_pixelformat *pixfmt,
+ struct v4l2_rect *res, int max_rect);
+int path_set_resolution(struct omap3mcplugin *plugin,
+ struct v4l2_rect *src_res,
+ enum mc_plugin_pixelformat *src_pix,
+ struct v4l2_rect *dst_res,
+ enum mc_plugin_pixelformat *dst_pix);
+int path_try_resolution(struct omap3mcplugin *plugin,
+ struct v4l2_rect *src_res,
+ enum mc_plugin_pixelformat *src_pix,
+ struct v4l2_rect *dst_res,
+ enum mc_plugin_pixelformat *dst_pix);
+
+
+#endif /* __PATHS_H__ */
new file mode 100644
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifndef __SINGLE_LINKED_LIST_H__
+#define __SINGLE_LINKED_LIST_H__
+
+/* Simple single linked list implementation. */
+
+struct list_head {
+ struct list_head *next;
+};
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+}
+
+/* Insert new node after known node */
+static inline void list_add_after(struct list_head *new,
+ struct list_head *prev)
+{
+ new->next = prev->next;
+ prev->next = new;
+}
+
+/* Insert new node at the end of the list */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ struct list_head *element = head;
+
+ while (element->next != head)
+ element = element->next;
+
+ list_add_after(new, element);
+}
+
+ /* Get the struct for this entry */
+#define list_entry(ptr, type, member)({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ ((type *)(void *)( (char *)__mptr - offsetof(type,member) ));})
+
+
+/* Iterate over the list */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#endif
Add Makefile. Add files for Media Controller pipelines initialization, configuration and destruction. Add file for list operations. Add config file. Signed-off-by: Yordan Kamenov <ykamenov@mm-sol.com> --- Makefile | 30 ++ omap3-mc.conf | 82 +++++ paths.c | 959 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ paths.h | 64 ++++ sl_list.h | 65 ++++ 5 files changed, 1200 insertions(+), 0 deletions(-) create mode 100644 Makefile create mode 100644 omap3-mc.conf create mode 100644 paths.c create mode 100644 paths.h create mode 100644 sl_list.h