cregit-Linux how code gets into the kernel

Release 4.12 drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c

/*
 * 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 MIN_WIDTH 32

#define MIN_HEIGHT 32

#define MIN_BUFFER_SIZE (80 * 1024)


#define MAX_VIDEO_MODE_WIDTH 1280

#define MAX_VIDEO_MODE_HEIGHT 720


#define MAX_BCM2835_CAMERAS 2

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");


#define UNSET (-1)

static int video_nr[] = {[0 ... (MAX_BCM2835_CAMERAS - 1)] = UNSET };
module_param_array(video_nr, int, NULL, 0644);
MODULE_PARM_DESC(video_nr, "videoX start numbers, -1 is autodetect");


static int max_video_width = MAX_VIDEO_MODE_WIDTH;

static int max_video_height = MAX_VIDEO_MODE_HEIGHT;
module_param(max_video_width, int, 0644);
MODULE_PARM_DESC(max_video_width, "Threshold for video mode");
module_param(max_video_height, int, 0644);
MODULE_PARM_DESC(max_video_height, "Threshold for video mode");

/* global device data array */

static struct bm2835_mmal_dev *gdev[MAX_BCM2835_CAMERAS];


#define FPS_MIN 1

#define FPS_MAX 90

/* timeperframe: min/max and default */
static const struct v4l2_fract
	
tpf_min     = {.numerator = 1,		.denominator = FPS_MAX},
	
tpf_max     = {.numerator = 1,	        .denominator = FPS_MIN},
	
tpf_default = {.numerator = 1000,	.denominator = 30000};

/* video formats */

static struct mmal_fmt formats[] = {
	{
	 .name = "4:2:0, planar, YUV",
	 .fourcc = V4L2_PIX_FMT_YUV420,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_I420,
	 .depth = 12,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 1,
         },
	{
	 .name = "4:2:2, packed, YUYV",
	 .fourcc = V4L2_PIX_FMT_YUYV,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_YUYV,
	 .depth = 16,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 2,
         },
	{
	 .name = "RGB24 (LE)",
	 .fourcc = V4L2_PIX_FMT_RGB24,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_RGB24,
	 .depth = 24,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 3,
         },
	{
	 .name = "JPEG",
	 .fourcc = V4L2_PIX_FMT_JPEG,
	 .flags = V4L2_FMT_FLAG_COMPRESSED,
	 .mmal = MMAL_ENCODING_JPEG,
	 .depth = 8,
	 .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
	 .ybbp = 0,
         },
	{
	 .name = "H264",
	 .fourcc = V4L2_PIX_FMT_H264,
	 .flags = V4L2_FMT_FLAG_COMPRESSED,
	 .mmal = MMAL_ENCODING_H264,
	 .depth = 8,
	 .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
	 .ybbp = 0,
         },
	{
	 .name = "MJPEG",
	 .fourcc = V4L2_PIX_FMT_MJPEG,
	 .flags = V4L2_FMT_FLAG_COMPRESSED,
	 .mmal = MMAL_ENCODING_MJPEG,
	 .depth = 8,
	 .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
	 .ybbp = 0,
         },
	{
	 .name = "4:2:2, packed, YVYU",
	 .fourcc = V4L2_PIX_FMT_YVYU,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_YVYU,
	 .depth = 16,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 2,
         },
	{
	 .name = "4:2:2, packed, VYUY",
	 .fourcc = V4L2_PIX_FMT_VYUY,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_VYUY,
	 .depth = 16,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 2,
         },
	{
	 .name = "4:2:2, packed, UYVY",
	 .fourcc = V4L2_PIX_FMT_UYVY,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_UYVY,
	 .depth = 16,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 2,
         },
	{
	 .name = "4:2:0, planar, NV12",
	 .fourcc = V4L2_PIX_FMT_NV12,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_NV12,
	 .depth = 12,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 1,
         },
	{
	 .name = "RGB24 (BE)",
	 .fourcc = V4L2_PIX_FMT_BGR24,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_BGR24,
	 .depth = 24,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 3,
         },
	{
	 .name = "4:2:0, planar, YVU",
	 .fourcc = V4L2_PIX_FMT_YVU420,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_YV12,
	 .depth = 12,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 1,
         },
	{
	 .name = "4:2:0, planar, NV21",
	 .fourcc = V4L2_PIX_FMT_NV21,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_NV21,
	 .depth = 12,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 1,
         },
	{
	 .name = "RGB32 (BE)",
	 .fourcc = V4L2_PIX_FMT_BGR32,
	 .flags = 0,
	 .mmal = MMAL_ENCODING_BGRA,
	 .depth = 32,
	 .mmal_component = MMAL_COMPONENT_CAMERA,
	 .ybbp = 4,
         },
};


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) return fmt; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt6595.59%150.00%
Narcisa Ana Maria Vasile34.41%150.00%
Total68100.00%2100.00%

