unsigned int timeout,int probe_fl,
                                void *write_data,unsigned int write_len,
                                void *read_data,unsigned int read_len);
+static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw);
 
 
 static void trace_stbit(const char *name,int val)
 
 static int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left)
 {
-       struct v4l2_cropcap *cap = &cptr->hdw->cropcap;
-       if (cap->bounds.width > 0) {
-               /* This statement is present purely to shut up
-                  checkpatch.pl */
-               *left = cap->bounds.left - cap->defrect.left;
-       } else {
-               /* This statement is present purely to shut up
-                  checkpatch.pl */
-               *left = -119;
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
        }
+       *left = cap->bounds.left;
        return 0;
 }
 
 static int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left)
 {
-       struct v4l2_cropcap *cap = &cptr->hdw->cropcap;
-       if (cap->bounds.width > 0) {
-               *left = cap->bounds.left + cap->bounds.width
-                       - cap->defrect.left;
-               *left += 3;
-               *left -= cptr->hdw->cropw_val;
-       } else {
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *left = cap->bounds.left;
+       if (cap->bounds.width > cptr->hdw->cropw_val) {
                /* This statement is present purely to shut up
                   checkpatch.pl */
-               *left = 340;
+               *left += cap->bounds.width - cptr->hdw->cropw_val;
        }
        return 0;
 }
 
 static int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top)
 {
-       struct v4l2_cropcap *cap = &cptr->hdw->cropcap;
-       if (cap->bounds.height > 0) {
-               /* This statement is present purely to shut up
-                  checkpatch.pl */
-               *top = cap->bounds.top - cap->defrect.top;
-       } else {
-               /* This statement is present purely to shut up
-                  checkpatch.pl */
-               *top = -19;
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
        }
+       *top = cap->bounds.top;
        return 0;
 }
 
-static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
+static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top)
 {
-       /* Actual maximum depends on the video standard in effect. */
-       if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) {
-               *vp = 480;
-       } else {
-               *vp = 576;
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *top = cap->bounds.top;
+       if (cap->bounds.height > cptr->hdw->croph_val) {
+               /* Keep checkpatch.pl quiet */
+               *top += cap->bounds.height - cptr->hdw->croph_val;
        }
        return 0;
 }
 
-static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top)
+static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *val)
 {
-       struct v4l2_cropcap *cap = &cptr->hdw->cropcap;
-       if (cap->bounds.height > 0) {
-               *top = cap->bounds.top + cap->bounds.height - cap->defrect.top;
-               *top -= cptr->hdw->croph_val;
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = 0;
+       if (cap->bounds.width > cptr->hdw->cropl_val) {
+               /* Keep checkpatch.pl quiet */
+               *val = cap->bounds.width - cptr->hdw->cropl_val;
+       }
+       return 0;
+}
+
+static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = 0;
+       if (cap->bounds.height > cptr->hdw->cropt_val) {
+               /* Keep checkpatch.pl quiet */
+               *val = cap->bounds.height - cptr->hdw->cropt_val;
+       }
+       return 0;
+}
+
+static int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->bounds.left;
+       return 0;
+}
+
+static int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->bounds.top;
+       return 0;
+}
+
+static int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->bounds.width;
+       return 0;
+}
+
+static int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->bounds.height;
+       return 0;
+}
+
+static int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->defrect.left;
+       return 0;
+}
+
+static int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->defrect.top;
+       return 0;
+}
+
+static int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->defrect.width;
+       return 0;
+}
+
+static int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->defrect.height;
+       return 0;
+}
+
+static int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->pixelaspect.numerator;
+       return 0;
+}
+
+static int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               /* Keep checkpatch.pl quiet */
+               return stat;
+       }
+       *val = cap->pixelaspect.denominator;
+       return 0;
+}
+
+static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       /* Actual maximum depends on the video standard in effect. */
+       if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) {
+               *vp = 480;
        } else {
-               ctrl_vres_max_get(cptr, top);
-               *top -= 32;
+               *vp = 576;
        }
        return 0;
 }
                DEFREF(mute),
                DEFBOOL,
        }, {
-               .desc = "Capture left margin",
+               .desc = "Capture crop left margin",
                .name = "crop_left",
                .internal_id = PVR2_CID_CROPL,
                .default_value = 0,
                DEFINT(-129, 340),
                .get_min_value = ctrl_cropl_min_get,
                .get_max_value = ctrl_cropl_max_get,
+               .get_def_value = ctrl_get_cropcapdl,
        }, {
-               .desc = "Capture top margin",
+               .desc = "Capture crop top margin",
                .name = "crop_top",
                .internal_id = PVR2_CID_CROPT,
                .default_value = 0,
                DEFINT(-35, 544),
                .get_min_value = ctrl_cropt_min_get,
                .get_max_value = ctrl_cropt_max_get,
+               .get_def_value = ctrl_get_cropcapdt,
        }, {
-               .desc = "Capture width",
+               .desc = "Capture crop width",
                .name = "crop_width",
                .internal_id = PVR2_CID_CROPW,
                .default_value = 720,
                DEFREF(cropw),
-               DEFINT(388, 849), /* determined empirically, any res_hor>=64 */
+               .get_max_value = ctrl_cropw_max_get,
+               .get_def_value = ctrl_get_cropcapdw,
        }, {
-               .desc = "Capture height",
+               .desc = "Capture crop height",
                .name = "crop_height",
                .internal_id = PVR2_CID_CROPH,
                .default_value = 480,
                DEFREF(croph),
-               DEFINT(32, 576),
-               .get_max_value = ctrl_vres_max_get,
+               .get_max_value = ctrl_croph_max_get,
+               .get_def_value = ctrl_get_cropcapdh,
+       }, {
+               .desc = "Capture capability pixel aspect numerator",
+               .name = "cropcap_pixel_numerator",
+               .internal_id = PVR2_CID_CROPCAPPAN,
+               .get_value = ctrl_get_cropcappan,
+       }, {
+               .desc = "Capture capability pixel aspect denominator",
+               .name = "cropcap_pixel_denominator",
+               .internal_id = PVR2_CID_CROPCAPPAD,
+               .get_value = ctrl_get_cropcappad,
+       }, {
+               .desc = "Capture capability bounds top",
+               .name = "cropcap_bounds_top",
+               .internal_id = PVR2_CID_CROPCAPBT,
+               .get_value = ctrl_get_cropcapbt,
+       }, {
+               .desc = "Capture capability bounds left",
+               .name = "cropcap_bounds_left",
+               .internal_id = PVR2_CID_CROPCAPBL,
+               .get_value = ctrl_get_cropcapbl,
+       }, {
+               .desc = "Capture capability bounds width",
+               .name = "cropcap_bounds_width",
+               .internal_id = PVR2_CID_CROPCAPBW,
+               .get_value = ctrl_get_cropcapbw,
+       }, {
+               .desc = "Capture capability bounds height",
+               .name = "cropcap_bounds_height",
+               .internal_id = PVR2_CID_CROPCAPBH,
+               .get_value = ctrl_get_cropcapbh,
        },{
                .desc = "Video Source",
                .name = "input",
                        valid_std_mask;
        }
 
