static int vpif_release(struct file *filep) { struct vpif_fh *fh = filep->private_data; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; if (mutex_lock_interruptible(&common->lock)) return -ERESTARTSYS; /* if this instance is doing IO */ if (fh->io_allowed[VPIF_VIDEO_INDEX]) { /* Reset io_usrs member of channel object */ common->io_usrs = 0; /* Disable channel */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { enable_channel2(0); channel2_intr_enable(0); } if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || (2 == common->started)) { enable_channel3(0); channel3_intr_enable(0); } common->started = 0; /* Free buffers allocated */ videobuf_queue_cancel(&common->buffer_queue); videobuf_mmap_free(&common->buffer_queue); common->numbuffers = config_params.numbuffers[ch->channel_id]; } mutex_unlock(&common->lock); /* Decrement channel usrs counter */ atomic_dec(&ch->usrs); /* If this file handle has initialize encoder device, reset it */ if (fh->initialized) ch->initialized = 0; /* Close the priority */ v4l2_prio_close(&ch->prio, fh->prio); filep->private_data = NULL; fh->initialized = 0; kfree(fh); return 0; }
static int vpif_streamoff(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]; 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 (!common->started) { vpif_err("channel->started\n"); return -EINVAL; } if (mutex_lock_interruptible(&common->lock)) return -ERESTARTSYS; if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* disable channel */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { enable_channel2(0); channel2_intr_enable(0); } if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || (2 == common->started)) { enable_channel3(0); channel3_intr_enable(0); } } common->started = 0; mutex_unlock(&common->lock); return videobuf_streamoff(&common->buffer_queue); }
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; }