提交 432907f7 编写于 作者: M Mike Isely 提交者: Mauro Carvalho Chehab

V4L/DVB (8900): pvrusb2: Implement cropping pass through

This builds upon the previous pvrusb2 change to more formally
implement full cropping support.  This enables access from the
driver's V4L interface, and enables access to full capabilities from
sysfs as well.  Note that this is only effective when in analog mode.
It also will only work when the underlying digitizer's driver (saa7115
or cx25840 depending on the hardware) also implements the appropriate
functions.
Signed-off-by: NMike Isely <isely@pobox.com>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 0b7c2c95
......@@ -308,6 +308,10 @@ struct pvr2_hdw {
struct v4l2_tuner tuner_signal_info;
int tuner_signal_stale;
/* Cropping capability info */
struct v4l2_cropcap cropcap_info;
int cropcap_stale;
/* Video standard handling */
v4l2_std_id std_mask_eeprom; // Hardware supported selections
v4l2_std_id std_mask_avail; // Which standards we may select from
......@@ -320,7 +324,6 @@ struct pvr2_hdw {
struct pvr2_ctl_info std_info_cur;
struct v4l2_standard *std_defs;
const char **std_enum_names;
struct v4l2_cropcap cropcap;
// Generated string names, one per actual V4L2 standard
const char *std_mask_ptrs[32];
......
......@@ -298,6 +298,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
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)
......@@ -404,70 +405,220 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
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;
}
......@@ -913,7 +1064,7 @@ static const struct pvr2_ctl_info control_defs[] = {
DEFREF(mute),
DEFBOOL,
}, {
.desc = "Capture left margin",
.desc = "Capture crop left margin",
.name = "crop_left",
.internal_id = PVR2_CID_CROPL,
.default_value = 0,
......@@ -921,8 +1072,9 @@ static const struct pvr2_ctl_info control_defs[] = {
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,
......@@ -930,21 +1082,53 @@ static const struct pvr2_ctl_info control_defs[] = {
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",
......@@ -2188,7 +2372,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
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;
......@@ -2728,6 +2912,9 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
}
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;
}
......@@ -2818,6 +3005,36 @@ void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
}
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)
{
......
......@@ -40,6 +40,12 @@
#define PVR2_CID_CROPT 10
#define PVR2_CID_CROPW 11
#define PVR2_CID_CROPH 12
#define PVR2_CID_CROPCAPPAN 13
#define PVR2_CID_CROPCAPPAD 14
#define PVR2_CID_CROPCAPBL 15
#define PVR2_CID_CROPCAPBT 16
#define PVR2_CID_CROPCAPBW 17
#define PVR2_CID_CROPCAPBH 18
/* Legal values for the INPUT state variable */
#define PVR2_CVAL_INPUT_TV 0
......@@ -174,6 +180,9 @@ void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
/* Return information about the tuner */
int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
/* Return information about cropping capabilities */
int pvr2_hdw_get_cropcap(struct pvr2_hdw *, struct v4l2_cropcap *);
/* Query device and see if it thinks it is on a high-speed USB link */
int pvr2_hdw_is_hsm(struct pvr2_hdw *);
......
......@@ -37,6 +37,7 @@ static void set_standard(struct pvr2_hdw *hdw)
pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
}
hdw->tuner_signal_stale = !0;
hdw->cropcap_stale = !0;
}
......@@ -235,34 +236,20 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
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)
......@@ -312,7 +299,19 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
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);
}
......
......@@ -891,6 +891,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
INIT_LIST_HEAD(&cp->list);
cp->client = client;
mutex_lock(&hdw->i2c_list_lock); do {
hdw->cropcap_stale = !0;
list_add_tail(&cp->list,&hdw->i2c_clients);
hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
} while (0); mutex_unlock(&hdw->i2c_list_lock);
......@@ -905,6 +906,7 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client)
unsigned long amask = 0;
int foundfl = 0;
mutex_lock(&hdw->i2c_list_lock); do {
hdw->cropcap_stale = !0;
list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
if (cp->client == client) {
trace_i2c("pvr2_i2c_detach"
......
......@@ -755,6 +755,92 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
break;
}
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
ret = -EINVAL;
break;
}
ret = pvr2_hdw_get_cropcap(hdw, cap);
cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
break;
}
case VIDIOC_G_CROP:
{
struct v4l2_crop *crop = (struct v4l2_crop *)arg;
int val = 0;
if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
ret = -EINVAL;
break;
}
ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
if (ret != 0) {
ret = -EINVAL;
break;
}
crop->c.left = val;
ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
if (ret != 0) {
ret = -EINVAL;
break;
}
crop->c.top = val;
ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
if (ret != 0) {
ret = -EINVAL;
break;
}
crop->c.width = val;
ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
if (ret != 0) {
ret = -EINVAL;
break;
}
crop->c.height = val;
}
case VIDIOC_S_CROP:
{
struct v4l2_crop *crop = (struct v4l2_crop *)arg;
struct v4l2_cropcap cap;
if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
ret = -EINVAL;
break;
}
cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
crop->c.left);
if (ret != 0) {
ret = -EINVAL;
break;
}
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
crop->c.top);
if (ret != 0) {
ret = -EINVAL;
break;
}
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
crop->c.width);
if (ret != 0) {
ret = -EINVAL;
break;
}
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
crop->c.height);
if (ret != 0) {
ret = -EINVAL;
break;
}
}
case VIDIOC_LOG_STATUS:
{
pvr2_hdw_trigger_module_log(hdw);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册