[media] ivtv: Internally separate encoder & decoder standard setting

Internally separates the setting of the broadcast standard for the encoder &
decoder. Externally there's no change in functionality.

[awalls@md.metrocast.net: Edited to fix a checkpatch gripe about multiple
assignment and to remove a now unused DEFINE_WAIT() due to this patch]

Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk>
Signed-off-by: Andy Walls <awalls@md.metrocast.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Ian Armstrong 2011-05-29 21:33:17 -03:00 committed by Mauro Carvalho Chehab
parent 6600cc301d
commit c5874c9245
6 changed files with 97 additions and 80 deletions

View File

@ -1328,6 +1328,8 @@ int ivtv_init_on_first_open(struct ivtv *itv)
if (!itv->has_cx23415)
write_reg_sync(0x03, IVTV_REG_DMACONTROL);
ivtv_s_std_enc(itv, &itv->tuner_std);
/* Default interrupts enabled. For the PVR350 this includes the
decoder VSYNC interrupt, which is always on. It is not only used
during decoding but also by the OSD.
@ -1336,12 +1338,10 @@ int ivtv_init_on_first_open(struct ivtv *itv)
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
ivtv_set_osd_alpha(itv);
}
else
ivtv_s_std_dec(itv, &itv->tuner_std);
} else {
ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
/* For cards with video out, this call needs interrupts enabled */
ivtv_s_std(NULL, &fh, &itv->tuner_std);
}
/* Setup initial controls */
cx2341x_handler_setup(&itv->cxhdl);

View File

@ -280,8 +280,6 @@ int ivtv_firmware_restart(struct ivtv *itv)
{
int rc = 0;
v4l2_std_id std;
struct ivtv_open_id fh;
fh.itv = itv;
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
/* Display test image during restart */
@ -301,14 +299,19 @@ int ivtv_firmware_restart(struct ivtv *itv)
/* Allow settings to reload */
ivtv_mailbox_cache_invalidate(itv);
/* Restore video standard */
/* Restore encoder video standard */
std = itv->std;
itv->std = 0;
ivtv_s_std(NULL, &fh, &std);
ivtv_s_std_enc(itv, &std);
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
ivtv_init_mpeg_decoder(itv);
/* Restore decoder video standard */
std = itv->std_out;
itv->std_out = 0;
ivtv_s_std_dec(itv, &std);
/* Restore framebuffer if active */
if (itv->ivtvfb_restore)
itv->ivtvfb_restore(itv);

View File

@ -1071,28 +1071,8 @@ static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
return 0;
}
int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std)
{
DEFINE_WAIT(wait);
struct ivtv *itv = fh2id(fh)->itv;
struct yuv_playback_info *yi = &itv->yuv_info;
int f;
if ((*std & V4L2_STD_ALL) == 0)
return -EINVAL;
if (*std == itv->std)
return 0;
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
atomic_read(&itv->capturing) > 0 ||
atomic_read(&itv->decoding) > 0) {
/* Switching standard would turn off the radio or mess
with already running streams, prevent that by
returning EBUSY. */
return -EBUSY;
}
itv->std = *std;
itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
itv->is_50hz = !itv->is_60hz;
@ -1106,48 +1086,79 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
if (itv->hw_flags & IVTV_HW_CX25840)
itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
/* Tuner */
ivtv_call_all(itv, core, s_std, itv->std);
}
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
/* set display standard */
itv->std_out = *std;
itv->is_out_60hz = itv->is_60hz;
itv->is_out_50hz = itv->is_50hz;
ivtv_call_all(itv, video, s_std_output, itv->std_out);
void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
{
struct yuv_playback_info *yi = &itv->yuv_info;
DEFINE_WAIT(wait);
int f;
/*
* The next firmware call is time sensitive. Time it to
* avoid risk of a hard lock, by trying to ensure the call
* happens within the first 100 lines of the top field.
* Make 4 attempts to sync to the decoder before giving up.
*/
for (f = 0; f < 4; f++) {
prepare_to_wait(&itv->vsync_waitq, &wait,
TASK_UNINTERRUPTIBLE);
if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100)
break;
schedule_timeout(msecs_to_jiffies(25));
}
finish_wait(&itv->vsync_waitq, &wait);
/* set display standard */
itv->std_out = *std;
itv->is_out_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
itv->is_out_50hz = !itv->is_out_60hz;
ivtv_call_all(itv, video, s_std_output, itv->std_out);
if (f == 4)
IVTV_WARN("Mode change failed to sync to decoder\n");
ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
itv->main_rect.left = itv->main_rect.top = 0;
itv->main_rect.width = 720;
itv->main_rect.height = itv->cxhdl.height;
ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
720, itv->main_rect.height, 0, 0);
yi->main_rect = itv->main_rect;
if (!itv->osd_info) {
yi->osd_full_w = 720;
yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
}
/*
* The next firmware call is time sensitive. Time it to
* avoid risk of a hard lock, by trying to ensure the call
* happens within the first 100 lines of the top field.
* Make 4 attempts to sync to the decoder before giving up.
*/
for (f = 0; f < 4; f++) {
prepare_to_wait(&itv->vsync_waitq, &wait,
TASK_UNINTERRUPTIBLE);
if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100)
break;
schedule_timeout(msecs_to_jiffies(25));
}
finish_wait(&itv->vsync_waitq, &wait);
if (f == 4)
IVTV_WARN("Mode change failed to sync to decoder\n");
ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
itv->main_rect.left = 0;
itv->main_rect.top = 0;
itv->main_rect.width = 720;
itv->main_rect.height = itv->is_out_50hz ? 576 : 480;
ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
720, itv->main_rect.height, 0, 0);
yi->main_rect = itv->main_rect;
if (!itv->osd_info) {
yi->osd_full_w = 720;
yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
}
}
int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
{
struct ivtv *itv = fh2id(fh)->itv;
if ((*std & V4L2_STD_ALL) == 0)
return -EINVAL;
if (*std == itv->std)
return 0;
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
atomic_read(&itv->capturing) > 0 ||
atomic_read(&itv->decoding) > 0) {
/* Switching standard would mess with already running
streams, prevent that by returning EBUSY. */
return -EBUSY;
}
IVTV_DEBUG_INFO("Switching standard to %llx.\n",
(unsigned long long)itv->std);
ivtv_s_std_enc(itv, std);
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
ivtv_s_std_dec(itv, std);
return 0;
}