/* ------------------------------------------------------------------ * Videobuf queue operations * ------------------------------------------------------------------ */
static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *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) { 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt17999.44%150.00%
Aishwarya Pant10.56%150.00%
Total180100.00%2100.00%


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); BUG_ON(!dev->capture.fmt); 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt11898.33%150.00%
Aishwarya Pant21.67%150.00%
Total120100.00%2100.00%


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]; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt32100.00%1100.00%
Total32100.00%1100.00%


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) { /* there was a buffer with the error so return it */ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } return; } else if (length == 0) { /* stream ended */ if (buf) { /* this should only ever happen if the port is * disabled and there are buffers still queued */ vb2_buffer_done(&buf->vb.vb2_buf, 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 && pts != 0) { struct timeval timestamp; 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); timestamp.tv_sec = dev->capture.kernel_start_ts.tv_sec + div; timestamp.tv_usec = dev->capture.kernel_start_ts.tv_usec + rem; if (timestamp.tv_usec >= USEC_PER_SEC) { timestamp.tv_sec++; 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)timestamp.tv_sec, (int)timestamp.tv_usec); buf->vb.vb2_buf.timestamp = timestamp.tv_sec * 1000000000ULL + timestamp.tv_usec * 1000ULL; } else { buf->vb.vb2_buf.timestamp = ktime_get_ns(); } vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length); vb2_buffer_done(&buf->vb.vb2_buf, 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 */ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); complete(&dev->capture.frame_cmplt); } } }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt521100.00%1100.00%
Total521100.00%1100.00%


static int enable_camera(struct bm2835_mmal_dev *dev) { int ret; if (!dev->camera_use_count) { ret = vchiq_mmal_port_parameter_set( dev->instance, &dev->component[MMAL_COMPONENT_CAMERA]->control, MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num, sizeof(dev->camera_num)); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "Failed setting camera num, ret %d\n", ret); return -EINVAL; } 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt146100.00%1100.00%
Total146100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt159100.00%1100.00%
Total159100.00%1100.00%


static void buffer_queue(struct vb2_buffer *vb) { struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); struct mmal_buffer *buf = container_of(vb2, 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.vb2_buf, 0); buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 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__); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt138100.00%1100.00%
Total138100.00%1100.00%


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) 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. " "Disabling camera port again\n", ret); vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port); if (disable_camera(dev) < 0) { v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n"); return -EINVAL; } 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt39599.75%150.00%
Aishwarya Pant10.25%150.00%
Total396100.00%2100.00%

/* abort streaming and wait for last buffer */
static void 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) { v4l2_err(&dev->v4l2_dev, "no capture port - stream not started?\n"); return; } 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\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt28799.65%150.00%
Aishwarya Pant10.35%150.00%
Total288100.00%2100.00%


