static int vpif_streamon(struct file *file, void *priv, enum v4l2_buf_type buftype) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; struct vpif_params *vpif = &ch->vpifparams; struct vpif_display_config *vpif_config_data = vpif_dev->platform_data; unsigned long addr = 0; int ret = 0; if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { vpif_err("buffer type not supported\n"); return -EINVAL; } if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { vpif_err("fh->io_allowed\n"); return -EACCES; } /* If Streaming is already started, return error */ if (common->started) { vpif_err("channel->started\n"); return -EBUSY; } if ((ch->channel_id == VPIF_CHANNEL2_VIDEO && oth_ch->common[VPIF_VIDEO_INDEX].started && ch->vpifparams.std_info.ycmux_mode == 0) || ((ch->channel_id == VPIF_CHANNEL3_VIDEO) && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { vpif_err("other channel is using\n"); return -EBUSY; } ret = vpif_check_format(ch, &common->fmt.fmt.pix); if (ret < 0) return ret; /* Call videobuf_streamon to start streaming in videobuf */ ret = videobuf_streamon(&common->buffer_queue); if (ret < 0) { vpif_err("videobuf_streamon\n"); return ret; } /* If buffer queue is empty, return error */ if (list_empty(&common->dma_queue)) { vpif_err("buffer queue is empty\n"); return -EIO; } /* Get the next frame from the buffer queue */ common->next_frm = common->cur_frm = list_entry(common->dma_queue.next, struct videobuf_buffer, queue); list_del(&common->cur_frm->queue); /* Mark state of the current frame to active */ common->cur_frm->state = VIDEOBUF_ACTIVE; /* Initialize field_id and started member */ ch->field_id = 0; common->started = 1; if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { addr = common->cur_frm->boff; /* Calculate the offset for Y and C data in the buffer */ vpif_calculate_offsets(ch); if ((ch->vpifparams.std_info.frm_fmt && ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || (!ch->vpifparams.std_info.frm_fmt && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { vpif_err("conflict in field format and std format\n"); return -EINVAL; } /* clock settings */ ret = vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, ch->vpifparams.std_info.hd_sd); if (ret < 0) { vpif_err("can't set clock\n"); return ret; } /* set the parameters and addresses */ ret = vpif_set_video_params(vpif, ch->channel_id + 2); if (ret < 0) return ret; common->started = ret; vpif_config_addr(ch, ret); common->set_addr((addr + common->ytop_off), (addr + common->ybtm_off), (addr + common->ctop_off), (addr + common->cbtm_off)); /* Set interrupt for both the fields in VPIF Register enable channel in VPIF register */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { channel2_intr_assert(); channel2_intr_enable(1); enable_channel2(1); } if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || (common->started == 2)) { channel3_intr_assert(); channel3_intr_enable(1); enable_channel3(1); } channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; } return ret; }
/** * vpif_streamon() - streamon handler * @file: file ptr * @priv: file handle * @buftype: v4l2 buffer type */ static int vpif_streamon(struct file *file, void *priv, enum v4l2_buf_type buftype) { struct vpif_capture_config *config = vpif_dev->platform_data; struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; struct vpif_params *vpif; unsigned long addr = 0; int ret = 0; vpif_dbg(2, debug, "vpif_streamon\n"); vpif = &ch->vpifparams; if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { vpif_dbg(1, debug, "buffer type not supported\n"); return -EINVAL; } /* If file handle is not allowed IO, return error */ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { vpif_dbg(1, debug, "io not allowed\n"); return -EACCES; } /* If Streaming is already started, return error */ if (common->started) { vpif_dbg(1, debug, "channel->started\n"); return -EBUSY; } if ((ch->channel_id == VPIF_CHANNEL0_VIDEO && oth_ch->common[VPIF_VIDEO_INDEX].started && vpif->std_info.ycmux_mode == 0) || ((ch->channel_id == VPIF_CHANNEL1_VIDEO) && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { vpif_dbg(1, debug, "other channel is being used\n"); return -EBUSY; } ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0); if (ret) return ret; /* Enable streamon on the sub device */ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, s_stream, 1); if (ret && (ret != -ENOIOCTLCMD)) { vpif_dbg(1, debug, "stream on failed in subdev\n"); return ret; } /* Call videobuf_streamon to start streaming in videobuf */ ret = videobuf_streamon(&common->buffer_queue); if (ret) { vpif_dbg(1, debug, "videobuf_streamon\n"); return ret; } if (mutex_lock_interruptible(&common->lock)) { ret = -ERESTARTSYS; goto streamoff_exit; } /* If buffer queue is empty, return error */ if (list_empty(&common->dma_queue)) { vpif_dbg(1, debug, "buffer queue is empty\n"); ret = -EIO; goto exit; } /* Get the next frame from the buffer queue */ common->cur_frm = list_entry(common->dma_queue.next, struct videobuf_buffer, queue); common->next_frm = common->cur_frm; /* Remove buffer from the buffer queue */ list_del(&common->cur_frm->queue); /* Mark state of the current frame to active */ common->cur_frm->state = VIDEOBUF_ACTIVE; /* Initialize field_id and started member */ ch->field_id = 0; common->started = 1; if (V4L2_MEMORY_USERPTR == common->memory) addr = common->cur_frm->boff; else addr = videobuf_to_dma_contig(common->cur_frm); /* Calculate the offset for Y and C data in the buffer */ vpif_calculate_offsets(ch); if ((vpif->std_info.frm_fmt && ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || (!vpif->std_info.frm_fmt && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { vpif_dbg(1, debug, "conflict in field format and std format\n"); ret = -EINVAL; goto exit; } /* configure 1 or 2 channel mode */ ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); if (ret < 0) { vpif_dbg(1, debug, "can't set vpif channel mode\n"); goto exit; } /* Call vpif_set_params function to set the parameters and addresses */ ret = vpif_set_video_params(vpif, ch->channel_id); if (ret < 0) { vpif_dbg(1, debug, "can't set video params\n"); goto exit; } common->started = ret; vpif_config_addr(ch, ret); common->set_addr(addr + common->ytop_off, addr + common->ybtm_off, addr + common->ctop_off, addr + common->cbtm_off); /** * Set interrupt for both the fields in VPIF Register enable channel in * VPIF register */ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { channel0_intr_assert(); channel0_intr_enable(1); enable_channel0(1); } if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || (common->started == 2)) { channel1_intr_assert(); channel1_intr_enable(1); enable_channel1(1); } channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; mutex_unlock(&common->lock); return ret; exit: mutex_unlock(&common->lock); streamoff_exit: ret = videobuf_streamoff(&common->buffer_queue); return ret; }
static int vpif_streamon(struct file *file, void *priv, enum v4l2_buf_type buftype) { struct vpif_capture_config *config = vpif_dev->platform_data; struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; struct vpif_params *vpif; unsigned long addr = 0; int ret = 0; vpif_dbg(2, debug, "vpif_streamon\n"); vpif = &ch->vpifparams; if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { vpif_dbg(1, debug, "buffer type not supported\n"); return -EINVAL; } if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { vpif_dbg(1, debug, "io not allowed\n"); return -EACCES; } if (common->started) { vpif_dbg(1, debug, "channel->started\n"); return -EBUSY; } if ((ch->channel_id == VPIF_CHANNEL0_VIDEO && oth_ch->common[VPIF_VIDEO_INDEX].started && vpif->std_info.ycmux_mode == 0) || ((ch->channel_id == VPIF_CHANNEL1_VIDEO) && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { vpif_dbg(1, debug, "other channel is being used\n"); return -EBUSY; } ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0); if (ret) return ret; ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, s_stream, 1); if (ret && (ret != -ENOIOCTLCMD)) { vpif_dbg(1, debug, "stream on failed in subdev\n"); return ret; } ret = videobuf_streamon(&common->buffer_queue); if (ret) { vpif_dbg(1, debug, "videobuf_streamon\n"); return ret; } if (list_empty(&common->dma_queue)) { vpif_dbg(1, debug, "buffer queue is empty\n"); ret = -EIO; goto exit; } common->cur_frm = list_entry(common->dma_queue.next, struct videobuf_buffer, queue); common->next_frm = common->cur_frm; list_del(&common->cur_frm->queue); common->cur_frm->state = VIDEOBUF_ACTIVE; ch->field_id = 0; common->started = 1; if (V4L2_MEMORY_USERPTR == common->memory) addr = common->cur_frm->boff; else addr = videobuf_to_dma_contig(common->cur_frm); vpif_calculate_offsets(ch); if ((vpif->std_info.frm_fmt && ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || (!vpif->std_info.frm_fmt && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { vpif_dbg(1, debug, "conflict in field format and std format\n"); ret = -EINVAL; goto exit; } ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); if (ret < 0) { vpif_dbg(1, debug, "can't set vpif channel mode\n"); goto exit; } ret = vpif_set_video_params(vpif, ch->channel_id); if (ret < 0) { vpif_dbg(1, debug, "can't set video params\n"); goto exit; } common->started = ret; vpif_config_addr(ch, ret); common->set_addr(addr + common->ytop_off, addr + common->ybtm_off, addr + common->ctop_off, addr + common->cbtm_off); if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { channel0_intr_assert(); channel0_intr_enable(1); enable_channel0(1); } if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || (common->started == 2)) { channel1_intr_assert(); channel1_intr_enable(1); enable_channel1(1); } channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; return ret; exit: videobuf_streamoff(&common->buffer_queue); return ret; }