summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c88
-rw-r--r--drivers/media/platform/sh_vou.c15
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c17
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c30
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c38
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c130
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c45
-rw-r--r--drivers/media/platform/soc_camera/soc_scale_crop.c97
-rw-r--r--drivers/media/platform/soc_camera/soc_scale_crop.h6
9 files changed, 223 insertions, 243 deletions
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 7d9f35976d18..7354469670b7 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -772,40 +772,45 @@ isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
}
static int
-isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
-{
- struct isp_video *video = video_drvdata(file);
- struct v4l2_subdev *subdev;
- int ret;
-
- subdev = isp_video_remote_subdev(video, NULL);
- if (subdev == NULL)
- return -EINVAL;
-
- mutex_lock(&video->mutex);
- ret = v4l2_subdev_call(subdev, video, cropcap, cropcap);
- mutex_unlock(&video->mutex);
-
- return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
-}
-
-static int
-isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+isp_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel)
{
struct isp_video *video = video_drvdata(file);
struct v4l2_subdev_format format;
struct v4l2_subdev *subdev;
+ struct v4l2_subdev_selection sdsel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = sel->target,
+ };
u32 pad;
int ret;
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
subdev = isp_video_remote_subdev(video, &pad);
if (subdev == NULL)
return -EINVAL;
- /* Try the get crop operation first and fallback to get format if not
+ /* Try the get selection operation first and fallback to get format if not
* implemented.
*/
- ret = v4l2_subdev_call(subdev, video, g_crop, crop);
+ sdsel.pad = pad;
+ ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel);
+ if (!ret)
+ sel->r = sdsel.r;
if (ret != -ENOIOCTLCMD)
return ret;
@@ -815,28 +820,50 @@ isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
if (ret < 0)
return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
- crop->c.left = 0;
- crop->c.top = 0;
- crop->c.width = format.format.width;
- crop->c.height = format.format.height;
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = format.format.width;
+ sel->r.height = format.format.height;
return 0;
}
static int
-isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
+isp_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel)
{
struct isp_video *video = video_drvdata(file);
struct v4l2_subdev *subdev;
+ struct v4l2_subdev_selection sdsel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = sel->target,
+ .flags = sel->flags,
+ .r = sel->r,
+ };
+ u32 pad;
int ret;
- subdev = isp_video_remote_subdev(video, NULL);
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ subdev = isp_video_remote_subdev(video, &pad);
if (subdev == NULL)
return -EINVAL;
+ sdsel.pad = pad;
mutex_lock(&video->mutex);
- ret = v4l2_subdev_call(subdev, video, s_crop, crop);
+ ret = v4l2_subdev_call(subdev, pad, set_selection, NULL, &sdsel);
mutex_unlock(&video->mutex);
+ if (!ret)
+ sel->r = sdsel.r;
return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
}
@@ -1252,9 +1279,8 @@ static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
.vidioc_g_fmt_vid_out = isp_video_get_format,
.vidioc_s_fmt_vid_out = isp_video_set_format,
.vidioc_try_fmt_vid_out = isp_video_try_format,
- .vidioc_cropcap = isp_video_cropcap,
- .vidioc_g_crop = isp_video_get_crop,
- .vidioc_s_crop = isp_video_set_crop,
+ .vidioc_g_selection = isp_video_get_selection,
+ .vidioc_s_selection = isp_video_set_selection,
.vidioc_g_parm = isp_video_get_param,
.vidioc_s_parm = isp_video_set_param,
.vidioc_reqbufs = isp_video_reqbufs,
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index e1f39b4cf1cd..4ee7b1570f62 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -937,7 +937,10 @@ static int sh_vou_s_selection(struct file *file, void *fh,
{
struct v4l2_rect *rect = &sel->r;
struct sh_vou_device *vou_dev = video_drvdata(file);
- struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
+ struct v4l2_subdev_selection sd_sel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = V4L2_SEL_TGT_COMPOSE,
+ };
struct v4l2_pix_format *pix = &vou_dev->pix;
struct sh_vou_geometry geo;
struct v4l2_subdev_format format = {
@@ -978,14 +981,14 @@ static int sh_vou_s_selection(struct file *file, void *fh,
geo.in_height = pix->height;
/* Configure the encoder one-to-one, position at 0, ignore errors */
- sd_crop.c.width = geo.output.width;
- sd_crop.c.height = geo.output.height;
+ sd_sel.r.width = geo.output.width;
+ sd_sel.r.height = geo.output.height;
/*
- * We first issue a S_CROP, so that the subsequent S_FMT delivers the
+ * We first issue a S_SELECTION, so that the subsequent S_FMT delivers the
* final encoder configuration.
*/
- v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
- s_crop, &sd_crop);
+ v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad,
+ set_selection, NULL, &sd_sel);
format.format.width = geo.output.width;
format.format.height = geo.output.height;
ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad,
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 2aaf4a8f71a0..ebbe514d64e2 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -1280,10 +1280,10 @@ static int pxa_camera_check_frame(u32 width, u32 height)
(width & 0x01);
}
-static int pxa_camera_set_crop(struct soc_camera_device *icd,
- const struct v4l2_crop *a)
+static int pxa_camera_set_selection(struct soc_camera_device *icd,
+ struct v4l2_selection *sel)
{
- const struct v4l2_rect *rect = &a->c;
+ const struct v4l2_rect *rect = &sel->r;
struct device *dev = icd->parent;
struct soc_camera_host *ici = to_soc_camera_host(dev);
struct pxa_camera_dev *pcdev = ici->priv;
@@ -1298,13 +1298,19 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
struct v4l2_mbus_framefmt *mf = &fmt.format;
struct pxa_cam *cam = icd->host_priv;
u32 fourcc = icd->current_fmt->host_fmt->fourcc;
+ struct v4l2_subdev_selection sdsel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = sel->target,
+ .flags = sel->flags,
+ .r = sel->r,
+ };
int ret;
/* If PCLK is used to latch data from the sensor, check sense */
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
icd->sense = &sense;
- ret = v4l2_subdev_call(sd, video, s_crop, a);
+ ret = v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel);
icd->sense = NULL;
@@ -1313,6 +1319,7 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
rect->width, rect->height, rect->left, rect->top);
return ret;
}
+ sel->r = sdsel.r;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
if (ret < 0)
@@ -1592,7 +1599,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.remove = pxa_camera_remove_device,
.clock_start = pxa_camera_clock_start,
.clock_stop = pxa_camera_clock_stop,
- .set_crop = pxa_camera_set_crop,
+ .set_selection = pxa_camera_set_selection,
.get_formats = pxa_camera_get_formats,
.put_formats = pxa_camera_put_formats,
.set_fmt = pxa_camera_set_fmt,
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 9c137522c660..077f12d1575f 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -515,7 +515,7 @@ struct rcar_vin_cam {
unsigned int out_width;
unsigned int out_height;
/*
- * User window from S_CROP / G_CROP, produced by client cropping and
+ * User window from S_SELECTION / G_SELECTION, produced by client cropping and
* scaling, VIN scaling and VIN cropping, mapped back onto the client
* input window
*/
@@ -1471,16 +1471,15 @@ static void rcar_vin_put_formats(struct soc_camera_device *icd)
icd->host_priv = NULL;
}
-static int rcar_vin_set_crop(struct soc_camera_device *icd,
- const struct v4l2_crop *a)
+static int rcar_vin_set_selection(struct soc_camera_device *icd,
+ struct v4l2_selection *sel)
{
- struct v4l2_crop a_writable = *a;
- const struct v4l2_rect *rect = &a_writable.c;
+ const struct v4l2_rect *rect = &sel->r;
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct rcar_vin_priv *priv = ici->priv;
- struct v4l2_crop cam_crop;
+ struct v4l2_selection cam_sel;
struct rcar_vin_cam *cam = icd->host_priv;
- struct v4l2_rect *cam_rect = &cam_crop.c;
+ struct v4l2_rect *cam_rect = &cam_sel.r;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
struct v4l2_subdev_format fmt = {
@@ -1490,15 +1489,15 @@ static int rcar_vin_set_crop(struct soc_camera_device *icd,
u32 vnmc;
int ret, i;
- dev_dbg(dev, "S_CROP(%ux%u@%u:%u)\n", rect->width, rect->height,
+ dev_dbg(dev, "S_SELECTION(%ux%u@%u:%u)\n", rect->width, rect->height,
rect->left, rect->top);
/* During camera cropping its output window can change too, stop VIN */
capture_stop_preserve(priv, &vnmc);
dev_dbg(dev, "VNMC_REG 0x%x\n", vnmc);
- /* Apply iterative camera S_CROP for new input window. */
- ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop,
+ /* Apply iterative camera S_SELECTION for new input window. */
+ ret = soc_camera_client_s_selection(sd, sel, &cam_sel,
&cam->rect, &cam->subrect);
if (ret < 0)
return ret;
@@ -1551,13 +1550,12 @@ static int rcar_vin_set_crop(struct soc_camera_device *icd,
return ret;
}
-static int rcar_vin_get_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+static int rcar_vin_get_selection(struct soc_camera_device *icd,
+ struct v4l2_selection *sel)
{
struct rcar_vin_cam *cam = icd->host_priv;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->c = cam->subrect;
+ sel->r = cam->subrect;
return 0;
}
@@ -1824,8 +1822,8 @@ static struct soc_camera_host_ops rcar_vin_host_ops = {
.remove = rcar_vin_remove_device,
.get_formats = rcar_vin_get_formats,
.put_formats = rcar_vin_put_formats,
- .get_crop = rcar_vin_get_crop,
- .set_crop = rcar_vin_set_crop,
+ .get_selection = rcar_vin_get_selection,
+ .set_selection = rcar_vin_set_selection,
.try_fmt = rcar_vin_try_fmt,
.set_fmt = rcar_vin_set_fmt,
.poll = rcar_vin_poll,
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 05eafe3a421e..e5571c8a368e 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -134,7 +134,7 @@ struct sh_mobile_ceu_cam {
unsigned int width;
unsigned int height;
/*
- * User window from S_CROP / G_CROP, produced by client cropping and
+ * User window from S_SELECTION / G_SELECTION, produced by client cropping and
* scaling, CEU scaling and CEU cropping, mapped back onto the client
* input window
*/
@@ -1109,17 +1109,16 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
* Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of
* scaling and cropping algorithms and for the meaning of referenced here steps.
*/
-static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
- const struct v4l2_crop *a)
+static int sh_mobile_ceu_set_selection(struct soc_camera_device *icd,
+ struct v4l2_selection *sel)
{
- struct v4l2_crop a_writable = *a;
- const struct v4l2_rect *rect = &a_writable.c;
+ struct v4l2_rect *rect = &sel->r;
struct device *dev = icd->parent;
struct soc_camera_host *ici = to_soc_camera_host(dev);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- struct v4l2_crop cam_crop;
+ struct v4l2_selection cam_sel;
struct sh_mobile_ceu_cam *cam = icd->host_priv;
- struct v4l2_rect *cam_rect = &cam_crop.c;
+ struct v4l2_rect *cam_rect = &cam_sel.r;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct v4l2_subdev_format fmt = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
@@ -1131,7 +1130,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
u32 capsr, cflcr;
int ret;
- dev_geo(dev, "S_CROP(%ux%u@%u:%u)\n", rect->width, rect->height,
+ dev_geo(dev, "S_SELECTION(%ux%u@%u:%u)\n", rect->width, rect->height,
rect->left, rect->top);
/* During camera cropping its output window can change too, stop CEU */
@@ -1139,10 +1138,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
/*
- * 1. - 2. Apply iterative camera S_CROP for new input window, read back
+ * 1. - 2. Apply iterative camera S_SELECTION for new input window, read back
* actual camera rectangle.
*/
- ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop,
+ ret = soc_camera_client_s_selection(sd, sel, &cam_sel,
&cam->rect, &cam->subrect);
if (ret < 0)
return ret;
@@ -1251,13 +1250,12 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
return ret;
}
-static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+static int sh_mobile_ceu_get_selection(struct soc_camera_device *icd,
+ struct v4l2_selection *sel)
{
struct sh_mobile_ceu_cam *cam = icd->host_priv;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->c = cam->subrect;
+ sel->r = cam->subrect;
return 0;
}
@@ -1499,8 +1497,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
return ret;
}
-static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
- const struct v4l2_crop *a)
+static int sh_mobile_ceu_set_liveselection(struct soc_camera_device *icd,
+ struct v4l2_selection *sel)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -1519,7 +1517,7 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
"Client failed to stop the stream: %d\n", ret);
else
/* Do the crop, if it fails, there's nothing more we can do */
- sh_mobile_ceu_set_crop(icd, a);
+ sh_mobile_ceu_set_selection(icd, sel);
dev_geo(icd->parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
@@ -1600,9 +1598,9 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.clock_stop = sh_mobile_ceu_clock_stop,
.get_formats = sh_mobile_ceu_get_formats,
.put_formats = sh_mobile_ceu_put_formats,
- .get_crop = sh_mobile_ceu_get_crop,
- .set_crop = sh_mobile_ceu_set_crop,
- .set_livecrop = sh_mobile_ceu_set_livecrop,
+ .get_selection = sh_mobile_ceu_get_selection,
+ .set_selection = sh_mobile_ceu_set_selection,
+ .set_liveselection = sh_mobile_ceu_set_liveselection,
.set_fmt = sh_mobile_ceu_set_fmt,
.try_fmt = sh_mobile_ceu_try_fmt,
.poll = sh_mobile_ceu_poll,
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 46c7186f7867..edd1c1de4e33 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -581,7 +581,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n",
pixfmtstr(pix->pixelformat), pix->width, pix->height);
- /* We always call try_fmt() before set_fmt() or set_crop() */
+ /* We always call try_fmt() before set_fmt() or set_selection() */
ret = soc_camera_try_fmt(icd, f);
if (ret < 0)
return ret;
@@ -1025,72 +1025,6 @@ static int soc_camera_streamoff(struct file *file, void *priv,
return ret;
}
-static int soc_camera_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- return ici->ops->cropcap(icd, a);
-}
-
-static int soc_camera_g_crop(struct file *file, void *fh,
- struct v4l2_crop *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- int ret;
-
- ret = ici->ops->get_crop(icd, a);
-
- return ret;
-}
-
-/*
- * According to the V4L2 API, drivers shall not update the struct v4l2_crop
- * argument with the actual geometry, instead, the user shall use G_CROP to
- * retrieve it.
- */
-static int soc_camera_s_crop(struct file *file, void *fh,
- const struct v4l2_crop *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- const struct v4l2_rect *rect = &a->c;
- struct v4l2_crop current_crop;
- int ret;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n",
- rect->width, rect->height, rect->left, rect->top);
-
- current_crop.type = a->type;
-
- /* If get_crop fails, we'll let host and / or client drivers decide */
- ret = ici->ops->get_crop(icd, &current_crop);
-
- /* Prohibit window size change with initialised buffers */
- if (ret < 0) {
- dev_err(icd->pdev,
- "S_CROP denied: getting current crop failed\n");
- } 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->pdev,
- "S_CROP denied: queue initialised and sizes differ\n");
- ret = -EBUSY;
- }
-
- return ret;
-}
-
static int soc_camera_g_selection(struct file *file, void *fh,
struct v4l2_selection *s)
{
@@ -1101,9 +1035,6 @@ static int soc_camera_g_selection(struct file *file, void *fh,
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (!ici->ops->get_selection)
- return -ENOTTY;
-
return ici->ops->get_selection(icd, s);
}
@@ -1135,10 +1066,11 @@ static int soc_camera_s_selection(struct file *file, void *fh,
return -EBUSY;
}
- if (!ici->ops->set_selection)
- return -ENOTTY;
-
- ret = ici->ops->set_selection(icd, s);
+ if (s->target == V4L2_SEL_TGT_CROP && is_streaming(ici, icd) &&
+ ici->ops->set_liveselection)
+ ret = ici->ops->set_liveselection(icd, s);
+ else
+ ret = ici->ops->set_selection(icd, s);
if (!ret &&
s->target == V4L2_SEL_TGT_COMPOSE) {
icd->user_width = s->r.width;
@@ -1881,23 +1813,40 @@ static int soc_camera_remove(struct soc_camera_device *icd)
return 0;
}
-static int default_cropcap(struct soc_camera_device *icd,
- struct v4l2_cropcap *a)
+static int default_g_selection(struct soc_camera_device *icd,
+ struct v4l2_selection *sel)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, cropcap, a);
-}
+ struct v4l2_subdev_selection sdsel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = sel->target,
+ };
+ int ret;
-static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, g_crop, a);
+ ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel);
+ if (ret)
+ return ret;
+ sel->r = sdsel.r;
+ return 0;
}
-static int default_s_crop(struct soc_camera_device *icd, const struct v4l2_crop *a)
+static int default_s_selection(struct soc_camera_device *icd,
+ struct v4l2_selection *sel)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, s_crop, a);
+ struct v4l2_subdev_selection sdsel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = sel->target,
+ .flags = sel->flags,
+ .r = sel->r,
+ };
+ int ret;
+
+ ret = v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel);
+ if (ret)
+ return ret;
+ sel->r = sdsel.r;
+ return 0;
}
static int default_g_parm(struct soc_camera_device *icd,
@@ -1968,12 +1917,10 @@ int soc_camera_host_register(struct soc_camera_host *ici)
!ici->v4l2_dev.dev)
return -EINVAL;
- if (!ici->ops->set_crop)
- ici->ops->set_crop = default_s_crop;
- if (!ici->ops->get_crop)
- ici->ops->get_crop = default_g_crop;
- if (!ici->ops->cropcap)
- ici->ops->cropcap = default_cropcap;
+ if (!ici->ops->set_selection)
+ ici->ops->set_selection = default_s_selection;
+ if (!ici->ops->get_selection)
+ ici->ops->get_selection = default_g_selection;
if (!ici->ops->set_parm)
ici->ops->set_parm = default_s_parm;
if (!ici->ops->get_parm)
@@ -2126,9 +2073,6 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_expbuf = soc_camera_expbuf,
.vidioc_streamon = soc_camera_streamon,
.vidioc_streamoff = soc_camera_streamoff,
- .vidioc_cropcap = soc_camera_cropcap,
- .vidioc_g_crop = soc_camera_g_crop,
- .vidioc_s_crop = soc_camera_s_crop,
.vidioc_g_selection = soc_camera_g_selection,
.vidioc_s_selection = soc_camera_s_selection,
.vidioc_g_parm = soc_camera_g_parm,
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c
index a51d2a42998c..534d6c3c6d60 100644
--- a/drivers/media/platform/soc_camera/soc_camera_platform.c
+++ b/drivers/media/platform/soc_camera/soc_camera_platform.c
@@ -76,35 +76,27 @@ static int soc_camera_platform_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int soc_camera_platform_g_crop(struct v4l2_subdev *sd,
- struct v4l2_crop *a)
-{
- struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
-
- a->c.left = 0;
- a->c.top = 0;
- a->c.width = p->format.width;
- a->c.height = p->format.height;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int soc_camera_platform_cropcap(struct v4l2_subdev *sd,
- struct v4l2_cropcap *a)
+static int soc_camera_platform_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = p->format.width;
- a->bounds.height = p->format.height;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
- return 0;
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = p->format.width;
+ sel->r.height = p->format.height;
+ return 0;
+ default:
+ return -EINVAL;
+ }
}
static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd,
@@ -120,13 +112,12 @@ static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd,
static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
.s_stream = soc_camera_platform_s_stream,
- .cropcap = soc_camera_platform_cropcap,
- .g_crop = soc_camera_platform_g_crop,
.g_mbus_config = soc_camera_platform_g_mbus_config,
};
static const struct v4l2_subdev_pad_ops platform_subdev_pad_ops = {
.enum_mbus_code = soc_camera_platform_enum_mbus_code,
+ .get_selection = soc_camera_platform_get_selection,
.get_fmt = soc_camera_platform_fill_fmt,
.set_fmt = soc_camera_platform_fill_fmt,
};
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
index bda29bc1b933..f77252d6ccd3 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -40,24 +40,22 @@ static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
/* Get and store current client crop */
int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
{
- struct v4l2_crop crop;
- struct v4l2_cropcap cap;
+ struct v4l2_subdev_selection sdsel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = V4L2_SEL_TGT_CROP,
+ };
int ret;
- crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- ret = v4l2_subdev_call(sd, video, g_crop, &crop);
+ ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel);
if (!ret) {
- *rect = crop.c;
+ *rect = sdsel.r;
return ret;
}
- /* Camera driver doesn't support .g_crop(), assume default rectangle */
- cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ sdsel.target = V4L2_SEL_TGT_CROP_DEFAULT;
+ ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel);
if (!ret)
- *rect = cap.defrect;
+ *rect = sdsel.r;
return ret;
}
@@ -93,17 +91,27 @@ static void update_subrect(struct v4l2_rect *rect, struct v4l2_rect *subrect)
* 2. if (1) failed, try to double the client image until we get one big enough
* 3. if (2) failed, try to request the maximum image
*/
-int soc_camera_client_s_crop(struct v4l2_subdev *sd,
- struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
+int soc_camera_client_s_selection(struct v4l2_subdev *sd,
+ struct v4l2_selection *sel, struct v4l2_selection *cam_sel,
struct v4l2_rect *target_rect, struct v4l2_rect *subrect)
{
- struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
+ struct v4l2_subdev_selection sdsel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = sel->target,
+ .flags = sel->flags,
+ .r = sel->r,
+ };
+ struct v4l2_subdev_selection bounds = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = V4L2_SEL_TGT_CROP_BOUNDS,
+ };
+ struct v4l2_rect *rect = &sel->r, *cam_rect = &cam_sel->r;
struct device *dev = sd->v4l2_dev->dev;
- struct v4l2_cropcap cap;
int ret;
unsigned int width, height;
- v4l2_subdev_call(sd, video, s_crop, crop);
+ v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel);
+ sel->r = sdsel.r;
ret = soc_camera_client_g_rect(sd, cam_rect);
if (ret < 0)
return ret;
@@ -113,29 +121,29 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd,
* be within camera cropcap bounds
*/
if (!memcmp(rect, cam_rect, sizeof(*rect))) {
- /* Even if camera S_CROP failed, but camera rectangle matches */
- dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
+ /* Even if camera S_SELECTION failed, but camera rectangle matches */
+ dev_dbg(dev, "Camera S_SELECTION successful for %dx%d@%d:%d\n",
rect->width, rect->height, rect->left, rect->top);
*target_rect = *cam_rect;
return 0;
}
/* Try to fix cropping, that camera hasn't managed to set */
- dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
+ dev_geo(dev, "Fix camera S_SELECTION for %dx%d@%d:%d to %dx%d@%d:%d\n",
cam_rect->width, cam_rect->height,
cam_rect->left, cam_rect->top,
rect->width, rect->height, rect->left, rect->top);
/* We need sensor maximum rectangle */
- ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &bounds);
if (ret < 0)
return ret;
/* Put user requested rectangle within sensor bounds */
- soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
- cap.bounds.width);
- soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
- cap.bounds.height);
+ soc_camera_limit_side(&rect->left, &rect->width, sdsel.r.left, 2,
+ bounds.r.width);
+ soc_camera_limit_side(&rect->top, &rect->height, sdsel.r.top, 4,
+ bounds.r.height);
/*
* Popular special case - some cameras can only handle fixed sizes like
@@ -150,7 +158,7 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd,
*/
while (!ret && (is_smaller(cam_rect, rect) ||
is_inside(cam_rect, rect)) &&
- (cap.bounds.width > width || cap.bounds.height > height)) {
+ (bounds.r.width > width || bounds.r.height > height)) {
width *= 2;
height *= 2;
@@ -168,36 +176,40 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd,
* Instead we just drop to the left and top bounds.
*/
if (cam_rect->left > rect->left)
- cam_rect->left = cap.bounds.left;
+ cam_rect->left = bounds.r.left;
if (cam_rect->left + cam_rect->width < rect->left + rect->width)
cam_rect->width = rect->left + rect->width -
cam_rect->left;
if (cam_rect->top > rect->top)
- cam_rect->top = cap.bounds.top;
+ cam_rect->top = bounds.r.top;
if (cam_rect->top + cam_rect->height < rect->top + rect->height)
cam_rect->height = rect->top + rect->height -
cam_rect->top;
- v4l2_subdev_call(sd, video, s_crop, cam_crop);
+ sdsel.r = *cam_rect;
+ v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel);
+ *cam_rect = sdsel.r;
ret = soc_camera_client_g_rect(sd, cam_rect);
- dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
+ dev_geo(dev, "Camera S_SELECTION %d for %dx%d@%d:%d\n", ret,
cam_rect->width, cam_rect->height,
cam_rect->left, cam_rect->top);
}
- /* S_CROP must not modify the rectangle */
+ /* S_SELECTION must not modify the rectangle */
if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) {
/*
* The camera failed to configure a suitable cropping,
* we cannot use the current rectangle, set to max
*/
- *cam_rect = cap.bounds;
- v4l2_subdev_call(sd, video, s_crop, cam_crop);
+ sdsel.r = bounds.r;
+ v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel);
+ *cam_rect = sdsel.r;
+
ret = soc_camera_client_g_rect(sd, cam_rect);
- dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
+ dev_geo(dev, "Camera S_SELECTION %d for max %dx%d@%d:%d\n", ret,
cam_rect->width, cam_rect->height,
cam_rect->left, cam_rect->top);
}
@@ -209,7 +221,7 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd,
return ret;
}
-EXPORT_SYMBOL(soc_camera_client_s_crop);
+EXPORT_SYMBOL(soc_camera_client_s_selection);
/* Iterative set_fmt, also updates cached client crop on success */
static int client_set_fmt(struct soc_camera_device *icd,
@@ -221,7 +233,10 @@ static int client_set_fmt(struct soc_camera_device *icd,
struct device *dev = icd->parent;
struct v4l2_mbus_framefmt *mf = &format->format;
unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
- struct v4l2_cropcap cap;
+ struct v4l2_subdev_selection sdsel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .target = V4L2_SEL_TGT_CROP_BOUNDS,
+ };
bool host_1to1;
int ret;
@@ -243,16 +258,14 @@ static int client_set_fmt(struct soc_camera_device *icd,
if (!host_can_scale)
goto update_cache;
- cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel);
if (ret < 0)
return ret;
- if (max_width > cap.bounds.width)
- max_width = cap.bounds.width;
- if (max_height > cap.bounds.height)
- max_height = cap.bounds.height;
+ if (max_width > sdsel.r.width)
+ max_width = sdsel.r.width;
+ if (max_height > sdsel.r.height)
+ max_height = sdsel.r.height;
/* Camera set a format, but geometry is not precise, try to improve */
tmp_w = mf->width;
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.h b/drivers/media/platform/soc_camera/soc_scale_crop.h
index 184a30dff541..9ca469312a1f 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.h
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.h
@@ -16,7 +16,7 @@
struct soc_camera_device;
-struct v4l2_crop;
+struct v4l2_selection;
struct v4l2_mbus_framefmt;
struct v4l2_pix_format;
struct v4l2_rect;
@@ -31,8 +31,8 @@ static inline unsigned int soc_camera_shift_scale(unsigned int size,
#define soc_camera_calc_scale(in, shift, out) soc_camera_shift_scale(in, shift, out)
int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
-int soc_camera_client_s_crop(struct v4l2_subdev *sd,
- struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
+int soc_camera_client_s_selection(struct v4l2_subdev *sd,
+ struct v4l2_selection *sel, struct v4l2_selection *cam_sel,
struct v4l2_rect *target_rect, struct v4l2_rect *subrect);
int soc_camera_client_scale(struct soc_camera_device *icd,
struct v4l2_rect *rect, struct v4l2_rect *subrect,