diff options
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r-- | drivers/media/video/soc_camera.c | 63 |
1 files changed, 37 insertions, 26 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index eb25756a07af..0421bf9453b4 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -164,35 +164,38 @@ static int soc_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; int ret; dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n", pixfmtstr(pix->pixelformat), pix->width, pix->height); - pix->bytesperline = 0; - pix->sizeimage = 0; + if (!(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) { + pix->bytesperline = 0; + pix->sizeimage = 0; + } ret = ici->ops->try_fmt(icd, f); if (ret < 0) return ret; - if (!pix->sizeimage) { - if (!pix->bytesperline) { - const struct soc_camera_format_xlate *xlate; + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) + return -EINVAL; - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) - return -EINVAL; + ret = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt); + if (ret < 0) + return ret; - ret = soc_mbus_bytes_per_line(pix->width, - xlate->host_fmt); - if (ret > 0) - pix->bytesperline = ret; - } - if (pix->bytesperline) - pix->sizeimage = pix->bytesperline * pix->height; - } + pix->bytesperline = max_t(u32, pix->bytesperline, ret); + + ret = soc_mbus_image_size(xlate->host_fmt, pix->bytesperline, + pix->height); + if (ret < 0) + return ret; + + pix->sizeimage = max_t(u32, pix->sizeimage, ret); return 0; } @@ -257,13 +260,13 @@ static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) return v4l2_subdev_call(sd, core, g_std, a); } -static int soc_camera_enum_fsizes(struct file *file, void *fh, +static int soc_camera_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { struct soc_camera_device *icd = file->private_data; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - return ici->ops->enum_fsizes(icd, fsize); + return ici->ops->enum_framesizes(icd, fsize); } static int soc_camera_reqbufs(struct file *file, void *priv, @@ -530,7 +533,10 @@ static int soc_camera_open(struct file *file) if (icl->reset) icl->reset(icd->pdev); + /* Don't mess with the host during probe */ + mutex_lock(&ici->host_lock); ret = ici->ops->add(icd); + mutex_unlock(&ici->host_lock); if (ret < 0) { dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret); goto eiciadd; @@ -956,7 +962,7 @@ static void scan_add_host(struct soc_camera_host *ici) { struct soc_camera_device *icd; - mutex_lock(&list_lock); + mutex_lock(&ici->host_lock); list_for_each_entry(icd, &devices, list) { if (icd->iface == ici->nr) { @@ -967,7 +973,7 @@ static void scan_add_host(struct soc_camera_host *ici) } } - mutex_unlock(&list_lock); + mutex_unlock(&ici->host_lock); } #ifdef CONFIG_I2C_BOARDINFO @@ -1241,8 +1247,8 @@ static int default_s_parm(struct soc_camera_device *icd, return v4l2_subdev_call(sd, video, s_parm, parm); } -static int default_enum_fsizes(struct soc_camera_device *icd, - struct v4l2_frmsizeenum *fsize) +static int default_enum_framesizes(struct soc_camera_device *icd, + struct v4l2_frmsizeenum *fsize) { int ret; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -1256,7 +1262,7 @@ static int default_enum_fsizes(struct soc_camera_device *icd, /* map xlate-code to pixel_format, sensor only handle xlate-code*/ fsize_mbus.pixel_format = xlate->code; - ret = v4l2_subdev_call(sd, video, enum_mbus_fsizes, &fsize_mbus); + ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus); if (ret < 0) return ret; @@ -1295,8 +1301,8 @@ int soc_camera_host_register(struct soc_camera_host *ici) ici->ops->set_parm = default_s_parm; if (!ici->ops->get_parm) ici->ops->get_parm = default_g_parm; - if (!ici->ops->enum_fsizes) - ici->ops->enum_fsizes = default_enum_fsizes; + if (!ici->ops->enum_framesizes) + ici->ops->enum_framesizes = default_enum_framesizes; mutex_lock(&list_lock); list_for_each_entry(ix, &hosts, list) { @@ -1313,6 +1319,7 @@ int soc_camera_host_register(struct soc_camera_host *ici) list_add_tail(&ici->list, &hosts); mutex_unlock(&list_lock); + mutex_init(&ici->host_lock); scan_add_host(ici); return 0; @@ -1386,7 +1393,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_s_input = soc_camera_s_input, .vidioc_s_std = soc_camera_s_std, .vidioc_g_std = soc_camera_g_std, - .vidioc_enum_framesizes = soc_camera_enum_fsizes, + .vidioc_enum_framesizes = soc_camera_enum_framesizes, .vidioc_reqbufs = soc_camera_reqbufs, .vidioc_querybuf = soc_camera_querybuf, .vidioc_qbuf = soc_camera_qbuf, @@ -1425,6 +1432,10 @@ static int video_dev_create(struct soc_camera_device *icd) vdev->tvnorms = V4L2_STD_UNKNOWN; vdev->ctrl_handler = &icd->ctrl_handler; vdev->lock = &icd->video_lock; + /* Locking in file operations other than ioctl should be done + by the driver, not the V4L2 core. + This driver needs auditing so that this flag can be removed. */ + set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags); icd->vdev = vdev; |