int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame) { u32 data[CX2341X_MBOX_MAX_DATA]; if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { *pts = (s64)((u64)itv->last_dec_timing[2] << 32) | (u64)itv->last_dec_timing[1]; *frame = itv->last_dec_timing[0]; return 0; } *pts = 0; *frame = 0; if (atomic_read(&itv->decoding)) { if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); return -EIO; } memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); *pts = (s64)((u64) data[2] << 32) | (u64) data[1]; *frame = data[0]; /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ } return 0; }
void ivtv_init_mpeg_decoder(struct ivtv *itv) { u32 data[CX2341X_MBOX_MAX_DATA]; long readbytes; volatile u8 __iomem *mem_offset; data[0] = 0; data[1] = itv->cxhdl.width; /* YUV source width */ data[2] = itv->cxhdl.height; data[3] = itv->cxhdl.audio_properties; /* Audio settings to use, bitmap. see docs. */ if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) { IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n"); return; } if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) { IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n"); return; } ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data); mem_offset = itv->dec_mem + data[1]; if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME, mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) { IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n", IVTV_DECODE_INIT_MPEG_FILENAME); } else { ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0); ivtv_msleep_timeout(100, 0); } ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); }
int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...) { va_list ap; int i; va_start(ap, args); for (i = 0; i < args; i++) { data[i] = va_arg(ap, u32); } va_end(ap); return ivtv_api(itv, cmd, args, data); }
static void ivtv_vbi_setup(struct ivtv *itv) { int raw = ivtv_raw_vbi(itv); u32 data[CX2341X_MBOX_MAX_DATA]; int lines; int i; /* Reset VBI */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); /* setup VBI registers */ if (raw) v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi); else v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced); /* determine number of lines and total number of VBI bytes. A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 The '- 1' byte is probably an unused U or V byte. Or something... A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal header, 42 data bytes + checksum (to be confirmed) */ if (raw) { lines = itv->vbi.count * 2; } else { lines = itv->is_60hz ? 24 : 38; if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840)) lines += 2; } itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); /* Note: sliced vs raw flag doesn't seem to have any effect TODO: check mode (0x02) value with older ivtv versions. */ data[0] = raw | 0x02 | (0xbd << 8); /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ data[1] = 1; /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size); /* The start/stop codes determine which VBI lines end up in the raw VBI data area. The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) code. These values for raw VBI are obtained from a driver disassembly. The sliced start/stop codes was deduced from this, but they do not appear in the driver. Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54. However, I have no idea what these values are for. */ if (itv->hw_flags & IVTV_HW_CX25840) { /* Setup VBI for the cx25840 digitizer */ if (raw) { data[3] = 0x20602060; data[4] = 0x30703070; } else { data[3] = 0xB0F0B0F0; data[4] = 0xA0E0A0E0; } /* Lines per frame */ data[5] = lines; /* bytes per line */ data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); } else { /* Setup VBI for the saa7115 digitizer */ if (raw) { data[3] = 0x25256262; data[4] = 0x387F7F7F; } else { data[3] = 0xABABECEC; data[4] = 0xB6F1F1F1; } /* Lines per frame */ data[5] = lines; /* bytes per line */ data[6] = itv->vbi.enc_size / lines; } IVTV_DEBUG_INFO( "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n", data[0], data[1], data[2], data[5], data[6]); ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data); /* returns the VBI encoder memory area. */ itv->vbi.enc_start = data[2]; itv->vbi.fpi = data[0]; if (!itv->vbi.fpi) itv->vbi.fpi = 1; IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n", itv->vbi.enc_start, data[1], itv->vbi.fpi); /* select VBI lines. Note that the sliced argument seems to have no effect. */ for (i = 2; i <= 24; i++) { int valid; if (itv->is_60hz) { valid = i >= 10 && i < 22; } else { valid = i >= 6 && i < 24; } ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1, valid, 0 , 0, 0); ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000, valid, 0, 0, 0); } /* Remaining VBI questions: - Is it possible to select particular VBI lines only for inclusion in the MPEG stream? Currently you can only get the first X lines. - Is mixed raw and sliced VBI possible? - What's the meaning of the raw/sliced flag? - What's the meaning of params 2, 3 & 4 of the Select VBI command? */ }
static void ivtv_vbi_setup(struct ivtv *itv) { int raw = ivtv_raw_vbi(itv); u32 data[CX2341X_MBOX_MAX_DATA]; int lines; int i; /* */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); /* */ if (raw) v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi); else v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced); /* */ if (raw) { lines = itv->vbi.count * 2; } else { lines = itv->is_60hz ? 24 : 38; if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840)) lines += 2; } itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); /* */ data[0] = raw | 0x02 | (0xbd << 8); /* */ data[1] = 1; /* */ data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size); /* */ if (itv->hw_flags & IVTV_HW_CX25840) { /* */ if (raw) { data[3] = 0x20602060; data[4] = 0x30703070; } else { data[3] = 0xB0F0B0F0; data[4] = 0xA0E0A0E0; } /* */ data[5] = lines; /* */ data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); } else { /* */ if (raw) { data[3] = 0x25256262; data[4] = 0x387F7F7F; } else { data[3] = 0xABABECEC; data[4] = 0xB6F1F1F1; } /* */ data[5] = lines; /* */ data[6] = itv->vbi.enc_size / lines; } IVTV_DEBUG_INFO( "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n", data[0], data[1], data[2], data[5], data[6]); ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data); /* */ itv->vbi.enc_start = data[2]; itv->vbi.fpi = data[0]; if (!itv->vbi.fpi) itv->vbi.fpi = 1; IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n", itv->vbi.enc_start, data[1], itv->vbi.fpi); /* */ for (i = 2; i <= 24; i++) { int valid; if (itv->is_60hz) { valid = i >= 10 && i < 22; } else { valid = i >= 6 && i < 24; } ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1, valid, 0 , 0, 0); ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000, valid, 0, 0, 0); } /* */ }
int ivtv_set_speed(struct ivtv *itv, int speed) { u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; int single_step = (speed == 1 || speed == -1); DEFINE_WAIT(wait); if (speed == 0) speed = 1000; /* No change? */ if (speed == itv->speed && !single_step) return 0; s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; if (single_step && (speed < 0) == (itv->speed < 0)) { /* Single step video and no need to change direction */ ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); itv->speed = speed; return 0; } if (single_step) /* Need to change direction */ speed = speed < 0 ? -1000 : 1000; data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0; data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0; data[1] = (speed < 0); data[2] = speed < 0 ? 3 : 7; data[3] = itv->params.video_b_frames; data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0; data[5] = 0; data[6] = 0; if (speed == 1500 || speed == -1500) data[0] |= 1; else if (speed == 2000 || speed == -2000) data[0] |= 2; else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed); else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed); /* If not decoding, just change speed setting */ if (atomic_read(&itv->decoding) > 0) { int got_sig = 0; /* Stop all DMA and decoding activity */ ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); /* Wait for any DMA to finish */ prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); while (itv->i_flags & IVTV_F_I_DMA) { got_sig = signal_pending(current); if (got_sig) break; got_sig = 0; schedule(); } finish_wait(&itv->dma_waitq, &wait); if (got_sig) return -EINTR; /* Change Speed safely */ ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data); IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", data[0], data[1], data[2], data[3], data[4], data[5], data[6]); } if (single_step) { speed = (speed < 0) ? -1 : 1; ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); } itv->speed = speed; return 0; }
int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { return ivtv_api(priv, cmd, in, data); }