|
@@ -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;
|