static void bm2835_mmal_lock(struct vb2_queue *vq) { struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq); mutex_lock(&dev->mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt29100.00%1100.00%
Total29100.00%1100.00%


static void bm2835_mmal_unlock(struct vb2_queue *vq) { struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq); mutex_unlock(&dev->mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt29100.00%1100.00%
Total29100.00%1100.00%

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 * ------------------------------------------------------------------ */
static int set_overlay_params(struct bm2835_mmal_dev *dev, struct vchiq_mmal_port *port) { 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 = dev->overlay.global_alpha, .fullscreen = 0, .dest_rect = { .x = dev->overlay.w.left, .y = dev->overlay.w.top, .width = dev->overlay.w.width, .height = dev->overlay.w.height, }, }; return vchiq_mmal_port_parameter_set(dev->instance, port, MMAL_PARAMETER_DISPLAYREGION, &prev_config, sizeof(prev_config)); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt12099.17%150.00%
Narcisa Ana Maria Vasile10.83%150.00%
Total121100.00%2100.00%

/* 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; f->flags = fmt->flags; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt87100.00%1100.00%
Total87100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt43100.00%1100.00%
Total43100.00%1100.00%


static int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct bm2835_mmal_dev *dev = video_drvdata(file); f->fmt.win.field = V4L2_FIELD_NONE; f->fmt.win.chromakey = 0; f->fmt.win.clips = NULL; f->fmt.win.clipcount = 0; f->fmt.win.bitmap = NULL; v4l_bound_align_image(&f->fmt.win.w.width, MIN_WIDTH, dev->max_width, 1, &f->fmt.win.w.height, MIN_HEIGHT, dev->max_height, 1, 0); v4l_bound_align_image(&f->fmt.win.w.left, MIN_WIDTH, dev->max_width, 1, &f->fmt.win.w.top, MIN_HEIGHT, dev->max_height, 1, 0); v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "Overlay: Now w/h %dx%d l/t %dx%d\n", f->fmt.win.w.width, f->fmt.win.w.height, f->fmt.win.w.left, f->fmt.win.w.top); v4l2_dump_win_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.win, __func__); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt244100.00%1100.00%
Total244100.00%1100.00%


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; if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) { set_overlay_params(dev, &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt83100.00%1100.00%
Total83100.00%1100.00%


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; 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 = set_overlay_params(dev, dst); 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt303100.00%1100.00%
Total303100.00%1100.00%


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. */ struct bm2835_mmal_dev *dev = video_drvdata(file); struct vchiq_mmal_port *preview_port = &dev->component[MMAL_COMPONENT_CAMERA]-> output[MMAL_CAMERA_PORT_PREVIEW]; a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_GLOBAL_ALPHA; a->flags = V4L2_FBUF_FLAG_OVERLAY; a->fmt.width = preview_port->es.video.width; a->fmt.height = preview_port->es.video.height; a->fmt.pixelformat = V4L2_PIX_FMT_YUV420; a->fmt.bytesperline = preview_port->es.video.width; a->fmt.sizeimage = (preview_port->es.video.width * preview_port->es.video.height * 3) >> 1; a->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt15199.34%150.00%
Derek Robson10.66%150.00%
Total152100.00%2100.00%

/* 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt55100.00%1100.00%
Total55100.00%1100.00%


static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { *i = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt28100.00%1100.00%
Total28100.00%1100.00%


static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { if (i != 0) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt32100.00%1100.00%
Total32100.00%1100.00%

/* 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt125100.00%1100.00%
Total125100.00%1100.00%


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; f->flags = fmt->flags; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt87100.00%1100.00%
Total87100.00%1100.00%


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 = dev->capture.stride; f->fmt.pix.sizeimage = dev->capture.buffersize; if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24) f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; else if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG) f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; else f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix, __func__); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt202100.00%1100.00%
Total202100.00%1100.00%


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; v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "Clipping/aligning %dx%d format %08X\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, dev->max_width, 1, &f->fmt.pix.height, MIN_HEIGHT, dev->max_height, 1, 0); f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp; /* Image buffer has to be padded to allow for alignment, even though * we then remove that padding before delivering the buffer. */ f->fmt.pix.sizeimage = ((f->fmt.pix.height + 15) & ~15) * (((f->fmt.pix.width + 31) & ~31) * mfmt->depth) >> 3; if ((mfmt->flags & V4L2_FMT_FLAG_COMPRESSED) && f->fmt.pix.sizeimage < MIN_BUFFER_SIZE) f->fmt.pix.sizeimage = MIN_BUFFER_SIZE; if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG) f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; else f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "Now %dx%d format %08X\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix, __func__); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt409100.00%1100.00%
Total409100.00%1100.00%


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 dependent 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_width && f->fmt.pix.height <= max_video_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; if (dev->rgb_bgr_swapped) { if (camera_port->format.encoding == MMAL_ENCODING_RGB24) camera_port->format.encoding = MMAL_ENCODING_BGR24; else if (camera_port->format.encoding == MMAL_ENCODING_BGR24) camera_port->format.encoding = MMAL_ENCODING_RGB24; } 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 = 0; camera_port->es.video.frame_rate.den = 1; camera_port->es.video.color_space = MMAL_COLOR_SPACE_JPEG_JFIF; 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 = dev->capture.timeperframe.denominator; preview_port->es.video.frame_rate.den = dev->capture.timeperframe.numerator; 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 %dx%d %08X\n", __func__, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); /* 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; 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 { port->es.video.width = f->fmt.pix.width; port->es.video.height = f->fmt.pix.height; port->es.video.crop.x = 0; port->es.video.crop.y = 0; port->es.video.crop.width = f->fmt.pix.width; port->es.video.crop.height = f->fmt.pix.height; port->es.video.frame_rate.num = dev->capture.timeperframe.denominator; port->es.video.frame_rate.den = dev->capture.timeperframe.numerator; 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 %dx%d fmt %08X\n", __func__, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat ); } if (!ret) { 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__); } } if (!ret) { /* 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, "JPG - buf size now %d was %d\n", f->fmt.pix.sizeimage, port->current_buffer.size); 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 - cur_buf.size set to %d\n", f->fmt.pix.sizeimage); port->current_buffer.alignment = 0; } } 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 = camera_port->es.video.crop.width; dev->capture.height = camera_port->es.video.crop.height; dev->capture.buffersize = port->current_buffer.size; /* select port for capture */ dev->capture.port = port; dev->capture.camera_port = camera_port; dev->capture.encode_component = encode_component; v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "Set dev->capture.fmt %08X, %dx%d, stride %d, size %d", port->format.encoding, dev->capture.width, dev->capture.height, dev->capture.stride, dev->capture.buffersize); } } /* todo: Need to convert the vchiq/mmal error into a v4l2 error. */ return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt1545100.00%2100.00%
Total1545100.00%2100.00%


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); ret = -EINVAL; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt19799.49%150.00%
Derek Robson10.51%150.00%
Total198100.00%2100.00%


