예제 #1
0
static int fimc_cap_s_input(struct file *file, void *priv,
				  unsigned int i)
{
	struct fimc_ctx *ctx = priv;
	struct fimc_dev *fimc = ctx->fimc_dev;
	struct s3c_platform_fimc *pdata = fimc->pdata;
	int ret;

	if (fimc_capture_active(ctx->fimc_dev))
		return -EBUSY;

	if (mutex_lock_interruptible(&fimc->lock))
		return -ERESTARTSYS;

	if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) {
		ret = -EINVAL;
		goto si_unlock;
	}

	if (fimc->vid_cap.sd) {
		ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
		if (ret)
			err("s_power failed: %d", ret);
	}

	/* Release the attached sensor subdevice. */
	fimc_subdev_unregister(fimc);

	ret = fimc_isp_subdev_init(fimc, i);

si_unlock:
	mutex_unlock(&fimc->lock);
	return ret;
}
예제 #2
0
static int fimc_cap_s_ctrl(struct file *file, void *priv,
			 struct v4l2_control *ctrl)
{
	struct fimc_ctx *ctx = priv;
	int ret = -EINVAL;

	if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
		return -ERESTARTSYS;

	/* Allow any controls but 90/270 rotation while streaming */
	if (!fimc_capture_active(ctx->fimc_dev) ||
	    ctrl->id != V4L2_CID_ROTATE ||
	    (ctrl->value != 90 && ctrl->value != 270)) {
		ret = check_ctrl_val(ctx, ctrl);
		if (!ret) {
			ret = fimc_s_ctrl(ctx, ctrl);
			if (!ret)
				ctx->state |= FIMC_PARAMS;
		}
	}
	if (ret == -EINVAL)
		ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
				       core, s_ctrl, ctrl);

	mutex_unlock(&ctx->fimc_dev->lock);
	return ret;
}
예제 #3
0
static int fimc_cap_s_input(struct file *file, void *priv,
                            unsigned int i)
{
    struct fimc_ctx *ctx = priv;
    struct fimc_dev *fimc = ctx->fimc_dev;
    struct s5p_platform_fimc *pdata = fimc->pdata;

    if (fimc_capture_active(ctx->fimc_dev))
        return -EBUSY;

    if (i >= pdata->num_clients)
        return -EINVAL;


    if (fimc->vid_cap.sd) {
        int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
        if (ret)
            err("s_power failed: %d", ret);

        clk_disable(fimc->clock[CLK_CAM]);
    }

    /* Release the attached sensor subdevice. */
    fimc_subdev_unregister(fimc);

    return fimc_isp_subdev_init(fimc, i);
}
예제 #4
0
static int fimc_stop_capture(struct fimc_dev *fimc)
{
	unsigned long flags;
	struct fimc_vid_cap *cap;
	int ret;

	cap = &fimc->vid_cap;

	if (!fimc_capture_active(fimc))
		return 0;

	spin_lock_irqsave(&fimc->slock, flags);
	set_bit(ST_CAPT_SHUT, &fimc->state);
	fimc_deactivate_capture(fimc);
	spin_unlock_irqrestore(&fimc->slock, flags);

	wait_event_timeout(fimc->irq_queue,
			   test_bit(ST_CAPT_SHUT, &fimc->state),
			   FIMC_SHUTDOWN_TIMEOUT);

	ret = v4l2_subdev_call(cap->sd, video, s_stream, 0);
	if (ret)
		v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n");

	spin_lock_irqsave(&fimc->slock, flags);
	fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
			1 << ST_CAPT_STREAM);

	fimc->vid_cap.active_buf_cnt = 0;
	spin_unlock_irqrestore(&fimc->slock, flags);

	dbg("state: 0x%lx", fimc->state);
	return 0;
}
예제 #5
0
static int stop_streaming(struct vb2_queue *q)
{
	struct fimc_ctx *ctx = q->drv_priv;
	struct fimc_dev *fimc = ctx->fimc_dev;

	if (!fimc_capture_active(fimc))
		return -EINVAL;

	return fimc_stop_capture(fimc, false);
}
예제 #6
0
static int fimc_cap_querybuf(struct file *file, void *priv,
			   struct v4l2_buffer *buf)
{
	struct fimc_ctx *ctx = priv;
	struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;

