static void fimc_is_ixc_buffer_queue(struct vb2_buffer *vb) { int ret = 0; struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv; struct fimc_is_queue *queue; struct fimc_is_video *video; struct fimc_is_device_ischain *device; struct fimc_is_subdev *subdev; BUG_ON(!vctx); BUG_ON(!GET_DEVICE(vctx)); BUG_ON(!GET_VIDEO(vctx)); #ifdef DBG_STREAMING mdbgv_ixc("%s(%d)\n", vctx, __func__, vb->v4l2_buf.index); #endif device = GET_DEVICE(vctx); video = GET_VIDEO(vctx); queue = GET_QUEUE(vctx); subdev = &device->ixc; ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb); if (ret) { merr("fimc_is_queue_buffer_queue is fail(%d)", device, ret); return; } ret = fimc_is_subdev_buffer_queue(subdev, vb->v4l2_buf.index); if (ret) { merr("fimc_is_subdev_buffer_queue is fail(%d)", device, ret); return; } }
static int fimc_is_dis_video_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { int ret = 0; struct fimc_is_video_ctx *vctx = file->private_data; struct fimc_is_device_ischain *device; struct fimc_is_queue *queue; #ifdef DBG_STREAMING mdbgv_dis("%s\n", vctx, __func__); #endif device = GET_DEVICE(vctx); queue = GET_QUEUE(vctx); if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) { merr("stream off state, can NOT qbuf", vctx); ret = -EINVAL; goto p_err; } ret = fimc_is_video_qbuf(file, vctx, buf); if (ret) merr("fimc_is_video_qbuf is fail(%d)", vctx, ret); p_err: return ret; }
static int fimc_is_ixc_queue_setup(struct vb2_queue *vbq, const struct v4l2_format *fmt, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { int ret = 0; struct fimc_is_video_ctx *vctx = vbq->drv_priv; struct fimc_is_video *video; struct fimc_is_queue *queue; BUG_ON(!vctx); BUG_ON(!vctx->video); mdbgv_ixc("%s\n", vctx, __func__); video = GET_VIDEO(vctx); queue = GET_QUEUE(vctx); ret = fimc_is_queue_setup(queue, video->alloc_ctx, num_planes, sizes, allocators); if (ret) merr("fimc_is_queue_setup is fail(%d)", vctx, ret); return ret; }
int fimc_is_video_close(struct fimc_is_video_ctx *vctx) { int ret = 0; struct fimc_is_video *video; struct fimc_is_queue *queue; BUG_ON(!vctx); BUG_ON(!GET_VIDEO(vctx)); video = GET_VIDEO(vctx); queue = GET_QUEUE(vctx); if (vctx->state < BIT(FIMC_IS_VIDEO_OPEN)) { mverr("already close(%lX)", vctx, video, vctx->state); return -ENOENT; } fimc_is_queue_close(queue); vb2_queue_release(queue->vbq); kfree(queue->vbq); /* * vb2 release can call stop callback * not if video node is not stream off */ vctx->device = NULL; vctx->state = BIT(FIMC_IS_VIDEO_CLOSE); return ret; }
int fimc_is_video_streamoff(struct file *file, struct fimc_is_video_ctx *vctx, enum v4l2_buf_type type) { int ret = 0; u32 qcount; struct fimc_is_queue *queue; struct vb2_queue *vbq; struct fimc_is_framemgr *framemgr; BUG_ON(!file); BUG_ON(!vctx); if (!(vctx->state & BIT(FIMC_IS_VIDEO_START))) { err("[V%02d] invalid streamoff is requested(%lX)", vctx->video->id, vctx->state); return -EINVAL; } queue = GET_QUEUE(vctx); framemgr = &queue->framemgr; vbq = queue->vbq; if (!vbq) { merr("vbq is NULL", vctx); ret = -EINVAL; goto p_err; } framemgr_e_barrier_irq(framemgr, FMGR_IDX_0); qcount = framemgr->frame_req_cnt + framemgr->frame_pro_cnt + framemgr->frame_com_cnt; framemgr_x_barrier_irq(framemgr, FMGR_IDX_0); if (qcount > 0) mwarn("video%d stream off : queued buffer is not empty(%d)", vctx, vctx->video->id, qcount); if (vbq->type != type) { merr("invalid stream type(%d != %d)", vctx, vbq->type, type); ret = -EINVAL; goto p_err; } if (!vbq->streaming) { merr("streamoff: not streaming", vctx); ret = -EINVAL; goto p_err; } ret = vb2_streamoff(vbq, type); if (ret) { err("[V%02d] vb2_streamoff is fail(%d)", vctx->video->id, ret); goto p_err; } vctx->state = BIT(FIMC_IS_VIDEO_STOP); p_err: return ret; }
static int fimc_is_ixc_start_streaming(struct vb2_queue *vbq, unsigned int count) { int ret = 0; struct fimc_is_video_ctx *vctx = vbq->drv_priv; struct fimc_is_queue *queue; struct fimc_is_device_ischain *device; BUG_ON(!vctx); BUG_ON(!GET_DEVICE(vctx)); mdbgv_ixc("%s\n", vctx, __func__); device = GET_DEVICE(vctx); queue = GET_QUEUE(vctx); ret = fimc_is_queue_start_streaming(queue, device); if (ret) { merr("fimc_is_queue_start_streaming is fail(%d)", device, ret); goto p_err; } p_err: return ret; }
int fimc_is_video_open(struct fimc_is_video_ctx *vctx, void *device, u32 buf_rdycount, struct fimc_is_video *video, const struct vb2_ops *vb2_ops, const struct fimc_is_queue_ops *qops) { int ret = 0; struct fimc_is_queue *queue; BUG_ON(!vctx); BUG_ON(!video); BUG_ON(!video->vb2); BUG_ON(!vb2_ops); if (!(vctx->state & BIT(FIMC_IS_VIDEO_CLOSE))) { err("[V%02d] already open(%lX)", video->id, vctx->state); return -EEXIST; } queue = GET_QUEUE(vctx); queue->vbq = NULL; queue->qops = qops; vctx->device = device; vctx->subdev = NULL; vctx->video = video; vctx->vb2_ops = vb2_ops; vctx->mem_ops = video->vb2->ops; mutex_init(&vctx->lock); ret = fimc_is_queue_open(queue, buf_rdycount); if (ret) { err("fimc_is_queue_open is fail(%d)", ret); goto p_err; } queue->vbq = kzalloc(sizeof(struct vb2_queue), GFP_KERNEL); if (!queue->vbq) { err("kzalloc is fail"); ret = -ENOMEM; goto p_err; } ret = queue_init(vctx, queue->vbq, NULL); if (ret) { err("queue_init fail"); kfree(queue->vbq); goto p_err; } vctx->state = BIT(FIMC_IS_VIDEO_OPEN); p_err: return ret; }
int fimc_is_video_dqbuf(struct file *file, struct fimc_is_video_ctx *vctx, struct v4l2_buffer *buf) { int ret = 0; bool blocking; struct fimc_is_video *video; struct fimc_is_queue *queue; BUG_ON(!file); BUG_ON(!vctx); BUG_ON(!GET_VIDEO(vctx)); BUG_ON(!buf); blocking = file->f_flags & O_NONBLOCK; video = GET_VIDEO(vctx); queue = GET_QUEUE(vctx); if (!queue->vbq) { mverr("vbq is NULL", vctx, video); ret = -EINVAL; goto p_err; } if (buf->type != queue->vbq->type) { mverr("buf type is invalid(%d != %d)", vctx, video, buf->type, queue->vbq->type); ret = -EINVAL; goto p_err; } if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) { mverr("queue is not streamon(%ld)", vctx, video, queue->state); ret = -EINVAL; goto p_err; } queue->buf_dqe++; ret = vb2_dqbuf(queue->vbq, buf, blocking); if (ret) { mverr("vb2_dqbuf is fail(%d)", vctx, video, ret); goto p_err; } #ifdef DBG_IMAGE_DUMP if ((vctx->video->id == DBG_IMAGE_DUMP_VIDEO) && (buf->index == DBG_IMAGE_DUMP_INDEX)) imgdump_request(queue->buf_box[buf->index][0], queue->buf_kva[buf->index][0], queue->framecfg.size[0]); #endif p_err: return ret; }
int fimc_is_video_querybuf(struct file *file, struct fimc_is_video_ctx *vctx, struct v4l2_buffer *buf) { int ret = 0; struct fimc_is_queue *queue; queue = GET_QUEUE(vctx); ret = vb2_querybuf(queue->vbq, buf); return ret; }
int fimc_is_video_poll(struct file *file, struct fimc_is_video_ctx *vctx, struct poll_table_struct *wait) { u32 ret = 0; struct fimc_is_queue *queue; BUG_ON(!vctx); queue = GET_QUEUE(vctx); ret = vb2_poll(queue->vbq, file, wait); return ret; }
int fimc_is_video_streamoff(struct file *file, struct fimc_is_video_ctx *vctx, enum v4l2_buf_type type) { int ret = 0; u32 qcount; struct fimc_is_queue *queue; struct vb2_queue *vbq; struct fimc_is_framemgr *framemgr; BUG_ON(!file); BUG_ON(!vctx); queue = GET_QUEUE(vctx, type); framemgr = &queue->framemgr; vbq = queue->vbq; if (!vbq) { merr("vbq is NULL", vctx); ret = -EINVAL; goto p_err; } framemgr_e_barrier_irq(framemgr, 0); qcount = framemgr->frame_req_cnt + framemgr->frame_pro_cnt + framemgr->frame_com_cnt; framemgr_x_barrier_irq(framemgr, 0); if (qcount > 0) mwarn("video%d stream off : queued buffer is not empty(%d)", vctx, vctx->video->id, qcount); if (vbq->type != type) { merr("invalid stream type(%d != %d)", vctx, vbq->type, type); ret = -EINVAL; goto p_err; } if (!vbq->streaming) { merr("streamoff: not streaming", vctx); ret = -EINVAL; goto p_err; } ret = vb2_streamoff(vbq, type); p_err: return ret; }
int fimc_is_video_mmap(struct file *file, struct fimc_is_video_ctx *vctx, struct vm_area_struct *vma) { u32 ret = 0; struct fimc_is_queue *queue; BUG_ON(!vctx); queue = GET_QUEUE(vctx); ret = vb2_mmap(queue->vbq, vma); return ret; }
int fimc_is_video_streamon(struct file *file, struct fimc_is_video_ctx *vctx, enum v4l2_buf_type type) { int ret = 0; struct vb2_queue *vbq; BUG_ON(!file); BUG_ON(!vctx); if (!(vctx->state & (BIT(FIMC_IS_VIDEO_S_BUFS) | BIT(FIMC_IS_VIDEO_STOP)))) { err("[V%02d] invalid streamon is requested(%lX)", vctx->video->id, vctx->state); return -EINVAL; } vbq = GET_QUEUE(vctx)->vbq; if (!vbq) { merr("vbq is NULL", vctx); ret = -EINVAL; goto p_err; } if (vbq->type != type) { merr("invalid stream type(%d != %d)", vctx, vbq->type, type); ret = -EINVAL; goto p_err; } if (vbq->streaming) { merr("streamon: already streaming", vctx); ret = -EINVAL; goto p_err; } ret = vb2_streamon(vbq, type); if (ret) { err("[V%02d] vb2_streamon is fail(%d)", vctx->video->id, ret); goto p_err; } vctx->state = BIT(FIMC_IS_VIDEO_START); p_err: return ret; }
int buffer_done(struct fimc_is_video_ctx *vctx, u32 index, u32 state) { int ret = 0; struct vb2_buffer *vb; struct fimc_is_queue *queue; BUG_ON(!vctx); BUG_ON(!vctx->video); BUG_ON(index >= FRAMEMGR_MAX_REQUEST); queue = GET_QUEUE(vctx); if (!queue->vbq) { err("vbq is NULL"); ret = -EINVAL; goto p_err; } vb = queue->vbq->bufs[index]; if (!vb) { err("vb is NULL"); ret = -EINVAL; goto p_err; } if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) { warn("%d video queue is not stream on", vctx->video->id); ret = -EINVAL; goto p_err; } if (vb->state != VB2_BUF_STATE_ACTIVE) { err("vb buffer[%d] state is not active(%d)", index, vb->state); ret = -EINVAL; goto p_err; } queue->buf_com++; vb2_buffer_done(vb, state); p_err: return ret; }
int fimc_is_video_set_format_mplane(struct file *file, struct fimc_is_video_ctx *vctx, struct v4l2_format *format) { int ret = 0; u32 condition; void *device; struct fimc_is_video *video; struct fimc_is_queue *queue; BUG_ON(!vctx); BUG_ON(!GET_DEVICE(vctx)); BUG_ON(!GET_VIDEO(vctx)); BUG_ON(!format); device = GET_DEVICE(vctx); video = GET_VIDEO(vctx); queue = GET_QUEUE(vctx); /* capture video node can skip s_input */ if (video->type == FIMC_IS_VIDEO_TYPE_LEADER) condition = BIT(FIMC_IS_VIDEO_S_INPUT) | BIT(FIMC_IS_VIDEO_S_BUFS); else condition = BIT(FIMC_IS_VIDEO_S_INPUT) | BIT(FIMC_IS_VIDEO_S_BUFS) | BIT(FIMC_IS_VIDEO_OPEN); if (!(vctx->state & condition)) { err("[V%02d] invalid s_format is requested(%lX)", video->id, vctx->state); return -EINVAL; } ret = fimc_is_queue_set_format_mplane(queue, device, format); if (ret) { err("[V%02d] fimc_is_queue_set_format_mplane is fail(%d)", video->id, ret); goto p_err; } vctx->state = BIT(FIMC_IS_VIDEO_S_FORMAT); p_err: mdbgv_vid("set_format(%d x %d)\n", queue->framecfg.width, queue->framecfg.height); return ret; }
static void fimc_is_scc_stop_streaming(struct vb2_queue *vbq) { int ret = 0; struct fimc_is_video_ctx *vctx = vbq->drv_priv; struct fimc_is_queue *queue; struct fimc_is_device_ischain *device; BUG_ON(!vctx); BUG_ON(!GET_DEVICE(vctx)); mdbgv_scc("%s\n", vctx, __func__); device = GET_DEVICE(vctx); queue = GET_QUEUE(vctx); ret = fimc_is_queue_stop_streaming(queue, device); if (ret) { merr("fimc_is_queue_stop_streaming is fail(%d)", device, ret); return; } }
int fimc_is_video_streamon(struct file *file, struct fimc_is_video_ctx *vctx, enum v4l2_buf_type type) { int ret = 0; struct fimc_is_queue *queue; struct vb2_queue *vbq; BUG_ON(!file); BUG_ON(!vctx); queue = GET_QUEUE(vctx, type); vbq = queue->vbq; if (!vbq) { merr("vbq is NULL", vctx); ret = -EINVAL; goto p_err; } if (vbq->type != type) { merr("invalid stream type(%d != %d)", vctx, vbq->type, type); ret = -EINVAL; goto p_err; } if (vbq->streaming) { merr("streamon: already streaming", vctx); ret = -EINVAL; goto p_err; } ret = vb2_streamon(vbq, type); p_err: return ret; }
static int fimc_is_isp_video_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { int ret = 0; int i2c_clk; struct fimc_is_video *video; struct fimc_is_video_ctx *vctx = file->private_data; struct fimc_is_device_ischain *device; struct fimc_is_core *core; BUG_ON(!vctx); BUG_ON(!vctx->device); BUG_ON(!vctx->video); dbg_isp("%s\n", __func__); device = vctx->device; video = vctx->video; core = container_of(video, struct fimc_is_core, video_isp); if (core->resourcemgr.dvfs_ctrl.cur_int_qos == DVFS_L0) i2c_clk = I2C_L0; else i2c_clk = I2C_L1; switch (ctrl->id) { case V4L2_CID_IS_DEBUG_DUMP: info("Print fimc-is info dump by HAL"); if (device != NULL) { fimc_is_hw_logdump(device->interface); fimc_is_hw_regdump(device->interface); CALL_POPS(device, print_clk, device->pdev); } if (ctrl->value) { err("BUG_ON from HAL"); BUG(); } break; case V4L2_CID_IS_DEBUG_SYNC_LOG: fimc_is_logsync(device->interface, ctrl->value, IS_MSG_TEST_SYNC_LOG); break; case V4L2_CID_IS_HAL_VERSION: if (ctrl->value < 0 || ctrl->value >= IS_HAL_VER_MAX) { merr("hal version(%d) is invalid", vctx, ctrl->value); ret = -EINVAL; goto p_err; } core->resourcemgr.hal_version = ctrl->value; break; case V4L2_CID_IS_G_CAPABILITY: ret = fimc_is_ischain_g_capability(device, ctrl->value); dbg_isp("V4L2_CID_IS_G_CAPABILITY : %X\n", ctrl->value); break; case V4L2_CID_IS_FORCE_DONE: set_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &device->group_isp.state); break; case V4L2_CID_IS_DVFS_LOCK: ret = fimc_is_itf_i2c_lock(device, I2C_L0, true); if (ret) { err("fimc_is_itf_i2_clock fail\n"); break; } pm_qos_add_request(&device->user_qos, PM_QOS_DEVICE_THROUGHPUT, ctrl->value); ret = fimc_is_itf_i2c_lock(device, I2C_L0, false); if (ret) { err("fimc_is_itf_i2c_unlock fail\n"); break; } dbg_isp("V4L2_CID_IS_DVFS_LOCK : %d\n", ctrl->value); break; case V4L2_CID_IS_DVFS_UNLOCK: ret = fimc_is_itf_i2c_lock(device, i2c_clk, true); if (ret) { err("fimc_is_itf_i2_clock fail\n"); break; } pm_qos_remove_request(&device->user_qos); ret = fimc_is_itf_i2c_lock(device, i2c_clk, false); if (ret) { err("fimc_is_itf_i2c_unlock fail\n"); break; } dbg_isp("V4L2_CID_IS_DVFS_UNLOCK : %d I2C(%d)\n", ctrl->value, i2c_clk); break; case V4L2_CID_IS_SET_SETFILE: if (test_bit(FIMC_IS_SUBDEV_START, &device->group_isp.leader.state)) { err("Setting setfile is only avaiable before starting device!! (0x%08x)", ctrl->value); ret = -EINVAL; } else { device->setfile = ctrl->value; minfo("[ISP:V] setfile: 0x%08X\n", vctx, ctrl->value); } break; case V4L2_CID_IS_COLOR_RANGE: if (test_bit(FIMC_IS_SUBDEV_START, &device->group_isp.leader.state)) { err("failed to change color range: device started already (0x%08x)", ctrl->value); ret = -EINVAL; } else { device->color_range &= ~FIMC_IS_ISP_CRANGE_MASK; if (ctrl->value) device->color_range |= (FIMC_IS_CRANGE_LIMITED << FIMC_IS_ISP_CRANGE_SHIFT); } break; case V4L2_CID_IS_MAP_BUFFER: { /* hack for 64bit addr */ ulong value_to_addr; struct fimc_is_queue *queue; struct fimc_is_framemgr *framemgr; struct fimc_is_frame *frame; struct dma_buf *dmabuf; struct dma_buf_attachment *attachment; dma_addr_t dva; struct v4l2_buffer *buf; struct v4l2_plane *planes; size_t size; u32 write, plane, group_id; size = sizeof(struct v4l2_buffer); buf = kmalloc(size, GFP_KERNEL); if (!buf) { merr("kmalloc is fail", vctx); ret = -EINVAL; goto p_err; } /* hack for 64bit addr */ value_to_addr = ctrl->value; ret = copy_from_user(buf, (void __user *)value_to_addr, size); if (ret) { merr("copy_from_user is fail(%d)", vctx, ret); kfree(buf); ret = -EINVAL; goto p_err; } if (!V4L2_TYPE_IS_MULTIPLANAR(buf->type)) { merr("single plane is not supported", vctx); kfree(buf); ret = -EINVAL; goto p_err; } if (buf->index >= FRAMEMGR_MAX_REQUEST) { merr("buffer index is invalid(%d)", vctx, buf->index); kfree(buf); ret = -EINVAL; goto p_err; } if (buf->length > VIDEO_MAX_PLANES) { merr("planes[%d] is invalid", vctx, buf->length); kfree(buf); ret = -EINVAL; goto p_err; } queue = GET_QUEUE(vctx, buf->type); if (queue->vbq->memory != V4L2_MEMORY_DMABUF) { merr("memory type(%d) is not supported", vctx, queue->vbq->memory); kfree(buf); ret = -EINVAL; goto p_err; } size = sizeof(struct v4l2_plane) * buf->length; planes = kmalloc(size, GFP_KERNEL); if (IS_ERR(planes)) { merr("kmalloc is fail(%p)", vctx, planes); kfree(buf); ret = -EINVAL; goto p_err; } ret = copy_from_user(planes, (void __user *)buf->m.planes, size); if (ret) { merr("copy_from_user is fail(%d)", vctx, ret); kfree(planes); kfree(buf); ret = -EINVAL; goto p_err; } framemgr = &queue->framemgr; frame = &framemgr->frame[buf->index]; if (test_bit(FRAME_MAP_MEM, &frame->memory)) { merr("this buffer(%d) is already mapped", vctx, buf->index); kfree(planes); kfree(buf); ret = -EINVAL; goto p_err; } /* only last buffer need to map */ if (buf->length >= 1) { plane = buf->length - 1; } else { merr("buffer length is not correct(%d)", vctx, buf->length); kfree(planes); kfree(buf); ret = -EINVAL; goto p_err; } dmabuf = dma_buf_get(planes[plane].m.fd); if (IS_ERR(dmabuf)) { merr("dma_buf_get is fail(%p)", vctx, dmabuf); kfree(planes); kfree(buf); ret = -EINVAL; goto p_err; } attachment = dma_buf_attach(dmabuf, &device->pdev->dev); if (IS_ERR(attachment)) { merr("dma_buf_attach is fail(%p)", vctx, attachment); kfree(planes); kfree(buf); dma_buf_put(dmabuf); ret = -EINVAL; goto p_err; } write = !V4L2_TYPE_IS_OUTPUT(buf->type); dva = ion_iovmm_map(attachment, 0, dmabuf->size, write, plane); if (IS_ERR_VALUE(dva)) { merr("ion_iovmm_map is fail(%pa)", vctx, &dva); kfree(planes); kfree(buf); dma_buf_detach(dmabuf, attachment); dma_buf_put(dmabuf); ret = -EINVAL; goto p_err; } group_id = GROUP_ID(device->group_isp.id); ret = fimc_is_itf_map(device, group_id, dva, dmabuf->size); if (ret) { merr("fimc_is_itf_map is fail(%d)", vctx, ret); kfree(planes); kfree(buf); dma_buf_detach(dmabuf, attachment); dma_buf_put(dmabuf); goto p_err; } minfo("[ISP:V] buffer%d.plane%d mapping\n", vctx, buf->index, plane); set_bit(FRAME_MAP_MEM, &frame->memory); dma_buf_detach(dmabuf, attachment); dma_buf_put(dmabuf); kfree(planes); kfree(buf); } break; default: err("unsupported ioctl(%d)\n", ctrl->id); ret = -EINVAL; break; } p_err: return ret; }
int fimc_is_video_qbuf(struct file *file, struct fimc_is_video_ctx *vctx, struct v4l2_buffer *buf) { int ret = 0; struct fimc_is_queue *queue; struct vb2_queue *vbq; struct vb2_buffer *vb; BUG_ON(!file); BUG_ON(!vctx); BUG_ON(!buf); buf->flags &= ~V4L2_BUF_FLAG_USE_SYNC; queue = GET_QUEUE(vctx); vbq = queue->vbq; if (!vbq) { merr("vbq is NULL", vctx); ret = -EINVAL; goto p_err; } if (vbq->fileio) { merr("file io in progress", vctx); ret = -EBUSY; goto p_err; } if (buf->type != queue->vbq->type) { merr("buf type is invalid(%d != %d)", vctx, buf->type, queue->vbq->type); ret = -EINVAL; goto p_err; } if (buf->index >= vbq->num_buffers) { merr("buffer index%d out of range", vctx, buf->index); ret = -EINVAL; goto p_err; } if (buf->memory != vbq->memory) { merr("invalid memory type%d", vctx, buf->memory); ret = -EINVAL; goto p_err; } vb = vbq->bufs[buf->index]; if (!vb) { merr("vb is NULL", vctx); ret = -EINVAL; goto p_err; } queue->buf_req++; ret = vb2_qbuf(queue->vbq, buf); if (ret) { merr("vb2_qbuf is fail(index : %d, %d)", vctx, buf->index, ret); goto p_err; } p_err: return ret; }
int fimc_is_video_s_ctrl(struct file *file, struct fimc_is_video_ctx *vctx, struct v4l2_control *ctrl) { int ret = 0; /* hack for 64bit addr */ ulong value_to_addr = 0; struct fimc_is_video *video; struct fimc_is_device_ischain *device; struct fimc_is_resourcemgr *resourcemgr; BUG_ON(!vctx); BUG_ON(!GET_DEVICE(vctx)); BUG_ON(!GET_VIDEO(vctx)); BUG_ON(!ctrl); device = GET_DEVICE(vctx); video = GET_VIDEO(vctx); resourcemgr = device->resourcemgr; switch (ctrl->id) { case V4L2_CID_IS_END_OF_STREAM: ret = fimc_is_ischain_open_wrap(device, true); if (ret) { merr("fimc_is_ischain_open_wrap is fail(%d)", device, ret); goto p_err; } break; case V4L2_CID_IS_SET_SETFILE: if (test_bit(FIMC_IS_ISCHAIN_START, &device->state)) { merr("device is already started, setfile applying is fail", device); ret = -EINVAL; goto p_err; } device->setfile = ctrl->value; break; case V4L2_CID_IS_HAL_VERSION: if (ctrl->value < 0 || ctrl->value >= IS_HAL_VER_MAX) { merr("hal version(%d) is invalid", device, ctrl->value); ret = -EINVAL; goto p_err; } resourcemgr->hal_version = ctrl->value; break; case V4L2_CID_IS_DEBUG_DUMP: info("Print fimc-is info dump by HAL"); fimc_is_hw_logdump(device->interface); fimc_is_hw_regdump(device->interface); CALL_POPS(device, print_clk); if (ctrl->value) panic("intentional panic from camera HAL"); break; case V4L2_CID_IS_DVFS_CLUSTER0: case V4L2_CID_IS_DVFS_CLUSTER1: fimc_is_resource_ioctl(resourcemgr, ctrl); break; case V4L2_CID_IS_DEBUG_SYNC_LOG: fimc_is_logsync(device->interface, ctrl->value, IS_MSG_TEST_SYNC_LOG); break; case V4L2_CID_IS_MAP_BUFFER: { struct fimc_is_queue *queue; struct fimc_is_framemgr *framemgr; struct fimc_is_frame *frame; struct dma_buf *dmabuf; struct dma_buf_attachment *attachment; dma_addr_t dva; struct v4l2_buffer *buf; struct v4l2_plane *planes; size_t size; u32 plane, group_id; size = sizeof(struct v4l2_buffer); buf = kmalloc(size, GFP_KERNEL); if (!buf) { mverr("kmalloc is fail(%p)", device, video, buf); ret = -EINVAL; goto p_err; } /* hack for 64bit addr */ value_to_addr = ctrl->value; ret = copy_from_user(buf, (void __user *)value_to_addr, size); if (ret) { mverr("copy_from_user is fail(%d)", device, video, ret); kfree(buf); ret = -EINVAL; goto p_err; } if (!V4L2_TYPE_IS_OUTPUT(buf->type)) { mverr("capture video type is not supported", device, video); kfree(buf); ret = -EINVAL; goto p_err; } if (!V4L2_TYPE_IS_MULTIPLANAR(buf->type)) { mverr("single plane is not supported", device, video); kfree(buf); ret = -EINVAL; goto p_err; } if (buf->index >= FRAMEMGR_MAX_REQUEST) { mverr("buffer index is invalid(%d)", device, video, buf->index); kfree(buf); ret = -EINVAL; goto p_err; } if (buf->length > VIDEO_MAX_PLANES) { mverr("planes[%d] is invalid", device, video, buf->length); kfree(buf); ret = -EINVAL; goto p_err; } queue = GET_QUEUE(vctx); if (queue->vbq->memory != V4L2_MEMORY_DMABUF) { mverr("memory type(%d) is not supported", device, video, queue->vbq->memory); kfree(buf); ret = -EINVAL; goto p_err; } size = sizeof(struct v4l2_plane) * buf->length; planes = kmalloc(size, GFP_KERNEL); if (!planes) { mverr("kmalloc is fail(%p)", device, video, planes); kfree(buf); ret = -EINVAL; goto p_err; } ret = copy_from_user(planes, (void __user *)buf->m.planes, size); if (ret) { mverr("copy_from_user is fail(%d)", device, video, ret); kfree(planes); kfree(buf); ret = -EINVAL; goto p_err; } framemgr = &queue->framemgr; frame = &framemgr->frame[buf->index]; if (test_bit(FRAME_MAP_MEM, &frame->memory)) { mverr("this buffer(%d) is already mapped", device, video, buf->index); kfree(planes); kfree(buf); ret = -EINVAL; goto p_err; } /* only last buffer need to map */ if (buf->length <= 1) { mverr("this buffer(%d) have no meta plane", device, video, buf->length); kfree(planes); kfree(buf); ret = -EINVAL; goto p_err; } plane = buf->length - 1; dmabuf = dma_buf_get(planes[plane].m.fd); if (IS_ERR(dmabuf)) { mverr("dma_buf_get is fail(%p)", device, video, dmabuf); kfree(planes); kfree(buf); ret = -EINVAL; goto p_err; } attachment = dma_buf_attach(dmabuf, &device->pdev->dev); if (IS_ERR(attachment)) { mverr("dma_buf_attach is fail(%p)", device, video, attachment); kfree(planes); kfree(buf); dma_buf_put(dmabuf); ret = -EINVAL; goto p_err; } /* only support output(read) video node */ dva = ion_iovmm_map(attachment, 0, dmabuf->size, 0, plane); if (IS_ERR_VALUE(dva)) { mverr("ion_iovmm_map is fail(%pa)", device, video, &dva); kfree(planes); kfree(buf); dma_buf_detach(dmabuf, attachment); dma_buf_put(dmabuf); ret = -EINVAL; goto p_err; } group_id = GROUP_ID(device->group_3aa.id); ret = fimc_is_itf_map(device, group_id, dva, dmabuf->size); if (ret) { mverr("fimc_is_itf_map is fail(%d)", device, video, ret); kfree(planes); kfree(buf); dma_buf_detach(dmabuf, attachment); dma_buf_put(dmabuf); goto p_err; } mvinfo(" B%d.P%d MAP\n", device, video, buf->index, plane); set_bit(FRAME_MAP_MEM, &frame->memory); dma_buf_detach(dmabuf, attachment); dma_buf_put(dmabuf); kfree(planes); kfree(buf); } break; default: err("unsupported ioctl(0x%X)", ctrl->id); ret = -EINVAL; break; } p_err: return ret; }
int fimc_is_video_reqbufs(struct file *file, struct fimc_is_video_ctx *vctx, struct v4l2_requestbuffers *request) { int ret = 0; struct fimc_is_queue *queue; struct fimc_is_framemgr *framemgr; BUG_ON(!vctx); BUG_ON(!request); if (!(vctx->state & (BIT(FIMC_IS_VIDEO_S_FORMAT) | BIT(FIMC_IS_VIDEO_STOP) | BIT(FIMC_IS_VIDEO_S_BUFS)))) { err("[V%02d] invalid reqbufs is requested(%lX)", vctx->video->id, vctx->state); return -EINVAL; } queue = GET_QUEUE(vctx); if (test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) { err("video is stream on, not applied"); ret = -EINVAL; goto p_err; } ret = CALL_QOPS(queue, request_bufs, GET_DEVICE(vctx), request->count); if (ret) { err("request_bufs is fail(%d)", ret); goto p_err; } ret = vb2_reqbufs(queue->vbq, request); if (ret) { err("vb2_reqbufs is fail(%d)", ret); goto p_err; } framemgr = &queue->framemgr; queue->buf_maxcount = request->count; if (queue->buf_maxcount == 0) { queue->buf_req = 0; queue->buf_pre = 0; queue->buf_que = 0; queue->buf_com = 0; queue->buf_dqe = 0; queue->buf_refcount = 0; clear_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state); clear_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state); fimc_is_frame_close(framemgr); } else { if (queue->buf_maxcount < queue->buf_rdycount) { err("buffer count is not invalid(%d < %d)", queue->buf_maxcount, queue->buf_rdycount); ret = -EINVAL; goto p_err; } ret = fimc_is_frame_open(framemgr, queue->buf_maxcount); if (ret) { err("[V%02d] fimc_is_frame_open is fail(%d)", vctx->video->id, ret); goto p_err; } } vctx->state = BIT(FIMC_IS_VIDEO_S_BUFS); p_err: return ret; }