static int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { struct bm2835_mmal_dev *dev = video_drvdata(file); static const struct v4l2_frmsize_stepwise sizes = { MIN_WIDTH, 0, 2, MIN_HEIGHT, 0, 2 }; int i; if (fsize->index) return -EINVAL; for (i = 0; i < ARRAY_SIZE(formats); i++) if (formats[i].fourcc == fsize->pixel_format) break; if (i == ARRAY_SIZE(formats)) return -EINVAL; fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; fsize->stepwise = sizes; fsize->stepwise.max_width = dev->max_width; fsize->stepwise.max_height = dev->max_height; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt14099.29%150.00%
Arnd Bergmann10.71%150.00%
Total141100.00%2100.00%

/* timeperframe is arbitrary and continuous */
static int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival) { struct bm2835_mmal_dev *dev = video_drvdata(file); int i; if (fival->index) return -EINVAL; for (i = 0; i < ARRAY_SIZE(formats); i++) if (formats[i].fourcc == fival->pixel_format) break; if (i == ARRAY_SIZE(formats)) return -EINVAL; /* regarding width & height - we support any within range */ if (fival->width < MIN_WIDTH || fival->width > dev->max_width || fival->height < MIN_HEIGHT || fival->height > dev->max_height) return -EINVAL; fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; /* fill in stepwise (step=1.0 is required by V4L2 spec) */ fival->stepwise.min = tpf_min; fival->stepwise.max = tpf_max; fival->stepwise.step = (struct v4l2_fract) {1, 1}; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt163100.00%2100.00%
Total163100.00%2100.00%


static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct bm2835_mmal_dev *dev = video_drvdata(file); if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; parm->parm.capture.timeperframe = dev->capture.timeperframe; parm->parm.capture.readbuffers = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt79100.00%1100.00%
Total79100.00%1100.00%

#define FRACT_CMP(a, OP, b) \ ((u64)(a).numerator * (b).denominator OP \ (u64)(b).numerator * (a).denominator)
static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct bm2835_mmal_dev *dev = video_drvdata(file); struct v4l2_fract tpf; struct mmal_parameter_rational fps_param; if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; tpf = parm->parm.capture.timeperframe; /* tpf: {*, 0} resets timing; clip to [min, max]*/ tpf = tpf.denominator ? tpf : tpf_default; tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf; tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf; dev->capture.timeperframe = tpf; parm->parm.capture.timeperframe = tpf; parm->parm.capture.readbuffers = 1; parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; fps_param.num = 0; /* Select variable fps, and then use * FPS_RANGE to select the actual limits. */ fps_param.den = 1; set_framerate_params(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt160100.00%1100.00%
Total160100.00%1100.00%

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_enum_framesizes = vidioc_enum_framesizes, .vidioc_enum_frameintervals = vidioc_enum_frameintervals, .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm, .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, }; /* Returns the number of cameras, and also the max resolution supported * by those cameras. */
static int get_num_cameras(struct vchiq_mmal_instance *instance, unsigned int resolutions[][2], int num_resolutions) { int ret; struct vchiq_mmal_component *cam_info_component; struct mmal_parameter_camera_info_t cam_info = {0}; int param_size = sizeof(cam_info); int i; /* create a camera_info component */ ret = vchiq_mmal_component_init(instance, "camera_info", &cam_info_component); if (ret < 0) /* Unusual failure - let's guess one camera. */ return 1; if (vchiq_mmal_port_parameter_get(instance, &cam_info_component->control, MMAL_PARAMETER_CAMERA_INFO, &cam_info, &param_size)) { pr_info("Failed to get camera info\n"); } for (i = 0; i < min_t(unsigned int, cam_info.num_cameras, num_resolutions); i++) { resolutions[i][0] = cam_info.cameras[i].max_width; resolutions[i][1] = cam_info.cameras[i].max_height; } vchiq_mmal_component_finalise(instance, cam_info_component); return cam_info.num_cameras; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt15995.21%150.00%
Narcisa Ana Maria Vasile84.79%150.00%
Total167100.00%2100.00%


static int set_camera_parameters(struct vchiq_mmal_instance *instance, struct vchiq_mmal_component *camera, struct bm2835_mmal_dev *dev) { int ret; struct mmal_parameter_camera_config cam_config = { .max_stills_w = dev->max_width, .max_stills_h = dev->max_height, .stills_yuv422 = 1, .one_shot_stills = 1, .max_preview_video_w = (max_video_width > 1920) ? max_video_width : 1920, .max_preview_video_h = (max_video_height > 1088) ? max_video_height : 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt125100.00%1100.00%
Total125100.00%1100.00%

#define MAX_SUPPORTED_ENCODINGS 20 /* MMAL instance and component init */
static int __init mmal_init(struct bm2835_mmal_dev *dev) { int ret; struct mmal_es_format_local *format; u32 bool_true = 1; u32 supported_encodings[MAX_SUPPORTED_ENCODINGS]; int param_size; struct vchiq_mmal_component *camera; 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; camera = dev->component[MMAL_COMPONENT_CAMERA]; if (camera->outputs < MMAL_CAMERA_PORT_COUNT) { ret = -EINVAL; goto unreg_camera; } ret = set_camera_parameters(dev->instance, camera, dev); if (ret < 0) goto unreg_camera; /* There was an error in the firmware that meant the camera component * produced BGR instead of RGB. * This is now fixed, but in order to support the old firmwares, we * have to check. */ dev->rgb_bgr_swapped = true; param_size = sizeof(supported_encodings); ret = vchiq_mmal_port_parameter_get(dev->instance, &camera->output[MMAL_CAMERA_PORT_CAPTURE], MMAL_PARAMETER_SUPPORTED_ENCODINGS, &supported_encodings, &param_size); if (ret == 0) { int i; for (i = 0; i < param_size / sizeof(u32); i++) { if (supported_encodings[i] == MMAL_ENCODING_BGR24) { /* Found BGR24 first - old firmware. */ break; } if (supported_encodings[i] == MMAL_ENCODING_RGB24) { /* Found RGB24 first * new firmware, so use RGB24. */ dev->rgb_bgr_swapped = false; break; } } } format = &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 = 0; /* Rely on fps_range */ format->es->video.frame_rate.den = 1; format = &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 = 0; /* Rely on fps_range */ format->es->video.frame_rate.den = 1; vchiq_mmal_port_parameter_set(dev->instance, &camera->output[MMAL_CAMERA_PORT_VIDEO], MMAL_PARAMETER_NO_IMAGE_PADDING, &bool_true, sizeof(bool_true)); format = &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 = 0; /* Rely on fps_range */ 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; dev->capture.timeperframe = tpf_default; dev->capture.enc_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; vchiq_mmal_port_parameter_set(dev->instance, &camera->output[MMAL_CAMERA_PORT_CAPTURE], MMAL_PARAMETER_NO_IMAGE_PADDING, &bool_true, sizeof(bool_true)); /* 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; } { struct vchiq_mmal_port *encoder_port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0]; encoder_port->format.encoding = MMAL_ENCODING_H264; ret = vchiq_mmal_port_set_format(dev->instance, encoder_port); } { 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; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt113499.91%150.00%
Michael Zoran10.09%150.00%
Total1135100.00%2100.00%


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; /* video device needs to be able to access instance data */ video_set_drvdata(vfd, dev); ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr[dev->camera_num]); if (ret < 0) return ret; v4l2_info(vfd->v4l2_dev, "V4L2 device registered as %s - stills mode > %dx%d\n", video_device_node_name(vfd), max_video_width, max_video_height); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt108100.00%1100.00%
Total108100.00%1100.00%


static void bcm2835_cleanup_instance(struct bm2835_mmal_dev *dev) { if (!dev) return; v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->vdev)); video_unregister_device(&dev->vdev); if (dev->capture.encode_component) { v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "mmal_exit - disconnect tunnel\n"); vchiq_mmal_port_connect_tunnel(dev->instance, dev->capture.camera_port, NULL); vchiq_mmal_component_disable(dev->instance, dev->capture.encode_component); } vchiq_mmal_component_disable(dev->instance, dev->component[MMAL_COMPONENT_CAMERA]); vchiq_mmal_component_finalise(dev->instance, dev-> component[MMAL_COMPONENT_VIDEO_ENCODE]); vchiq_mmal_component_finalise(dev->instance, dev-> component[MMAL_COMPONENT_IMAGE_ENCODE]); vchiq_mmal_component_finalise(dev->instance, dev->component[MMAL_COMPONENT_PREVIEW]); vchiq_mmal_component_finalise(dev->instance, dev->component[MMAL_COMPONENT_CAMERA]); v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt18599.46%150.00%
Arnd Bergmann10.54%150.00%
Total186100.00%2100.00%

static struct v4l2_format default_v4l2_format = { .fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG, .fmt.pix.width = 1024, .fmt.pix.bytesperline = 0, .fmt.pix.height = 768, .fmt.pix.sizeimage = 1024 * 768, };
static int __init bm2835_mmal_init(void) { int ret; struct bm2835_mmal_dev *dev; struct vb2_queue *q; int camera; unsigned int num_cameras; struct vchiq_mmal_instance *instance; unsigned int resolutions[MAX_BCM2835_CAMERAS][2]; int i; ret = vchiq_mmal_init(&instance); if (ret < 0) return ret; num_cameras = get_num_cameras(instance, resolutions, MAX_BCM2835_CAMERAS); if (num_cameras > MAX_BCM2835_CAMERAS) num_cameras = MAX_BCM2835_CAMERAS; for (camera = 0; camera < num_cameras; camera++) { dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; goto cleanup_gdev; } dev->camera_num = camera; dev->max_width = resolutions[camera][0]; dev->max_height = resolutions[camera][1]; /* 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->overlay.global_alpha = 255; 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 */ dev->instance = instance; 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_flags = 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; /* Really want to call vidioc_s_fmt_vid_cap with the default * format, but currently the APIs don't join up. */ 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[camera] = dev; } return 0; unreg_dev: v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_device_unregister(&dev->v4l2_dev); free_dev: kfree(dev); cleanup_gdev: for (i = 0; i < camera; i++) { bcm2835_cleanup_instance(gdev[i]); gdev[i] = NULL; } pr_info("%s: error %d while loading driver\n", BM2835_MMAL_MODULE_NAME, ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt55795.87%133.33%
Dan Carpenter223.79%133.33%
Aishwarya Pant20.34%133.33%
Total581100.00%3100.00%


static void __exit bm2835_mmal_exit(void) { int camera; struct vchiq_mmal_instance *instance = gdev[0]->instance; for (camera = 0; camera < MAX_BCM2835_CAMERAS; camera++) { bcm2835_cleanup_instance(gdev[camera]); gdev[camera] = NULL; } vchiq_mmal_finalise(instance); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt59100.00%1100.00%
Total59100.00%1100.00%

module_init(bm2835_mmal_init); module_exit(bm2835_mmal_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
Eric Anholt984399.48%323.08%
Dan Carpenter220.22%17.69%
Narcisa Ana Maria Vasile120.12%323.08%
Aishwarya Pant70.07%215.38%
Derek Robson70.07%215.38%
Arnd Bergmann20.02%17.69%
Michael Zoran10.01%17.69%
Total9894100.00%13100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.