int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) { struct cx18 *cx = s->cx; if (!cx18_stream_enabled(s)) return -EINVAL; /* This function assumes that you are allowed to stop the capture and that we are actually capturing */ CX18_DEBUG_INFO("Stop Capture\n"); if (atomic_read(&cx->tot_capturing) == 0) return 0; set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); else cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); } if (s->type != CX18_ENC_STREAM_TYPE_TS) atomic_dec(&cx->ana_capturing); atomic_dec(&cx->tot_capturing); /* Clear capture and no-read bits */ clear_bit(CX18_F_S_STREAMING, &s->s_flags); /* Tell the CX23418 it can't use our buffers anymore */ cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) > 0) return 0; cx2341x_handler_set_busy(&cx->cxhdl, 0); cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); wake_up(&s->waitq); return 0; }
struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle) { int i; struct cx18_stream *s; if (handle == CX18_INVALID_TASK_HANDLE) return NULL; for (i = 0; i < CX18_MAX_STREAMS; i++) { s = &cx->streams[i]; if (s->handle != handle) continue; if (cx18_stream_enabled(s)) return s; } return NULL; }
void cx18_stream_rotate_idx_mdls(struct cx18 *cx) { struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; struct cx18_mdl *mdl; if (!cx18_stream_enabled(s)) return; if ((atomic_read(&s->q_free.depth) + atomic_read(&s->q_busy.depth)) >= CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN) return; if (atomic_read(&s->q_full.depth) < 2) return; mdl = cx18_dequeue(s, &s->q_full); if (mdl != NULL) cx18_enqueue(s, mdl, &s->q_free); }
int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; struct cx18 *cx = s->cx; int captype = 0; struct cx18_stream *s_idx; if (!cx18_stream_enabled(s)) return -EINVAL; CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { case CX18_ENC_STREAM_TYPE_MPG: captype = CAPTURE_CHANNEL_TYPE_MPEG; cx->mpg_data_received = cx->vbi_data_inserted = 0; cx->dualwatch_jiffies = jiffies; cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); cx->search_pack_header = 0; break; case CX18_ENC_STREAM_TYPE_IDX: captype = CAPTURE_CHANNEL_TYPE_INDEX; break; case CX18_ENC_STREAM_TYPE_TS: captype = CAPTURE_CHANNEL_TYPE_TS; break; case CX18_ENC_STREAM_TYPE_YUV: captype = CAPTURE_CHANNEL_TYPE_YUV; break; case CX18_ENC_STREAM_TYPE_PCM: captype = CAPTURE_CHANNEL_TYPE_PCM; break; case CX18_ENC_STREAM_TYPE_VBI: #ifdef CX18_ENCODER_PARSES_SLICED captype = cx18_raw_vbi(cx) ? CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; #else /* * Currently we set things up so that Sliced VBI from the * digitizer is handled as Raw VBI by the encoder */ captype = CAPTURE_CHANNEL_TYPE_VBI; #endif cx->vbi.frame = 0; cx->vbi.inserted_frame = 0; memset(cx->vbi.sliced_mpeg_size, 0, sizeof(cx->vbi.sliced_mpeg_size)); break; default: return -EINVAL; } /* Clear Streamoff flags in case left from last capture */ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); s->handle = data[0]; cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); /* * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and * set up all the parameters, as it is not obvious which parameters the * firmware shares across capture channel types and which it does not. * * Some of the cx18_vapi() calls below apply to only certain capture * channel types. We're hoping there's no harm in calling most of them * anyway, as long as the values are all consistent. Setting some * shared parameters will have no effect once an analog capture channel * has started streaming. */ if (captype != CAPTURE_CHANNEL_TYPE_TS) { cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); /* * Audio related reset according to * Documentation/video4linux/cx2341x/fw-encoder-api.txt */ if (atomic_read(&cx->ana_capturing) == 0) cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12); /* * Number of lines for Field 1 & Field 2 according to * Documentation/video4linux/cx2341x/fw-encoder-api.txt * Field 1 is 312 for 625 line systems in BT.656 * Field 2 is 313 for 625 line systems in BT.656 */ cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, s->handle, 312, 313); if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) cx18_vbi_setup(s); /* * Select to receive I, P, and B frame index entries, if the * index stream is enabled. Otherwise disable index entry * generation. */ s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2, s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); /* Call out to the common CX2341x API setup for user controls */ cx->cxhdl.priv = s; cx2341x_handler_setup(&cx->cxhdl); /* * When starting a capture and we're set for radio, * ensure the video is muted, despite the user control. */ if (!cx->cxhdl.video_mute && test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); /* Enable the Video Format Converter for UYVY 4:2:2 support, * rather than the default HM12 Macroblovk 4:2:0 support. */ if (captype == CAPTURE_CHANNEL_TYPE_YUV) { if (s->pixelformat == V4L2_PIX_FMT_UYVY) cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, s->handle, 1); else /* If in doubt, default to HM12 */ cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, s->handle, 0); } } if (atomic_read(&cx->tot_capturing) == 0) { cx2341x_handler_set_busy(&cx->cxhdl, 1); clear_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); } cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); /* Init all the cpu_mdls for this stream */ cx18_stream_configure_mdls(s); _cx18_stream_load_fw_queue(s); /* begin_capture */ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { CX18_DEBUG_WARN("Error starting capture!\n"); /* Ensure we're really not capturing before releasing MDLs */ set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); else cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); clear_bit(CX18_F_S_STREAMING, &s->s_flags); /* FIXME - CX18_F_S_STREAMOFF as well? */ cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) == 0) { set_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); } return -EINVAL; } /* you're live! sit back and await interrupts :) */ if (captype != CAPTURE_CHANNEL_TYPE_TS) atomic_inc(&cx->ana_capturing); atomic_inc(&cx->tot_capturing); return 0; }
int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; struct cx18 *cx = s->cx; int captype = 0; struct cx18_stream *s_idx; if (!cx18_stream_enabled(s)) return -EINVAL; CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { case CX18_ENC_STREAM_TYPE_MPG: captype = CAPTURE_CHANNEL_TYPE_MPEG; cx->mpg_data_received = cx->vbi_data_inserted = 0; cx->dualwatch_jiffies = jiffies; cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); cx->search_pack_header = 0; break; case CX18_ENC_STREAM_TYPE_IDX: captype = CAPTURE_CHANNEL_TYPE_INDEX; break; case CX18_ENC_STREAM_TYPE_TS: captype = CAPTURE_CHANNEL_TYPE_TS; break; case CX18_ENC_STREAM_TYPE_YUV: captype = CAPTURE_CHANNEL_TYPE_YUV; break; case CX18_ENC_STREAM_TYPE_PCM: captype = CAPTURE_CHANNEL_TYPE_PCM; break; case CX18_ENC_STREAM_TYPE_VBI: #ifdef CX18_ENCODER_PARSES_SLICED captype = cx18_raw_vbi(cx) ? CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; #else captype = CAPTURE_CHANNEL_TYPE_VBI; #endif cx->vbi.frame = 0; cx->vbi.inserted_frame = 0; memset(cx->vbi.sliced_mpeg_size, 0, sizeof(cx->vbi.sliced_mpeg_size)); break; default: return -EINVAL; } clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); s->handle = data[0]; cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); if (captype != CAPTURE_CHANNEL_TYPE_TS) { cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); if (atomic_read(&cx->ana_capturing) == 0) cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12); cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, s->handle, 312, 313); if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) cx18_vbi_setup(s); s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2, s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); cx->cxhdl.priv = s; cx2341x_handler_setup(&cx->cxhdl); if (!cx->cxhdl.video_mute && test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); if (captype == CAPTURE_CHANNEL_TYPE_YUV) { if (s->pixelformat == V4L2_PIX_FMT_UYVY) cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, s->handle, 1); else cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, s->handle, 0); } } if (atomic_read(&cx->tot_capturing) == 0) { cx2341x_handler_set_busy(&cx->cxhdl, 1); clear_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); } cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); cx18_stream_configure_mdls(s); _cx18_stream_load_fw_queue(s); if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { CX18_DEBUG_WARN("Error starting capture!\n"); set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); else cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); clear_bit(CX18_F_S_STREAMING, &s->s_flags); cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) == 0) { set_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); } return -EINVAL; } if (captype != CAPTURE_CHANNEL_TYPE_TS) atomic_inc(&cx->ana_capturing); atomic_inc(&cx->tot_capturing); return 0; }
int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) { struct cx18 *cx = s->cx; unsigned long then; if (!cx18_stream_enabled(s)) return -EINVAL; /* This function assumes that you are allowed to stop the capture and that we are actually capturing */ CX18_DEBUG_INFO("Stop Capture\n"); if (atomic_read(&cx->tot_capturing) == 0) return 0; set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); else cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); then = jiffies; if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { #if 0 /* only run these if we're shutting down the last cap */ DECLARE_WAITQUEUE(wait, current); unsigned long duration; then = jiffies; add_wait_queue(&cx->cap_w, &wait); set_current_state(TASK_INTERRUPTIBLE); /* TODO: wait 2s for EOS interrupt */ while (!test_bit(CX18_F_I_EOS, &cx->i_flags) && time_before(jiffies, then + msecs_to_jiffies(2000))) schedule_timeout(msecs_to_jiffies(10)); duration = jiffies_to_msecs(jiffies - then); if (!test_bit(CX18_F_I_EOS, &cx->i_flags)) { CX18_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name); CX18_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration); } else { CX18_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); } set_current_state(TASK_RUNNING); remove_wait_queue(&cx->cap_w, &wait); #else CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); #endif } if (s->type != CX18_ENC_STREAM_TYPE_TS) atomic_dec(&cx->ana_capturing); atomic_dec(&cx->tot_capturing); /* Clear capture and no-read bits */ clear_bit(CX18_F_S_STREAMING, &s->s_flags); /* Tell the CX23418 it can't use our buffers anymore */ cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) > 0) return 0; cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); wake_up(&s->waitq); return 0; }