summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch')
-rw-r--r--target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch718
1 files changed, 718 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch b/target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch
new file mode 100644
index 0000000000..7f9ec20f8f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch
@@ -0,0 +1,718 @@
+From 12b8bcf4d6d4a188ad2bcbae564f32fba4166f71 Mon Sep 17 00:00:00 2001
+From: 6by9 <6by9@users.noreply.github.com>
+Date: Fri, 8 Apr 2016 18:15:43 +0100
+Subject: [PATCH 233/304] V4L2 driver updates (#1393)
+
+* 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,
++ &param_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];
++};