	if (fimc_capture_active(ctx->fimc_dev))
		return -EBUSY;

	return videobuf_querybuf(&cap->vbq, buf);
}
예제 #7
0
static int fimc_cap_s_fmt(struct file *file, void *priv,
			     struct v4l2_format *f)
{
	struct fimc_ctx *ctx = priv;
	struct fimc_dev *fimc = ctx->fimc_dev;
	struct fimc_frame *frame;
	struct v4l2_pix_format *pix;
	int ret;

	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	ret = fimc_vidioc_try_fmt(file, priv, f);
	if (ret)
		return ret;

	if (mutex_lock_interruptible(&fimc->lock))
		return -ERESTARTSYS;

	if (fimc_capture_active(fimc)) {
		ret = -EBUSY;
		goto sf_unlock;
	}

	frame = &ctx->d_frame;

	pix = &f->fmt.pix;
	frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
	if (!frame->fmt) {
		err("fimc target format not found\n");
		ret = -EINVAL;
		goto sf_unlock;
	}

	/* Output DMA frame pixel size and offsets. */
	frame->f_width	= pix->bytesperline * 8 / frame->fmt->depth;
	frame->f_height = pix->height;
	frame->width	= pix->width;
	frame->height	= pix->height;
	frame->o_width	= pix->width;
	frame->o_height = pix->height;
	frame->size	= (pix->width * pix->height * frame->fmt->depth) >> 3;
	frame->offs_h	= 0;
	frame->offs_v	= 0;

	ret = sync_capture_fmt(ctx);

	ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);

sf_unlock:
	mutex_unlock(&fimc->lock);
	return ret;
}
예제 #8
0
static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
                                 struct v4l2_format *f)
{
    struct fimc_ctx *ctx = priv;
    struct fimc_dev *fimc = ctx->fimc_dev;
    struct fimc_frame *frame;
    struct v4l2_pix_format_mplane *pix;
    int ret;
    int i;

    if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
        return -EINVAL;

    ret = fimc_vidioc_try_fmt_mplane(file, priv, f);
    if (ret)
        return ret;

    if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
        return -EBUSY;

    frame = &ctx->d_frame;

    pix = &f->fmt.pix_mp;
    frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
    if (!frame->fmt) {
        err("fimc target format not found\n");
        return -EINVAL;
    }

    for (i = 0; i < frame->fmt->colplanes; i++) {
        frame->payload[i] =
            (pix->width * pix->height * frame->fmt->depth[i]) >> 3;
    }

    /* Output DMA frame pixel size and offsets. */
    frame->f_width = pix->plane_fmt[0].bytesperline * 8
                     / frame->fmt->depth[0];
    frame->f_height = pix->height;
    frame->width	= pix->width;
    frame->height	= pix->height;
    frame->o_width	= pix->width;
    frame->o_height = pix->height;
    frame->offs_h	= 0;
    frame->offs_v	= 0;

    ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);

    ret = sync_capture_fmt(ctx);
    return ret;
}
예제 #9
0
static int fimc_cap_streamon(struct file *file, void *priv,
                             enum v4l2_buf_type type)
{
    struct fimc_ctx *ctx = priv;
    struct fimc_dev *fimc = ctx->fimc_dev;

    if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
        return -EBUSY;

    if (!(ctx->state & FIMC_DST_FMT)) {
        v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
        return -EINVAL;
    }