View File

@ -27,7 +27,8 @@ u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
void ivtv_set_osd_alpha(struct ivtv *itv);
int ivtv_set_speed(struct ivtv *itv, int speed);
void ivtv_set_funcs(struct video_device *vdev);
int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std);
void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std);
void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std);
int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);

View File

@ -71,7 +71,7 @@ static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
Turning this signal on and off can confuse certain
TVs. As far as I can tell there is no reason not to
transmit this signal. */
if ((itv->std & V4L2_STD_625_50) && !enabled) {
if ((itv->std_out & V4L2_STD_625_50) && !enabled) {
enabled = 1;
mode = 0x08; /* 4x3 full format */
}

View File

@ -247,7 +247,7 @@ static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords
static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
{
int osd_height_limit = itv->is_50hz ? 576 : 480;
int osd_height_limit = itv->is_out_50hz ? 576 : 480;
/* Only fail if resolution too high, otherwise fudge the start coords. */
if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
@ -471,9 +471,9 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
FB_VBLANK_HAVE_VSYNC;
trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
if (itv->is_50hz && trace > 312)
if (itv->is_out_50hz && trace > 312)
trace -= 312;
else if (itv->is_60hz && trace > 262)
else if (itv->is_out_60hz && trace > 262)
trace -= 262;
if (trace == 1)
vblank.flags |= FB_VBLANK_VSYNCING;
@ -656,7 +656,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
/* Set base references for mode calcs. */
if (itv->is_50hz) {
if (itv->is_out_50hz) {
pixclock = 84316;
hlimit = 776;
vlimit = 591;
@ -784,12 +784,12 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
If the margins are too large, just center the screen
(enforcing margins causes too many problems) */
if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1)
var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
}
if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
}
if (var->upper_margin + var->yres > (itv->is_out_50hz ? 577 : 481))
var->upper_margin = 1 + (((itv->is_out_50hz ? 576 : 480) -
var->yres) / 2);
/* Maintain overall 'size' for a constant refresh rate */
var->right_margin = hlimit - var->left_margin - var->xres;
@ -1008,19 +1008,21 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
/* Hardware coords start at 0, user coords start at 1. */
osd_left--;
start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
start_window.left = osd_left >= 0 ?
osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
oi->display_byte_stride =
start_window.width * oi->bytes_per_pixel;
/* Vertical size & position */
max_height = itv->is_50hz ? 576 : 480;
max_height = itv->is_out_50hz ? 576 : 480;
if (osd_yres > max_height)
osd_yres = max_height;
start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400;
start_window.height = osd_yres ?
osd_yres : itv->is_out_50hz ? 480 : 400;
/* Check vertical start (osd_upper). */
if (osd_upper + start_window.height > max_height + 1) {