-       memset(&hdw->cropcap, 0, sizeof hdw->cropcap);
+       hdw->cropcap_stale = !0;
        hdw->eeprom_addr = -1;
        hdw->unit_number = -1;
        hdw->v4l_minor_number_video = -1;
        }
 
        hdw->state_pipeline_config = !0;
+       /* Hardware state may have changed in a way to cause the cropping
+          capabilities to have changed.  So mark it stale, which will
+          cause a later re-fetch. */
        trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
        return !0;
 }
 }
 
 
+static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw)
+{
+       if (!hdw->cropcap_stale) {
+               /* Keep checkpatch.pl quiet */
+               return 0;
+       }
+       pvr2_i2c_core_status_poll(hdw);
+       if (hdw->cropcap_stale) {
+               /* Keep checkpatch.pl quiet */
+               return -EIO;
+       }
+       return 0;
+}
+
+
+/* Return information about cropping capabilities */
+int pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp)
+{
+       int stat = 0;
+       LOCK_TAKE(hdw->big_lock);
+       stat = pvr2_hdw_check_cropcap(hdw);
+       if (!stat) {
+               /* Keep checkpatch.pl quiet */
+               memcpy(pp, &hdw->cropcap_info, sizeof(hdw->cropcap_info));
+       }
+       LOCK_GIVE(hdw->big_lock);
+       return stat;
+}
+
+
 /* Return information about the tuner */
 int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
 {
 
                pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
        }
        hdw->tuner_signal_stale = !0;
+       hdw->cropcap_stale = !0;
 }
 
 
 
 static void set_crop(struct pvr2_hdw *hdw)
 {
-       struct v4l2_cropcap cap;
        struct v4l2_crop crop;
-       int stat;
-
-       memset(&cap, 0, sizeof cap);
-       cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       stat = pvr2_i2c_core_cmd(hdw, VIDIOC_CROPCAP, &cap);
-       hdw->cropcap = cap;
 
        memset(&crop, 0, sizeof crop);
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       crop.c = cap.defrect;
-       crop.c.left += hdw->cropl_val;
-       crop.c.top += hdw->cropt_val;
+       crop.c.left = hdw->cropl_val;
+       crop.c.top = hdw->cropt_val;
        crop.c.height = hdw->croph_val;
        crop.c.width = hdw->cropw_val;
 
        pvr2_trace(PVR2_TRACE_CHIPS,
-                  "i2c v4l2 set_crop stat=%d cap=%d:%d:%d:%d"
-                  " crop=%d:%d:%d:%d", stat, cap.bounds.width,
-                  cap.bounds.height, cap.bounds.left, cap.bounds.top,
+                  "i2c v4l2 set_crop crop=%d:%d:%d:%d",
                   crop.c.width, crop.c.height, crop.c.left, crop.c.top);
 
-       if (stat >= 0) {
-               /* This comment is present purely to keep
-                  checkpatch.pl quiet */
-               pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
-       }
+       pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
 }
 
 static int check_crop(struct pvr2_hdw *hdw)
 
 void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
 {
-       pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+       int stat;
+       struct pvr2_hdw *hdw = cp->hdw;
+       if (hdw->cropcap_stale) {
+               hdw->cropcap_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               stat = pvr2_i2c_client_cmd(cp, VIDIOC_CROPCAP,
+                                          &hdw->cropcap_info);
+               if (stat == 0) {
+                       /* Check was successful, so the data is no
+                          longer considered stale. */
+                       hdw->cropcap_stale = 0;
+               }
+       }
+       pvr2_i2c_client_cmd(cp, VIDIOC_G_TUNER, &hdw->tuner_signal_info);
 }