summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-3.10/0111-bcm2835-add-v4l2-camera-device.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-3.10/0111-bcm2835-add-v4l2-camera-device.patch')
-rw-r--r--target/linux/brcm2708/patches-3.10/0111-bcm2835-add-v4l2-camera-device.patch5938
1 files changed, 5938 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-3.10/0111-bcm2835-add-v4l2-camera-device.patch b/target/linux/brcm2708/patches-3.10/0111-bcm2835-add-v4l2-camera-device.patch
new file mode 100644
index 0000000000..8f731afe87
--- /dev/null
+++ b/target/linux/brcm2708/patches-3.10/0111-bcm2835-add-v4l2-camera-device.patch
@@ -0,0 +1,5938 @@
+From 2ba75a0486033660ce65c2dd2406d619fe73a20b Mon Sep 17 00:00:00 2001
+From: Vincent Sanders <vincent.sanders@collabora.co.uk>
+Date: Wed, 30 Jan 2013 12:45:18 +0000
+Subject: [PATCH 111/174] bcm2835: add v4l2 camera device
+
+- Supports raw YUV capture, preview, JPEG and H264.
+- Uses videobuf2 for data transfer, using dma_buf.
+- Uses 3.6.10 timestamping
+- Camera power based on use
+- Uses immutable input mode on video encoder
+
+Signed-off-by: Daniel Stone <daniels@collabora.com>
+Signed-off-by: Luke Diamand <luked@broadcom.com>
+---
+ Documentation/video4linux/bcm2835-v4l2.txt | 60 +
+ drivers/media/platform/Kconfig | 1 +
+ drivers/media/platform/Makefile | 2 +
+ drivers/media/platform/bcm2835/Kconfig | 25 +
+ drivers/media/platform/bcm2835/Makefile | 5 +
+ drivers/media/platform/bcm2835/bcm2835-camera.c | 1478 +++++++++++++++++
+ drivers/media/platform/bcm2835/bcm2835-camera.h | 113 ++
+ drivers/media/platform/bcm2835/controls.c | 725 ++++++++
+ drivers/media/platform/bcm2835/mmal-common.h | 52 +
+ drivers/media/platform/bcm2835/mmal-encodings.h | 93 ++
+ drivers/media/platform/bcm2835/mmal-msg-common.h | 50 +
+ drivers/media/platform/bcm2835/mmal-msg-format.h | 81 +
+ drivers/media/platform/bcm2835/mmal-msg-port.h | 107 ++
+ drivers/media/platform/bcm2835/mmal-msg.h | 404 +++++
+ drivers/media/platform/bcm2835/mmal-parameters.h | 539 ++++++
+ drivers/media/platform/bcm2835/mmal-vchiq.c | 1916 ++++++++++++++++++++++
+ drivers/media/platform/bcm2835/mmal-vchiq.h | 178 ++
+ 17 files changed, 5829 insertions(+)
+ create mode 100644 Documentation/video4linux/bcm2835-v4l2.txt
+ create mode 100644 drivers/media/platform/bcm2835/Kconfig
+ create mode 100644 drivers/media/platform/bcm2835/Makefile
+ create mode 100644 drivers/media/platform/bcm2835/bcm2835-camera.c
+ create mode 100644 drivers/media/platform/bcm2835/bcm2835-camera.h
+ create mode 100644 drivers/media/platform/bcm2835/controls.c
+ create mode 100644 drivers/media/platform/bcm2835/mmal-common.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-encodings.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-msg-common.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-msg-format.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-msg-port.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-msg.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-parameters.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-vchiq.c
+ create mode 100644 drivers/media/platform/bcm2835/mmal-vchiq.h
+
+--- /dev/null
++++ b/Documentation/video4linux/bcm2835-v4l2.txt
+@@ -0,0 +1,60 @@
++
++BCM2835 (aka Raspberry Pi) V4L2 driver
++======================================
++
++1. Copyright
++============
++
++Copyright © 2013 Raspberry Pi (Trading) Ltd.
++
++2. License
++==========
++
++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., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++3. Quick Start
++==============
++
++You need a version 1.0 or later of v4l2-ctl, available from:
++ git://git.linuxtv.org/v4l-utils.git
++
++$ sudo modprobe bcm2835-v4l2
++
++Turn on the overlay:
++
++$ v4l2-ctl --overlay=1
++
++Turn off the overlay:
++
++$ v4l2-ctl --overlay=0
++
++Set the capture format for video:
++
++$ v4l2-ctl --set-fmt-video=width=1920,height=1088,pixelformat=4
++
++(Note: 1088 not 1080).
++
++Capture:
++
++$ v4l2-ctl --stream-mmap=3 --stream-count=100 --stream-to=somefile.h264
++
++Stills capture:
++
++$ v4l2-ctl --set-fmt-video=width=2592,height=1944,pixelformat=3
++$ v4l2-ctl --stream-mmap=3 --stream-count=1 --stream-to=somefile.jpg
++
++List of available formats:
++
++$ v4l2-ctl --list-formats
+--- a/drivers/media/platform/Kconfig
++++ b/drivers/media/platform/Kconfig
+@@ -124,6 +124,7 @@ config VIDEO_S3C_CAMIF
+ source "drivers/media/platform/soc_camera/Kconfig"
+ source "drivers/media/platform/exynos4-is/Kconfig"
+ source "drivers/media/platform/s5p-tv/Kconfig"
++source "drivers/media/platform/bcm2835/Kconfig"
+
+ endif # V4L_PLATFORM_DRIVERS
+
+--- a/drivers/media/platform/Makefile
++++ b/drivers/media/platform/Makefile
+@@ -50,4 +50,6 @@ obj-y += davinci/
+
+ obj-$(CONFIG_ARCH_OMAP) += omap/
+
++obj-$(CONFIG_VIDEO_BCM2835) += bcm2835/
++
+ ccflags-y += -I$(srctree)/drivers/media/i2c
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/Kconfig
+@@ -0,0 +1,25 @@
++# Broadcom VideoCore IV v4l2 camera support
++
++config VIDEO_BCM2835
++ bool "Broadcom BCM2835 camera interface driver"
++ depends on VIDEO_V4L2 && ARCH_BCM2708
++ ---help---
++ Say Y here to enable camera host interface devices for
++ Broadcom BCM2835 SoC. This operates over the VCHIQ interface
++ to a service running on VideoCore.
++
++
++if VIDEO_BCM2835
++
++config VIDEO_BCM2835_MMAL
++ tristate "Broadcom BM2835 MMAL camera interface driver"
++ depends on BCM2708_VCHIQ
++ select VIDEOBUF2_VMALLOC
++ ---help---
++ This is a V4L2 driver for the Broadcom BCM2835 MMAL camera host interface
++
++ To compile this driver as a module, choose M here: the
++ module will be called bcm2835-v4l2.o
++
++
++endif # VIDEO_BM2835
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/Makefile
+@@ -0,0 +1,5 @@
++bcm2835-v4l2-objs := bcm2835-camera.o controls.o mmal-vchiq.o
++
++obj-$(CONFIG_VIDEO_BCM2835_MMAL) += bcm2835-v4l2.o
++
++ccflags-$(CONFIG_VIDEO_BCM2835) += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
+@@ -0,0 +1,1478 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <media/videobuf2-vmalloc.h>
++#include <media/videobuf2-dma-contig.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-common.h>
++#include <linux/delay.h>
++
++#include "mmal-common.h"
++#include "mmal-encodings.h"
++#include "mmal-vchiq.h"
++#include "mmal-msg.h"
++#include "mmal-parameters.h"
++#include "bcm2835-camera.h"
++
++#define BM2835_MMAL_VERSION "0.0.2"
++#define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2"
++
++#define MAX_WIDTH 2592
++#define MAX_HEIGHT 1944
++#define MIN_BUFFER_SIZE (80*1024)
++
++#define MAX_VIDEO_MODE_WIDTH 1280
++#define MAX_VIDEO_MODE_HEIGHT 720
++
++MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
++MODULE_AUTHOR("Vincent Sanders");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(BM2835_MMAL_VERSION);
++
++int bcm2835_v4l2_debug;
++module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
++MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
++
++static struct bm2835_mmal_dev *gdev; /* global device data */
++
++/* video formats */
++static struct mmal_fmt formats[] = {
++ {
++ .name = "4:2:0, packed YUV",
++ .fourcc = V4L2_PIX_FMT_YUV420,
++ .mmal = MMAL_ENCODING_I420,
++ .depth = 12,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ },
++ {
++ .name = "4:2:2, packed, YUYV",
++ .fourcc = V4L2_PIX_FMT_YUYV,
++ .mmal = MMAL_ENCODING_YUYV,
++ .depth = 16,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ },
++ {
++ .name = "RGB24 (BE)",
++ .fourcc = V4L2_PIX_FMT_BGR24,
++ .mmal = MMAL_ENCODING_BGR24,
++ .depth = 24,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ },
++ {
++ .name = "JPEG",
++ .fourcc = V4L2_PIX_FMT_JPEG,
++ .mmal = MMAL_ENCODING_JPEG,
++ .depth = 8,
++ .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
++ },
++ {
++ .name = "H264",
++ .fourcc = V4L2_PIX_FMT_H264,
++ .mmal = MMAL_ENCODING_H264,
++ .depth = 8,
++ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
++ }
++};
++
++static struct mmal_fmt *get_format(struct v4l2_format *f)
++{
++ struct mmal_fmt *fmt;
++ unsigned int k;
++
++ for (k = 0; k < ARRAY_SIZE(formats); k++) {
++ fmt = &formats[k];
++ if (fmt->fourcc == f->fmt.pix.pixelformat)
++ break;
++ }
++
++ if (k == ARRAY_SIZE(formats))
++ return NULL;
++
++ return &formats[k];
++}
++
++/* ------------------------------------------------------------------
++ Videobuf queue operations
++ ------------------------------------------------------------------*/
++
++static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
++ unsigned int *nbuffers, unsigned int *nplanes,
++ unsigned int sizes[], void *alloc_ctxs[])
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++ unsigned long size;
++
++ /* refuse queue setup if port is not configured */
++ if (dev->capture.port == NULL) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s: capture port not configured\n", __func__);
++ return -EINVAL;
++ }
++
++ size = dev->capture.port->current_buffer.size;
++ if (size == 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s: capture port buffer size is zero\n", __func__);
++ return -EINVAL;
++ }
++
++ if (*nbuffers < (dev->capture.port->current_buffer.num + 2))
++ *nbuffers = (dev->capture.port->current_buffer.num + 2);
++
++ *nplanes = 1;
++
++ sizes[0] = size;
++
++ /*
++ * videobuf2-vmalloc allocator is context-less so no need to set
++ * alloc_ctxs array.
++ */
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
++ __func__, dev);
++
++ return 0;
++}
++
++static int buffer_prepare(struct vb2_buffer *vb)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
++ unsigned long size;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
++ __func__, dev);
++
++ BUG_ON(dev->capture.port == NULL);
++ BUG_ON(dev->capture.fmt == NULL);
++
++ size = dev->capture.stride * dev->capture.height;
++ if (vb2_plane_size(vb, 0) < size) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s data will not fit into plane (%lu < %lu)\n",
++ __func__, vb2_plane_size(vb, 0), size);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static inline bool is_capturing(struct bm2835_mmal_dev *dev)
++{
++ return dev->capture.camera_port ==
++ &dev->
++ component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
++}
++
++static void buffer_cb(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ int status,
++ struct mmal_buffer *buf,
++ unsigned long length, u32 mmal_flags, s64 dts, s64 pts)
++{
++ struct bm2835_mmal_dev *dev = port->cb_ctx;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
++ __func__, status, buf, length, mmal_flags, pts);
++
++ if (status != 0) {
++ /* error in transfer */
++ if (buf != NULL) {
++ /* there was a buffer with the error so return it */
++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
++ }
++ return;
++ } else if (length == 0) {
++ /* stream ended */
++ if (buf != NULL) {
++ /* this should only ever happen if the port is
++ * disabled and there are buffers still queued
++ */
++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
++ pr_debug("Empty buffer");
++ } else if (dev->capture.frame_count) {
++ /* grab another frame */
++ if (is_capturing(dev)) {
++ pr_debug("Grab another frame");
++ vchiq_mmal_port_parameter_set(
++ instance,
++ dev->capture.
++ camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.
++ frame_count,
++ sizeof(dev->capture.frame_count));
++ }
++ } else {
++ /* signal frame completion */
++ complete(&dev->capture.frame_cmplt);
++ }
++ } else {
++ if (dev->capture.frame_count) {
++ if (dev->capture.vc_start_timestamp != -1) {
++ s64 runtime_us = pts -
++ dev->capture.vc_start_timestamp;
++ u32 div = 0;
++ u32 rem = 0;
++
++ div =
++ div_u64_rem(runtime_us, USEC_PER_SEC, &rem);
++ buf->vb.v4l2_buf.timestamp.tv_sec =
++ dev->capture.kernel_start_ts.tv_sec - 1 +
++ div;
++ buf->vb.v4l2_buf.timestamp.tv_usec =
++ dev->capture.kernel_start_ts.tv_usec + rem;
++
++ if (buf->vb.v4l2_buf.timestamp.tv_usec >=
++ USEC_PER_SEC) {
++ buf->vb.v4l2_buf.timestamp.tv_sec++;
++ buf->vb.v4l2_buf.timestamp.tv_usec -=
++ USEC_PER_SEC;
++ }
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Convert start time %d.%06d and %llu"
++ "with offset %llu to %d.%06d\n",
++ (int)dev->capture.kernel_start_ts.
++ tv_sec,
++ (int)dev->capture.kernel_start_ts.
++ tv_usec,
++ dev->capture.vc_start_timestamp, pts,
++ (int)buf->vb.v4l2_buf.timestamp.tv_sec,
++ (int)buf->vb.v4l2_buf.timestamp.
++ tv_usec);
++ } else {
++ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
++ }
++
++ vb2_set_plane_payload(&buf->vb, 0, length);
++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
++
++ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
++ is_capturing(dev)) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Grab another frame as buffer has EOS");
++ vchiq_mmal_port_parameter_set(
++ instance,
++ dev->capture.
++ camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.
++ frame_count,
++ sizeof(dev->capture.frame_count));
++ }
++ } else {
++ /* signal frame completion */
++ complete(&dev->capture.frame_cmplt);
++ }
++ }
++}
++
++static int enable_camera(struct bm2835_mmal_dev *dev)
++{
++ int ret;
++ if (!dev->camera_use_count) {
++ ret = vchiq_mmal_component_enable(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed enabling camera, ret %d\n", ret);
++ return -EINVAL;
++ }
++ }
++ dev->camera_use_count++;
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev, "enabled camera (refcount %d)\n",
++ dev->camera_use_count);
++ return 0;
++}
++
++static int disable_camera(struct bm2835_mmal_dev *dev)
++{
++ int ret;
++ if (!dev->camera_use_count) {
++ v4l2_err(&dev->v4l2_dev,
++ "Disabled the camera when already disabled\n");
++ return -EINVAL;
++ }
++ dev->camera_use_count--;
++ if (!dev->camera_use_count) {
++ unsigned int i = 0xFFFFFFFF;
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Disabling camera\n");
++ ret =
++ vchiq_mmal_component_disable(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed disabling camera, ret %d\n", ret);
++ return -EINVAL;
++ }
++ vchiq_mmal_port_parameter_set(
++ dev->instance,
++ &dev->component[MMAL_COMPONENT_CAMERA]->control,
++ MMAL_PARAMETER_CAMERA_NUM, &i,
++ sizeof(i));
++ }
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Camera refcount now %d\n", dev->camera_use_count);
++ return 0;
++}
++
++static void buffer_queue(struct vb2_buffer *vb)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
++ struct mmal_buffer *buf = container_of(vb, struct mmal_buffer, vb);
++ int ret;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: dev:%p buf:%p\n", __func__, dev, buf);
++
++ buf->buffer = vb2_plane_vaddr(&buf->vb, 0);
++ buf->buffer_size = vb2_plane_size(&buf->vb, 0);
++
++ ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf);
++ if (ret < 0)
++ v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n",
++ __func__);
++}
++
++static int start_streaming(struct vb2_queue *vq, unsigned int count)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++ int ret;
++ int parameter_size;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
++ __func__, dev);
++
++ /* ensure a format has actually been set */
++ if (dev->capture.port == NULL)
++ return -EINVAL;
++
++ if (enable_camera(dev) < 0) {
++ v4l2_err(&dev->v4l2_dev, "Failed to enable camera\n");
++ return -EINVAL;
++ }
++
++ /*init_completion(&dev->capture.frame_cmplt); */
++
++ /* enable frame capture */
++ dev->capture.frame_count = 1;
++
++ /* if the preview is not already running, wait for a few frames for AGC
++ * to settle down.
++ */
++ if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
++ msleep(300);
++
++ /* enable the connection from camera to encoder (if applicable) */
++ if (dev->capture.camera_port != dev->capture.port
++ && dev->capture.camera_port) {
++ ret = vchiq_mmal_port_enable(dev->instance,
++ dev->capture.camera_port, NULL);
++ if (ret) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed to enable encode tunnel - error %d\n",
++ ret);
++ return -1;
++ }
++ }
++
++ /* Get VC timestamp at this point in time */
++ parameter_size = sizeof(dev->capture.vc_start_timestamp);
++ if (vchiq_mmal_port_parameter_get(dev->instance,
++ dev->capture.camera_port,
++ MMAL_PARAMETER_SYSTEM_TIME,
++ &dev->capture.vc_start_timestamp,
++ &parameter_size)) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed to get VC start time - update your VC f/w\n");
++
++ /* Flag to indicate just to rely on kernel timestamps */
++ dev->capture.vc_start_timestamp = -1;
++ } else
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Start time %lld size %d\n",
++ dev->capture.vc_start_timestamp, parameter_size);
++
++ v4l2_get_timestamp(&dev->capture.kernel_start_ts);
++
++ /* enable the camera port */
++ dev->capture.port->cb_ctx = dev;
++ ret =
++ vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
++ if (ret) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed to enable capture port - error %d\n", ret);
++ return -1;
++ }
++
++ /* capture the first frame */
++ vchiq_mmal_port_parameter_set(dev->instance,
++ dev->capture.camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.frame_count,
++ sizeof(dev->capture.frame_count));
++ return 0;
++}
++
++/* abort streaming and wait for last buffer */
++static int stop_streaming(struct vb2_queue *vq)
++{
++ int ret;
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
++ __func__, dev);
++
++ init_completion(&dev->capture.frame_cmplt);
++ dev->capture.frame_count = 0;
++
++ /* ensure a format has actually been set */
++ if (dev->capture.port == NULL)
++ return -EINVAL;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "stopping capturing\n");
++
++ /* stop capturing frames */
++ vchiq_mmal_port_parameter_set(dev->instance,
++ dev->capture.camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.frame_count,
++ sizeof(dev->capture.frame_count));
++
++ /* wait for last frame to complete */
++ ret = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
++ if (ret <= 0)
++ v4l2_err(&dev->v4l2_dev,
++ "error %d waiting for frame completion\n", ret);
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "disabling connection\n");
++
++ /* disable the connection from camera to encoder */
++ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port);
++ if (!ret && dev->capture.camera_port != dev->capture.port) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "disabling port\n");
++ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port);
++ } else if (dev->capture.camera_port != dev->capture.port) {
++ v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n",
++ ret);
++ }
++
++ if (disable_camera(dev) < 0) {
++ v4l2_err(&dev->v4l2_dev, "Failed to disable camera");
++ return -EINVAL;
++ }
++
++ return ret;
++}
++
++static void bm2835_mmal_lock(struct vb2_queue *vq)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++ mutex_lock(&dev->mutex);
++}
++
++static void bm2835_mmal_unlock(struct vb2_queue *vq)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++ mutex_unlock(&dev->mutex);
++}
++
++static struct vb2_ops bm2835_mmal_video_qops = {
++ .queue_setup = queue_setup,
++ .buf_prepare = buffer_prepare,
++ .buf_queue = buffer_queue,
++ .start_streaming = start_streaming,
++ .stop_streaming = stop_streaming,
++ .wait_prepare = bm2835_mmal_unlock,
++ .wait_finish = bm2835_mmal_lock,
++};
++
++/* ------------------------------------------------------------------
++ IOCTL operations
++ ------------------------------------------------------------------*/
++
++/* overlay ioctl */
++static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
++ struct v4l2_fmtdesc *f)
++{
++ struct mmal_fmt *fmt;
++
++ if (f->index >= ARRAY_SIZE(formats))
++ return -EINVAL;
++
++ fmt = &formats[f->index];
++
++ strlcpy(f->description, fmt->name, sizeof(f->description));
++ f->pixelformat = fmt->fourcc;
++
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++
++ f->fmt.win = dev->overlay;
++
++ return 0;
++}
++
++static int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ /* Only support one format so get the current one. */
++ vidioc_g_fmt_vid_overlay(file, priv, f);
++
++ /* todo: allow the size and/or offset to be changed. */
++ return 0;
++}
++
++static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++
++ vidioc_try_fmt_vid_overlay(file, priv, f);
++
++ dev->overlay = f->fmt.win;
++
++ /* todo: program the preview port parameters */
++ return 0;
++}
++
++static int vidioc_overlay(struct file *file, void *f, unsigned int on)
++{
++ int ret;
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ struct vchiq_mmal_port *src;
++ struct vchiq_mmal_port *dst;
++ struct mmal_parameter_displayregion prev_config = {
++ .set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_ALPHA |
++ MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN,
++ .layer = PREVIEW_LAYER,
++ .alpha = 255,
++ .fullscreen = 0,
++ .dest_rect = {
++ .x = dev->overlay.w.left,
++ .y = dev->overlay.w.top,
++ .width = dev->overlay.w.width,
++ .height = dev->overlay.w.height,
++ },
++ };
++
++ if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
++ (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
++ return 0; /* already in requested state */
++
++ src =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_PREVIEW];
++
++ if (!on) {
++ /* disconnect preview ports and disable component */
++ ret = vchiq_mmal_port_disable(dev->instance, src);
++ if (!ret)
++ ret =
++ vchiq_mmal_port_connect_tunnel(dev->instance, src,
++ NULL);
++ if (ret >= 0)
++ ret = vchiq_mmal_component_disable(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_PREVIEW]);
++
++ disable_camera(dev);
++ return ret;
++ }
++
++ /* set preview port format and connect it to output */
++ dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
++
++ ret = vchiq_mmal_port_set_format(dev->instance, src);
++ if (ret < 0)
++ goto error;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, dst,
++ MMAL_PARAMETER_DISPLAYREGION,
++ &prev_config, sizeof(prev_config));
++ if (ret < 0)
++ goto error;
++
++ if (enable_camera(dev) < 0)
++ goto error;
++
++ ret = vchiq_mmal_component_enable(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_PREVIEW]);
++ if (ret < 0)
++ goto error;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
++ src, dst);
++ ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
++ if (!ret)
++ ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
++error:
++ return ret;
++}
++
++static int vidioc_g_fbuf(struct file *file, void *fh,
++ struct v4l2_framebuffer *a)
++{
++ /* The video overlay must stay within the framebuffer and can't be
++ positioned independently. */
++ a->flags = V4L2_FBUF_FLAG_OVERLAY;
++
++ /* todo: v4l2_framebuffer still needs more info filling in
++ * in order to pass the v4l2-compliance test. */
++
++ return 0;
++}
++
++/* input ioctls */
++static int vidioc_enum_input(struct file *file, void *priv,
++ struct v4l2_input *inp)
++{
++ /* only a single camera input */
++ if (inp->index != 0)
++ return -EINVAL;
++
++ inp->type = V4L2_INPUT_TYPE_CAMERA;
++ sprintf(inp->name, "Camera %u", inp->index);
++ return 0;
++}
++
++static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
++{
++ *i = 0;
++ return 0;
++}
++
++static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
++{
++ if (i != 0)
++ return -EINVAL;
++
++ return 0;
++}
++
++/* capture ioctls */
++static int vidioc_querycap(struct file *file, void *priv,
++ struct v4l2_capability *cap)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ u32 major;
++ u32 minor;
++
++ vchiq_mmal_version(dev->instance, &major, &minor);
++
++ strcpy(cap->driver, "bm2835 mmal");
++ snprintf(cap->card, sizeof(cap->card), "mmal service %d.%d",
++ major, minor);
++
++ snprintf(cap->bus_info, sizeof(cap->bus_info),
++ "platform:%s", dev->v4l2_dev.name);
++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
++ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
++
++ return 0;
++}
++
++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_fmtdesc *f)
++{
++ struct mmal_fmt *fmt;
++
++ if (f->index >= ARRAY_SIZE(formats))
++ return -EINVAL;
++
++ fmt = &formats[f->index];
++
++ strlcpy(f->description, fmt->name, sizeof(f->description));
++ f->pixelformat = fmt->fourcc;
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++
++ f->fmt.pix.width = dev->capture.width;
++ f->fmt.pix.height = dev->capture.height;
++ f->fmt.pix.field = V4L2_FIELD_NONE;
++ f->fmt.pix.pixelformat = dev->capture.fmt->fourcc;
++ f->fmt.pix.bytesperline =
++ (f->fmt.pix.width * dev->capture.fmt->depth) >> 3;
++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
++ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG
++ && f->fmt.pix.sizeimage < (100 << 10)) {
++ /* Need a minimum size for JPEG to account for EXIF. */
++ f->fmt.pix.sizeimage = (100 << 10);
++ }
++
++ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_YUYV ||
++ dev->capture.fmt->fourcc == V4L2_PIX_FMT_UYVY)
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
++ else
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
++ f->fmt.pix.priv = 0;
++
++ v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
++ __func__);
++ return 0;
++}
++
++static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ struct mmal_fmt *mfmt;
++
++ mfmt = get_format(f);
++ if (!mfmt) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Fourcc format (0x%08x) unknown.\n",
++ f->fmt.pix.pixelformat);
++ f->fmt.pix.pixelformat = formats[0].fourcc;
++ mfmt = get_format(f);
++ }
++
++ f->fmt.pix.field = V4L2_FIELD_NONE;
++ /* image must be a multiple of 32 pixels wide and 16 lines high */
++ v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 5,
++ &f->fmt.pix.height, 32, MAX_HEIGHT, 4, 0);
++ f->fmt.pix.bytesperline = (f->fmt.pix.width * mfmt->depth) >> 3;
++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
++ if (f->fmt.pix.sizeimage < MIN_BUFFER_SIZE)
++ f->fmt.pix.sizeimage = MIN_BUFFER_SIZE;
++
++ if (mfmt->fourcc == V4L2_PIX_FMT_YUYV ||
++ mfmt->fourcc == V4L2_PIX_FMT_UYVY)
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
++ else
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
++ f->fmt.pix.priv = 0;
++
++ v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
++ __func__);
++ return 0;
++}
++
++static int mmal_setup_components(struct bm2835_mmal_dev *dev,
++ struct v4l2_format *f)
++{
++ int ret;
++ struct vchiq_mmal_port *port = NULL, *camera_port = NULL;
++ struct vchiq_mmal_component *encode_component = NULL;
++ struct mmal_fmt *mfmt = get_format(f);
++
++ BUG_ON(!mfmt);
++
++ if (dev->capture.encode_component) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "vid_cap - disconnect previous tunnel\n");
++
++ /* Disconnect any previous connection */
++ vchiq_mmal_port_connect_tunnel(dev->instance,
++ dev->capture.camera_port, NULL);
++ dev->capture.camera_port = NULL;
++ ret = vchiq_mmal_component_disable(dev->instance,
++ dev->capture.
++ encode_component);
++ if (ret)
++ v4l2_err(&dev->v4l2_dev,
++ "Failed to disable encode component %d\n",
++ ret);
++
++ dev->capture.encode_component = NULL;
++ }
++ /* format dependant port setup */
++ switch (mfmt->mmal_component) {
++ case MMAL_COMPONENT_CAMERA:
++ /* Make a further decision on port based on resolution */
++ if (f->fmt.pix.width <= MAX_VIDEO_MODE_WIDTH
++ && f->fmt.pix.height <= MAX_VIDEO_MODE_HEIGHT)
++ camera_port = port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO];
++ else
++ camera_port = port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_CAPTURE];
++ break;
++ case MMAL_COMPONENT_IMAGE_ENCODE:
++ encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
++ port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
++ camera_port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_CAPTURE];
++ break;
++ case MMAL_COMPONENT_VIDEO_ENCODE:
++ encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
++ port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++ camera_port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO];
++ break;
++ default:
++ break;
++ }
++
++ if (!port)
++ return -EINVAL;
++
++ if (encode_component)
++ camera_port->format.encoding = MMAL_ENCODING_OPAQUE;
++ else
++ camera_port->format.encoding = mfmt->mmal;
++
++ camera_port->format.encoding_variant = 0;
++ camera_port->es.video.width = f->fmt.pix.width;
++ camera_port->es.video.height = f->fmt.pix.height;
++ camera_port->es.video.crop.x = 0;
++ camera_port->es.video.crop.y = 0;
++ camera_port->es.video.crop.width = f->fmt.pix.width;
++ camera_port->es.video.crop.height = f->fmt.pix.height;
++ camera_port->es.video.frame_rate.num = 30;
++ camera_port->es.video.frame_rate.den = 1;
++
++ ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
++
++ if (!ret
++ && camera_port ==
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO]) {
++ bool overlay_enabled =
++ !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
++ struct vchiq_mmal_port *preview_port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_PREVIEW];
++ /* Preview and encode ports need to match on resolution */
++ if (overlay_enabled) {
++ /* Need to disable the overlay before we can update
++ * the resolution
++ */
++ ret =
++ vchiq_mmal_port_disable(dev->instance,
++ preview_port);
++ if (!ret)
++ ret =
++ vchiq_mmal_port_connect_tunnel(
++ dev->instance,
++ preview_port,
++ NULL);
++ }
++ preview_port->es.video.width = f->fmt.pix.width;
++ preview_port->es.video.height = f->fmt.pix.height;
++ preview_port->es.video.crop.x = 0;
++ preview_port->es.video.crop.y = 0;
++ preview_port->es.video.crop.width = f->fmt.pix.width;
++ preview_port->es.video.crop.height = f->fmt.pix.height;
++ preview_port->es.video.frame_rate.num = 30;
++ preview_port->es.video.frame_rate.den = 1;
++ ret = vchiq_mmal_port_set_format(dev->instance, preview_port);
++ if (overlay_enabled) {
++ ret = vchiq_mmal_port_connect_tunnel(
++ dev->instance,
++ preview_port,
++ &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
++ if (!ret)
++ ret = vchiq_mmal_port_enable(dev->instance,
++ preview_port,
++ NULL);
++ }
++ }
++
++ if (ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s failed to set format\n", __func__);
++ /* ensure capture is not going to be tried */
++ dev->capture.port = NULL;
++ } else {
++ if (encode_component) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "vid_cap - set up encode comp\n");
++
++ /* configure buffering */
++ camera_port->current_buffer.size =
++ camera_port->recommended_buffer.size;
++ camera_port->current_buffer.num =
++ camera_port->recommended_buffer.num;
++
++ port->format.encoding = mfmt->mmal;
++ port->format.encoding_variant = 0;
++ /* Set any encoding specific parameters */
++ switch (mfmt->mmal_component) {
++ case MMAL_COMPONENT_VIDEO_ENCODE:
++ port->format.bitrate =
++ dev->capture.encode_bitrate;
++ break;
++ case MMAL_COMPONENT_IMAGE_ENCODE:
++ /* Could set EXIF parameters here */
++ break;
++ default:
++ break;
++ }
++ ret = vchiq_mmal_port_set_format(dev->instance, port);
++
++ if (ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s failed to set format\n", __func__);
++ } else {
++ ret = vchiq_mmal_component_enable(
++ dev->instance,
++ encode_component);
++ if (ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "%s Failed to enable encode components\n",
++ __func__);
++ } else {
++ /* configure buffering */
++ port->current_buffer.num = 1;
++ port->current_buffer.size =
++ f->fmt.pix.sizeimage;
++ if (port->format.encoding ==
++ MMAL_ENCODING_JPEG) {
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "JPEG - fiddle buffer size\n");
++ port->current_buffer.size =
++ (f->fmt.pix.sizeimage <
++ (100 << 10))
++ ? (100 << 10) : f->fmt.pix.
++ sizeimage;
++ }
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "vid_cap - current_buffer.size being set to %d\n",
++ f->fmt.pix.sizeimage);
++ port->current_buffer.alignment = 0;
++ ret =
++ vchiq_mmal_port_connect_tunnel(
++ dev->instance,
++ camera_port,
++ &encode_component->input[0]);
++ if (ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "%s failed to create connection\n",
++ __func__);
++ /* ensure capture is not going to be tried */
++ dev->capture.port = NULL;
++ }
++ }
++ }
++ } else {
++ /* configure buffering */
++ camera_port->current_buffer.num = 1;
++ camera_port->current_buffer.size = f->fmt.pix.sizeimage;
++ camera_port->current_buffer.alignment = 0;
++ }
++
++ if (!ret) {
++ dev->capture.fmt = mfmt;
++ dev->capture.stride = f->fmt.pix.bytesperline;
++ dev->capture.width = port->es.video.crop.width;
++ dev->capture.height = port->es.video.crop.height;
++
++ /* select port for capture */
++ dev->capture.port = port;
++ dev->capture.camera_port = camera_port;
++ dev->capture.encode_component = encode_component;
++ }
++ }
++
++ /* todo: Need to convert the vchiq/mmal error into a v4l2 error. */
++ return ret;
++}
++
++static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ int ret;
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ struct mmal_fmt *mfmt;
++
++ /* try the format to set valid parameters */
++ ret = vidioc_try_fmt_vid_cap(file, priv, f);
++ if (ret) {
++ v4l2_err(&dev->v4l2_dev,
++ "vid_cap - vidioc_try_fmt_vid_cap failed\n");
++ return ret;
++ }
++
++ /* if a capture is running refuse to set format */
++ if (vb2_is_busy(&dev->capture.vb_vidq)) {
++ v4l2_info(&dev->v4l2_dev, "%s device busy\n", __func__);
++ return -EBUSY;
++ }
++
++ /* If the format is unsupported v4l2 says we should switch to
++ * a supported one and not return an error. */
++ mfmt = get_format(f);
++ if (!mfmt) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Fourcc format (0x%08x) unknown.\n",
++ f->fmt.pix.pixelformat);
++ f->fmt.pix.pixelformat = formats[0].fourcc;
++ mfmt = get_format(f);
++ }
++
++ ret = mmal_setup_components(dev, f);
++ if (ret != 0)
++ v4l2_err(&dev->v4l2_dev,
++ "%s: failed to setup mmal components: %d\n",
++ __func__, ret);
++
++ return ret;
++}
++
++static const struct v4l2_ioctl_ops camera0_ioctl_ops = {
++ /* overlay */
++ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
++ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
++ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
++ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
++ .vidioc_overlay = vidioc_overlay,
++ .vidioc_g_fbuf = vidioc_g_fbuf,
++
++ /* inputs */
++ .vidioc_enum_input = vidioc_enum_input,
++ .vidioc_g_input = vidioc_g_input,
++ .vidioc_s_input = vidioc_s_input,
++
++ /* capture */
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
++
++ /* buffer management */
++ .vidioc_reqbufs = vb2_ioctl_reqbufs,
++ .vidioc_create_bufs = vb2_ioctl_create_bufs,
++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
++ .vidioc_querybuf = vb2_ioctl_querybuf,
++ .vidioc_qbuf = vb2_ioctl_qbuf,
++ .vidioc_dqbuf = vb2_ioctl_dqbuf,
++ .vidioc_streamon = vb2_ioctl_streamon,
++ .vidioc_streamoff = vb2_ioctl_streamoff,
++
++ .vidioc_log_status = v4l2_ctrl_log_status,
++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
++};
++
++/* ------------------------------------------------------------------
++ Driver init/finalise
++ ------------------------------------------------------------------*/
++
++static const struct v4l2_file_operations camera0_fops = {
++ .owner = THIS_MODULE,
++ .open = v4l2_fh_open,
++ .release = vb2_fop_release,
++ .read = vb2_fop_read,
++ .poll = vb2_fop_poll,
++ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
++ .mmap = vb2_fop_mmap,
++};
++
++static struct video_device vdev_template = {
++ .name = "camera0",
++ .fops = &camera0_fops,
++ .ioctl_ops = &camera0_ioctl_ops,
++ .release = video_device_release_empty,
++};
++
++static int set_camera_parameters(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *camera)
++{
++ int ret;
++ struct mmal_parameter_camera_config cam_config = {
++ .max_stills_w = MAX_WIDTH,
++ .max_stills_h = MAX_HEIGHT,
++ .stills_yuv422 = 1,
++ .one_shot_stills = 1,
++ .max_preview_video_w = 1920,
++ .max_preview_video_h = 1088,
++ .num_preview_video_frames = 3,
++ .stills_capture_circular_buffer_height = 0,
++ .fast_preview_resume = 0,
++ .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
++ };
++
++ ret = vchiq_mmal_port_parameter_set(instance, &camera->control,
++ MMAL_PARAMETER_CAMERA_CONFIG,
++ &cam_config, sizeof(cam_config));
++ return ret;
++}
++
++/* MMAL instance and component init */
++static int __init mmal_init(struct bm2835_mmal_dev *dev)
++{
++ int ret;
++ struct mmal_es_format *format;
++
++ ret = vchiq_mmal_init(&dev->instance);
++ if (ret < 0)
++ return ret;
++
++ /* get the camera component ready */
++ ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
++ &dev->component[MMAL_COMPONENT_CAMERA]);
++ if (ret < 0)
++ goto unreg_mmal;
++
++ if (dev->component[MMAL_COMPONENT_CAMERA]->outputs <
++ MMAL_CAMERA_PORT_COUNT) {
++ ret = -EINVAL;
++ goto unreg_camera;
++ }
++
++ ret = set_camera_parameters(dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++ if (ret < 0)
++ goto unreg_camera;
++
++ format =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_PREVIEW].format;
++
++ format->encoding = MMAL_ENCODING_OPAQUE;
++ format->encoding_variant = MMAL_ENCODING_I420;
++
++ format->es->video.width = 1024;
++ format->es->video.height = 768;
++ format->es->video.crop.x = 0;
++ format->es->video.crop.y = 0;
++ format->es->video.crop.width = 1024;
++ format->es->video.crop.height = 768;
++ format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
++ format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
++
++ format =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO].format;
++
++ format->encoding = MMAL_ENCODING_OPAQUE;
++ format->encoding_variant = MMAL_ENCODING_I420;
++
++ format->es->video.width = 1024;
++ format->es->video.height = 768;
++ format->es->video.crop.x = 0;
++ format->es->video.crop.y = 0;
++ format->es->video.crop.width = 1024;
++ format->es->video.crop.height = 768;
++ format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
++ format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
++
++ format =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_CAPTURE].format;
++
++ format->encoding = MMAL_ENCODING_OPAQUE;
++
++ format->es->video.width = 2592;
++ format->es->video.height = 1944;
++ format->es->video.crop.x = 0;
++ format->es->video.crop.y = 0;
++ format->es->video.crop.width = 2592;
++ format->es->video.crop.height = 1944;
++ format->es->video.frame_rate.num = 30;
++ format->es->video.frame_rate.den = 1;
++
++ dev->capture.width = format->es->video.width;
++ dev->capture.height = format->es->video.height;
++ dev->capture.fmt = &formats[0];
++ dev->capture.encode_component = NULL;
++
++ /* get the preview component ready */
++ ret = vchiq_mmal_component_init(
++ dev->instance, "ril.video_render",
++ &dev->component[MMAL_COMPONENT_PREVIEW]);
++ if (ret < 0)
++ goto unreg_camera;
++
++ if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
++ ret = -EINVAL;
++ pr_debug("too few input ports %d needed %d\n",
++ dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
++ goto unreg_preview;
++ }
++
++ /* get the image encoder component ready */
++ ret = vchiq_mmal_component_init(
++ dev->instance, "ril.image_encode",
++ &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
++ if (ret < 0)
++ goto unreg_preview;
++
++ if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
++ ret = -EINVAL;
++ v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
++ dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
++ 1);
++ goto unreg_image_encoder;
++ }
++
++ /* get the video encoder component ready */
++ ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
++ &dev->
++ component[MMAL_COMPONENT_VIDEO_ENCODE]);
++ if (ret < 0)
++ goto unreg_image_encoder;
++
++ if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
++ ret = -EINVAL;
++ v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
++ dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
++ 1);
++ goto unreg_vid_encoder;
++ }
++
++ {
++ unsigned int enable = 1;
++ vchiq_mmal_port_parameter_set(
++ dev->instance,
++ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
++ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
++ &enable, sizeof(enable));
++
++ vchiq_mmal_port_parameter_set(dev->instance,
++ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
++ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
++ &enable,
++ sizeof(enable));
++ }
++ ret = bm2835_mmal_set_all_camera_controls(dev);
++ if (ret < 0)
++ goto unreg_vid_encoder;
++
++ return 0;
++
++unreg_vid_encoder:
++ pr_err("Cleanup: Destroy video encoder\n");
++ vchiq_mmal_component_finalise(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
++
++unreg_image_encoder:
++ pr_err("Cleanup: Destroy image encoder\n");
++ vchiq_mmal_component_finalise(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
++
++unreg_preview:
++ pr_err("Cleanup: Destroy video render\n");
++ vchiq_mmal_component_finalise(dev->instance,
++ dev->component[MMAL_COMPONENT_PREVIEW]);
++
++unreg_camera:
++ pr_err("Cleanup: Destroy camera\n");
++ vchiq_mmal_component_finalise(dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++
++unreg_mmal:
++ vchiq_mmal_finalise(dev->instance);
++ return ret;
++}
++
++static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev,
++ struct video_device *vfd)
++{
++ int ret;
++
++ *vfd = vdev_template;
++
++ vfd->v4l2_dev = &dev->v4l2_dev;
++
++ vfd->lock = &dev->mutex;
++
++ vfd->queue = &dev->capture.vb_vidq;
++
++ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
++
++ /* video device needs to be able to access instance data */
++ video_set_drvdata(vfd, dev);
++
++ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
++ if (ret < 0)
++ return ret;
++
++ v4l2_info(vfd->v4l2_dev, "V4L2 device registered as %s\n",
++ video_device_node_name(vfd));
++
++ return 0;
++}
++
++static struct v4l2_format default_v4l2_format = {
++ .fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG,
++ .fmt.pix.width = 1024,
++ .fmt.pix.bytesperline = 1024 * 3 / 2,
++ .fmt.pix.height = 768,
++ .fmt.pix.sizeimage = 1<<18,
++};
++
++static int __init bm2835_mmal_init(void)
++{
++ int ret;
++ struct bm2835_mmal_dev *dev;
++ struct vb2_queue *q;
++
++ dev = kzalloc(sizeof(*gdev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++
++ /* setup device defaults */
++ dev->overlay.w.left = 150;
++ dev->overlay.w.top = 50;
++ dev->overlay.w.width = 1024;
++ dev->overlay.w.height = 768;
++ dev->overlay.clipcount = 0;
++ dev->overlay.field = V4L2_FIELD_NONE;
++
++ dev->capture.fmt = &formats[3]; /* JPEG */
++
++ /* v4l device registration */
++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
++ "%s", BM2835_MMAL_MODULE_NAME);
++ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
++ if (ret)
++ goto free_dev;
++
++ /* setup v4l controls */
++ ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
++ if (ret < 0)
++ goto unreg_dev;
++ dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
++
++ /* mmal init */
++ ret = mmal_init(dev);
++ if (ret < 0)
++ goto unreg_dev;
++
++ /* initialize queue */
++ q = &dev->capture.vb_vidq;
++ memset(q, 0, sizeof(*q));
++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
++ q->drv_priv = dev;
++ q->buf_struct_size = sizeof(struct mmal_buffer);
++ q->ops = &bm2835_mmal_video_qops;
++ q->mem_ops = &vb2_vmalloc_memops;
++ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
++ ret = vb2_queue_init(q);
++ if (ret < 0)
++ goto unreg_dev;
++
++ /* v4l2 core mutex used to protect all fops and v4l2 ioctls. */
++ mutex_init(&dev->mutex);
++
++ /* initialise video devices */
++ ret = bm2835_mmal_init_device(dev, &dev->vdev);
++ if (ret < 0)
++ goto unreg_dev;
++
++ ret = mmal_setup_components(dev, &default_v4l2_format);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s: could not setup components\n", __func__);
++ goto unreg_dev;
++ }
++
++ v4l2_info(&dev->v4l2_dev,
++ "Broadcom 2835 MMAL video capture ver %s loaded.\n",
++ BM2835_MMAL_VERSION);
++
++ gdev = dev;
++ return 0;
++
++unreg_dev:
++ v4l2_ctrl_handler_free(&dev->ctrl_handler);
++ v4l2_device_unregister(&dev->v4l2_dev);
++
++free_dev:
++ kfree(dev);
++
++ v4l2_err(&dev->v4l2_dev,
++ "%s: error %d while loading driver\n",
++ BM2835_MMAL_MODULE_NAME, ret);
++
++ return ret;
++}
++
++static void __exit bm2835_mmal_exit(void)
++{
++ if (!gdev)
++ return;
++
++ v4l2_info(&gdev->v4l2_dev, "unregistering %s\n",
++ video_device_node_name(&gdev->vdev));
++
++ video_unregister_device(&gdev->vdev);
++
++ if (gdev->capture.encode_component) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &gdev->v4l2_dev,
++ "mmal_exit - disconnect tunnel\n");
++ vchiq_mmal_port_connect_tunnel(gdev->instance,
++ gdev->capture.camera_port, NULL);
++ vchiq_mmal_component_disable(gdev->instance,
++ gdev->capture.encode_component);
++ }
++ vchiq_mmal_component_disable(gdev->instance,
++ gdev->component[MMAL_COMPONENT_CAMERA]);
++
++ vchiq_mmal_component_finalise(gdev->instance,
++ gdev->
++ component[MMAL_COMPONENT_VIDEO_ENCODE]);
++
++ vchiq_mmal_component_finalise(gdev->instance,
++ gdev->
++ component[MMAL_COMPONENT_IMAGE_ENCODE]);
++
++ vchiq_mmal_component_finalise(gdev->instance,
++ gdev->component[MMAL_COMPONENT_PREVIEW]);
++
++ vchiq_mmal_component_finalise(gdev->instance,
++ gdev->component[MMAL_COMPONENT_CAMERA]);
++
++ vchiq_mmal_finalise(gdev->instance);
++
++ v4l2_ctrl_handler_free(&gdev->ctrl_handler);
++
++ v4l2_device_unregister(&gdev->v4l2_dev);
++
++ kfree(gdev);
++}
++
++module_init(bm2835_mmal_init);
++module_exit(bm2835_mmal_exit);
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.h
+@@ -0,0 +1,113 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ *
++ * core driver device
++ */
++
++#define V4L2_CTRL_COUNT 18 /* number of v4l controls */
++
++enum {
++ MMAL_COMPONENT_CAMERA = 0,
++ MMAL_COMPONENT_PREVIEW,
++ MMAL_COMPONENT_IMAGE_ENCODE,
++ MMAL_COMPONENT_VIDEO_ENCODE,
++ MMAL_COMPONENT_COUNT
++};
++
++enum {
++ MMAL_CAMERA_PORT_PREVIEW = 0,
++ MMAL_CAMERA_PORT_VIDEO,
++ MMAL_CAMERA_PORT_CAPTURE,
++ MMAL_CAMERA_PORT_COUNT
++};
++
++#define PREVIEW_FRAME_RATE_NUM 30
++#define PREVIEW_FRAME_RATE_DEN 1
++
++#define PREVIEW_LAYER 2
++
++extern int bcm2835_v4l2_debug;
++
++struct bm2835_mmal_dev {
++ /* v4l2 devices */
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ struct mutex mutex;
++
++ /* controls */
++ struct v4l2_ctrl_handler ctrl_handler;
++ struct v4l2_ctrl *ctrls[V4L2_CTRL_COUNT];
++ struct mmal_colourfx colourfx;
++ int hflip;
++ int vflip;
++
++ /* allocated mmal instance and components */
++ struct vchiq_mmal_instance *instance;
++ struct vchiq_mmal_component *component[MMAL_COMPONENT_COUNT];
++ int camera_use_count;
++
++ struct v4l2_window overlay;
++
++ struct {
++ unsigned int width; /* width */
++ unsigned int height; /* height */
++ unsigned int stride; /* stride */
++ struct mmal_fmt *fmt;
++
++ /* H264 encode bitrate */
++ int encode_bitrate;
++ /* H264 bitrate mode. CBR/VBR */
++ int encode_bitrate_mode;
++ /* JPEG Q-factor */
++ int q_factor;
++
++ struct vb2_queue vb_vidq;
++
++ /* VC start timestamp for streaming */
++ s64 vc_start_timestamp;
++ /* Kernel start timestamp for streaming */
++ struct timeval kernel_start_ts;
++
++ struct vchiq_mmal_port *port; /* port being used for capture */
++ /* camera port being used for capture */
++ struct vchiq_mmal_port *camera_port;
++ /* component being used for encode */
++ struct vchiq_mmal_component *encode_component;
++ /* number of frames remaining which driver should capture */
++ unsigned int frame_count;
++ /* last frame completion */
++ struct completion frame_cmplt;
++
++ } capture;
++
++};
++
++int bm2835_mmal_init_controls(
++ struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl_handler *hdl);
++
++int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev);
++
++
++/* Debug helpers */
++
++#define v4l2_dump_pix_format(level, debug, dev, pix_fmt, desc) \
++{ \
++ v4l2_dbg(level, debug, dev, \
++"%s: w %u h %u field %u pfmt 0x%x bpl %u sz_img %u colorspace 0x%x priv %u\n", \
++ desc == NULL ? "" : desc, \
++ (pix_fmt)->width, (pix_fmt)->height, (pix_fmt)->field, \
++ (pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
++ (pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
++}
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/controls.c
+@@ -0,0 +1,725 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <media/videobuf2-vmalloc.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-common.h>
++
++#include "mmal-common.h"
++#include "mmal-vchiq.h"
++#include "mmal-parameters.h"
++#include "bcm2835-camera.h"
++
++/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -24 to +24.
++ * These are in 1/6th increments so the effective range is -4.0EV to +4.0EV.
++ */
++static const s64 ev_bias_qmenu[] = {
++ -24, -21, -18, -15, -12, -9, -6, -3, 0, 3, 6, 9, 12, 15, 18, 21, 24
++};
++
++/* Supported ISO values
++ * ISOO = auto ISO
++ */
++static const s64 iso_qmenu[] = {
++ 0, 100, 200, 400, 800,
++};
++
++/* Supported video encode modes */
++static const s64 bitrate_mode_qmenu[] = {
++ (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
++ (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
++};
++
++
++enum bm2835_mmal_ctrl_type {
++ MMAL_CONTROL_TYPE_STD,
++ MMAL_CONTROL_TYPE_STD_MENU,
++ MMAL_CONTROL_TYPE_INT_MENU,
++ MMAL_CONTROL_TYPE_CLUSTER, /* special cluster entry */
++};
++
++struct bm2835_mmal_v4l2_ctrl;
++
++typedef int(bm2835_mmal_v4l2_ctrl_cb)(
++ struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl);
++
++struct bm2835_mmal_v4l2_ctrl {
++ u32 id; /* v4l2 control identifier */
++ enum bm2835_mmal_ctrl_type type;
++ /* control minimum value or
++ * mask for MMAL_CONTROL_TYPE_STD_MENU */
++ s32 min;
++ s32 max; /* maximum value of control */
++ s32 def; /* default value of control */
++ s32 step; /* step size of the control */
++ const s64 *imenu; /* integer menu array */
++ u32 mmal_id; /* mmal parameter id */
++ bm2835_mmal_v4l2_ctrl_cb *setter;
++};
++
++struct v4l2_to_mmal_effects_setting {
++ u32 v4l2_effect;
++ u32 mmal_effect;
++ s32 col_fx_enable;
++ s32 col_fx_fixed_cbcr;
++ u32 u;
++ u32 v;
++ u32 num_effect_params;
++ u32 effect_params[MMAL_MAX_IMAGEFX_PARAMETERS];
++};
++
++static const struct v4l2_to_mmal_effects_setting
++ v4l2_to_mmal_effects_values[] = {
++ { V4L2_COLORFX_NONE, MMAL_PARAM_IMAGEFX_NONE,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_BW, MMAL_PARAM_IMAGEFX_NONE,
++ 1, 0, 128, 128, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SEPIA, MMAL_PARAM_IMAGEFX_NONE,
++ 1, 0, 87, 151, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_NEGATIVE, MMAL_PARAM_IMAGEFX_NEGATIVE,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_EMBOSS, MMAL_PARAM_IMAGEFX_EMBOSS,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SKETCH, MMAL_PARAM_IMAGEFX_SKETCH,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SKY_BLUE, MMAL_PARAM_IMAGEFX_PASTEL,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_GRASS_GREEN, MMAL_PARAM_IMAGEFX_WATERCOLOUR,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SKIN_WHITEN, MMAL_PARAM_IMAGEFX_WASHEDOUT,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_VIVID, MMAL_PARAM_IMAGEFX_SATURATION,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_AQUA, MMAL_PARAM_IMAGEFX_NONE,
++ 1, 0, 171, 121, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_ART_FREEZE, MMAL_PARAM_IMAGEFX_HATCH,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SILHOUETTE, MMAL_PARAM_IMAGEFX_FILM,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SOLARIZATION, MMAL_PARAM_IMAGEFX_SOLARIZE,
++ 0, 0, 0, 0, 5, {1, 128, 160, 160, 48} },
++ { V4L2_COLORFX_ANTIQUE, MMAL_PARAM_IMAGEFX_COLOURBALANCE,
++ 0, 0, 0, 0, 3, {108, 274, 238, 0, 0} },
++ { V4L2_COLORFX_SET_CBCR, MMAL_PARAM_IMAGEFX_NONE,
++ 1, 1, 0, 0, 0, {0, 0, 0, 0, 0} }
++};
++
++
++/* control handlers*/
++
++static int ctrl_set_rational(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ struct {
++ s32 num; /**< Numerator */
++ s32 den; /**< Denominator */
++ } rational_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ rational_value.num = ctrl->val;
++ rational_value.den = 100;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &rational_value,
++ sizeof(rational_value));
++}
++
++static int ctrl_set_value(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ u32_value = ctrl->val;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_rotate(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret;
++ u32 u32_value;
++ struct vchiq_mmal_component *camera;
++
++ camera = dev->component[MMAL_COMPONENT_CAMERA];
++
++ u32_value = ((ctrl->val % 360) / 90) * 90;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[0],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ if (ret < 0)
++ return ret;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[1],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ if (ret < 0)
++ return ret;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[2],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++
++ return ret;
++}
++
++static int ctrl_set_flip(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret;
++ u32 u32_value;
++ struct vchiq_mmal_component *camera;
++
++ if (ctrl->id == V4L2_CID_HFLIP)
++ dev->hflip = ctrl->val;
++ else
++ dev->vflip = ctrl->val;
++
++ camera = dev->component[MMAL_COMPONENT_CAMERA];
++
++ if (dev->hflip && dev->vflip)
++ u32_value = MMAL_PARAM_MIRROR_BOTH;
++ else if (dev->hflip)
++ u32_value = MMAL_PARAM_MIRROR_HORIZONTAL;
++ else if (dev->vflip)
++ u32_value = MMAL_PARAM_MIRROR_VERTICAL;
++ else
++ u32_value = MMAL_PARAM_MIRROR_NONE;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[0],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ if (ret < 0)
++ return ret;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[1],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ if (ret < 0)
++ return ret;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[2],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++
++ return ret;
++
++}
++
++static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ switch (ctrl->val) {
++ case V4L2_EXPOSURE_AUTO:
++ u32_value = MMAL_PARAM_EXPOSUREMODE_AUTO;
++ break;
++
++ case V4L2_EXPOSURE_MANUAL:
++ u32_value = MMAL_PARAM_EXPOSUREMODE_OFF;
++ break;
++
++ case V4L2_EXPOSURE_SHUTTER_PRIORITY:
++ u32_value = MMAL_PARAM_EXPOSUREMODE_SPORTS;
++ break;
++
++ case V4L2_EXPOSURE_APERTURE_PRIORITY:
++ u32_value = MMAL_PARAM_EXPOSUREMODE_NIGHT;
++ break;
++
++ }
++
++ /* todo: what about the other ten modes there are MMAL parameters for */
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ switch (ctrl->val) {
++ case V4L2_EXPOSURE_METERING_AVERAGE:
++ u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
++ break;
++
++ case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
++ u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT;
++ break;
++
++ case V4L2_EXPOSURE_METERING_SPOT:
++ u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT;
++ break;
++
++ /* todo matrix weighting not added to Linux API till 3.9
++ case V4L2_EXPOSURE_METERING_MATRIX:
++ u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX;
++ break;
++ */
++
++ }
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ switch (ctrl->val) {
++ case V4L2_WHITE_BALANCE_MANUAL:
++ u32_value = MMAL_PARAM_AWBMODE_OFF;
++ break;
++
++ case V4L2_WHITE_BALANCE_AUTO:
++ u32_value = MMAL_PARAM_AWBMODE_AUTO;
++ break;
++
++ case V4L2_WHITE_BALANCE_INCANDESCENT:
++ u32_value = MMAL_PARAM_AWBMODE_INCANDESCENT;
++ break;
++
++ case V4L2_WHITE_BALANCE_FLUORESCENT:
++ u32_value = MMAL_PARAM_AWBMODE_FLUORESCENT;
++ break;
++
++ case V4L2_WHITE_BALANCE_FLUORESCENT_H:
++ u32_value = MMAL_PARAM_AWBMODE_TUNGSTEN;
++ break;
++
++ case V4L2_WHITE_BALANCE_HORIZON:
++ u32_value = MMAL_PARAM_AWBMODE_HORIZON;
++ break;
++
++ case V4L2_WHITE_BALANCE_DAYLIGHT:
++ u32_value = MMAL_PARAM_AWBMODE_SUNLIGHT;
++ break;
++
++ case V4L2_WHITE_BALANCE_FLASH:
++ u32_value = MMAL_PARAM_AWBMODE_FLASH;
++ break;
++
++ case V4L2_WHITE_BALANCE_CLOUDY:
++ u32_value = MMAL_PARAM_AWBMODE_CLOUDY;
++ break;
++
++ case V4L2_WHITE_BALANCE_SHADE:
++ u32_value = MMAL_PARAM_AWBMODE_SHADE;
++ break;
++
++ }
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret = -EINVAL;
++ int i, j;
++ struct vchiq_mmal_port *control;
++ struct mmal_parameter_imagefx_parameters imagefx;
++
++ for (i = 0; i < ARRAY_SIZE(v4l2_to_mmal_effects_values); i++) {
++ if (ctrl->val == v4l2_to_mmal_effects_values[i].v4l2_effect) {
++
++ imagefx.effect =
++ v4l2_to_mmal_effects_values[i].mmal_effect;
++ imagefx.num_effect_params =
++ v4l2_to_mmal_effects_values[i].num_effect_params;
++
++ if (imagefx.num_effect_params > MMAL_MAX_IMAGEFX_PARAMETERS)
++ imagefx.num_effect_params = MMAL_MAX_IMAGEFX_PARAMETERS;
++
++ for (j = 0; j < imagefx.num_effect_params; j++)
++ imagefx.effect_parameter[j] =
++ v4l2_to_mmal_effects_values[i].effect_params[j];
++
++ dev->colourfx.enable =
++ v4l2_to_mmal_effects_values[i].col_fx_enable;
++ if (!v4l2_to_mmal_effects_values[i].col_fx_fixed_cbcr) {
++ dev->colourfx.u =
++ v4l2_to_mmal_effects_values[i].u;
++ dev->colourfx.v =
++ v4l2_to_mmal_effects_values[i].v;
++ }
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ ret = vchiq_mmal_port_parameter_set(
++ dev->instance, control,
++ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
++ &imagefx, sizeof(imagefx));
++ if (ret)
++ goto exit;
++
++ ret = vchiq_mmal_port_parameter_set(
++ dev->instance, control,
++ MMAL_PARAMETER_COLOUR_EFFECT,
++ &dev->colourfx, sizeof(dev->colourfx));
++ }
++ }
++
++exit:
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "mmal_ctrl:%p ctrl id:0x%x ctrl val:%d imagefx:0x%x color_effect:%s u:%d v:%d ret %d(%d)\n",
++ mmal_ctrl, ctrl->id, ctrl->val, imagefx.effect,
++ dev->colourfx.enable ? "true" : "false",
++ dev->colourfx.u, dev->colourfx.v,
++ ret, (ret == 0 ? 0 : -EINVAL));
++ return (ret == 0 ? 0 : EINVAL);
++}
++
++static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret = -EINVAL;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
++ dev->colourfx.enable = ctrl->val & 0xff;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
++ MMAL_PARAMETER_COLOUR_EFFECT,
++ &dev->colourfx, sizeof(dev->colourfx));
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "After: mmal_ctrl:%p ctrl id:0x%x ctrl val:%d ret %d(%d)\n",
++ mmal_ctrl, ctrl->id, ctrl->val, ret,
++ (ret == 0 ? 0 : -EINVAL));
++ return (ret == 0 ? 0 : EINVAL);
++}
++
++static int ctrl_set_bitrate(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret;
++ struct vchiq_mmal_port *encoder_out;
++
++ dev->capture.encode_bitrate = ctrl->val;
++
++ encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
++ mmal_ctrl->mmal_id,
++ &ctrl->val, sizeof(ctrl->val));
++ ret = 0;
++ return ret;
++}
++
++static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 bitrate_mode;
++ struct vchiq_mmal_port *encoder_out;
++
++ encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++
++ dev->capture.encode_bitrate_mode = ctrl->val;
++ switch (ctrl->val) {
++ default:
++ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
++ bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE;
++ break;
++ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
++ bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT;
++ break;
++ }
++
++ vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
++ mmal_ctrl->mmal_id,
++ &bitrate_mode,
++ sizeof(bitrate_mode));
++ return 0;
++}
++
++static int ctrl_set_q_factor(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *jpeg_out;
++
++ jpeg_out = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
++
++ u32_value = ctrl->val;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, jpeg_out,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct bm2835_mmal_dev *dev =
++ container_of(ctrl->handler, struct bm2835_mmal_dev,
++ ctrl_handler);
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl = ctrl->priv;
++
++ if ((mmal_ctrl == NULL) ||
++ (mmal_ctrl->id != ctrl->id) ||
++ (mmal_ctrl->setter == NULL)) {
++ pr_warn("mmal_ctrl:%p ctrl id:%d\n", mmal_ctrl, ctrl->id);
++ return -EINVAL;
++ }
++
++ return mmal_ctrl->setter(dev, ctrl, mmal_ctrl);
++}
++
++static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = {
++ .s_ctrl = bm2835_mmal_s_ctrl,
++};
++
++
++
++static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
++ {
++ V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD,
++ -100, 100, 0, 1, NULL,
++ MMAL_PARAMETER_SATURATION, &ctrl_set_rational
++ },
++ {
++ V4L2_CID_SHARPNESS, MMAL_CONTROL_TYPE_STD,
++ -100, 100, 0, 1, NULL,
++ MMAL_PARAMETER_SHARPNESS, &ctrl_set_rational
++ },
++ {
++ V4L2_CID_CONTRAST, MMAL_CONTROL_TYPE_STD,
++ -100, 100, 0, 1, NULL,
++ MMAL_PARAMETER_CONTRAST, &ctrl_set_rational
++ },
++ {
++ V4L2_CID_BRIGHTNESS, MMAL_CONTROL_TYPE_STD,
++ 0, 100, 50, 1, NULL,
++ MMAL_PARAMETER_BRIGHTNESS, &ctrl_set_rational
++ },
++ {
++ V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU,
++ 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu,
++ MMAL_PARAMETER_ISO, &ctrl_set_value
++ },
++ {
++ V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD,
++ 0, 1, 0, 1, NULL,
++ MMAL_PARAMETER_VIDEO_STABILISATION, &ctrl_set_value
++ },
++/* {
++ 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL
++ },
++*/ {
++ V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
++ ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL,
++ MMAL_PARAMETER_EXPOSURE_MODE, &ctrl_set_exposure
++ },
++/* todo this needs mixing in with set exposure
++ {
++ V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
++ },
++ */
++ {
++ V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU,
++ 0, ARRAY_SIZE(ev_bias_qmenu) - 1,
++ (ARRAY_SIZE(ev_bias_qmenu)+1)/2 - 1, 0, ev_bias_qmenu,
++ MMAL_PARAMETER_EXPOSURE_COMP, &ctrl_set_value
++ },
++ {
++ V4L2_CID_EXPOSURE_METERING,
++ MMAL_CONTROL_TYPE_STD_MENU,
++ ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
++ MMAL_PARAMETER_EXP_METERING_MODE, &ctrl_set_metering_mode
++ },
++ {
++ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
++ MMAL_CONTROL_TYPE_STD_MENU,
++ ~0x3fe, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL,
++ MMAL_PARAMETER_AWB_MODE, &ctrl_set_awb_mode
++ },
++ {
++ V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
++ 0, 15, V4L2_COLORFX_NONE, 0, NULL,
++ MMAL_PARAMETER_IMAGE_EFFECT, &ctrl_set_image_effect
++ },
++ {
++ V4L2_CID_COLORFX_CBCR, MMAL_CONTROL_TYPE_STD,
++ 0, 0xffff, 0x8080, 1, NULL,
++ MMAL_PARAMETER_COLOUR_EFFECT, &ctrl_set_colfx
++ },
++ {
++ V4L2_CID_ROTATE, MMAL_CONTROL_TYPE_STD,
++ 0, 360, 0, 90, NULL,
++ MMAL_PARAMETER_ROTATION, &ctrl_set_rotate
++ },
++ {
++ V4L2_CID_HFLIP, MMAL_CONTROL_TYPE_STD,
++ 0, 1, 0, 1, NULL,
++ MMAL_PARAMETER_MIRROR, &ctrl_set_flip
++ },
++ {
++ V4L2_CID_VFLIP, MMAL_CONTROL_TYPE_STD,
++ 0, 1, 0, 1, NULL,
++ MMAL_PARAMETER_MIRROR, &ctrl_set_flip
++ },
++ {
++ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
++ 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1,
++ 0, 0, bitrate_mode_qmenu,
++ MMAL_PARAMETER_RATECONTROL, &ctrl_set_bitrate_mode
++ },
++ {
++ V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD,
++ 25*1000, 25*1000*1000, 10*1000*1000, 25*1000, NULL,
++ MMAL_PARAMETER_VIDEO_BIT_RATE, &ctrl_set_bitrate
++ },
++ {
++ V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD,
++ 0, 100,
++ 30, 1, NULL,
++ MMAL_PARAMETER_JPEG_Q_FACTOR, &ctrl_set_q_factor
++ },
++};
++
++int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev)
++{
++ int c;
++ int ret;
++
++ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
++ if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) {
++ ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c],
++ &v4l2_ctrls[c]);
++ if (ret)
++ break;
++ }
++ }
++ return ret;
++}
++
++int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl_handler *hdl)
++{
++ int c;
++ const struct bm2835_mmal_v4l2_ctrl *ctrl;
++
++ v4l2_ctrl_handler_init(hdl, V4L2_CTRL_COUNT);
++
++ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
++ ctrl = &v4l2_ctrls[c];
++
++ switch (ctrl->type) {
++ case MMAL_CONTROL_TYPE_STD:
++ dev->ctrls[c] = v4l2_ctrl_new_std(hdl,
++ &bm2835_mmal_ctrl_ops, ctrl->id,
++ ctrl->min, ctrl->max, ctrl->step, ctrl->def);
++ break;
++
++ case MMAL_CONTROL_TYPE_STD_MENU:
++ dev->ctrls[c] = v4l2_ctrl_new_std_menu(hdl,
++ &bm2835_mmal_ctrl_ops, ctrl->id,
++ ctrl->max, ctrl->min, ctrl->def);
++ break;
++
++ case MMAL_CONTROL_TYPE_INT_MENU:
++ dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,
++ &bm2835_mmal_ctrl_ops, ctrl->id,
++ ctrl->max, ctrl->def, ctrl->imenu);
++ break;
++
++ case MMAL_CONTROL_TYPE_CLUSTER:
++ /* skip this entry when constructing controls */
++ continue;
++ }
++
++ if (hdl->error)
++ break;
++
++ dev->ctrls[c]->priv = (void *)ctrl;
++ }
++
++ if (hdl->error) {
++ pr_err("error adding control %d/%d id 0x%x\n", c,
++ V4L2_CTRL_COUNT, ctrl->id);
++ return hdl->error;
++ }
++
++ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
++ ctrl = &v4l2_ctrls[c];
++
++ switch (ctrl->type) {
++ case MMAL_CONTROL_TYPE_CLUSTER:
++ v4l2_ctrl_auto_cluster(ctrl->min,
++ &dev->ctrls[c+1],
++ ctrl->max,
++ ctrl->def);
++ break;
++
++ case MMAL_CONTROL_TYPE_STD:
++ case MMAL_CONTROL_TYPE_STD_MENU:
++ case MMAL_CONTROL_TYPE_INT_MENU:
++ break;
++ }
++
++ }
++
++ return 0;
++}
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-common.h
+@@ -0,0 +1,52 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ *
++ * MMAL structures
++ *
++ */
++
++#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
++#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
++
++/** Special value signalling that time is not known */
++#define MMAL_TIME_UNKNOWN (1LL<<63)
++
++/* mapping between v4l and mmal video modes */
++struct mmal_fmt {
++ char *name;
++ u32 fourcc; /* v4l2 format id */
++ u32 mmal;
++ int depth;
++ u32 mmal_component; /* MMAL component index to be used to encode */
++};
++
++/* buffer for one video frame */
++struct mmal_buffer {
++ /* v4l buffer data -- must be first */
++ struct vb2_buffer vb;
++
++ /* list of buffers available */
++ struct list_head list;
++
++ void *buffer; /* buffer pointer */
++ unsigned long buffer_size; /* size of allocated buffer */
++};
++
++/* */
++struct mmal_colourfx {
++ s32 enable;
++ u32 u;
++ u32 v;
++};
++
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-encodings.h
+@@ -0,0 +1,93 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4')
++#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3')
++#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V')
++#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V')
++#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V')
++#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3')
++#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2')
++#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1')
++#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1')
++#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ')
++#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ')
++#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ')
++#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O')
++#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K')
++
++#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G')
++#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ')
++#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ')
++#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ')
++#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ')
++#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ')
++
++#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0')
++#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0')
++#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2')
++#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2')
++#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2')
++#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V')
++#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U')
++#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y')
++#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y')
++#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2')
++#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1')
++#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B')
++#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A')
++#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R')
++#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A')
++#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2')
++#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3')
++#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4')
++#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2')
++#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3')
++#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4')
++
++/** SAND Video (YUVUV128) format, native format understood by VideoCore.
++ * This format is *not* opaque - if requested you will receive full frames
++ * of YUV_UV video.
++ */
++#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D')
++
++/** VideoCore opaque image format, image handles are returned to
++ * the host but not the actual image data.
++ */
++#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
++
++/** An EGL image handle
++ */
++#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
++
++/* }@ */
++
++/** \name Pre-defined audio encodings */
++/* @{ */
++#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U')
++#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u')
++#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S')
++#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's')
++#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F')
++#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f')
++
++/* Pre-defined H264 encoding variants */
++
++/** ISO 14496-10 Annex B byte stream format */
++#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0
++/** ISO 14496-15 AVC stream format */
++#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1')
++/** Implicitly delineated NAL units without emulation prevention */
++#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ')
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-msg-common.h
+@@ -0,0 +1,50 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#ifndef MMAL_MSG_COMMON_H
++#define MMAL_MSG_COMMON_H
++
++enum mmal_msg_status {
++ MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */
++ MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */
++ MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */
++ MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */
++ MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */
++ MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */
++ MMAL_MSG_STATUS_ENXIO, /**< No such device or address */
++ MMAL_MSG_STATUS_EIO, /**< I/O error */
++ MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */
++ MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */
++ MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */
++ MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */
++ MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */
++ MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */
++ MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */
++ MMAL_MSG_STATUS_EFAULT, /**< Bad address */
++};
++
++struct mmal_rect {
++ s32 x; /**< x coordinate (from left) */
++ s32 y; /**< y coordinate (from top) */
++ s32 width; /**< width */
++ s32 height; /**< height */
++};
++
++struct mmal_rational {
++ s32 num; /**< Numerator */
++ s32 den; /**< Denominator */
++};
++
++#endif /* MMAL_MSG_COMMON_H */
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-msg-format.h
+@@ -0,0 +1,81 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#ifndef MMAL_MSG_FORMAT_H
++#define MMAL_MSG_FORMAT_H
++
++#include "mmal-msg-common.h"
++
++/* MMAL_ES_FORMAT_T */
++
++
++struct mmal_audio_format {
++ u32 channels; /**< Number of audio channels */
++ u32 sample_rate; /**< Sample rate */
++
++ u32 bits_per_sample; /**< Bits per sample */
++ u32 block_align; /**< Size of a block of data */
++};
++
++struct mmal_video_format {
++ u32 width; /**< Width of frame in pixels */
++ u32 height; /**< Height of frame in rows of pixels */
++ struct mmal_rect crop; /**< Visible region of the frame */
++ struct mmal_rational frame_rate; /**< Frame rate */
++ struct mmal_rational par; /**< Pixel aspect ratio */
++
++ /* FourCC specifying the color space of the video stream. See the
++ * \ref MmalColorSpace "pre-defined color spaces" for some examples.
++ */
++ u32 color_space;
++};
++
++struct mmal_subpicture_format {
++ u32 x_offset;
++ u32 y_offset;
++};
++
++union mmal_es_specific_format {
++ struct mmal_audio_format audio;
++ struct mmal_video_format video;
++ struct mmal_subpicture_format subpicture;
++};
++
++/** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
++struct mmal_es_format {
++ u32 type; /* enum mmal_es_type */
++
++ u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
++ u32 encoding_variant; /* FourCC specifying the specific
++ * encoding variant of the elementary
++ * stream.
++ */
++
++ union mmal_es_specific_format *es; /* TODO: pointers in
++ * message serialisation?!?
++ */
++ /* Type specific
++ * information for the
++ * elementary stream
++ */
++
++ u32 bitrate; /**< Bitrate in bits per second */
++ u32 flags; /**< Flags describing properties of the elementary stream. */
++
++ u32 extradata_size; /**< Size of the codec specific data */
++ u8 *extradata; /**< Codec specific data */
++};
++
++#endif /* MMAL_MSG_FORMAT_H */
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-msg-port.h
+@@ -0,0 +1,107 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++/* MMAL_PORT_TYPE_T */
++enum mmal_port_type {
++ MMAL_PORT_TYPE_UNKNOWN = 0, /**< Unknown port type */
++ MMAL_PORT_TYPE_CONTROL, /**< Control port */
++ MMAL_PORT_TYPE_INPUT, /**< Input port */
++ MMAL_PORT_TYPE_OUTPUT, /**< Output port */
++ MMAL_PORT_TYPE_CLOCK, /**< Clock port */
++};
++
++/** The port is pass-through and doesn't need buffer headers allocated */
++#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
++/** The port wants to allocate the buffer payloads.
++ * This signals a preference that payload allocation should be done
++ * on this port for efficiency reasons. */
++#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
++/** The port supports format change events.
++ * This applies to input ports and is used to let the client know
++ * whether the port supports being reconfigured via a format
++ * change event (i.e. without having to disable the port). */
++#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
++
++/* mmal port structure (MMAL_PORT_T)
++ *
++ * most elements are informational only, the pointer values for
++ * interogation messages are generally provided as additional
++ * strucures within the message. When used to set values only teh
++ * buffer_num, buffer_size and userdata parameters are writable.
++ */
++struct mmal_port {
++ void *priv; /* Private member used by the framework */
++ const char *name; /* Port name. Used for debugging purposes (RO) */
++
++ u32 type; /* Type of the port (RO) enum mmal_port_type */
++ u16 index; /* Index of the port in its type list (RO) */
++ u16 index_all; /* Index of the port in the list of all ports (RO) */
++
++ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
++ struct mmal_es_format *format; /* Format of the elementary stream */
++
++ u32 buffer_num_min; /* Minimum number of buffers the port
++ * requires (RO). This is set by the
++ * component.
++ */
++
++ u32 buffer_size_min; /* Minimum size of buffers the port
++ * requires (RO). This is set by the
++ * component.
++ */
++
++ u32 buffer_alignment_min; /* Minimum alignment requirement for
++ * the buffers (RO). A value of
++ * zero means no special alignment
++ * requirements. This is set by the
++ * component.
++ */
++
++ u32 buffer_num_recommended; /* Number of buffers the port
++ * recommends for optimal
++ * performance (RO). A value of
++ * zero means no special
++ * recommendation. This is set
++ * by the component.
++ */
++
++ u32 buffer_size_recommended; /* Size of buffers the port
++ * recommends for optimal
++ * performance (RO). A value of
++ * zero means no special
++ * recommendation. This is set
++ * by the component.
++ */
++
++ u32 buffer_num; /* Actual number of buffers the port will use.
++ * This is set by the client.
++ */
++
++ u32 buffer_size; /* Actual maximum size of the buffers that
++ * will be sent to the port. This is set by
++ * the client.
++ */
++
++ void *component; /* Component this port belongs to (Read Only) */
++
++ void *userdata; /* Field reserved for use by the client */
++
++ u32 capabilities; /* Flags describing the capabilities of a
++ * port (RO). Bitwise combination of \ref
++ * portcapabilities "Port capabilities"
++ * values.
++ */
++
++};
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-msg.h
+@@ -0,0 +1,404 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++/* all the data structures which serialise the MMAL protocol. note
++ * these are directly mapped onto the recived message data.
++ *
++ * BEWARE: They seem to *assume* pointers are u32 and that there is no
++ * structure padding!
++ *
++ * NOTE: this implementation uses kernel types to ensure sizes. Rather
++ * than assigning values to enums to force their size the
++ * implementation uses fixed size types and not the enums (though the
++ * comments have the actual enum type
++ */
++
++#define VC_MMAL_VER 15
++#define VC_MMAL_MIN_VER 10
++#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal")
++
++/* max total message size is 512 bytes */
++#define MMAL_MSG_MAX_SIZE 512
++/* with six 32bit header elements max payload is therefore 488 bytes */
++#define MMAL_MSG_MAX_PAYLOAD 488
++
++#include "mmal-msg-common.h"
++#include "mmal-msg-format.h"
++#include "mmal-msg-port.h"
++
++enum mmal_msg_type {
++ MMAL_MSG_TYPE_QUIT = 1,
++ MMAL_MSG_TYPE_SERVICE_CLOSED,
++ MMAL_MSG_TYPE_GET_VERSION,
++ MMAL_MSG_TYPE_COMPONENT_CREATE,
++ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
++ MMAL_MSG_TYPE_COMPONENT_ENABLE,
++ MMAL_MSG_TYPE_COMPONENT_DISABLE,
++ MMAL_MSG_TYPE_PORT_INFO_GET,
++ MMAL_MSG_TYPE_PORT_INFO_SET,
++ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
++ MMAL_MSG_TYPE_BUFFER_FROM_HOST,
++ MMAL_MSG_TYPE_BUFFER_TO_HOST,
++ MMAL_MSG_TYPE_GET_STATS,
++ MMAL_MSG_TYPE_PORT_PARAMETER_SET,
++ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
++ MMAL_MSG_TYPE_EVENT_TO_HOST,
++ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
++ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
++ MMAL_MSG_TYPE_CONSUME_MEM,
++ MMAL_MSG_TYPE_LMK, /* 20 */
++ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
++ MMAL_MSG_TYPE_DRM_GET_LHS32,
++ MMAL_MSG_TYPE_DRM_GET_TIME,
++ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
++ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
++ MMAL_MSG_TYPE_HOST_LOG,
++ MMAL_MSG_TYPE_MSG_LAST
++};
++
++/* port action request messages differ depending on the action type */
++enum mmal_msg_port_action_type {
++ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unkown action */
++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
++ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
++ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
++};
++
++struct mmal_msg_header {
++ u32 magic;
++ u32 type; /** enum mmal_msg_type */
++
++ /* Opaque handle to the control service */
++ struct mmal_control_service *control_service;
++
++ struct mmal_msg_context *context; /** a u32 per message context */
++ u32 status; /** The status of the vchiq operation */
++ u32 padding;
++};
++
++/* Send from VC to host to report version */
++struct mmal_msg_version {
++ u32 flags;
++ u32 major;
++ u32 minor;
++ u32 minimum;
++};
++
++/* request to VC to create component */
++struct mmal_msg_component_create {
++ void *client_component; /* component context */
++ char name[128];
++ u32 pid; /* For debug */
++};
++
++/* reply from VC to component creation request */
++struct mmal_msg_component_create_reply {
++ u32 status; /** enum mmal_msg_status - how does this differ to
++ * the one in the header?
++ */
++ u32 component_handle; /* VideoCore handle for component */
++ u32 input_num; /* Number of input ports */
++ u32 output_num; /* Number of output ports */
++ u32 clock_num; /* Number of clock ports */
++};
++
++/* request to VC to destroy a component */
++struct mmal_msg_component_destroy {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_destroy_reply {
++ u32 status; /** The component destruction status */
++};
++
++
++/* request and reply to VC to enable a component */
++struct mmal_msg_component_enable {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_enable_reply {
++ u32 status; /** The component enable status */
++};
++
++
++/* request and reply to VC to disable a component */
++struct mmal_msg_component_disable {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_disable_reply {
++ u32 status; /** The component disable status */
++};
++
++/* request to VC to get port information */
++struct mmal_msg_port_info_get {
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 index; /* port index to query */
++};
++
++/* reply from VC to get port info request */
++struct mmal_msg_port_info_get_reply {
++ u32 status; /** enum mmal_msg_status */
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 port_index; /* port indexed in query */
++ s32 found; /* unused */
++ u32 port_handle; /**< Handle to use for this port */
++ struct mmal_port port;
++ struct mmal_es_format format; /* elementry stream format */
++ union mmal_es_specific_format es; /* es type specific data */
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */
++};
++
++/* request to VC to set port information */
++struct mmal_msg_port_info_set {
++ u32 component_handle;
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 port_index; /* port indexed in query */
++ struct mmal_port port;
++ struct mmal_es_format format;
++ union mmal_es_specific_format es;
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
++};
++
++/* reply from VC to port info set request */
++struct mmal_msg_port_info_set_reply {
++ u32 status;
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 index; /* port indexed in query */
++ s32 found; /* unused */
++ u32 port_handle; /**< Handle to use for this port */
++ struct mmal_port port;
++ struct mmal_es_format format;
++ union mmal_es_specific_format es;
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
++};
++
++
++/* port action requests that take a mmal_port as a parameter */
++struct mmal_msg_port_action_port {
++ u32 component_handle;
++ u32 port_handle;
++ u32 action; /* enum mmal_msg_port_action_type */
++ struct mmal_port port;
++};
++
++/* port action requests that take handles as a parameter */
++struct mmal_msg_port_action_handle {
++ u32 component_handle;
++ u32 port_handle;
++ u32 action; /* enum mmal_msg_port_action_type */
++ u32 connect_component_handle;
++ u32 connect_port_handle;
++};
++
++struct mmal_msg_port_action_reply {
++ u32 status; /** The port action operation status */
++};
++
++
++
++
++/* MMAL buffer transfer */
++
++/** Size of space reserved in a buffer message for short messages. */
++#define MMAL_VC_SHORT_DATA 128
++
++/** Signals that the current payload is the end of the stream of data */
++#define MMAL_BUFFER_HEADER_FLAG_EOS (1<<0)
++/** Signals that the start of the current payload starts a frame */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME_START (1<<1)
++/** Signals that the end of the current payload ends a frame */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME_END (1<<2)
++/** Signals that the current payload contains only complete frames (>1) */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME \
++ (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
++/** Signals that the current payload is a keyframe (i.e. self decodable) */
++#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME (1<<3)
++/** Signals a discontinuity in the stream of data (e.g. after a seek).
++ * Can be used for instance by a decoder to reset its state */
++#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY (1<<4)
++/** Signals a buffer containing some kind of config data for the component
++ * (e.g. codec config data) */
++#define MMAL_BUFFER_HEADER_FLAG_CONFIG (1<<5)
++/** Signals an encrypted payload */
++#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED (1<<6)
++/** Signals a buffer containing side information */
++#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO (1<<7)
++/** Signals a buffer which is the snapshot/postview image from a stills
++ * capture
++ */
++#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT (1<<8)
++/** Signals a buffer which contains data known to be corrupted */
++#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED (1<<9)
++/** Signals that a buffer failed to be transmitted */
++#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED (1<<10)
++
++struct mmal_driver_buffer {
++ u32 magic;
++ u32 component_handle;
++ u32 port_handle;
++ void *client_context;
++};
++
++/* buffer header */
++struct mmal_buffer_header {
++ struct mmal_buffer_header *next; /* next header */
++ void *priv; /* framework private data */
++ u32 cmd;
++ void *data;
++ u32 alloc_size;
++ u32 length;
++ u32 offset;
++ u32 flags;
++ s64 pts;
++ s64 dts;
++ void *type;
++ void *user_data;
++};
++
++struct mmal_buffer_header_type_specific {
++ union {
++ struct {
++ u32 planes;
++ u32 offset[4];
++ u32 pitch[4];
++ u32 flags;
++ } video;
++ } u;
++};
++
++struct mmal_msg_buffer_from_host {
++ /* The front 32 bytes of the buffer header are copied
++ * back to us in the reply to allow for context. This
++ * area is used to store two mmal_driver_buffer structures to
++ * allow for multiple concurrent service users.
++ */
++ /* control data */
++ struct mmal_driver_buffer drvbuf;
++
++ /* referenced control data for passthrough buffer management */
++ struct mmal_driver_buffer drvbuf_ref;
++ struct mmal_buffer_header buffer_header; /* buffer header itself */
++ struct mmal_buffer_header_type_specific buffer_header_type_specific;
++ s32 is_zero_copy;
++ s32 has_reference;
++
++ /** allows short data to be xfered in control message */
++ u32 payload_in_message;
++ u8 short_data[MMAL_VC_SHORT_DATA];
++};
++
++
++/* port parameter setting */
++
++#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
++
++struct mmal_msg_port_parameter_set {
++ u32 component_handle; /* component */
++ u32 port_handle; /* port */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
++};
++
++struct mmal_msg_port_parameter_set_reply {
++ u32 status; /** enum mmal_msg_status todo: how does this
++ * differ to the one in the header?
++ */
++};
++
++/* port parameter getting */
++
++struct mmal_msg_port_parameter_get {
++ u32 component_handle; /* component */
++ u32 port_handle; /* port */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++};
++
++struct mmal_msg_port_parameter_get_reply {
++ u32 status; /* Status of mmal_port_parameter_get call */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
++};
++
++/* event messages */
++#define MMAL_WORKER_EVENT_SPACE 256
++
++struct mmal_msg_event_to_host {
++ void *client_component; /* component context */
++
++ u32 port_type;
++ u32 port_num;
++
++ u32 cmd;
++ u32 length;
++ u8 data[MMAL_WORKER_EVENT_SPACE];
++ struct mmal_buffer_header *delayed_buffer;
++};
++
++/* all mmal messages are serialised through this structure */
++struct mmal_msg {
++ /* header */
++ struct mmal_msg_header h;
++ /* payload */
++ union {
++ struct mmal_msg_version version;
++
++ struct mmal_msg_component_create component_create;
++ struct mmal_msg_component_create_reply component_create_reply;
++
++ struct mmal_msg_component_destroy component_destroy;
++ struct mmal_msg_component_destroy_reply component_destroy_reply;
++
++ struct mmal_msg_component_enable component_enable;
++ struct mmal_msg_component_enable_reply component_enable_reply;
++
++ struct mmal_msg_component_disable component_disable;
++ struct mmal_msg_component_disable_reply component_disable_reply;
++
++ struct mmal_msg_port_info_get port_info_get;
++ struct mmal_msg_port_info_get_reply port_info_get_reply;
++
++ struct mmal_msg_port_info_set port_info_set;
++ struct mmal_msg_port_info_set_reply port_info_set_reply;
++
++ struct mmal_msg_port_action_port port_action_port;
++ struct mmal_msg_port_action_handle port_action_handle;
++ struct mmal_msg_port_action_reply port_action_reply;
++
++ struct mmal_msg_buffer_from_host buffer_from_host;
++
++ struct mmal_msg_port_parameter_set port_parameter_set;
++ struct mmal_msg_port_parameter_set_reply
++ port_parameter_set_reply;
++ struct mmal_msg_port_parameter_get
++ port_parameter_get;
++ struct mmal_msg_port_parameter_get_reply
++ port_parameter_get_reply;
++
++ struct mmal_msg_event_to_host event_to_host;
++
++ u8 payload[MMAL_MSG_MAX_PAYLOAD];
++ } u;
++};
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-parameters.h
+@@ -0,0 +1,539 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++/* common parameters */
++
++/** @name Parameter groups
++ * Parameters are divided into groups, and then allocated sequentially within
++ * a group using an enum.
++ * @{
++ */
++
++/** Common parameter ID group, used with many types of component. */
++#define MMAL_PARAMETER_GROUP_COMMON (0<<16)
++/** Camera-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_CAMERA (1<<16)
++/** Video-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_VIDEO (2<<16)
++/** Audio-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_AUDIO (3<<16)
++/** Clock-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_CLOCK (4<<16)
++/** Miracast-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_MIRACAST (5<<16)
++
++/* Common parameters */
++enum mmal_parameter_common_type {
++ MMAL_PARAMETER_UNUSED /**< Never a valid parameter ID */
++ = MMAL_PARAMETER_GROUP_COMMON,
++ MMAL_PARAMETER_SUPPORTED_ENCODINGS, /**< MMAL_PARAMETER_ENCODING_T */
++ MMAL_PARAMETER_URI, /**< MMAL_PARAMETER_URI_T */
++
++ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
++ MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
++
++ /** MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ZERO_COPY,
++
++ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
++ MMAL_PARAMETER_BUFFER_REQUIREMENTS,
++
++ MMAL_PARAMETER_STATISTICS, /**< MMAL_PARAMETER_STATISTICS_T */
++ MMAL_PARAMETER_CORE_STATISTICS, /**< MMAL_PARAMETER_CORE_STATISTICS_T */
++ MMAL_PARAMETER_MEM_USAGE, /**< MMAL_PARAMETER_MEM_USAGE_T */
++ MMAL_PARAMETER_BUFFER_FLAG_FILTER, /**< MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */
++ MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */
++ MMAL_PARAMETER_SYSTEM_TIME /**< MMAL_PARAMETER_UINT64_T */
++};
++
++/* camera parameters */
++
++enum mmal_parameter_camera_type {
++ /* 0 */
++ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
++ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION
++ = MMAL_PARAMETER_GROUP_CAMERA,
++ MMAL_PARAMETER_CAPTURE_QUALITY, /**< Unused? */
++ MMAL_PARAMETER_ROTATION, /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_EXIF_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_EXIF, /**< @ref MMAL_PARAMETER_EXIF_T */
++ MMAL_PARAMETER_AWB_MODE, /**< @ref MMAL_PARAM_AWBMODE_T */
++ MMAL_PARAMETER_IMAGE_EFFECT, /**< @ref MMAL_PARAMETER_IMAGEFX_T */
++ MMAL_PARAMETER_COLOUR_EFFECT, /**< @ref MMAL_PARAMETER_COLOURFX_T */
++ MMAL_PARAMETER_FLICKER_AVOID, /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
++ MMAL_PARAMETER_FLASH, /**< @ref MMAL_PARAMETER_FLASH_T */
++ MMAL_PARAMETER_REDEYE, /**< @ref MMAL_PARAMETER_REDEYE_T */
++ MMAL_PARAMETER_FOCUS, /**< @ref MMAL_PARAMETER_FOCUS_T */
++ MMAL_PARAMETER_FOCAL_LENGTHS, /**< Unused? */
++ MMAL_PARAMETER_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_ZOOM, /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
++ MMAL_PARAMETER_MIRROR, /**< @ref MMAL_PARAMETER_MIRROR_T */
++
++ /* 0x10 */
++ MMAL_PARAMETER_CAMERA_NUM, /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_EXPOSURE_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
++ MMAL_PARAMETER_EXP_METERING_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
++ MMAL_PARAMETER_FOCUS_STATUS, /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
++ MMAL_PARAMETER_CAMERA_CONFIG, /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
++ MMAL_PARAMETER_CAPTURE_STATUS, /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
++ MMAL_PARAMETER_FACE_TRACK, /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
++ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_JPEG_Q_FACTOR, /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_FRAME_RATE, /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
++ MMAL_PARAMETER_USE_STC, /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
++ MMAL_PARAMETER_CAMERA_INFO, /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
++ MMAL_PARAMETER_VIDEO_STABILISATION, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_FACE_TRACK_RESULTS, /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
++ MMAL_PARAMETER_ENABLE_RAW_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++
++ /* 0x20 */
++ MMAL_PARAMETER_DPF_FILE, /**< @ref MMAL_PARAMETER_URI_T */
++ MMAL_PARAMETER_ENABLE_DPF_FILE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_DPF_FAIL_IS_FATAL, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAPTURE_MODE, /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
++ MMAL_PARAMETER_FOCUS_REGIONS, /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
++ MMAL_PARAMETER_INPUT_CROP, /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
++ MMAL_PARAMETER_SENSOR_INFORMATION, /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
++ MMAL_PARAMETER_FLASH_SELECT, /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
++ MMAL_PARAMETER_FIELD_OF_VIEW, /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
++ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< @ref MMAL_PARAMETER_DRC_T */
++ MMAL_PARAMETER_ALGORITHM_CONTROL, /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
++ MMAL_PARAMETER_SHARPNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_CONTRAST, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_BRIGHTNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_SATURATION, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++
++ /* 0x30 */
++ MMAL_PARAMETER_ISO, /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_ANTISHAKE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++
++ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
++ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAMERA_MIN_ISO,
++
++ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
++ MMAL_PARAMETER_CAMERA_USE_CASE,
++
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAPTURE_STATS_PASS,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ENABLE_REGISTER_FILE,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
++
++ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
++ MMAL_PARAMETER_CONFIGFILE_REGISTERS,
++
++ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
++ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
++ MMAL_PARAMETER_JPEG_ATTACH_LOG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ZERO_SHUTTER_LAG, /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
++ MMAL_PARAMETER_FPS_RANGE, /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
++ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
++
++ /* 0x40 */
++ MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++};
++
++enum mmal_parameter_camera_config_timestamp_mode {
++ MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */
++ MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value
++ * for the frame timestamp
++ */
++ MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp
++ * but subtract the
++ * timestamp of the first
++ * frame sent to give a
++ * zero based timestamp.
++ */
++};
++
++/* camera configuration parameter */
++struct mmal_parameter_camera_config {
++ /* Parameters for setting up the image pools */
++ u32 max_stills_w; /* Max size of stills capture */
++ u32 max_stills_h;
++ u32 stills_yuv422; /* Allow YUV422 stills capture */
++ u32 one_shot_stills; /* Continuous or one shot stills captures. */
++
++ u32 max_preview_video_w; /* Max size of the preview or video
++ * capture frames
++ */
++ u32 max_preview_video_h;
++ u32 num_preview_video_frames;
++
++ /** Sets the height of the circular buffer for stills capture. */
++ u32 stills_capture_circular_buffer_height;
++
++ /** Allows preview/encode to resume as fast as possible after the stills
++ * input frame has been received, and then processes the still frame in
++ * the background whilst preview/encode has resumed.
++ * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
++ */
++ u32 fast_preview_resume;
++
++ /** Selects algorithm for timestamping frames if
++ * there is no clock component connected.
++ * enum mmal_parameter_camera_config_timestamp_mode
++ */
++ s32 use_stc_timestamp;
++};
++
++
++enum mmal_parameter_exposuremode {
++ MMAL_PARAM_EXPOSUREMODE_OFF,
++ MMAL_PARAM_EXPOSUREMODE_AUTO,
++ MMAL_PARAM_EXPOSUREMODE_NIGHT,
++ MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
++ MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
++ MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
++ MMAL_PARAM_EXPOSUREMODE_SPORTS,
++ MMAL_PARAM_EXPOSUREMODE_SNOW,
++ MMAL_PARAM_EXPOSUREMODE_BEACH,
++ MMAL_PARAM_EXPOSUREMODE_VERYLONG,
++ MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
++ MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
++ MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
++};
++
++enum mmal_parameter_exposuremeteringmode {
++ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
++};
++
++enum mmal_parameter_awbmode {
++ MMAL_PARAM_AWBMODE_OFF,
++ MMAL_PARAM_AWBMODE_AUTO,
++ MMAL_PARAM_AWBMODE_SUNLIGHT,
++ MMAL_PARAM_AWBMODE_CLOUDY,
++ MMAL_PARAM_AWBMODE_SHADE,
++ MMAL_PARAM_AWBMODE_TUNGSTEN,
++ MMAL_PARAM_AWBMODE_FLUORESCENT,
++ MMAL_PARAM_AWBMODE_INCANDESCENT,
++ MMAL_PARAM_AWBMODE_FLASH,
++ MMAL_PARAM_AWBMODE_HORIZON,
++};
++
++enum mmal_parameter_imagefx {
++ MMAL_PARAM_IMAGEFX_NONE,
++ MMAL_PARAM_IMAGEFX_NEGATIVE,
++ MMAL_PARAM_IMAGEFX_SOLARIZE,
++ MMAL_PARAM_IMAGEFX_POSTERIZE,
++ MMAL_PARAM_IMAGEFX_WHITEBOARD,
++ MMAL_PARAM_IMAGEFX_BLACKBOARD,
++ MMAL_PARAM_IMAGEFX_SKETCH,
++ MMAL_PARAM_IMAGEFX_DENOISE,
++ MMAL_PARAM_IMAGEFX_EMBOSS,
++ MMAL_PARAM_IMAGEFX_OILPAINT,
++ MMAL_PARAM_IMAGEFX_HATCH,
++ MMAL_PARAM_IMAGEFX_GPEN,
++ MMAL_PARAM_IMAGEFX_PASTEL,
++ MMAL_PARAM_IMAGEFX_WATERCOLOUR,
++ MMAL_PARAM_IMAGEFX_FILM,
++ MMAL_PARAM_IMAGEFX_BLUR,
++ MMAL_PARAM_IMAGEFX_SATURATION,
++ MMAL_PARAM_IMAGEFX_COLOURSWAP,
++ MMAL_PARAM_IMAGEFX_WASHEDOUT,
++ MMAL_PARAM_IMAGEFX_POSTERISE,
++ MMAL_PARAM_IMAGEFX_COLOURPOINT,
++ MMAL_PARAM_IMAGEFX_COLOURBALANCE,
++ MMAL_PARAM_IMAGEFX_CARTOON,
++};
++
++/** Manner of video rate control */
++enum mmal_parameter_rate_control_mode {
++ MMAL_VIDEO_RATECONTROL_DEFAULT,
++ MMAL_VIDEO_RATECONTROL_VARIABLE,
++ MMAL_VIDEO_RATECONTROL_CONSTANT,
++ MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
++ MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES
++};
++
++/* video parameters */
++
++enum mmal_parameter_video_type {
++ /** @ref MMAL_DISPLAYREGION_T */
++ MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO,
++
++ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
++ MMAL_PARAMETER_SUPPORTED_PROFILES,
++
++ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
++ MMAL_PARAMETER_PROFILE,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_INTRAPERIOD,
++
++ /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
++ MMAL_PARAMETER_RATECONTROL,
++
++ /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
++ MMAL_PARAMETER_NALUNITFORMAT,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
++
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Setting the value to zero resets to the default (one slice per frame).
++ */
++ MMAL_PARAMETER_MB_ROWS_PER_SLICE,
++
++ /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
++ MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,
++
++ /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
++ MMAL_PARAMETER_VIDEO_EEDE_ENABLE,
++
++ /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
++ MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */
++ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
++ /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
++ MMAL_PARAMETER_VIDEO_INTRA_REFRESH,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */
++ MMAL_PARAMETER_VIDEO_BIT_RATE,
++
++ /** @ref MMAL_PARAMETER_FRAME_RATE_T */
++ MMAL_PARAMETER_VIDEO_FRAME_RATE,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
++
++ /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,
++
++ MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Changing this parameter from the default can reduce frame rate
++ * because image buffers need to be re-pitched.
++ */
++ MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,
++
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Changing this parameter from the default can reduce frame rate
++ * because image buffers need to be re-pitched.
++ */
++ MMAL_PARAMETER_VIDEO_ALIGN_VERT,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
++
++ /**< @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_QP_P,
++
++ /**< @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,
++
++ /* H264 specific parameters */
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,
++
++ /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
++
++ /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
++ MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
++
++ /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
++ MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,
++
++ /** @ref MMAL_PARAMETER_BYTES_T */
++ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3
++};
++
++/** Valid mirror modes */
++enum mmal_parameter_mirror {
++ MMAL_PARAM_MIRROR_NONE,
++ MMAL_PARAM_MIRROR_VERTICAL,
++ MMAL_PARAM_MIRROR_HORIZONTAL,
++ MMAL_PARAM_MIRROR_BOTH,
++};
++
++enum mmal_parameter_displaytransform {
++ MMAL_DISPLAY_ROT0 = 0,
++ MMAL_DISPLAY_MIRROR_ROT0 = 1,
++ MMAL_DISPLAY_MIRROR_ROT180 = 2,
++ MMAL_DISPLAY_ROT180 = 3,
++ MMAL_DISPLAY_MIRROR_ROT90 = 4,
++ MMAL_DISPLAY_ROT270 = 5,
++ MMAL_DISPLAY_ROT90 = 6,
++ MMAL_DISPLAY_MIRROR_ROT270 = 7,
++};
++
++enum mmal_parameter_displaymode {
++ MMAL_DISPLAY_MODE_FILL = 0,
++ MMAL_DISPLAY_MODE_LETTERBOX = 1,
++};
++
++enum mmal_parameter_displayset {
++ MMAL_DISPLAY_SET_NONE = 0,
++ MMAL_DISPLAY_SET_NUM = 1,
++ MMAL_DISPLAY_SET_FULLSCREEN = 2,
++ MMAL_DISPLAY_SET_TRANSFORM = 4,
++ MMAL_DISPLAY_SET_DEST_RECT = 8,
++ MMAL_DISPLAY_SET_SRC_RECT = 0x10,
++ MMAL_DISPLAY_SET_MODE = 0x20,
++ MMAL_DISPLAY_SET_PIXEL = 0x40,
++ MMAL_DISPLAY_SET_NOASPECT = 0x80,
++ MMAL_DISPLAY_SET_LAYER = 0x100,
++ MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
++ MMAL_DISPLAY_SET_ALPHA = 0x400,
++};
++
++struct mmal_parameter_displayregion {
++ /** Bitfield that indicates which fields are set and should be
++ * used. All other fields will maintain their current value.
++ * \ref MMAL_DISPLAYSET_T defines the bits that can be
++ * combined.
++ */
++ u32 set;
++
++ /** Describes the display output device, with 0 typically
++ * being a directly connected LCD display. The actual values
++ * will depend on the hardware. Code using hard-wired numbers
++ * (e.g. 2) is certain to fail.
++ */
++
++ u32 display_num;
++ /** Indicates that we are using the full device screen area,
++ * rather than a window of the display. If zero, then
++ * dest_rect is used to specify a region of the display to
++ * use.
++ */
++
++ s32 fullscreen;
++ /** Indicates any rotation or flipping used to map frames onto
++ * the natural display orientation.
++ */
++ u32 transform; /* enum mmal_parameter_displaytransform */
++
++ /** Where to display the frame within the screen, if
++ * fullscreen is zero.
++ */
++ struct vchiq_mmal_rect dest_rect;
++
++ /** Indicates which area of the frame to display. If all
++ * values are zero, the whole frame will be used.
++ */
++ struct vchiq_mmal_rect src_rect;
++
++ /** If set to non-zero, indicates that any display scaling
++ * should disregard the aspect ratio of the frame region being
++ * displayed.
++ */
++ s32 noaspect;
++
++ /** Indicates how the image should be scaled to fit the
++ * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates
++ * that the image should fill the screen by potentially
++ * cropping the frames. Setting \code mode \endcode to \code
++ * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the
++ * source region should be displayed and black bars added if
++ * necessary.
++ */
++ u32 mode; /* enum mmal_parameter_displaymode */
++
++ /** If non-zero, defines the width of a source pixel relative
++ * to \code pixel_y \endcode. If zero, then pixels default to
++ * being square.
++ */
++ u32 pixel_x;
++
++ /** If non-zero, defines the height of a source pixel relative
++ * to \code pixel_x \endcode. If zero, then pixels default to
++ * being square.
++ */
++ u32 pixel_y;
++
++ /** Sets the relative depth of the images, with greater values
++ * being in front of smaller values.
++ */
++ u32 layer;
++
++ /** Set to non-zero to ensure copy protection is used on
++ * output.
++ */
++ s32 copyprotect_required;
++
++ /** Level of opacity of the layer, where zero is fully
++ * transparent and 255 is fully opaque.
++ */
++ u32 alpha;
++};
++
++#define MMAL_MAX_IMAGEFX_PARAMETERS 5
++
++struct mmal_parameter_imagefx_parameters {
++ enum mmal_parameter_imagefx effect;
++ u32 num_effect_params;
++ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
++};
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-vchiq.c
+@@ -0,0 +1,1916 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ *
++ * V4L2 driver MMAL vchiq interface code
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/mutex.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/completion.h>
++#include <linux/vmalloc.h>
++#include <asm/cacheflush.h>
++#include <media/videobuf2-vmalloc.h>
++
++#include "mmal-common.h"
++#include "mmal-vchiq.h"
++#include "mmal-msg.h"
++
++#define USE_VCHIQ_ARM
++#include "interface/vchi/vchi.h"
++
++/* maximum number of components supported */
++#define VCHIQ_MMAL_MAX_COMPONENTS 4
++
++/*#define FULL_MSG_DUMP 1*/
++
++#ifdef DEBUG
++static const char *const msg_type_names[] = {
++ "UNKNOWN",
++ "QUIT",
++ "SERVICE_CLOSED",
++ "GET_VERSION",
++ "COMPONENT_CREATE",
++ "COMPONENT_DESTROY",
++ "COMPONENT_ENABLE",
++ "COMPONENT_DISABLE",
++ "PORT_INFO_GET",
++ "PORT_INFO_SET",
++ "PORT_ACTION",
++ "BUFFER_FROM_HOST",
++ "BUFFER_TO_HOST",
++ "GET_STATS",
++ "PORT_PARAMETER_SET",
++ "PORT_PARAMETER_GET",
++ "EVENT_TO_HOST",
++ "GET_CORE_STATS_FOR_PORT",
++ "OPAQUE_ALLOCATOR",
++ "CONSUME_MEM",
++ "LMK",
++ "OPAQUE_ALLOCATOR_DESC",
++ "DRM_GET_LHS32",
++ "DRM_GET_TIME",
++ "BUFFER_FROM_HOST_ZEROLEN",
++ "PORT_FLUSH",
++ "HOST_LOG",
++};
++#endif
++
++static const char *const port_action_type_names[] = {
++ "UNKNOWN",
++ "ENABLE",
++ "DISABLE",
++ "FLUSH",
++ "CONNECT",
++ "DISCONNECT",
++ "SET_REQUIREMENTS",
++};
++
++#if defined(DEBUG)
++#if defined(FULL_MSG_DUMP)
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
++ do { \
++ pr_debug(TITLE" type:%s(%d) length:%d\n", \
++ msg_type_names[(MSG)->h.type], \
++ (MSG)->h.type, (MSG_LEN)); \
++ print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
++ 16, 4, (MSG), \
++ sizeof(struct mmal_msg_header), 1); \
++ print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
++ 16, 4, \
++ ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
++ (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
++ } while (0)
++#else
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
++ { \
++ pr_debug(TITLE" type:%s(%d) length:%d\n", \
++ msg_type_names[(MSG)->h.type], \
++ (MSG)->h.type, (MSG_LEN)); \
++ }
++#endif
++#else
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
++#endif
++
++/* normal message context */
++struct mmal_msg_context {
++ union {
++ struct {
++ /* work struct for defered callback - must come first */
++ struct work_struct work;
++ /* mmal instance */
++ struct vchiq_mmal_instance *instance;
++ /* mmal port */
++ struct vchiq_mmal_port *port;
++ /* actual buffer used to store bulk reply */
++ struct mmal_buffer *buffer;
++ /* amount of buffer used */
++ unsigned long buffer_used;
++ /* MMAL buffer flags */
++ u32 mmal_flags;
++ /* Presentation and Decode timestamps */
++ s64 pts;
++ s64 dts;
++
++ int status; /* context status */
++
++ } bulk; /* bulk data */
++
++ struct {
++ /* message handle to release */
++ VCHI_HELD_MSG_T msg_handle;
++ /* pointer to received message */
++ struct mmal_msg *msg;
++ /* received message length */
++ u32 msg_len;
++ /* completion upon reply */
++ struct completion cmplt;
++ } sync; /* synchronous response */
++ } u;
++
++};
++
++struct vchiq_mmal_instance {
++ VCHI_SERVICE_HANDLE_T handle;
++
++ /* ensure serialised access to service */
++ struct mutex vchiq_mutex;
++
++ /* ensure serialised access to bulk operations */
++ struct mutex bulk_mutex;
++
++ /* vmalloc page to receive scratch bulk xfers into */
++ void *bulk_scratch;
++
++ /* component to use next */
++ int component_idx;
++ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
++};
++
++static struct mmal_msg_context *get_msg_context(struct vchiq_mmal_instance
++ *instance)
++{
++ struct mmal_msg_context *msg_context;
++
++ /* todo: should this be allocated from a pool to avoid kmalloc */
++ msg_context = kmalloc(sizeof(*msg_context), GFP_KERNEL);
++ memset(msg_context, 0, sizeof(*msg_context));
++
++ return msg_context;
++}
++
++static void release_msg_context(struct mmal_msg_context *msg_context)
++{
++ kfree(msg_context);
++}
++
++/* deals with receipt of event to host message */
++static void event_to_host_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg, u32 msg_len)
++{
++ pr_debug("unhandled event\n");
++ pr_debug("component:%p port type:%d num:%d cmd:0x%x length:%d\n",
++ msg->u.event_to_host.client_component,
++ msg->u.event_to_host.port_type,
++ msg->u.event_to_host.port_num,
++ msg->u.event_to_host.cmd, msg->u.event_to_host.length);
++}
++
++/* workqueue scheduled callback
++ *
++ * we do this because it is important we do not call any other vchiq
++ * sync calls from witin the message delivery thread
++ */
++static void buffer_work_cb(struct work_struct *work)
++{
++ struct mmal_msg_context *msg_context = (struct mmal_msg_context *)work;
++
++ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
++ msg_context->u.bulk.port,
++ msg_context->u.bulk.status,
++ msg_context->u.bulk.buffer,
++ msg_context->u.bulk.buffer_used,
++ msg_context->u.bulk.mmal_flags,
++ msg_context->u.bulk.dts,
++ msg_context->u.bulk.pts);
++
++ /* release message context */
++ release_msg_context(msg_context);
++}
++
++/* enqueue a bulk receive for a given message context */
++static int bulk_receive(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ struct mmal_msg_context *msg_context)
++{
++ unsigned long rd_len;
++ unsigned long flags = 0;
++ int ret;
++
++ /* bulk mutex stops other bulk operations while we have a
++ * receive in progress - released in callback
++ */
++ ret = mutex_lock_interruptible(&instance->bulk_mutex);
++ if (ret != 0)
++ return ret;
++
++ rd_len = msg->u.buffer_from_host.buffer_header.length;
++
++ /* take buffer from queue */
++ spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
++ if (list_empty(&msg_context->u.bulk.port->buffers)) {
++ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
++ pr_err("buffer list empty trying to submit bulk receive\n");
++
++ /* todo: this is a serious error, we should never have
++ * commited a buffer_to_host operation to the mmal
++ * port without the buffer to back it up (underflow
++ * handling) and there is no obvious way to deal with
++ * this - how is the mmal servie going to react when
++ * we fail to do the xfer and reschedule a buffer when
++ * it arrives? perhaps a starved flag to indicate a
++ * waiting bulk receive?
++ */
++
++ mutex_unlock(&instance->bulk_mutex);
++
++ return -EINVAL;
++ }
++
++ msg_context->u.bulk.buffer =
++ list_entry(msg_context->u.bulk.port->buffers.next,
++ struct mmal_buffer, list);
++ list_del(&msg_context->u.bulk.buffer->list);
++
++ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
++
++ /* ensure we do not overrun the available buffer */
++ if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
++ rd_len = msg_context->u.bulk.buffer->buffer_size;
++ pr_warn("short read as not enough receive buffer space\n");
++ /* todo: is this the correct response, what happens to
++ * the rest of the message data?
++ */
++ }
++
++ /* store length */
++ msg_context->u.bulk.buffer_used = rd_len;
++ msg_context->u.bulk.mmal_flags =
++ msg->u.buffer_from_host.buffer_header.flags;
++ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
++ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
++
++ // only need to flush L1 cache here, as VCHIQ takes care of the L2
++ // cache.
++ __cpuc_flush_dcache_area(msg_context->u.bulk.buffer->buffer, rd_len);
++
++ /* queue the bulk submission */
++ vchi_service_use(instance->handle);
++ ret = vchi_bulk_queue_receive(instance->handle,
++ msg_context->u.bulk.buffer->buffer,
++ /* Actual receive needs to be a multiple
++ * of 4 bytes
++ */
++ (rd_len + 3) & ~3,
++ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
++ msg_context);
++
++ vchi_service_release(instance->handle);
++
++ if (ret != 0) {
++ /* callback will not be clearing the mutex */
++ mutex_unlock(&instance->bulk_mutex);
++ }
++
++ return ret;
++}
++
++/* enque a dummy bulk receive for a given message context */
++static int dummy_bulk_receive(struct vchiq_mmal_instance *instance,
++ struct mmal_msg_context *msg_context)
++{
++ int ret;
++
++ /* bulk mutex stops other bulk operations while we have a
++ * receive in progress - released in callback
++ */
++ ret = mutex_lock_interruptible(&instance->bulk_mutex);
++ if (ret != 0)
++ return ret;
++
++ /* zero length indicates this was a dummy transfer */
++ msg_context->u.bulk.buffer_used = 0;
++
++ /* queue the bulk submission */
++ vchi_service_use(instance->handle);
++
++ ret = vchi_bulk_queue_receive(instance->handle,
++ instance->bulk_scratch,
++ 8,
++ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
++ msg_context);
++
++ vchi_service_release(instance->handle);
++
++ if (ret != 0) {
++ /* callback will not be clearing the mutex */
++ mutex_unlock(&instance->bulk_mutex);
++ }
++
++ return ret;
++}
++
++/* data in message, memcpy from packet into output buffer */
++static int inline_receive(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ struct mmal_msg_context *msg_context)
++{
++ unsigned long flags = 0;
++
++ /* take buffer from queue */
++ spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
++ if (list_empty(&msg_context->u.bulk.port->buffers)) {
++ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
++ pr_err("buffer list empty trying to receive inline\n");
++
++ /* todo: this is a serious error, we should never have
++ * commited a buffer_to_host operation to the mmal
++ * port without the buffer to back it up (with
++ * underflow handling) and there is no obvious way to
++ * deal with this. Less bad than the bulk case as we
++ * can just drop this on the floor but...unhelpful
++ */
++ return -EINVAL;
++ }
++
++ msg_context->u.bulk.buffer =
++ list_entry(msg_context->u.bulk.port->buffers.next,
++ struct mmal_buffer, list);
++ list_del(&msg_context->u.bulk.buffer->list);
++
++ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
++
++ memcpy(msg_context->u.bulk.buffer->buffer,
++ msg->u.buffer_from_host.short_data,
++ msg->u.buffer_from_host.payload_in_message);
++
++ msg_context->u.bulk.buffer_used =
++ msg->u.buffer_from_host.payload_in_message;
++
++ return 0;
++}
++
++/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
++static int
++buffer_from_host(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port, struct mmal_buffer *buf)
++{
++ struct mmal_msg_context *msg_context;
++ struct mmal_msg m;
++ int ret;
++
++ pr_debug("instance:%p buffer:%p\n", instance->handle, buf);
++
++ /* bulk mutex stops other bulk operations while we
++ * have a receive in progress
++ */
++ if (mutex_lock_interruptible(&instance->bulk_mutex))
++ return -EINTR;
++
++ /* get context */
++ msg_context = get_msg_context(instance);
++ if (msg_context == NULL)
++ return -ENOMEM;
++
++ /* store bulk message context for when data arrives */
++ msg_context->u.bulk.instance = instance;
++ msg_context->u.bulk.port = port;
++ msg_context->u.bulk.buffer = NULL; /* not valid until bulk xfer */
++ msg_context->u.bulk.buffer_used = 0;
++
++ /* initialise work structure ready to schedule callback */
++ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
++
++ /* prep the buffer from host message */
++ memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
++
++ m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
++ m.h.magic = MMAL_MAGIC;
++ m.h.context = msg_context;
++ m.h.status = 0;
++
++ /* drvbuf is our private data passed back */
++ m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
++ m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
++ m.u.buffer_from_host.drvbuf.port_handle = port->handle;
++ m.u.buffer_from_host.drvbuf.client_context = msg_context;
++
++ /* buffer header */
++ m.u.buffer_from_host.buffer_header.cmd = 0;
++ m.u.buffer_from_host.buffer_header.data = buf->buffer;
++ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
++ m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
++ m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
++ m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
++ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
++ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
++
++ /* clear buffer type sepecific data */
++ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
++ sizeof(m.u.buffer_from_host.buffer_header_type_specific));
++
++ /* no payload in message */
++ m.u.buffer_from_host.payload_in_message = 0;
++
++ vchi_service_use(instance->handle);
++
++ ret = vchi_msg_queue(instance->handle, &m,
++ sizeof(struct mmal_msg_header) +
++ sizeof(m.u.buffer_from_host),
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (ret != 0) {
++ release_msg_context(msg_context);
++ /* todo: is this correct error value? */
++ }
++
++ vchi_service_release(instance->handle);
++
++ mutex_unlock(&instance->bulk_mutex);
++
++ return ret;
++}
++
++/* submit a buffer to the mmal sevice
++ *
++ * the buffer_from_host uses size data from the ports next available
++ * mmal_buffer and deals with there being no buffer available by
++ * incrementing the underflow for later
++ */
++static int port_buffer_from_host(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_buffer *buf;
++ unsigned long flags = 0;
++
++ if (!port->enabled)
++ return -EINVAL;
++
++ /* peek buffer from queue */
++ spin_lock_irqsave(&port->slock, flags);
++ if (list_empty(&port->buffers)) {
++ port->buffer_underflow++;
++ spin_unlock_irqrestore(&port->slock, flags);
++ return -ENOSPC;
++ }
++
++ buf = list_entry(port->buffers.next, struct mmal_buffer, list);
++
++ spin_unlock_irqrestore(&port->slock, flags);
++
++ /* issue buffer to mmal service */
++ ret = buffer_from_host(instance, port, buf);
++ if (ret) {
++ pr_err("adding buffer header failed\n");
++ /* todo: how should this be dealt with */
++ }
++
++ return ret;
++}
++
++/* deals with receipt of buffer to host message */
++static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg, u32 msg_len)
++{
++ struct mmal_msg_context *msg_context;
++
++ pr_debug("buffer_to_host_cb: instance:%p msg:%p msg_len:%d\n",
++ instance, msg, msg_len);
++
++ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
++ msg_context = msg->u.buffer_from_host.drvbuf.client_context;
++ } else {
++ pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
++ return;
++ }
++
++ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
++ /* message reception had an error */
++ pr_warn("error %d in reply\n", msg->h.status);
++
++ msg_context->u.bulk.status = msg->h.status;
++
++ } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
++ /* empty buffer */
++ if (msg->u.buffer_from_host.buffer_header.flags &
++ MMAL_BUFFER_HEADER_FLAG_EOS) {
++ msg_context->u.bulk.status =
++ dummy_bulk_receive(instance, msg_context);
++ if (msg_context->u.bulk.status == 0)
++ return; /* successful bulk submission, bulk
++ * completion will trigger callback
++ */
++ } else {
++ /* do callback with empty buffer - not EOS though */
++ msg_context->u.bulk.status = 0;
++ msg_context->u.bulk.buffer_used = 0;
++ }
++ } else if (msg->u.buffer_from_host.payload_in_message == 0) {
++ /* data is not in message, queue a bulk receive */
++ msg_context->u.bulk.status =
++ bulk_receive(instance, msg, msg_context);
++ if (msg_context->u.bulk.status == 0)
++ return; /* successful bulk submission, bulk
++ * completion will trigger callback
++ */
++
++ /* failed to submit buffer, this will end badly */
++ pr_err("error %d on bulk submission\n",
++ msg_context->u.bulk.status);
++
++ } else if (msg->u.buffer_from_host.payload_in_message <=
++ MMAL_VC_SHORT_DATA) {
++ /* data payload within message */
++ msg_context->u.bulk.status = inline_receive(instance, msg,
++ msg_context);
++ } else {
++ pr_err("message with invalid short payload\n");
++
++ /* signal error */
++ msg_context->u.bulk.status = -EINVAL;
++ msg_context->u.bulk.buffer_used =
++ msg->u.buffer_from_host.payload_in_message;
++ }
++
++ /* replace the buffer header */
++ port_buffer_from_host(instance, msg_context->u.bulk.port);
++
++ /* schedule the port callback */
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg_context *msg_context)
++{
++ /* bulk receive operation complete */
++ mutex_unlock(&msg_context->u.bulk.instance->bulk_mutex);
++
++ /* replace the buffer header */
++ port_buffer_from_host(msg_context->u.bulk.instance,
++ msg_context->u.bulk.port);
++
++ msg_context->u.bulk.status = 0;
++
++ /* schedule the port callback */
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg_context *msg_context)
++{
++ pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
++
++ /* bulk receive operation complete */
++ mutex_unlock(&msg_context->u.bulk.instance->bulk_mutex);
++
++ /* replace the buffer header */
++ port_buffer_from_host(msg_context->u.bulk.instance,
++ msg_context->u.bulk.port);
++
++ msg_context->u.bulk.status = -EINTR;
++
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++/* incoming event service callback */
++static void service_callback(void *param,
++ const VCHI_CALLBACK_REASON_T reason,
++ void *bulk_ctx)
++{
++ struct vchiq_mmal_instance *instance = param;
++ int status;
++ u32 msg_len;
++ struct mmal_msg *msg;
++ VCHI_HELD_MSG_T msg_handle;
++
++ if (!instance) {
++ pr_err("Message callback passed NULL instance\n");
++ return;
++ }
++
++ switch (reason) {
++ case VCHI_CALLBACK_MSG_AVAILABLE:
++ status = vchi_msg_hold(instance->handle, (void **)&msg,
++ &msg_len, VCHI_FLAGS_NONE, &msg_handle);
++ if (status) {
++ pr_err("Unable to dequeue a message (%d)\n", status);
++ break;
++ }
++
++ DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
++
++ /* handling is different for buffer messages */
++ switch (msg->h.type) {
++
++ case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
++ vchi_held_msg_release(&msg_handle);
++ break;
++
++ case MMAL_MSG_TYPE_EVENT_TO_HOST:
++ event_to_host_cb(instance, msg, msg_len);
++ vchi_held_msg_release(&msg_handle);
++
++ break;
++
++ case MMAL_MSG_TYPE_BUFFER_TO_HOST:
++ buffer_to_host_cb(instance, msg, msg_len);
++ vchi_held_msg_release(&msg_handle);
++ break;
++
++ default:
++ /* messages dependant on header context to complete */
++
++ /* todo: the msg.context really ought to be sanity
++ * checked before we just use it, afaict it comes back
++ * and is used raw from the videocore. Perhaps it
++ * should be verified the address lies in the kernel
++ * address space.
++ */
++ if (msg->h.context == NULL) {
++ pr_err("received message context was null!\n");
++ vchi_held_msg_release(&msg_handle);
++ break;
++ }
++
++ /* fill in context values */
++ msg->h.context->u.sync.msg_handle = msg_handle;
++ msg->h.context->u.sync.msg = msg;
++ msg->h.context->u.sync.msg_len = msg_len;
++
++ /* todo: should this check (completion_done()
++ * == 1) for no one waiting? or do we need a
++ * flag to tell us the completion has been
++ * interrupted so we can free the message and
++ * its context. This probably also solves the
++ * message arriving after interruption todo
++ * below
++ */
++
++ /* complete message so caller knows it happened */
++ complete(&msg->h.context->u.sync.cmplt);
++ break;
++ }
++
++ break;
++
++ case VCHI_CALLBACK_BULK_RECEIVED:
++ bulk_receive_cb(instance, bulk_ctx);
++ break;
++
++ case VCHI_CALLBACK_BULK_RECEIVE_ABORTED:
++ bulk_abort_cb(instance, bulk_ctx);
++ break;
++
++ case VCHI_CALLBACK_SERVICE_CLOSED:
++ /* TODO: consider if this requires action if received when
++ * driver is not explicitly closing the service
++ */
++ break;
++
++ default:
++ pr_err("Received unhandled message reason %d\n", reason);
++ break;
++ }
++}
++
++static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ unsigned int payload_len,
++ struct mmal_msg **msg_out,
++ VCHI_HELD_MSG_T *msg_handle_out)
++{
++ struct mmal_msg_context msg_context;
++ int ret;
++
++ /* payload size must not cause message to exceed max size */
++ if (payload_len >
++ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
++ pr_err("payload length %d exceeds max:%d\n", payload_len,
++ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header)));
++ return -EINVAL;
++ }
++
++ init_completion(&msg_context.u.sync.cmplt);
++
++ msg->h.magic = MMAL_MAGIC;
++ msg->h.context = &msg_context;
++ msg->h.status = 0;
++
++ DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
++ ">>> sync message");
++
++ vchi_service_use(instance->handle);
++
++ ret = vchi_msg_queue(instance->handle,
++ msg,
++ sizeof(struct mmal_msg_header) + payload_len,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ vchi_service_release(instance->handle);
++
++ if (ret) {
++ pr_err("error %d queuing message\n", ret);
++ return ret;
++ }
++
++ ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, HZ);
++ if (ret <= 0) {
++ pr_err("error %d waiting for sync completion\n", ret);
++ if (ret == 0)
++ ret = -ETIME;
++ /* todo: what happens if the message arrives after aborting */
++ return ret;
++ }
++
++ *msg_out = msg_context.u.sync.msg;
++ *msg_handle_out = msg_context.u.sync.msg_handle;
++
++ return 0;
++}
++
++static void dump_port_info(struct vchiq_mmal_port *port)
++{
++ pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
++
++ pr_debug("buffer minimum num:%d size:%d align:%d\n",
++ port->minimum_buffer.num,
++ port->minimum_buffer.size, port->minimum_buffer.alignment);
++
++ pr_debug("buffer recommended num:%d size:%d align:%d\n",
++ port->recommended_buffer.num,
++ port->recommended_buffer.size,
++ port->recommended_buffer.alignment);
++
++ pr_debug("buffer current values num:%d size:%d align:%d\n",
++ port->current_buffer.num,
++ port->current_buffer.size, port->current_buffer.alignment);
++
++ pr_debug("elementry stream: type:%d encoding:0x%x varient:0x%x\n",
++ port->format.type,
++ port->format.encoding, port->format.encoding_variant);
++
++ pr_debug(" bitrate:%d flags:0x%x\n",
++ port->format.bitrate, port->format.flags);
++
++ if (port->format.type == MMAL_ES_TYPE_VIDEO) {
++ pr_debug
++ ("es video format: width:%d height:%d colourspace:0x%x\n",
++ port->es.video.width, port->es.video.height,
++ port->es.video.color_space);
++
++ pr_debug(" : crop xywh %d,%d,%d,%d\n",
++ port->es.video.crop.x,
++ port->es.video.crop.y,
++ port->es.video.crop.width, port->es.video.crop.height);
++ pr_debug(" : framerate %d/%d aspect %d/%d\n",
++ port->es.video.frame_rate.num,
++ port->es.video.frame_rate.den,
++ port->es.video.par.num, port->es.video.par.den);
++ }
++}
++
++static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
++{
++
++ /* todo do readonly fields need setting at all? */
++ p->type = port->type;
++ p->index = port->index;
++ p->index_all = 0;
++ p->is_enabled = port->enabled;
++ p->buffer_num_min = port->minimum_buffer.num;
++ p->buffer_size_min = port->minimum_buffer.size;
++ p->buffer_alignment_min = port->minimum_buffer.alignment;
++ p->buffer_num_recommended = port->recommended_buffer.num;
++ p->buffer_size_recommended = port->recommended_buffer.size;
++
++ /* only three writable fields in a port */
++ p->buffer_num = port->current_buffer.num;
++ p->buffer_size = port->current_buffer.size;
++ p->userdata = port;
++}
++
++static int port_info_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ pr_debug("setting port info port %p\n", port);
++ if (!port)
++ return -1;
++ dump_port_info(port);
++
++ m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
++
++ m.u.port_info_set.component_handle = port->component->handle;
++ m.u.port_info_set.port_type = port->type;
++ m.u.port_info_set.port_index = port->index;
++
++ port_to_mmal_msg(port, &m.u.port_info_set.port);
++
++ /* elementry stream format setup */
++ m.u.port_info_set.format.type = port->format.type;
++ m.u.port_info_set.format.encoding = port->format.encoding;
++ m.u.port_info_set.format.encoding_variant =
++ port->format.encoding_variant;
++ m.u.port_info_set.format.bitrate = port->format.bitrate;
++ m.u.port_info_set.format.flags = port->format.flags;
++
++ memcpy(&m.u.port_info_set.es, &port->es,
++ sizeof(union mmal_es_specific_format));
++
++ m.u.port_info_set.format.extradata_size = port->format.extradata_size;
++ memcpy(rmsg->u.port_info_set.extradata, port->format.extradata,
++ port->format.extradata_size);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_info_set),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ /* return operation status */
++ ret = -rmsg->u.port_info_get_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
++ port->component->handle, port->handle);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++
++}
++
++/* use port info get message to retrive port information */
++static int port_info_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ /* port info time */
++ m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
++ m.u.port_info_get.component_handle = port->component->handle;
++ m.u.port_info_get.port_type = port->type;
++ m.u.port_info_get.index = port->index;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_info_get),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ /* return operation status */
++ ret = -rmsg->u.port_info_get_reply.status;
++ if (ret != MMAL_MSG_STATUS_SUCCESS)
++ goto release_msg;
++
++ if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
++ port->enabled = false;
++ else
++ port->enabled = true;
++
++ /* copy the values out of the message */
++ port->handle = rmsg->u.port_info_get_reply.port_handle;
++
++ /* port type and index cached to use on port info set becuase
++ * it does not use a port handle
++ */
++ port->type = rmsg->u.port_info_get_reply.port_type;
++ port->index = rmsg->u.port_info_get_reply.port_index;
++
++ port->minimum_buffer.num =
++ rmsg->u.port_info_get_reply.port.buffer_num_min;
++ port->minimum_buffer.size =
++ rmsg->u.port_info_get_reply.port.buffer_size_min;
++ port->minimum_buffer.alignment =
++ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
++
++ port->recommended_buffer.alignment =
++ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
++ port->recommended_buffer.num =
++ rmsg->u.port_info_get_reply.port.buffer_num_recommended;
++
++ port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
++ port->current_buffer.size =
++ rmsg->u.port_info_get_reply.port.buffer_size;
++
++ /* stream format */
++ port->format.type = rmsg->u.port_info_get_reply.format.type;
++ port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
++ port->format.encoding_variant =
++ rmsg->u.port_info_get_reply.format.encoding_variant;
++ port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
++ port->format.flags = rmsg->u.port_info_get_reply.format.flags;
++
++ /* elementry stream format */
++ memcpy(&port->es,
++ &rmsg->u.port_info_get_reply.es,
++ sizeof(union mmal_es_specific_format));
++ port->format.es = &port->es;
++
++ port->format.extradata_size =
++ rmsg->u.port_info_get_reply.format.extradata_size;
++ memcpy(port->format.extradata,
++ rmsg->u.port_info_get_reply.extradata,
++ port->format.extradata_size);
++
++ pr_debug("received port info\n");
++ dump_port_info(port);
++
++release_msg:
++
++ pr_debug("%s:result:%d component:0x%x port:%d\n",
++ __func__, ret, port->component->handle, port->handle);
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* create comonent on vc */
++static int create_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component,
++ const char *name)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ /* build component create message */
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
++ m.u.component_create.client_component = component;
++ strncpy(m.u.component_create.name, name,
++ sizeof(m.u.component_create.name));
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_create),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_create_reply.status;
++ if (ret != MMAL_MSG_STATUS_SUCCESS)
++ goto release_msg;
++
++ /* a valid component response received */
++ component->handle = rmsg->u.component_create_reply.component_handle;
++ component->inputs = rmsg->u.component_create_reply.input_num;
++ component->outputs = rmsg->u.component_create_reply.output_num;
++ component->clocks = rmsg->u.component_create_reply.clock_num;
++
++ pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
++ component->handle,
++ component->inputs, component->outputs, component->clocks);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* destroys a component on vc */
++static int destroy_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
++ m.u.component_destroy.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_destroy),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_destroy_reply.status;
++
++release_msg:
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* enable a component on vc */
++static int enable_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
++ m.u.component_enable.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_enable),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_enable_reply.status;
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* disable a component on vc */
++static int disable_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
++ m.u.component_disable.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_disable),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_disable_reply.status;
++
++release_msg:
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* get version of mmal implementation */
++static int get_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out, u32 *minor_out)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_GET_VERSION;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.version),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ *major_out = rmsg->u.version.major;
++ *minor_out = rmsg->u.version.minor;
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* do a port action with a port as a parameter */
++static int port_action_port(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ enum mmal_msg_port_action_type action_type)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
++ m.u.port_action_port.component_handle = port->component->handle;
++ m.u.port_action_port.port_handle = port->handle;
++ m.u.port_action_port.action = action_type;
++
++ port_to_mmal_msg(port, &m.u.port_action_port.port);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_action_port),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_action_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
++ __func__,
++ ret, port->component->handle, port->handle,
++ port_action_type_names[action_type], action_type);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* do a port action with handles as parameters */
++static int port_action_handle(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ enum mmal_msg_port_action_type action_type,
++ u32 connect_component_handle,
++ u32 connect_port_handle)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
++
++ m.u.port_action_handle.component_handle = port->component->handle;
++ m.u.port_action_handle.port_handle = port->handle;
++ m.u.port_action_handle.action = action_type;
++
++ m.u.port_action_handle.connect_component_handle =
++ connect_component_handle;
++ m.u.port_action_handle.connect_port_handle = connect_port_handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_action_handle),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_action_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)" \
++ " connect component:0x%x connect port:%d\n",
++ __func__,
++ ret, port->component->handle, port->handle,
++ port_action_type_names[action_type],
++ action_type, connect_component_handle, connect_port_handle);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++static int port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter_id, void *value, u32 value_size)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
++
++ m.u.port_parameter_set.component_handle = port->component->handle;
++ m.u.port_parameter_set.port_handle = port->handle;
++ m.u.port_parameter_set.id = parameter_id;
++ m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
++ memcpy(&m.u.port_parameter_set.value, value, value_size);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ (4 * sizeof(u32)) + value_size,
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_parameter_set_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
++ __func__,
++ ret, port->component->handle, port->handle, parameter_id);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++static int port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter_id, void *value, u32 *value_size)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
++
++ m.u.port_parameter_get.component_handle = port->component->handle;
++ m.u.port_parameter_get.port_handle = port->handle;
++ m.u.port_parameter_get.id = parameter_id;
++ m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(struct
++ mmal_msg_port_parameter_get),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
++ /* got an unexpected message type in reply */
++ pr_err("Incorrect reply type %d\n", rmsg->h.type);
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_parameter_get_reply.status;
++ if (ret) {
++ /* Copy only as much as we have space for
++ * but report true size of parameter
++ */
++ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
++ *value_size);
++ *value_size = rmsg->u.port_parameter_get_reply.size;
++ } else
++ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
++ rmsg->u.port_parameter_get_reply.size);
++
++ pr_info("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
++ ret, port->component->handle, port->handle, parameter_id);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* disables a port and drains buffers from it */
++static int port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct list_head *q, *buf_head;
++ unsigned long flags = 0;
++
++ if (!port->enabled)
++ return 0;
++
++ port->enabled = false;
++
++ ret = port_action_port(instance, port,
++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
++ if (ret == 0) {
++
++ /* drain all queued buffers on port */
++ spin_lock_irqsave(&port->slock, flags);
++
++ list_for_each_safe(buf_head, q, &port->buffers) {
++ struct mmal_buffer *mmalbuf;
++ mmalbuf = list_entry(buf_head, struct mmal_buffer,
++ list);
++ list_del(buf_head);
++ if (port->buffer_cb)
++ port->buffer_cb(instance,
++ port, 0, mmalbuf, 0, 0,
++ MMAL_TIME_UNKNOWN,
++ MMAL_TIME_UNKNOWN);
++ }
++
++ spin_unlock_irqrestore(&port->slock, flags);
++
++ ret = port_info_get(instance, port);
++ }
++
++ return ret;
++}
++
++/* enable a port */
++static int port_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ unsigned int hdr_count;
++ struct list_head *buf_head;
++ int ret;
++
++ if (port->enabled)
++ return 0;
++
++ /* ensure there are enough buffers queued to cover the buffer headers */
++ if (port->buffer_cb != NULL) {
++ hdr_count = 0;
++ list_for_each(buf_head, &port->buffers) {
++ hdr_count++;
++ }
++ if (hdr_count < port->current_buffer.num)
++ return -ENOSPC;
++ }
++
++ ret = port_action_port(instance, port,
++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
++ if (ret)
++ goto done;
++
++ port->enabled = true;
++
++ if (port->buffer_cb) {
++ /* send buffer headers to videocore */
++ hdr_count = 1;
++ list_for_each(buf_head, &port->buffers) {
++ struct mmal_buffer *mmalbuf;
++ mmalbuf = list_entry(buf_head, struct mmal_buffer,
++ list);
++ ret = buffer_from_host(instance, port, mmalbuf);
++ if (ret)
++ goto done;
++
++ hdr_count++;
++ if (hdr_count > port->current_buffer.num)
++ break;
++ }
++ }
++
++ ret = port_info_get(instance, port);
++
++done:
++ return ret;
++}
++
++/* ------------------------------------------------------------------
++ * Exported API
++ *------------------------------------------------------------------*/
++
++int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_info_set(instance, port);
++ if (ret)
++ goto release_unlock;
++
++ /* read what has actually been set */
++ ret = port_info_get(instance, port);
++
++release_unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++
++}
++
++int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter, void *value, u32 value_size)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_parameter_set(instance, port, parameter, value, value_size);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter, void *value, u32 *value_size)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_parameter_get(instance, port, parameter, value, value_size);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/* enable a port
++ *
++ * enables a port and queues buffers for satisfying callbacks if we
++ * provide a callback handler
++ */
++int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ vchiq_mmal_buffer_cb buffer_cb)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ /* already enabled - noop */
++ if (port->enabled) {
++ ret = 0;
++ goto unlock;
++ }
++
++ port->buffer_cb = buffer_cb;
++
++ ret = port_enable(instance, port);
++
++unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (!port->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = port_disable(instance, port);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/* ports will be connected in a tunneled manner so data buffers
++ * are not handled by client.
++ */
++int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *src,
++ struct vchiq_mmal_port *dst)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ /* disconnect ports if connected */
++ if (src->connected != NULL) {
++ ret = port_disable(instance, src);
++ if (ret) {
++ pr_err("failed disabling src port(%d)\n", ret);
++ goto release_unlock;
++ }
++
++ /* do not need to disable the destination port as they
++ * are connected and it is done automatically
++ */
++
++ ret = port_action_handle(instance, src,
++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
++ src->connected->component->handle,
++ src->connected->handle);
++ if (ret < 0) {
++ pr_err("failed disconnecting src port\n");
++ goto release_unlock;
++ }
++ src->connected->enabled = false;
++ src->connected = NULL;
++ }
++
++ if (dst == NULL) {
++ /* do not make new connection */
++ ret = 0;
++ pr_debug("not making new connection\n");
++ goto release_unlock;
++ }
++
++ /* copy src port format to dst */
++ dst->format.encoding = src->format.encoding;
++ dst->es.video.width = src->es.video.width;
++ dst->es.video.height = src->es.video.height;
++ dst->es.video.crop.x = src->es.video.crop.x;
++ dst->es.video.crop.y = src->es.video.crop.y;
++ dst->es.video.crop.width = src->es.video.crop.width;
++ dst->es.video.crop.height = src->es.video.crop.height;
++ dst->es.video.frame_rate.num = src->es.video.frame_rate.num;
++ dst->es.video.frame_rate.den = src->es.video.frame_rate.den;
++
++ /* set new format */
++ ret = port_info_set(instance, dst);
++ if (ret) {
++ pr_debug("setting port info failed\n");
++ goto release_unlock;
++ }
++
++ /* read what has actually been set */
++ ret = port_info_get(instance, dst);
++ if (ret) {
++ pr_debug("read back port info failed\n");
++ goto release_unlock;
++ }
++
++ /* connect two ports together */
++ ret = port_action_handle(instance, src,
++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
++ dst->component->handle, dst->handle);
++ if (ret < 0) {
++ pr_debug("connecting port %d:%d to %d:%d failed\n",
++ src->component->handle, src->handle,
++ dst->component->handle, dst->handle);
++ goto release_unlock;
++ }
++ src->connected = dst;
++
++release_unlock:
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ struct mmal_buffer *buffer)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&port->slock, flags);
++ list_add_tail(&buffer->list, &port->buffers);
++ spin_unlock_irqrestore(&port->slock, flags);
++
++ /* the port previously underflowed because it was missing a
++ * mmal_buffer which has just been added, submit that buffer
++ * to the mmal service.
++ */
++ if (port->buffer_underflow) {
++ port_buffer_from_host(instance, port);
++ port->buffer_underflow--;
++ }
++
++ return 0;
++}
++
++/* Initialise a mmal component and its ports
++ *
++ */
++int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
++ const char *name,
++ struct vchiq_mmal_component **component_out)
++{
++ int ret;
++ int idx; /* port index */
++ struct vchiq_mmal_component *component;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
++ ret = -EINVAL; /* todo is this correct error? */
++ goto unlock;
++ }
++
++ component = &instance->component[instance->component_idx];
++
++ ret = create_component(instance, component, name);
++ if (ret < 0)
++ goto unlock;
++
++ /* ports info needs gathering */
++ component->control.type = MMAL_PORT_TYPE_CONTROL;
++ component->control.index = 0;
++ component->control.component = component;
++ spin_lock_init(&component->control.slock);
++ INIT_LIST_HEAD(&component->control.buffers);
++ ret = port_info_get(instance, &component->control);
++ if (ret < 0)
++ goto release_component;
++
++ for (idx = 0; idx < component->inputs; idx++) {
++ component->input[idx].type = MMAL_PORT_TYPE_INPUT;
++ component->input[idx].index = idx;
++ component->input[idx].component = component;
++ spin_lock_init(&component->input[idx].slock);
++ INIT_LIST_HEAD(&component->input[idx].buffers);
++ ret = port_info_get(instance, &component->input[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ for (idx = 0; idx < component->outputs; idx++) {
++ component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
++ component->output[idx].index = idx;
++ component->output[idx].component = component;
++ spin_lock_init(&component->output[idx].slock);
++ INIT_LIST_HEAD(&component->output[idx].buffers);
++ ret = port_info_get(instance, &component->output[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ for (idx = 0; idx < component->clocks; idx++) {
++ component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
++ component->clock[idx].index = idx;
++ component->clock[idx].component = component;
++ spin_lock_init(&component->clock[idx].slock);
++ INIT_LIST_HEAD(&component->clock[idx].buffers);
++ ret = port_info_get(instance, &component->clock[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ instance->component_idx++;
++
++ *component_out = component;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return 0;
++
++release_component:
++ destroy_component(instance, component);
++unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/*
++ * cause a mmal component to be destroyed
++ */
++int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (component->enabled)
++ ret = disable_component(instance, component);
++
++ ret = destroy_component(instance, component);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/*
++ * cause a mmal component to be enabled
++ */
++int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (component->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = enable_component(instance, component);
++ if (ret == 0)
++ component->enabled = true;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/*
++ * cause a mmal component to be enabled
++ */
++int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (!component->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = disable_component(instance, component);
++ if (ret == 0)
++ component->enabled = false;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out, u32 *minor_out)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = get_version(instance, major_out, minor_out);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
++{
++ int status = 0;
++
++ if (instance == NULL)
++ return -EINVAL;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ vchi_service_use(instance->handle);
++
++ status = vchi_service_close(instance->handle);
++ if (status != 0)
++ pr_err("mmal-vchiq: VCHIQ close failed");
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ vfree(instance->bulk_scratch);
++
++ kfree(instance);
++
++ return status;
++}
++
++int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
++{
++ int status;
++ struct vchiq_mmal_instance *instance;
++ static VCHI_CONNECTION_T *vchi_connection;
++ static VCHI_INSTANCE_T vchi_instance;
++ SERVICE_CREATION_T params = {
++ VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
++ VC_MMAL_SERVER_NAME,
++ vchi_connection,
++ 0, /* rx fifo size (unused) */
++ 0, /* tx fifo size (unused) */
++ service_callback,
++ NULL, /* service callback parameter */
++ 1, /* unaligned bulk receives */
++ 1, /* unaligned bulk transmits */
++ 0 /* want crc check on bulk transfers */
++ };
++
++ /* compile time checks to ensure structure size as they are
++ * directly (de)serialised from memory.
++ */
++
++ /* ensure the header structure has packed to the correct size */
++ BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
++
++ /* ensure message structure does not exceed maximum length */
++ BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
++
++ /* mmal port struct is correct size */
++ BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
++
++ /* create a vchi instance */
++ status = vchi_initialise(&vchi_instance);
++ if (status) {
++ pr_err("Failed to initialise VCHI instance (status=%d)\n",
++ status);
++ return -EIO;
++ }
++
++ status = vchi_connect(NULL, 0, vchi_instance);
++ if (status) {
++ pr_err("Failed to connect VCHI instance (status=%d)\n", status);
++ return -EIO;
++ }
++
++ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
++ memset(instance, 0, sizeof(*instance));
++
++ mutex_init(&instance->vchiq_mutex);
++ mutex_init(&instance->bulk_mutex);
++
++ instance->bulk_scratch = vmalloc(PAGE_SIZE);
++
++ params.callback_param = instance;
++
++ status = vchi_service_open(vchi_instance, &params, &instance->handle);
++ if (status) {
++ pr_err("Failed to open VCHI service connection (status=%d)\n",
++ status);
++ goto err_close_services;
++ }
++
++ vchi_service_release(instance->handle);
++
++ *out_instance = instance;
++
++ return 0;
++
++err_close_services:
++
++ vchi_service_close(instance->handle);
++ vfree(instance->bulk_scratch);
++ kfree(instance);
++ return -ENODEV;
++}
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-vchiq.h
+@@ -0,0 +1,178 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ *
++ * MMAL interface to VCHIQ message passing
++ */
++
++#ifndef MMAL_VCHIQ_H
++#define MMAL_VCHIQ_H
++
++#include "mmal-msg-format.h"
++
++#define MAX_PORT_COUNT 4
++
++/* Maximum size of the format extradata. */
++#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
++
++struct vchiq_mmal_instance;
++
++enum vchiq_mmal_es_type {
++ MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
++ MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */
++ MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */
++ MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */
++ MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */
++};
++
++/* rectangle, used lots so it gets its own struct */
++struct vchiq_mmal_rect {
++ s32 x;
++ s32 y;
++ s32 width;
++ s32 height;
++};
++
++struct vchiq_mmal_port_buffer {
++ unsigned int num; /* number of buffers */
++ u32 size; /* size of buffers */
++ u32 alignment; /* alignment of buffers */
++};
++
++struct vchiq_mmal_port;
++
++typedef void (*vchiq_mmal_buffer_cb)(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ int status, struct mmal_buffer *buffer,
++ unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
++
++struct vchiq_mmal_port {
++ bool enabled;
++ u32 handle;
++ u32 type; /* port type, cached to use on port info set */
++ u32 index; /* port index, cached to use on port info set */
++
++ /* component port belongs to, allows simple deref */
++ struct vchiq_mmal_component *component;
++
++ struct vchiq_mmal_port *connected; /* port conencted to */
++
++ /* buffer info */
++ struct vchiq_mmal_port_buffer minimum_buffer;
++ struct vchiq_mmal_port_buffer recommended_buffer;
++ struct vchiq_mmal_port_buffer current_buffer;
++
++ /* stream format */
++ struct mmal_es_format format;
++ /* elementry stream format */
++ union mmal_es_specific_format es;
++
++ /* data buffers to fill */
++ struct list_head buffers;
++ /* lock to serialise adding and removing buffers from list */
++ spinlock_t slock;
++ /* count of how many buffer header refils have failed because
++ * there was no buffer to satisfy them
++ */
++ int buffer_underflow;
++ /* callback on buffer completion */
++ vchiq_mmal_buffer_cb buffer_cb;
++ /* callback context */
++ void *cb_ctx;
++};
++
++struct vchiq_mmal_component {
++ bool enabled;
++ u32 handle; /* VideoCore handle for component */
++ u32 inputs; /* Number of input ports */
++ u32 outputs; /* Number of output ports */
++ u32 clocks; /* Number of clock ports */
++ struct vchiq_mmal_port control; /* control port */
++ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
++ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
++ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
++};
++
++
++int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
++int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
++
++/* Initialise a mmal component and its ports
++*
++*/
++int vchiq_mmal_component_init(
++ struct vchiq_mmal_instance *instance,
++ const char *name,
++ struct vchiq_mmal_component **component_out);
++
++int vchiq_mmal_component_finalise(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++int vchiq_mmal_component_enable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++int vchiq_mmal_component_disable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++
++
++/* enable a mmal port
++ *
++ * enables a port and if a buffer callback provided enque buffer
++ * headers as apropriate for the port.
++ */
++int vchiq_mmal_port_enable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ vchiq_mmal_buffer_cb buffer_cb);
++
++/* disable a port
++ *
++ * disable a port will dequeue any pending buffers
++ */
++int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port);
++
++
++int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter,
++ void *value,
++ u32 value_size);
++
++int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter,
++ void *value,
++ u32 *value_size);
++
++int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port);
++
++int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *src,
++ struct vchiq_mmal_port *dst);
++
++int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out,
++ u32 *minor_out);
++
++int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ struct mmal_buffer *buf);
++
++#endif /* MMAL_VCHIQ_H */