    return vb2_streamon(&fimc->vid_cap.vbq, type);
}
예제 #10
0
static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend)
{
	unsigned long flags;

	if (!fimc_capture_active(fimc))
		return 0;

	spin_lock_irqsave(&fimc->slock, flags);
	set_bit(ST_CAPT_SHUT, &fimc->state);
	fimc_deactivate_capture(fimc);
	spin_unlock_irqrestore(&fimc->slock, flags);

	wait_event_timeout(fimc->irq_queue,
			   !test_bit(ST_CAPT_SHUT, &fimc->state),
			   (2*HZ/10)); /* 200 ms */

	return fimc_capture_state_cleanup(fimc, suspend);
}
예제 #11
0
static int fimc_stop_capture(struct fimc_dev *fimc)
{
    unsigned long flags;
    struct fimc_vid_cap *cap;
    struct fimc_vid_buffer *buf;

    cap = &fimc->vid_cap;

    if (!fimc_capture_active(fimc))
        return 0;

    spin_lock_irqsave(&fimc->slock, flags);
    set_bit(ST_CAPT_SHUT, &fimc->state);
    fimc_deactivate_capture(fimc);
    spin_unlock_irqrestore(&fimc->slock, flags);

    wait_event_timeout(fimc->irq_queue,
                       !test_bit(ST_CAPT_SHUT, &fimc->state),
                       FIMC_SHUTDOWN_TIMEOUT);

    v4l2_subdev_call(cap->sd, video, s_stream, 0);

    spin_lock_irqsave(&fimc->slock, flags);
    fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
                     1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM);

    fimc->vid_cap.active_buf_cnt = 0;

    /* Release buffers that were enqueued in the driver by videobuf2. */
    while (!list_empty(&cap->pending_buf_q)) {
        buf = pending_queue_pop(cap);
        vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
    }

    while (!list_empty(&cap->active_buf_q)) {
        buf = active_queue_pop(cap);
        vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
    }

    spin_unlock_irqrestore(&fimc->slock, flags);

    dbg("state: 0x%lx", fimc->state);
    return 0;
}
예제 #12
0
static int fimc_cap_streamon(struct file *file, void *priv,
			     enum v4l2_buf_type type)
{
	struct fimc_dev *fimc = video_drvdata(file);
	struct fimc_pipeline *p = &fimc->pipeline;
	int ret;

	if (fimc_capture_active(fimc))
		return -EBUSY;

	media_entity_pipeline_start(&p->sensor->entity, p->pipe);

	if (fimc->vid_cap.user_subdev_api) {
		ret = fimc_pipeline_validate(fimc);
		if (ret)
			return ret;
	}
	return vb2_streamon(&fimc->vid_cap.vbq, type);
}
예제 #13
0
static int fimc_cap_s_crop(struct file *file, void *fh,
			       struct v4l2_crop *cr)
{
	struct fimc_frame *f;
	struct fimc_ctx *ctx = file->private_data;
	struct fimc_dev *fimc = ctx->fimc_dev;
	int ret = -EINVAL;

	if (fimc_capture_active(fimc))
		return -EBUSY;

	ret = fimc_try_crop(ctx, cr);
	if (ret)
		return ret;

	if (mutex_lock_interruptible(&fimc->lock))
		return -ERESTARTSYS;

	if (!(ctx->state & FIMC_DST_FMT)) {
		v4l2_err(&fimc->vid_cap.v4l2_dev,
			 "Capture color format not set\n");
		goto sc_unlock;
	}

	f = &ctx->s_frame;
	/* Check for the pixel scaling ratio when cropping input image. */
	ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
	if (ret) {
		v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
	} else {
		ret = 0;
		f->offs_h = cr->c.left;
		f->offs_v = cr->c.top;
		f->width  = cr->c.width;
		f->height = cr->c.height;
	}

sc_unlock:
	mutex_unlock(&fimc->lock);
	return ret;
}
예제 #14
0
static int fimc_cap_reqbufs(struct file *file, void *priv,
			  struct v4l2_requestbuffers *reqbufs)
{
	struct fimc_ctx *ctx = priv;
	struct fimc_dev *fimc = ctx->fimc_dev;
	struct fimc_vid_cap *cap = &fimc->vid_cap;
	int ret;

	if (fimc_capture_active(ctx->fimc_dev))
		return -EBUSY;

	if (mutex_lock_interruptible(&fimc->lock))
		return -ERESTARTSYS;

