diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index ddb4c091dedc..3fb533c4d334 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -41,6 +41,11 @@ #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 480 +#define is_streaming(ici, icd) \ + (((ici)->ops->init_videobuf) ? \ + (icd)->vb_vidq.streaming : \ + vb2_is_streaming(&(icd)->vb2_vidq)) + static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ @@ -662,7 +667,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, if (icd->streamer && icd->streamer != file) return -EBUSY; - if (icd->vb_vidq.bufs[0]) { + if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) { dev_err(&icd->dev, "S_FMT denied: queue initialised\n"); return -EBUSY; } @@ -903,14 +908,17 @@ static int soc_camera_s_crop(struct file *file, void *fh, if (ret < 0) { dev_err(&icd->dev, "S_CROP denied: getting current crop failed\n"); - } else if (icd->vb_vidq.bufs[0] && - (a->c.width != current_crop.c.width || - a->c.height != current_crop.c.height)) { + } else if ((a->c.width == current_crop.c.width && + a->c.height == current_crop.c.height) || + !is_streaming(ici, icd)) { + /* same size or not streaming - use .set_crop() */ + ret = ici->ops->set_crop(icd, a); + } else if (ici->ops->set_livecrop) { + ret = ici->ops->set_livecrop(icd, a); + } else { dev_err(&icd->dev, "S_CROP denied: queue initialised and sizes differ\n"); ret = -EBUSY; - } else { - ret = ici->ops->set_crop(icd, a); } return ret; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index f80b5372baf3..844cd09d7d3e 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -80,6 +80,11 @@ struct soc_camera_host_ops { int (*cropcap)(struct soc_camera_device *, struct v4l2_cropcap *); int (*get_crop)(struct soc_camera_device *, struct v4l2_crop *); int (*set_crop)(struct soc_camera_device *, struct v4l2_crop *); + /* + * The difference to .set_crop() is, that .set_livecrop is not allowed + * to change the output sizes + */ + int (*set_livecrop)(struct soc_camera_device *, struct v4l2_crop *); int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *); int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *); void (*init_videobuf)(struct videobuf_queue *,