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; }
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; }
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); }
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; }
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); }
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); }
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; }
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; }
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); }
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); }
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; }
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); }
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; }
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; }
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; }
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); }
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; }