+/* Given cropping boundaries b and the scaled width and height of a
+ single field or frame, which must not exceed hardware limits, this
+ function adjusts the cropping parameters c. */
+static void
+bttv_crop_adjust (struct bttv_crop * c,
+ const struct v4l2_rect * b,
+ __s32 width,
+ __s32 height,
+ enum v4l2_field field)
+{
+ __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
+ __s32 max_left;
+ __s32 max_top;
+
+ if (width < c->min_scaled_width) {
+ /* Max. hor. scale factor 16:1. */
+ c->rect.width = width * 16;
+ } else if (width > c->max_scaled_width) {
+ /* Min. hor. scale factor 1:1. */
+ c->rect.width = width;
+
+ max_left = b->left + b->width - width;
+ max_left = min(max_left, (__s32) MAX_HDELAY);
+ if (c->rect.left > max_left)
+ c->rect.left = max_left;
+ }
+
+ if (height < c->min_scaled_height) {
+ /* Max. vert. scale factor 16:1, single fields 8:1. */
+ c->rect.height = height * 16;
+ } else if (frame_height > c->max_scaled_height) {
+ /* Min. vert. scale factor 1:1.
+ Top and height count field lines times two. */
+ c->rect.height = (frame_height + 1) & ~1;
+
+ max_top = b->top + b->height - c->rect.height;
+ if (c->rect.top > max_top)
+ c->rect.top = max_top;
+ }
+
+ bttv_crop_calc_limits(c);
+}
+
+/* Returns an error if scaling to a frame or single field with the given
+ width and height is not possible with the current cropping parameters
+ and width aligned according to width_mask. If adjust_size is TRUE the
+ function may adjust the width and/or height instead, rounding width
+ to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
+ also adjust the current cropping parameters to get closer to the
+ desired image size. */
+static int
+limit_scaled_size (struct bttv_fh * fh,
+ __s32 * width,
+ __s32 * height,
+ enum v4l2_field field,
+ unsigned int width_mask,
+ unsigned int width_bias,
+ int adjust_size,
+ int adjust_crop)
+{
+ struct bttv *btv = fh->btv;
+ const struct v4l2_rect *b;
+ struct bttv_crop *c;
+ __s32 min_width;
+ __s32 min_height;
+ __s32 max_width;
+ __s32 max_height;
+ int rc;
+
+ BUG_ON((int) width_mask >= 0 ||
+ width_bias >= (unsigned int) -width_mask);
+
+ /* Make sure tvnorm, vbi_end and the current cropping parameters
+ remain consistent until we're done. */
+ mutex_lock(&btv->lock);
+
+ b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+ /* Do crop - use current, don't - use default parameters. */
+ c = &btv->crop[!!fh->do_crop];
+
+ if (fh->do_crop
+ && adjust_size
+ && adjust_crop
+ && !locked_btres(btv, VIDEO_RESOURCES)) {
+ min_width = 48;
+ min_height = 32;
+
+ /* We cannot scale up. When the scaled image is larger
+ than crop.rect we adjust the crop.rect as required
+ by the V4L2 spec, hence cropcap.bounds are our limit. */
+ max_width = min(b->width, (__s32) MAX_HACTIVE);
+ max_height = b->height;
+
+ /* We cannot capture the same line as video and VBI data.
+ Note btv->vbi_end is really a minimum, see
+ bttv_vbi_try_fmt(). */
+ if (btv->vbi_end > b->top) {
+ max_height -= btv->vbi_end - b->top;
+ rc = -EBUSY;
+ if (min_height > max_height)
+ goto fail;
+ }
+ } else {
+ rc = -EBUSY;
+ if (btv->vbi_end > c->rect.top)
+ goto fail;
+
+ min_width = c->min_scaled_width;
+ min_height = c->min_scaled_height;
+ max_width = c->max_scaled_width;
+ max_height = c->max_scaled_height;
+
+ adjust_crop = 0;
+ }
+
+ min_width = (min_width - width_mask - 1) & width_mask;
+ max_width = max_width & width_mask;
+
+ /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
+ min_height = min_height;
+ /* Min. scale factor is 1:1. */
+ max_height >>= !V4L2_FIELD_HAS_BOTH(field);
+
+ if (adjust_size) {
+ *width = clamp(*width, min_width, max_width);
+ *height = clamp(*height, min_height, max_height);
+
+ /* Round after clamping to avoid overflow. */
+ *width = (*width + width_bias) & width_mask;
+
+ if (adjust_crop) {
+ bttv_crop_adjust(c, b, *width, *height, field);
+
+ if (btv->vbi_end > c->rect.top) {
+ /* Move the crop window out of the way. */
+ c->rect.top = btv->vbi_end;
+ }
+ }
+ } else {
+ rc = -EINVAL;
+ if (*width < min_width ||
+ *height < min_height ||
+ *width > max_width ||
+ *height > max_height ||
+ 0 != (*width & ~width_mask))
+ goto fail;
+ }
+
+ rc = 0; /* success */
+
+ fail:
+ mutex_unlock(&btv->lock);
+
+ return rc;
+}
+
+/* Returns an error if the given overlay window dimensions are not
+ possible with the current cropping parameters. If adjust_size is
+ TRUE the function may adjust the window width and/or height
+ instead, however it always rounds the horizontal position and
+ width as btcx_align() does. If adjust_crop is TRUE the function
+ may also adjust the current cropping parameters to get closer
+ to the desired window size. */
+static int
+verify_window (struct bttv_fh * fh,
+ struct v4l2_window * win,
+ int adjust_size,
+ int adjust_crop)