[pvrusb2] [patch] 24xxx capture window cropping support
vdb128 at picaros.org
vdb128 at picaros.org
Sat Sep 5 08:48:17 CDT 2009
Here below is a patch for the setup:
Linux 2.6.29.6, 24xxx device, cx25840 decoder, firmware 2.06.039.
Notes:
1. The vblank default puts the WSS/625 waveform at line 23 in the
first halfline of the frame. The odd field image starts at line 23.5.
http://www.isely.net/pipermail/pvrusb2/2009-July/002512.html
2. The M/PAL/525 timing seems an anachronism. If the top of the frame
contains a few black lines or if the image is bottom centered, try
setting ctl_crop_top/cur_val to 6.
3. An odd value in ctl_crop_top/cur_val swaps the spatial interlacing.
Useful for fixing badly captured system N tapes.
4. All is childproof since the cx25840 driver now limits width and
height. Read ctl_crop_*/cur_val after write to see what was set.
Installation:
* The function call layout in v4l2-subdef.h has changed. Removing *
* and adding the modules pvrusb2 and cx25840 will crash the system. *
patch,
make clean && make bzImage && make modules
&& make install && make modules_install,
rmmod pvrusb2 cx25840 wm8775 tuner v4l2_common videodev,
reboot if the above doesn't work,
modprobe pvrusb2
Sat Sep 5 14:08:04 CEST 2009
--- linux-2.6.29.6/drivers/media/video/v4l2-subdev-d.c 2009-07-03 01:41:20.000000000 +0200
+++ linux-2.6.29.6/drivers/media/video/v4l2-subdev.c 2009-09-03 18:19:04.000000000 +0200
@@ -64,6 +64,8 @@ int v4l2_subdev_command(struct v4l2_subd
return v4l2_subdev_call(sd, tuner, g_tuner, arg);
case VIDIOC_S_STD:
return v4l2_subdev_call(sd, tuner, s_std, *(v4l2_std_id *)arg);
+ case VIDIOC_G_STD:
+ return v4l2_subdev_call(sd, tuner, g_std, arg);
case VIDIOC_S_FREQUENCY:
return v4l2_subdev_call(sd, tuner, s_frequency, arg);
case VIDIOC_G_FREQUENCY:
@@ -92,6 +94,12 @@ int v4l2_subdev_command(struct v4l2_subd
return v4l2_subdev_call(sd, video, g_vbi_data, arg);
case VIDIOC_G_SLICED_VBI_CAP:
return v4l2_subdev_call(sd, video, g_sliced_vbi_cap, arg);
+ case VIDIOC_CROPCAP:
+ return v4l2_subdev_call(sd, video, cropcap, arg);
+ case VIDIOC_S_CROP:
+ return v4l2_subdev_call(sd, video, s_crop, arg);
+ case VIDIOC_G_CROP:
+ return v4l2_subdev_call(sd, video, g_crop, arg);
case VIDIOC_S_FMT:
return v4l2_subdev_call(sd, video, s_fmt, arg);
case VIDIOC_G_FMT:
--- linux-2.6.29.6/drivers/media/video/cx25840/cx25840-core-d.c 2009-07-03 01:41:20.000000000 +0200
+++ linux-2.6.29.6/drivers/media/video/cx25840/cx25840-core.c 2009-09-05 07:50:20.000000000 +0200
@@ -348,35 +348,73 @@ static void cx23885_initialize(struct i2
/* ----------------------------------------------------------------------- */
+/* This code allows for seamless autodetect. */
+static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct cx25840_state *state = to_state(sd);
+ v4l2_std_id fmt2id[16]={
+ V4L2_STD_UNKNOWN, V4L2_STD_NTSC_M, /* 0, 1, */
+ V4L2_STD_NTSC_M_JP, V4L2_STD_NTSC_443, /* 2, 3, */
+ V4L2_STD_PAL, V4L2_STD_PAL_M, /* 4, 5, */
+ V4L2_STD_PAL_N, V4L2_STD_PAL_Nc, /* 6, 7, */
+ V4L2_STD_PAL_60, V4L2_STD_UNKNOWN, /* 8, 9, */
+ V4L2_STD_UNKNOWN, V4L2_STD_UNKNOWN, /* 10, 11, */
+ V4L2_STD_SECAM, V4L2_STD_UNKNOWN, /* 12, 13 */
+ V4L2_STD_UNKNOWN, V4L2_STD_UNKNOWN /* 14, 15 */
+ };
+ v4l2_std_id res;
+
+ res=state->std;
+ if(res == V4L2_STD_UNKNOWN) { /* unset or auto: read from decoder */
+ u8 fmt;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* check VID_FMT_SEL first */
+ fmt = cx25840_read(client, 0x400) & 0xf;
+ if (!fmt) /* set to autodetect: check AFD_FMT_STAT if */
+ fmt = cx25840_read(client, 0x40d) & 0xf;
+
+ res=fmt2id[fmt];
+
+ if(res == V4L2_STD_NTSC_M
+ && !state->is_cx25836 && cx25840_read(client, 0x805) == 2)
+ res=V4L2_STD_NTSC_M_KR;
+ }
+ *std=res;
+
+ return 0;
+}
+
void cx25840_std_setup(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
- v4l2_std_id std = state->std;
+ v4l2_std_id std;
int hblank, hactive, burst, vblank, vactive, sc;
int vblank656, src_decimation;
int luma_lpf, uv_lpf, comb;
u32 pll_int, pll_frac, pll_post;
+ cx25840_g_std(i2c_get_clientdata(client), &std);
+
/* datasheet startup, step 8d */
if (std & ~V4L2_STD_NTSC)
cx25840_write(client, 0x49f, 0x11);
else
cx25840_write(client, 0x49f, 0x14);
+ src_decimation = 543;
if (std & V4L2_STD_625_50) {
- hblank = 132;
+ hblank = 136; /* 132 */
hactive = 720;
burst = 93;
- vblank = 36;
+ vblank = 34;
vactive = 580;
- vblank656 = 40;
- src_decimation = 0x21f;
luma_lpf = 2;
if (std & V4L2_STD_SECAM) {
uv_lpf = 0;
comb = 0;
- sc = 0x0a425f;
+ sc = 672351; /* 0x0a425f */
} else if (std == V4L2_STD_PAL_Nc) {
uv_lpf = 1;
comb = 0x20;
@@ -384,37 +422,34 @@ void cx25840_std_setup(struct i2c_client
} else {
uv_lpf = 1;
comb = 0x20;
- sc = 688739;
+ sc = 688739; /* 0x0a8263 */
}
} else {
- hactive = 720;
hblank = 122;
+ hactive = 720;
vactive = 487;
luma_lpf = 1;
uv_lpf = 1;
- src_decimation = 0x21f;
if (std == V4L2_STD_PAL_60) {
vblank = 26;
- vblank656 = 26;
burst = 0x5b;
luma_lpf = 2;
comb = 0x20;
sc = 688739;
} else if (std == V4L2_STD_PAL_M) {
vblank = 20;
- vblank656 = 24;
burst = 0x61;
comb = 0x20;
sc = 555452;
} else {
vblank = 26;
- vblank656 = 26;
burst = 0x5b;
comb = 0x66;
sc = 556063;
}
}
+ vblank656 = vblank+4;
/* DEBUG: Displays configured PLL frequency */
pll_int = cx25840_read(client, 0x108);
@@ -446,8 +481,8 @@ void cx25840_std_setup(struct i2c_client
v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
"vblank %i, vactive %i, vblank656 %i, src_dec %i, "
- "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, "
- "sc 0x%06x\n",
+ "burst %i, luma_lpf %i, uv_lpf %i, comb 0x%02x, "
+ "sc %i\n",
hblank, hactive, vblank, vactive, vblank656,
src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
}
@@ -491,20 +526,24 @@ void cx25840_std_setup(struct i2c_client
cx25840_write(client, 0x47f, 0x00);
state->vbi_line_offset = 8;
}
+ /* Alignment test: force the use of vblank656 VIP_OPT_AL */
+ /* cx25840_write(client, 0x406, 0x17); */
}
/* ----------------------------------------------------------------------- */
static void input_change(struct i2c_client *client)
{
- struct cx25840_state *state = to_state(i2c_get_clientdata(client));
- v4l2_std_id std = state->std;
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(sd);
+ v4l2_std_id std;
+
+ cx25840_g_std(sd, &std);
/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
if (std & V4L2_STD_SECAM) {
cx25840_write(client, 0x402, 0);
- }
- else {
+ } else {
cx25840_write(client, 0x402, 0x04);
cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
}
@@ -711,6 +750,7 @@ static int set_v4lstd(struct i2c_client
cx25840_and_or(client, 0x47b, ~6, 0);
}
cx25840_and_or(client, 0x400, ~0xf, fmt);
+ if(!fmt) pal_m=2;
cx25840_and_or(client, 0x403, ~0x3, pal_m);
cx25840_std_setup(client);
if (!state->is_cx25836)
@@ -720,6 +760,191 @@ static int set_v4lstd(struct i2c_client
/* ----------------------------------------------------------------------- */
+struct cdefst {
+ int hblank, hactive, htotal; /* per line, unit = 1 dot */
+ int vblank, vactive, vtotal, vpre; /* per field, unit = 1 halfline */
+ int doth, dotv; /* relative size dot: horizontal, vertical */
+};
+static struct cdefst *cdefaulttiming(v4l2_std_id std)
+{
+ static struct cdefst cdef525={ 122, 720, 858, 26, 487, 525, 7, 10, 11 };
+ static struct cdefst cdef525m={ 122, 720, 858, 20, 487, 525, 7, 10, 11 };
+ static struct cdefst cdef625={ 136, 720, 864, 34, 580, 625, 4, 59, 54 };
+
+ if(std & V4L2_STD_625_50) return &cdef625;
+
+ if(std == V4L2_STD_PAL_M) return &cdef525m;
+
+ return &cdef525;
+}
+
+static int min_vblank=2; /* min vblank delay 2 halfline */
+static int cropcap_origin(struct v4l2_subdev *sd, v4l2_std_id *cstd, struct cdefst **cdef, struct v4l2_rect *bounds)
+{
+ v4l2_std_id std;
+ struct cdefst *def;
+
+ cx25840_g_std(sd, &std);
+ if(cstd) *cstd=std;
+
+ def=cdefaulttiming(std);
+ if(cdef) *cdef=def;
+
+ if(bounds) {
+ bounds->left=4-def->hblank; /* hblank delay >=4 dot */
+ bounds->width=def->htotal-2; /* EAV bt.656 */
+ bounds->top=min_vblank-def->vblank; /* vblank delay >=2h */
+ bounds->height=def->vtotal-2-min_vblank;/* field_sync + min_vblank */
+ }
+
+ return 0;
+}
+
+static int cx25840_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cap)
+{
+ v4l2_std_id std;
+ struct cdefst *def;
+
+ if(cap->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cropcap_origin(sd, &std, &def, &cap->bounds);
+
+ cap->defrect.left=0;
+ cap->defrect.width=def->hactive;
+ cap->defrect.top=0;
+ cap->defrect.height=def->vactive-def->vpre;
+
+ cap->pixelaspect.numerator=def->dotv;
+ cap->pixelaspect.denominator=def->doth;
+
+ return 0;
+}
+
+/* base [7:0]=blank_cnt_low
+ * base+1 [7:4]=active_cnt_low [3:2]=ss [1:0]=blank_cnt_high
+ * base+2 [7:6]=rr [5:0]=active_cnt_high
+ */
+static int bsa_read(struct i2c_client *client, int base, int *pbl, int *psav, int *pact)
+{
+ int save, blank, active;
+
+ blank = cx25840_read(client, base);
+ save = cx25840_read(client, base+1);
+ blank |= ((save & 3) << 8);
+ active = ((save & 0xf0) >> 4)
+ | ((cx25840_read(client, base+2) & 0x3f) << 4);
+
+ if(pbl) *pbl=blank;
+ if(psav) *psav=save;
+ if(pact) *pact=active;
+ return 0;
+}
+
+static int bsa_write(struct i2c_client *client, int base, int blank, int save, int active)
+{
+ int snew;
+
+ cx25840_write(client, base, blank & 0xff);
+ snew = (save & 0x0c) | ((active & 0xf) << 4) | ((blank >> 8) & 3);
+ cx25840_write(client, base+1, snew);
+ cx25840_write(client, base+2, active >> 4);
+ return 0;
+}
+
+static int cx25840_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ v4l2_std_id std;
+ struct cdefst *def;
+ int hblank, hactive;
+ int vblank, vactive;
+
+ if(crop->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cropcap_origin(sd, &std, &def, NULL);
+
+ bsa_read(client, 0x470, &hblank, NULL, &hactive);
+ crop->c.left = hblank-def->hblank;
+ crop->c.width = hactive;
+
+ bsa_read(client, 0x474, &vblank, NULL, &vactive);
+ crop->c.top = vblank-def->vblank;
+ crop->c.height = vactive-def->vpre;
+
+ return 0;
+}
+
+static int cx25840_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ v4l2_std_id std;
+ struct cdefst *def;
+ struct v4l2_rect b, c;
+ int bleftend, btopend, hwidthmax, vheightmax;
+ int hbnew, hanew, hsave, hblank, hactive;
+ int vbnew, vbnew656, vanew, vsave, vblank, vblank656, vactive;
+
+ if(crop->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cropcap_origin(sd, &std, &def, &b);
+ c=crop->c;
+
+ if(c.width < 2 || c.height<2) {
+ v4l_err(client, "invalid crop=%d:%d:%d:%d\n", c.width,
+ c.height, c.left, c.top);
+ return -ERANGE;
+ }
+
+ hwidthmax=def->htotal-16;
+ if(c.width > hwidthmax) c.width=hwidthmax;
+
+ vheightmax=def->vtotal-def->vpre-min_vblank;
+ if(c.height > vheightmax) c.height=vheightmax;
+
+ /* An odd value for c.top swaps spatial interlacing. Not enforced
+ * since VHS tapes with incorrect interlacing exist.
+ */
+
+ bleftend=b.left+b.width;
+ if(c.left < b.left || c.left+c.width > bleftend) {
+ v4l_err(client, "invalid horizontal crop %d %d\n",
+ crop->c.left, crop->c.width);
+ return -ERANGE;
+ }
+ hbnew=c.left+def->hblank;
+ hanew=c.width;
+
+ btopend=b.top+b.height;
+ if(c.top < b.top || c.top+c.height > b.top+b.height) {
+ v4l_err(client, "invalid vertical crop %d %d\n",
+ crop->c.top, crop->c.height);
+ return -ERANGE;
+ }
+ vbnew=c.top+def->vblank;
+ vbnew656=vbnew+4;
+ vanew=c.height+def->vpre;
+ //vbnew=34;
+
+ bsa_read(client, 0x470, &hblank, &hsave, &hactive);
+ bsa_write(client, 0x470, hbnew, hsave, hanew);
+ v4l_dbg(1, cx25840_debug, client, "hblank=%i->%i hactive=%i->%i\n",
+ hblank, hbnew, hactive, hanew);
+
+ bsa_read(client, 0x474, &vblank, &vsave, &vactive);
+ vblank656 = cx25840_read(client, 0x477);
+ bsa_write(client, 0x474, vbnew, vsave, vanew);
+ cx25840_write(client, 0x477, vbnew656 & 0xff); /* XXX at 256 */
+ v4l_dbg(1, cx25840_debug, client, "vblank=%i->%i vactive=%i->%i"
+ " vblank656=%i->%i\n", vblank,vbnew, vactive,vanew,
+ vblank656,vbnew656);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct cx25840_state *state = to_state(sd);
@@ -844,7 +1069,7 @@ static int cx25840_s_fmt(struct v4l2_sub
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct v4l2_pix_format *pix;
int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
- int is_50Hz = !(state->std & V4L2_STD_525_60);
+ int is_50Hz = state->std & V4L2_STD_625_50;
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -1272,14 +1497,16 @@ static int cx25840_g_tuner(struct v4l2_s
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+ u8 vpres = cx25840_read(client, 0x40e);
u8 mode;
- int val = 0;
+ int signal, val = 0;
if (state->radio)
return 0;
- vt->signal = vpres ? 0xffff : 0x0;
+ signal= vpres & 0x7f;
+ if(vpres & 0x20) signal|= 0xff80;
+ vt->signal = signal;
if (state->is_cx25836)
return 0;
@@ -1382,6 +1609,7 @@ static int cx25840_log_status(struct v4l
static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg)
{
+ struct v4l2_subdev *sd;
/* ignore this command */
if (cmd == TUNER_SET_TYPE_ADDR || cmd == TUNER_SET_CONFIG)
return 0;
@@ -1389,8 +1617,9 @@ static int cx25840_command(struct i2c_cl
/* Old-style drivers rely on initialization on first use, so
call the init whenever a command is issued to this driver.
New-style drivers using v4l2_subdev should call init explicitly. */
- cx25840_init(i2c_get_clientdata(client), 0);
- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+ sd = i2c_get_clientdata(client);
+ cx25840_init(sd, 0);
+ return v4l2_subdev_command(sd, cmd, arg);
}
/* ----------------------------------------------------------------------- */
@@ -1412,6 +1641,7 @@ static const struct v4l2_subdev_core_ops
static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
.s_frequency = cx25840_s_frequency,
.s_std = cx25840_s_std,
+ .g_std = cx25840_g_std,
.s_radio = cx25840_s_radio,
.g_tuner = cx25840_g_tuner,
.s_tuner = cx25840_s_tuner,
@@ -1424,6 +1654,9 @@ static const struct v4l2_subdev_audio_op
static const struct v4l2_subdev_video_ops cx25840_video_ops = {
.s_routing = cx25840_s_video_routing,
+ .cropcap = cx25840_cropcap,
+ .g_crop = cx25840_g_crop,
+ .s_crop = cx25840_s_crop,
.g_fmt = cx25840_g_fmt,
.s_fmt = cx25840_s_fmt,
.decode_vbi_line = cx25840_decode_vbi_line,
--- linux-2.6.29.6/drivers/media/video/pvrusb2/pvrusb2-hdw-d.c 2009-07-03 01:41:20.000000000 +0200
+++ linux-2.6.29.6/drivers/media/video/pvrusb2/pvrusb2-hdw.c 2009-09-05 04:59:59.000000000 +0200
@@ -450,31 +450,35 @@ static int ctrl_cropt_max_get(struct pvr
return 0;
}
-static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *val)
+static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *width)
{
struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+ int stat, bleftend, cleft;
+
+ stat = pvr2_hdw_check_cropcap(cptr->hdw);
if (stat != 0) {
return stat;
}
- *val = 0;
- if (cap->bounds.width > cptr->hdw->cropl_val) {
- *val = cap->bounds.width - cptr->hdw->cropl_val;
- }
+ bleftend=cap->bounds.left+cap->bounds.width;
+ cleft=cptr->hdw->cropl_val;
+
+ *width= cleft<bleftend ? bleftend-cleft : 0;
return 0;
}
-static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *val)
+static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *height)
{
struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+ int stat, btopend, ctop;
+
+ stat = pvr2_hdw_check_cropcap(cptr->hdw);
if (stat != 0) {
return stat;
}
- *val = 0;
- if (cap->bounds.height > cptr->hdw->cropt_val) {
- *val = cap->bounds.height - cptr->hdw->cropt_val;
- }
+ btopend=cap->bounds.top+cap->bounds.height;
+ ctop=cptr->hdw->cropt_val;
+
+ *height= ctop<btopend ? btopend-ctop : 0;
return 0;
}
--- linux-2.6.29.6/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2-d.c 2009-07-03 01:41:20.000000000 +0200
+++ linux-2.6.29.6/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c 2009-09-05 06:25:43.000000000 +0200
@@ -237,19 +237,33 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l
static void set_crop(struct pvr2_hdw *hdw)
{
struct v4l2_crop crop;
+ struct v4l2_rect *c=&crop.c;
+ int err;
memset(&crop, 0, sizeof crop);
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- crop.c.left = hdw->cropl_val;
- crop.c.top = hdw->cropt_val;
- crop.c.height = hdw->croph_val;
- crop.c.width = hdw->cropw_val;
+ c->left = hdw->cropl_val;
+ c->top = hdw->cropt_val;
+ c->height = hdw->croph_val;
+ c->width = hdw->cropw_val;
pvr2_trace(PVR2_TRACE_CHIPS,
- "i2c v4l2 set_crop crop=%d:%d:%d:%d",
- crop.c.width, crop.c.height, crop.c.left, crop.c.top);
+ "i2c v4l2 set_crop S crop=%d:%d:%d:%d",
+ c->width, c->height, c->left, c->top);
- pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
+ err=pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
+ if(!err) {
+ err=pvr2_i2c_core_cmd(hdw, VIDIOC_G_CROP, &crop);
+ pvr2_trace(PVR2_TRACE_CHIPS,
+ "i2c v4l2 set_crop G err=%i %d:%d:%d:%d", err,
+ c->width, c->height, c->left, c->top);
+ if(!err) {
+ hdw->cropl_val = c->left;
+ hdw->cropt_val = c->top;
+ hdw->croph_val = c->height;
+ hdw->cropw_val = c->width;
+ }
+ }
}
static int check_crop(struct pvr2_hdw *hdw)
@@ -295,16 +309,23 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2
void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
{
- 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);
+ int *ccstale=&hdw->cropcap_stale;
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c pvr2_v4l2_cmd_status_poll cropcap %d",
+ *ccstale);
+
+ if (*ccstale) {
+ struct v4l2_cropcap *ccinfo=&hdw->cropcap_info;
+ int stat;
+
+ memset(ccinfo, 0, sizeof(*ccinfo));
+ ccinfo->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ stat = pvr2_i2c_client_cmd(cp, VIDIOC_CROPCAP, ccinfo);
if (stat == 0) {
/* Check was successful, so the data is no
longer considered stale. */
- hdw->cropcap_stale = 0;
+ *ccstale = 0;
}
}
pvr2_i2c_client_cmd(cp, VIDIOC_G_TUNER, &hdw->tuner_signal_info);
--- linux-2.6.29.6/drivers/media/video/pvrusb2/pvrusb2-i2c-core-d.c 2009-07-03 01:41:20.000000000 +0200
+++ linux-2.6.29.6/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c 2009-09-05 06:01:18.000000000 +0200
@@ -564,7 +564,7 @@ int pvr2_i2c_client_cmd(struct pvr2_i2c_
int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
{
struct pvr2_i2c_client *cp, *ncp;
- int stat = -EINVAL;
+ int stat = -EINVAL, success = 0;
if (!hdw) return stat;
@@ -573,10 +573,11 @@ int pvr2_i2c_core_cmd(struct pvr2_hdw *h
if (!cp->recv_enable) continue;
mutex_unlock(&hdw->i2c_list_lock);
stat = pvr2_i2c_client_cmd(cp,cmd,arg);
+ if(!stat) success++;
mutex_lock(&hdw->i2c_list_lock);
}
mutex_unlock(&hdw->i2c_list_lock);
- return stat;
+ return success ? 0 : stat;
}
--- linux-2.6.29.6/include/media/v4l2-subdev-d.h 2009-07-03 01:41:20.000000000 +0200
+++ linux-2.6.29.6/include/media/v4l2-subdev.h 2009-09-04 03:48:38.000000000 +0200
@@ -94,6 +94,7 @@ struct v4l2_subdev_tuner_ops {
int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm);
+ int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm);
int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type);
int (*s_config)(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *config);
};
@@ -113,6 +114,9 @@ struct v4l2_subdev_video_ops {
int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap);
int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
int (*s_stream)(struct v4l2_subdev *sd, int enable);
+ int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cap);
+ int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
+ int (*g_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
int (*g_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
};
More information about the pvrusb2
mailing list