@@ -445,6 +445,7 @@ static int soc_camera_open(struct file *file)
goto esfmt;
ici->ops->init_videobuf(&icd->vb_vidq, icd);
+ v4l2_ctrl_handler_setup(&icd->ctrl_handler);
}
file->private_data = icd;
@@ -679,75 +680,6 @@ static int soc_camera_streamoff(struct file *file, void *priv,
return 0;
}
-static int soc_camera_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- int i;
-
- WARN_ON(priv != file->private_data);
-
- if (!qc->id)
- return -EINVAL;
-
- /* First check host controls */
- for (i = 0; i < ici->ops->num_controls; i++)
- if (qc->id == ici->ops->controls[i].id) {
- memcpy(qc, &(ici->ops->controls[i]),
- sizeof(*qc));
- return 0;
- }
-
- /* Then device controls */
- for (i = 0; i < icd->ops->num_controls; i++)
- if (qc->id == icd->ops->controls[i].id) {
- memcpy(qc, &(icd->ops->controls[i]),
- sizeof(*qc));
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int soc_camera_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- int ret;
-
- WARN_ON(priv != file->private_data);
-
- if (ici->ops->get_ctrl) {
- ret = ici->ops->get_ctrl(icd, ctrl);
- if (ret != -ENOIOCTLCMD)
- return ret;
- }
-
- return v4l2_subdev_call(sd, core, g_ctrl, ctrl);
-}
-
-static int soc_camera_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- int ret;
-
- WARN_ON(priv != file->private_data);
-
- if (ici->ops->set_ctrl) {
- ret = ici->ops->set_ctrl(icd, ctrl);
- if (ret != -ENOIOCTLCMD)
- return ret;
- }
-
- return v4l2_subdev_call(sd, core, s_ctrl, ctrl);
-}
-
static int soc_camera_cropcap(struct file *file, void *fh,
struct v4l2_cropcap *a)
{
@@ -908,6 +840,8 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
icl->board_info, NULL);
if (!subdev)
goto ei2cnd;
+ if (v4l2_ctrl_add_handler(&icd->ctrl_handler, subdev->ctrl_handler))
+ goto ei2cnd;
client = v4l2_get_subdevdata(subdev);
@@ -963,15 +897,15 @@ static int soc_camera_probe(struct device *dev)
if (icl->reset)
icl->reset(icd->pdev);
- ret = ici->ops->add(icd);
- if (ret < 0)
- goto eadd;
-
/* Must have icd->vdev before registering the device */
ret = video_dev_create(icd);
if (ret < 0)
goto evdc;
+ ret = ici->ops->add(icd);
+ if (ret < 0)
+ goto eadd;
+
/* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
if (icl->board_info) {
ret = soc_camera_init_i2c(icd, icl);
@@ -1054,10 +988,10 @@ eiufmt:
}
enodrv:
eadddev:
- video_device_release(icd->vdev);
-evdc:
ici->ops->remove(icd);
eadd:
+ video_device_release(icd->vdev);
+evdc:
soc_camera_power_set(icd, icl, 0);
epower:
regulator_bulk_free(icl->num_regulators, icl->regulators);
@@ -1324,9 +1258,6 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_dqbuf = soc_camera_dqbuf,
.vidioc_streamon = soc_camera_streamon,
.vidioc_streamoff = soc_camera_streamoff,
- .vidioc_queryctrl = soc_camera_queryctrl,
- .vidioc_g_ctrl = soc_camera_g_ctrl,
- .vidioc_s_ctrl = soc_camera_s_ctrl,
.vidioc_cropcap = soc_camera_cropcap,
.vidioc_g_crop = soc_camera_g_crop,
.vidioc_s_crop = soc_camera_s_crop,
@@ -1355,6 +1286,7 @@ static int video_dev_create(struct soc_camera_device *icd)
vdev->ioctl_ops = &soc_camera_ioctl_ops;
vdev->release = video_device_release;
vdev->tvnorms = V4L2_STD_UNKNOWN;
+ vdev->ctrl_handler = &icd->ctrl_handler;
icd->vdev = vdev;
@@ -1402,13 +1334,24 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
if (!icd)
return -ENOMEM;
+ /*
+ * Currently the subdev with the largest number of controls (13) is
+ * ov6550. So let's pick 16 as a hint for the control handler. Note
+ * that this is a hint only: too large and you waste some memory, too
+ * small and there is a (very) small performance hit when looking up
+ * controls in the internal hash.
+ */
+ ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16);
+ if (ret < 0)
+ goto escdevreg;
+
icd->iface = icl->bus_id;
icd->pdev = &pdev->dev;
platform_set_drvdata(pdev, icd);
ret = soc_camera_device_register(icd);
if (ret < 0)
- goto escdevreg;
+ goto eschdlinit;
soc_camera_device_init(&icd->dev, icl);
@@ -1417,6 +1360,8 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
return 0;
+eschdlinit:
+ v4l2_ctrl_handler_free(&icd->ctrl_handler);
escdevreg:
kfree(icd);
@@ -1437,6 +1382,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
soc_camera_device_unregister(icd);
+ v4l2_ctrl_handler_free(&icd->ctrl_handler);
kfree(icd);
return 0;
@@ -174,9 +174,13 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
if (ret)
goto evdrs;
+ ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, priv->subdev.ctrl_handler);
+ if (ret)
+ goto evunreg;
+ return 0;
- return ret;
-
+evunreg:
+ v4l2_device_unregister_subdev(&priv->subdev);
evdrs:
icd->ops = NULL;
platform_set_drvdata(pdev, NULL);
@@ -18,6 +18,7 @@
#include <linux/videodev2.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
extern struct bus_type soc_camera_bus_type;
@@ -35,6 +36,7 @@ struct soc_camera_device {
struct soc_camera_sense *sense; /* See comment in struct definition */
struct soc_camera_ops *ops;
struct video_device *vdev;
+ struct v4l2_ctrl_handler ctrl_handler;
const struct soc_camera_format_xlate *current_fmt;
struct soc_camera_format_xlate *user_formats;
int num_user_formats;