	ret = videobuf_reqbufs(&cap->vbq, reqbufs);
	if (!ret)
		cap->reqbufs_count = reqbufs->count;

	mutex_unlock(&fimc->lock);
	return ret;
}
예제 #15
0
static int fimc_cap_s_crop(struct file *file, void *fh,
                           struct v4l2_crop *cr)
{
    struct fimc_frame *f;
    struct fimc_ctx *ctx = file->private_data;
    struct fimc_dev *fimc = ctx->fimc_dev;
    int ret = -EINVAL;

    if (fimc_capture_active(fimc))
        return -EBUSY;

    ret = fimc_try_crop(ctx, cr);
    if (ret)
        return ret;

    if (!(ctx->state & FIMC_DST_FMT)) {
        v4l2_err(&fimc->vid_cap.v4l2_dev,
                 "Capture color format not set\n");
        return -EINVAL; /* TODO: make sure this is the right value */
    }

    f = &ctx->s_frame;
    /* Check for the pixel scaling ratio when cropping input image. */
    ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height,
                                  ctx->d_frame.width, ctx->d_frame.height,
                                  ctx->rotation);
    if (ret) {
        v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n");
        return ret;
    }

    f->offs_h = cr->c.left;
    f->offs_v = cr->c.top;
    f->width  = cr->c.width;
    f->height = cr->c.height;

    return 0;
}
예제 #16
0
static int fimc_cap_streamon(struct file *file, void *priv,
			     enum v4l2_buf_type type)
{
	struct fimc_dev *fimc = video_drvdata(file);
	struct fimc_pipeline *p = &fimc->pipeline;
	struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];
	int ret;

	if (fimc_capture_active(fimc))
		return -EBUSY;

	ret = media_entity_pipeline_start(&sd->entity, p->m_pipeline);
	if (ret < 0)
		return ret;

	if (fimc->vid_cap.user_subdev_api) {
		ret = fimc_pipeline_validate(fimc);
		if (ret < 0) {
			media_entity_pipeline_stop(&sd->entity);
			return ret;
		}
	}
	return vb2_streamon(&fimc->vid_cap.vbq, type);
}
예제 #17
0
static int fimc_cap_streamon(struct file *file, void *priv,
			   enum v4l2_buf_type type)
{
	struct s3c_fimc_isp_info *isp_info;
	struct fimc_ctx *ctx = priv;
	struct fimc_dev *fimc = ctx->fimc_dev;
	int ret = -EBUSY;

	if (mutex_lock_interruptible(&fimc->lock))
		return -ERESTARTSYS;

	if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
		goto s_unlock;

	if (!(ctx->state & FIMC_DST_FMT)) {
		v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
		ret = -EINVAL;
		goto s_unlock;
	}

	ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
	if (ret && ret != -ENOIOCTLCMD)
		goto s_unlock;

	ret = fimc_prepare_config(ctx, ctx->state);
	if (ret)
		goto s_unlock;

	isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
	fimc_hw_set_camera_type(fimc, isp_info);
	fimc_hw_set_camera_source(fimc, isp_info);
	fimc_hw_set_camera_offset(fimc, &ctx->s_frame);

	if (ctx->state & FIMC_PARAMS) {
		ret = fimc_set_scaler_info(ctx);
		if (ret) {
			err("Scaler setup error");
			goto s_unlock;
		}
		fimc_hw_set_input_path(ctx);
		fimc_hw_set_scaler(ctx);
		fimc_hw_set_target_format(ctx);
		fimc_hw_set_rotation(ctx);
		fimc_hw_set_effect(ctx);
	}

	fimc_hw_set_output_path(ctx);
	fimc_hw_set_out_dma(ctx);

	INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
	INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
	fimc->vid_cap.active_buf_cnt = 0;
	fimc->vid_cap.frame_count = 0;

	set_bit(ST_CAPT_PEND, &fimc->state);
	ret = videobuf_streamon(&fimc->vid_cap.vbq);

s_unlock:
	mutex_unlock(&fimc->lock);
	return ret;
}