2016-09-10 12:54:26 +00:00
|
|
|
From 35730c81cb94119c117901bbdcc148baf35aa37c Mon Sep 17 00:00:00 2001
|
2016-04-24 11:03:39 +00:00
|
|
|
From: 6by9 <6by9@users.noreply.github.com>
|
|
|
|
Date: Fri, 8 Apr 2016 18:15:43 +0100
|
2016-09-10 12:54:26 +00:00
|
|
|
Subject: [PATCH] V4L2 driver updates (#1393)
|
2016-04-24 11:03:39 +00:00
|
|
|
|
|
|
|
* BCM2835-V4L2: Correct ISO control and add V4L2_CID_ISO_SENSITIVITY_AUTO
|
|
|
|
|
|
|
|
https://github.com/raspberrypi/linux/issues/1251
|
|
|
|
|
|
|
|
V4L2_CID_ISO_SENSITIVITY was not advertising ISO*1000 as it should.
|
|
|
|
V4L2_CID_ISO_SENSITIVITY_AUTO was not implemented, so was taking
|
|
|
|
V4L2_CID_ISO_SENSITIVITY as 0 for auto mode.
|
|
|
|
Still accepts 0 for auto, but also abides by the new parameter.
|
|
|
|
|
|
|
|
Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
|
|
|
|
|
|
|
|
* BCM2835-V4L2: Add a video_nr parameter.
|
|
|
|
|
|
|
|
Adds a kernel parameter "video_nr" to specify the preferred
|
|
|
|
/dev/videoX device node.
|
|
|
|
https://www.raspberrypi.org/forums/viewtopic.php?f=38&t=136120&p=905545
|
|
|
|
|
|
|
|
Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
|
|
|
|
|
|
|
|
* BCM2835-V4L2: Add support for multiple cameras
|
|
|
|
|
|
|
|
Ask GPU on load how many cameras have been detected, and
|
|
|
|
enumerate that number of devices.
|
|
|
|
Only applicable on the Compute Module as no other device
|
|
|
|
exposes multiple CSI2 interfaces.
|
|
|
|
|
|
|
|
Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
|
|
|
|
|
|
|
|
* BCM2835-V4L2: Add control of the overlay location and alpha.
|
|
|
|
|
|
|
|
Actually do something useful in vidioc_s_fmt_vid_overlay and
|
|
|
|
vidioc_try_fmt_vid_overlay, rather than effectively having
|
|
|
|
read-only fields.
|
|
|
|
|
|
|
|
Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
|
|
|
|
|
|
|
|
* BCM2835-V4L2: V4L2-Compliance failure fix
|
|
|
|
|
|
|
|
VIDIOC_TRY_FMT was failing due to bytesperline not
|
|
|
|
being set correctly by default.
|
|
|
|
|
|
|
|
Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
|
|
|
|
|
|
|
|
* BCM2835-V4L2: Make all module parameters static
|
|
|
|
|
|
|
|
Clean up to correct variable scope
|
|
|
|
|
|
|
|
Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
|
|
|
|
---
|
|
|
|
drivers/media/platform/bcm2835/bcm2835-camera.c | 372 +++++++++++++++--------
|
|
|
|
drivers/media/platform/bcm2835/bcm2835-camera.h | 19 +-
|
|
|
|
drivers/media/platform/bcm2835/controls.c | 31 +-
|
|
|
|
drivers/media/platform/bcm2835/mmal-parameters.h | 33 ++
|
|
|
|
4 files changed, 320 insertions(+), 135 deletions(-)
|
|
|
|
|
|
|
|
--- a/drivers/media/platform/bcm2835/bcm2835-camera.c
|
|
|
|
+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
|
|
|
|
@@ -45,6 +45,8 @@
|
|
|
|
#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");
|
|
|
|
@@ -54,8 +56,13 @@ int bcm2835_v4l2_debug;
|
|
|
|
module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
|
|
|
|
MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
|
|
|
|
|
|
|
|
-int max_video_width = MAX_VIDEO_MODE_WIDTH;
|
|
|
|
-int max_video_height = MAX_VIDEO_MODE_HEIGHT;
|
|
|
|
+#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, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
|
|
MODULE_PARM_DESC(max_video_width, "Threshold for video mode");
|
|
|
|
module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
|
|
@@ -70,11 +77,12 @@ MODULE_PARM_DESC(max_video_height, "Thre
|
|
|
|
* our function table list (actually switch to an alternate set, but same
|
|
|
|
* result).
|
|
|
|
*/
|
|
|
|
-int gst_v4l2src_is_broken = 0;
|
|
|
|
+static int gst_v4l2src_is_broken;
|
|
|
|
module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
|
|
MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer");
|
|
|
|
|
|
|
|
-static struct bm2835_mmal_dev *gdev; /* global device data */
|
|
|
|
+/* global device data array */
|
|
|
|
+static struct bm2835_mmal_dev *gdev[MAX_BCM2835_CAMERAS];
|
|
|
|
|
|
|
|
#define FPS_MIN 1
|
|
|
|
#define FPS_MAX 90
|
|
|
|
@@ -413,6 +421,17 @@ static int enable_camera(struct bm2835_m
|
|
|
|
{
|
|
|
|
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]);
|
|
|
|
@@ -647,6 +666,30 @@ static struct vb2_ops bm2835_mmal_video_
|
|
|
|
IOCTL operations
|
|
|
|
------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
+static int set_overlay_params(struct bm2835_mmal_dev *dev,
|
|
|
|
+ struct vchiq_mmal_port *port)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+ 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,
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+ ret = vchiq_mmal_port_parameter_set(dev->instance, port,
|
|
|
|
+ MMAL_PARAMETER_DISPLAYREGION,
|
|
|
|
+ &prev_config, sizeof(prev_config));
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
/* overlay ioctl */
|
|
|
|
static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
|
|
|
|
struct v4l2_fmtdesc *f)
|
|
|
|
@@ -678,10 +721,31 @@ static int vidioc_g_fmt_vid_overlay(stru
|
|
|
|
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);
|
|
|
|
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
|
|
|
|
|
|
|
|
- /* todo: allow the size and/or offset to be changed. */
|
|
|
|
+ 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, MAX_WIDTH, 1,
|
|
|
|
+ &f->fmt.win.w.height, MIN_HEIGHT, MAX_HEIGHT,
|
|
|
|
+ 1, 0);
|
|
|
|
+ v4l_bound_align_image(&f->fmt.win.w.left, MIN_WIDTH, MAX_WIDTH, 1,
|
|
|
|
+ &f->fmt.win.w.top, MIN_HEIGHT, 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -693,8 +757,11 @@ static int vidioc_s_fmt_vid_overlay(stru
|
|
|
|
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]);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /* todo: program the preview port parameters */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -704,20 +771,6 @@ static int vidioc_overlay(struct file *f
|
|
|
|
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 */
|
|
|
|
@@ -749,9 +802,7 @@ static int vidioc_overlay(struct file *f
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
- ret = vchiq_mmal_port_parameter_set(dev->instance, dst,
|
|
|
|
- MMAL_PARAMETER_DISPLAYREGION,
|
|
|
|
- &prev_config, sizeof(prev_config));
|
|
|
|
+ ret = set_overlay_params(dev, dst);
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
@@ -782,6 +833,9 @@ static int vidioc_g_fbuf(struct file *fi
|
|
|
|
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;
|
|
|
|
@@ -1445,6 +1499,34 @@ static struct video_device vdev_template
|
|
|
|
.release = video_device_release_empty,
|
|
|
|
};
|
|
|
|
|
|
|
|
+static int get_num_cameras(struct vchiq_mmal_instance *instance)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+ struct vchiq_mmal_component *cam_info_component;
|
|
|
|
+ struct mmal_parameter_camera_info_t cam_info = {0};
|
|
|
|
+ int param_size = sizeof(cam_info);
|
|
|
|
+
|
|
|
|
+ /* 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,
|
|
|
|
+ ¶m_size)) {
|
|
|
|
+ pr_info("Failed to get camera info\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ vchiq_mmal_component_finalise(instance,
|
|
|
|
+ cam_info_component);
|
|
|
|
+
|
|
|
|
+ return cam_info.num_cameras;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static int set_camera_parameters(struct vchiq_mmal_instance *instance,
|
|
|
|
struct vchiq_mmal_component *camera)
|
|
|
|
{
|
|
|
|
@@ -1685,7 +1767,9 @@ static int __init bm2835_mmal_init_devic
|
|
|
|
/* video device needs to be able to access instance data */
|
|
|
|
video_set_drvdata(vfd, dev);
|
|
|
|
|
|
|
|
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
|
|
|
|
+ ret = video_register_device(vfd,
|
|
|
|
+ VFL_TYPE_GRABBER,
|
|
|
|
+ video_nr[dev->camera_num]);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
@@ -1696,10 +1780,52 @@ static int __init bm2835_mmal_init_devic
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
+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);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static struct v4l2_format default_v4l2_format = {
|
|
|
|
.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG,
|
|
|
|
.fmt.pix.width = 1024,
|
|
|
|
- .fmt.pix.bytesperline = 1024,
|
|
|
|
+ .fmt.pix.bytesperline = 0,
|
|
|
|
.fmt.pix.height = 768,
|
|
|
|
.fmt.pix.sizeimage = 1024*768,
|
|
|
|
};
|
|
|
|
@@ -1709,76 +1835,93 @@ 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;
|
|
|
|
|
|
|
|
- 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);
|
|
|
|
+ ret = vchiq_mmal_init(&instance);
|
|
|
|
if (ret < 0)
|
|
|
|
- goto unreg_dev;
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
- /* 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;
|
|
|
|
+ num_cameras = get_num_cameras(instance);
|
|
|
|
+ if (num_cameras > MAX_BCM2835_CAMERAS)
|
|
|
|
+ num_cameras = MAX_BCM2835_CAMERAS;
|
|
|
|
+
|
|
|
|
+ for (camera = 0; camera < num_cameras; camera++) {
|
|
|
|
+ dev = kzalloc(sizeof(struct bm2835_mmal_dev), GFP_KERNEL);
|
|
|
|
+ if (!dev)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ dev->camera_num = camera;
|
|
|
|
+
|
|
|
|
+ /* 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;
|
|
|
|
|
|
|
|
- /* v4l2 core mutex used to protect all fops and v4l2 ioctls. */
|
|
|
|
- mutex_init(&dev->mutex);
|
|
|
|
+ /* 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;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /* initialise video devices */
|
|
|
|
- ret = bm2835_mmal_init_device(dev, &dev->vdev);
|
|
|
|
- if (ret < 0)
|
|
|
|
- goto unreg_dev;
|
|
|
|
+ v4l2_info(&dev->v4l2_dev,
|
|
|
|
+ "Broadcom 2835 MMAL video capture ver %s loaded.\n",
|
|
|
|
+ BM2835_MMAL_VERSION);
|
|
|
|
|
|
|
|
- /* 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;
|
|
|
|
+ gdev[camera] = dev;
|
|
|
|
}
|
|
|
|
-
|
|
|
|
- v4l2_info(&dev->v4l2_dev,
|
|
|
|
- "Broadcom 2835 MMAL video capture ver %s loaded.\n",
|
|
|
|
- BM2835_MMAL_VERSION);
|
|
|
|
-
|
|
|
|
- gdev = dev;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unreg_dev:
|
|
|
|
@@ -1788,8 +1931,11 @@ unreg_dev:
|
|
|
|
free_dev:
|
|
|
|
kfree(dev);
|
|
|
|
|
|
|
|
- v4l2_err(&dev->v4l2_dev,
|
|
|
|
- "%s: error %d while loading driver\n",
|
|
|
|
+ for ( ; camera > 0; camera--) {
|
|
|
|
+ bcm2835_cleanup_instance(gdev[camera]);
|
|
|
|
+ gdev[camera] = NULL;
|
|
|
|
+ }
|
|
|
|
+ pr_info("%s: error %d while loading driver\n",
|
|
|
|
BM2835_MMAL_MODULE_NAME, ret);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
@@ -1797,46 +1943,14 @@ free_dev:
|
|
|
|
|
|
|
|
static void __exit bm2835_mmal_exit(void)
|
|
|
|
{
|
|
|
|
- if (!gdev)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- v4l2_info(&gdev->v4l2_dev, "unregistering %s\n",
|
|
|
|
- video_device_node_name(&gdev->vdev));
|
|
|
|
+ int camera;
|
|
|
|
+ struct vchiq_mmal_instance *instance = gdev[0]->instance;
|
|
|
|
|
|
|
|
- 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);
|
|
|
|
+ for (camera = 0; camera < MAX_BCM2835_CAMERAS; camera++) {
|
|
|
|
+ bcm2835_cleanup_instance(gdev[camera]);
|
|
|
|
+ gdev[camera] = NULL;
|
|
|
|
}
|
|
|
|
- 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);
|
|
|
|
+ vchiq_mmal_finalise(instance);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(bm2835_mmal_init);
|
|
|
|
--- a/drivers/media/platform/bcm2835/bcm2835-camera.h
|
|
|
|
+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h
|
|
|
|
@@ -15,7 +15,7 @@
|
|
|
|
* core driver device
|
|
|
|
*/
|
|
|
|
|
|
|
|
-#define V4L2_CTRL_COUNT 28 /* number of v4l controls */
|
|
|
|
+#define V4L2_CTRL_COUNT 29 /* number of v4l controls */
|
|
|
|
|
|
|
|
enum {
|
|
|
|
MMAL_COMPONENT_CAMERA = 0,
|
|
|
|
@@ -58,6 +58,8 @@ struct bm2835_mmal_dev {
|
|
|
|
enum mmal_parameter_exposuremeteringmode metering_mode;
|
|
|
|
unsigned int manual_shutter_speed;
|
|
|
|
bool exp_auto_priority;
|
|
|
|
+ bool manual_iso_enabled;
|
|
|
|
+ uint32_t iso;
|
|
|
|
|
|
|
|
/* allocated mmal instance and components */
|
|
|
|
struct vchiq_mmal_instance *instance;
|
|
|
|
@@ -104,6 +106,8 @@ struct bm2835_mmal_dev {
|
|
|
|
|
|
|
|
} capture;
|
|
|
|
|
|
|
|
+ unsigned int camera_num;
|
|
|
|
+
|
|
|
|
};
|
|
|
|
|
|
|
|
int bm2835_mmal_init_controls(
|
|
|
|
@@ -124,3 +128,16 @@ int set_framerate_params(struct bm2835_m
|
|
|
|
(pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
|
|
|
|
(pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
|
|
|
|
}
|
|
|
|
+#define v4l2_dump_win_format(level, debug, dev, win_fmt, desc) \
|
|
|
|
+{ \
|
|
|
|
+ v4l2_dbg(level, debug, dev, \
|
|
|
|
+"%s: w %u h %u l %u t %u field %u chromakey %06X clip %p " \
|
|
|
|
+"clipcount %u bitmap %p\n", \
|
|
|
|
+ desc == NULL ? "" : desc, \
|
|
|
|
+ (win_fmt)->w.width, (win_fmt)->w.height, \
|
|
|
|
+ (win_fmt)->w.left, (win_fmt)->w.top, \
|
|
|
|
+ (win_fmt)->field, \
|
|
|
|
+ (win_fmt)->chromakey, \
|
|
|
|
+ (win_fmt)->clips, (win_fmt)->clipcount, \
|
|
|
|
+ (win_fmt)->bitmap); \
|
|
|
|
+}
|
|
|
|
--- a/drivers/media/platform/bcm2835/controls.c
|
|
|
|
+++ b/drivers/media/platform/bcm2835/controls.c
|
|
|
|
@@ -49,10 +49,13 @@ static const s64 ev_bias_qmenu[] = {
|
|
|
|
4000
|
|
|
|
};
|
|
|
|
|
|
|
|
-/* Supported ISO values
|
|
|
|
+/* Supported ISO values (*1000)
|
|
|
|
* ISOO = auto ISO
|
|
|
|
*/
|
|
|
|
static const s64 iso_qmenu[] = {
|
|
|
|
+ 0, 100000, 200000, 400000, 800000,
|
|
|
|
+};
|
|
|
|
+static const uint32_t iso_values[] = {
|
|
|
|
0, 100, 200, 400, 800,
|
|
|
|
};
|
|
|
|
|
|
|
|
@@ -201,7 +204,7 @@ static int ctrl_set_value(struct bm2835_
|
|
|
|
&u32_value, sizeof(u32_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
-static int ctrl_set_value_menu(struct bm2835_mmal_dev *dev,
|
|
|
|
+static int ctrl_set_iso(struct bm2835_mmal_dev *dev,
|
|
|
|
struct v4l2_ctrl *ctrl,
|
|
|
|
const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
|
|
|
|
{
|
|
|
|
@@ -211,12 +214,23 @@ static int ctrl_set_value_menu(struct bm
|
|
|
|
if (ctrl->val > mmal_ctrl->max || ctrl->val < mmal_ctrl->min)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
+ if (ctrl->id == V4L2_CID_ISO_SENSITIVITY)
|
|
|
|
+ dev->iso = iso_values[ctrl->val];
|
|
|
|
+ else if (ctrl->id == V4L2_CID_ISO_SENSITIVITY_AUTO)
|
|
|
|
+ dev->manual_iso_enabled =
|
|
|
|
+ (ctrl->val == V4L2_ISO_SENSITIVITY_MANUAL ?
|
|
|
|
+ true :
|
|
|
|
+ false);
|
|
|
|
+
|
|
|
|
control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
|
|
|
|
|
|
|
|
- u32_value = mmal_ctrl->imenu[ctrl->val];
|
|
|
|
+ if (dev->manual_iso_enabled)
|
|
|
|
+ u32_value = dev->iso;
|
|
|
|
+ else
|
|
|
|
+ u32_value = 0;
|
|
|
|
|
|
|
|
return vchiq_mmal_port_parameter_set(dev->instance, control,
|
|
|
|
- mmal_ctrl->mmal_id,
|
|
|
|
+ MMAL_PARAMETER_ISO,
|
|
|
|
&u32_value, sizeof(u32_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -956,7 +970,14 @@ static const struct bm2835_mmal_v4l2_ctr
|
|
|
|
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_menu,
|
|
|
|
+ &ctrl_set_iso,
|
|
|
|
+ false
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
|
|
|
|
+ 0, 1, V4L2_ISO_SENSITIVITY_AUTO, 1, NULL,
|
|
|
|
+ MMAL_PARAMETER_ISO,
|
|
|
|
+ &ctrl_set_iso,
|
|
|
|
false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
--- a/drivers/media/platform/bcm2835/mmal-parameters.h
|
|
|
|
+++ b/drivers/media/platform/bcm2835/mmal-parameters.h
|
|
|
|
@@ -654,3 +654,36 @@ struct mmal_parameter_imagefx_parameters
|
|
|
|
u32 num_effect_params;
|
|
|
|
u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
|
|
|
|
};
|
|
|
|
+
|
|
|
|
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4
|
|
|
|
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2
|
|
|
|
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16
|
|
|
|
+
|
|
|
|
+struct mmal_parameter_camera_info_camera_t {
|
|
|
|
+ u32 port_id;
|
|
|
|
+ u32 max_width;
|
|
|
|
+ u32 max_height;
|
|
|
|
+ u32 lens_present;
|
|
|
|
+ u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN];
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+enum mmal_parameter_camera_info_flash_type_t {
|
|
|
|
+ /* Make values explicit to ensure they match values in config ini */
|
|
|
|
+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0,
|
|
|
|
+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1,
|
|
|
|
+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2,
|
|
|
|
+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+struct mmal_parameter_camera_info_flash_t {
|
|
|
|
+ enum mmal_parameter_camera_info_flash_type_t flash_type;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+struct mmal_parameter_camera_info_t {
|
|
|
|
+ u32 num_cameras;
|
|
|
|
+ u32 num_flashes;
|
|
|
|
+ struct mmal_parameter_camera_info_camera_t
|
|
|
|
+ cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
|
|
|
|
+ struct mmal_parameter_camera_info_flash_t
|
|
|
|
+ flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
|
|
|
|
+};
|