📄 mxc_v4l2_capture.c
字号:
* * @return status 0 success, EINVAL failed */static int mxc_set_v42l_control(cam_data * cam, struct v4l2_control *c){ switch (c->id) { case V4L2_CID_HFLIP: if (c->value == 1) { if ((cam->rotation != IPU_ROTATE_VERT_FLIP) && (cam->rotation != IPU_ROTATE_180)) cam->rotation = IPU_ROTATE_HORIZ_FLIP; else cam->rotation = IPU_ROTATE_180; } else { if (cam->rotation == IPU_ROTATE_HORIZ_FLIP) cam->rotation = IPU_ROTATE_NONE; if (cam->rotation == IPU_ROTATE_180) cam->rotation = IPU_ROTATE_VERT_FLIP; } break; case V4L2_CID_VFLIP: if (c->value == 1) { if ((cam->rotation != IPU_ROTATE_HORIZ_FLIP) && (cam->rotation != IPU_ROTATE_180)) cam->rotation = IPU_ROTATE_VERT_FLIP; else cam->rotation = IPU_ROTATE_180; } else { if (cam->rotation == IPU_ROTATE_VERT_FLIP) cam->rotation = IPU_ROTATE_NONE; if (cam->rotation == IPU_ROTATE_180) cam->rotation = IPU_ROTATE_HORIZ_FLIP; } break; case V4L2_CID_MXC_ROT: switch (c->value) { case V4L2_MXC_ROTATE_NONE: cam->rotation = IPU_ROTATE_NONE; break; case V4L2_MXC_ROTATE_VERT_FLIP: cam->rotation = IPU_ROTATE_VERT_FLIP; break; case V4L2_MXC_ROTATE_HORIZ_FLIP: cam->rotation = IPU_ROTATE_HORIZ_FLIP; break; case V4L2_MXC_ROTATE_180: cam->rotation = IPU_ROTATE_180; break; case V4L2_MXC_ROTATE_90_RIGHT: cam->rotation = IPU_ROTATE_90_RIGHT; break; case V4L2_MXC_ROTATE_90_RIGHT_VFLIP: cam->rotation = IPU_ROTATE_90_RIGHT_VFLIP; break; case V4L2_MXC_ROTATE_90_RIGHT_HFLIP: cam->rotation = IPU_ROTATE_90_RIGHT_HFLIP; break; case V4L2_MXC_ROTATE_90_LEFT: cam->rotation = IPU_ROTATE_90_LEFT; break; default: return -EINVAL; } break; case V4L2_CID_HUE: cam->hue = c->value; break; case V4L2_CID_CONTRAST: cam->contrast = c->value; break; case V4L2_CID_BRIGHTNESS: cam->bright = c->value; case V4L2_CID_SATURATION: cam->saturation = c->value; case V4L2_CID_RED_BALANCE: cam->red = c->value; case V4L2_CID_BLUE_BALANCE: cam->blue = c->value; ipu_csi_enable_mclk(CSI_MCLK_I2C, true, true); cam->cam_sensor->set_color(cam->bright, cam->saturation, cam->red, cam->green, cam->blue); ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false); break; case V4L2_CID_BLACK_LEVEL: cam->ae_mode = c->value & 0x03; ipu_csi_enable_mclk(CSI_MCLK_I2C, true, true); if (cam->cam_sensor->set_ae_mode) cam->cam_sensor->set_ae_mode(cam->ae_mode); ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false); break; case V4L2_CID_MXC_FLASH: ipu_csi_flash_strobe(true); break; default: return -EINVAL; } return 0;}/*! * V4L2 - mxc_v4l2_s_param function * * @param cam structure cam_data * * * @param parm structure v4l2_streamparm * * * @return status 0 success, EINVAL failed */static int mxc_v4l2_s_param(cam_data * cam, struct v4l2_streamparm *parm){ sensor_interface *param; ipu_csi_signal_cfg_t csi_param; int err = 0; if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { printk(KERN_ERR "mxc_v4l2_s_param invalid type\n"); return -EINVAL; } if (parm->parm.capture.timeperframe.denominator > cam->standard.frameperiod.denominator) { printk(KERN_ERR "mxc_v4l2_s_param frame rate %d larger " "than standard supported %d\n", parm->parm.capture.timeperframe.denominator, cam->standard.frameperiod.denominator); return -EINVAL; } /* Stop the viewfinder */ if (cam->overlay_on == true) { stop_preview(cam); } cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; ipu_csi_enable_mclk(CSI_MCLK_I2C, true, true); param = cam->cam_sensor->config (&parm->parm.capture.timeperframe.denominator, parm->parm.capture.capturemode); ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false); cam->streamparm.parm.capture.timeperframe = parm->parm.capture.timeperframe; if ((parm->parm.capture.capturemode != 0) && (parm->parm.capture.capturemode != V4L2_MODE_HIGHQUALITY)) { printk(KERN_ERR "mxc_v4l2_s_param frame un-supported capture mode\n"); err = -EINVAL; goto exit; } if (parm->parm.capture.capturemode == cam->streamparm.parm.capture.capturemode) { goto exit; } /* resolution changed, so need to re-program the CSI */ csi_param.sens_clksrc = 0; csi_param.clk_mode = param->clk_mode; csi_param.pixclk_pol = param->pixclk_pol; csi_param.data_width = param->data_width; csi_param.data_pol = param->data_pol; csi_param.ext_vsync = param->ext_vsync; csi_param.Vsync_pol = param->Vsync_pol; csi_param.Hsync_pol = param->Hsync_pol; ipu_csi_init_interface(param->width, param->height, param->pixel_fmt, csi_param); ipu_csi_set_window_size(param->width + 1, param->height + 1); if (parm->parm.capture.capturemode != V4L2_MODE_HIGHQUALITY) { cam->streamparm.parm.capture.capturemode = 0; } else { cam->streamparm.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY; cam->streamparm.parm.capture.extendedmode = parm->parm.capture.extendedmode; cam->streamparm.parm.capture.readbuffers = 1; } exit: if (cam->overlay_on == true) { start_preview(cam); } return err;}/*! * Dequeue one V4L capture buffer * * @param cam structure cam_data * * @param buf structure v4l2_buffer * * * @return status 0 success, EINVAL invalid frame number, * ETIME timeout, ERESTARTSYS interrupted by user */static int mxc_v4l_dqueue(cam_data * cam, struct v4l2_buffer *buf){ int retval = 0; struct mxc_v4l_frame *frame; if (!wait_event_interruptible_timeout(cam->enc_queue, cam->enc_counter != 0, 10 * HZ)) { printk(KERN_ERR "mxc_v4l_dqueue timeout enc_counter %x\n", cam->enc_counter); return -ETIME; } else if (signal_pending(current)) { printk(KERN_ERR "mxc_v4l_dqueue() interrupt received\n"); mxc_free_frames(cam); return -ERESTARTSYS; } cam->enc_counter--; frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue); list_del(cam->done_q.next); if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) { frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE; } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { printk(KERN_ERR "VIDIOC_DQBUF: Buffer not filled.\n"); frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; retval = -EINVAL; } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) { printk(KERN_ERR "VIDIOC_DQBUF: Buffer not queued.\n"); retval = -EINVAL; } buf->bytesused = cam->v2f.fmt.pix.sizeimage; buf->index = frame->index; buf->flags = frame->buffer.flags; buf->m = cam->frame[frame->index].buffer.m; return retval;}/*! * V4L interface - open function * * @param inode structure inode * * @param file structure file * * * @return status 0 success, ENODEV invalid device instance, * ENODEV timeout, ERESTARTSYS interrupted by user */static int mxc_v4l_open(struct inode *inode, struct file *file){ sensor_interface *param; ipu_csi_signal_cfg_t csi_param; struct video_device *dev = video_devdata(file); cam_data *cam = dev->priv; int err = 0; if (!cam) { printk(KERN_ERR "Internal error, cam_data not found!\n"); return -EBADF; } down(&cam->busy_lock); err = 0; if (signal_pending(current)) goto oops; if (cam->open_count++ == 0) { wait_event_interruptible(cam->power_queue, cam->low_power == false);#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) err = prp_enc_select(cam);#endif cam->enc_counter = 0; cam->skip_frame = 0; INIT_LIST_HEAD(&cam->ready_q); INIT_LIST_HEAD(&cam->working_q); INIT_LIST_HEAD(&cam->done_q); ipu_csi_enable_mclk(CSI_MCLK_I2C, true, true); param = cam->cam_sensor->reset(); csi_param.sens_clksrc = 0; csi_param.clk_mode = param->clk_mode; csi_param.pixclk_pol = param->pixclk_pol; csi_param.data_width = param->data_width; csi_param.data_pol = param->data_pol; csi_param.ext_vsync = param->ext_vsync; csi_param.Vsync_pol = param->Vsync_pol; csi_param.Hsync_pol = param->Hsync_pol; ipu_csi_init_interface(param->width, param->height, param->pixel_fmt, csi_param); cam->cam_sensor->get_color(&cam->bright, &cam->saturation, &cam->red, &cam->green, &cam->blue); if (cam->cam_sensor->get_ae_mode) cam->cam_sensor->get_ae_mode(&cam->ae_mode); /* pr_info("mxc_v4l_open saturation %x ae_mode %x\n", cam->saturation, cam->ae_mode); */ ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false); } file->private_data = dev; oops: up(&cam->busy_lock); return err;}/*! * V4L interface - close function * * @param inode struct inode * * @param file struct file * * * @return 0 success */static int mxc_v4l_close(struct inode *inode, struct file *file){ struct video_device *dev = video_devdata(file); int err = 0; cam_data *cam = dev->priv; if (!cam) { printk(KERN_ERR "Internal error, cam_data not found!\n"); return -EBADF; } /* for the case somebody hit the ctrl C */ if (cam->overlay_pid == current->pid) { err = stop_preview(cam); } if (cam->capture_pid == current->pid) { err |= mxc_streamoff(cam); wake_up_interruptible(&cam->enc_queue); } if (--cam->open_count == 0) { wait_event_interruptible(cam->power_queue, cam->low_power == false); pr_info("mxc_v4l_close: release resource\n");#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) err |= prp_enc_deselect(cam);#endif mxc_free_frame_buf(cam); file->private_data = NULL; /* capture off */ wake_up_interruptible(&cam->enc_queue); mxc_free_frames(cam); cam->enc_counter++; } return err;}#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)/* * V4L interface - read function * * @param file struct file * * @param read buf char * * @param count size_t * @param ppos structure loff_t * * * @return bytes read */static ssize_tmxc_v4l_read(struct file *file, char *buf, size_t count, loff_t * ppos){ int err = 0; u8 *v_address; struct video_device *dev = video_devdata(file); cam_data *cam = dev->priv; if (down_interruptible(&cam->busy_lock)) return -EINTR; /* Stop the viewfinder */ if (cam->overlay_on == true) stop_preview(cam); v_address = dma_alloc_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), &cam->still_buf, GFP_DMA | GFP_KERNEL); if (!v_address) { err = -ENOBUFS; goto exit0; } err = prp_still_select(cam); if (err != 0) { err = -EIO; goto exit1; } cam->still_counter = 0; err = cam->csi_start(cam); if (err != 0) { err = -EIO; goto exit2; } if (!wait_event_interruptible_timeout(cam->still_queue, cam->still_counter != 0, 10 * HZ)) { printk(KERN_ERR "mxc_v4l_read timeout counter %x\n", cam->still_counter); err = -ETIME; goto exit2; } err = copy_to_user(buf, v_address, cam->v2f.fmt.pix.sizeimage); exit2: prp_still_deselect(cam); exit1: dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address, cam->still_buf); cam->still_buf = 0; exit0: if (cam->overlay_on == true) { start_preview(cam); } up(&cam->busy_lock); if (err < 0) return err; return (cam->v2f.fmt.pix.sizeimage - err);}#endif/*! * V4L interface - ioctl function * * @param inode struct inode * * * @param file struct file * * * @param ioctlnr unsigned int * * @param arg void * * * @return 0 success, ENODEV for invalid device instance, * -1 for other errors. */static intmxc_v4l_do_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, void *arg){ struct video_device *dev = video_devdata(file); cam_data *cam = dev->priv; int retval = 0; uint32_t lock_flags; wait_event_interruptible(cam->power_queue, cam->low_power == false); /* make this _really_ smp-safe */ if (down_interruptible(&cam->busy_lock)) return -EBUSY; switch (ioctlnr) { /*! * V4l2 VIDIOC_QUERYCAP ioctl */ case VIDIOC_QUERYCAP:{ struct v4l2_capability *cap = arg; strcpy(cap->driver, "mxc_v4l2"); cap->version = KERNEL_VERSION(0, 1, 11); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; cap->card[0] = '\0'; cap->bus_info[0] = '\0'; retval = 0; break; } /*! * V4l2 VIDIOC_G_FMT ioctl */ case VIDIOC_G_FMT:{ struct v4l2_format *gf = arg; retval = mxc_v4l2_g_fmt(cam, gf); break; } /*! * V4l2 VIDIOC_S_FMT ioctl */ case VIDIOC_S_FMT:{ struct v4l2_format *sf = arg; retval = mxc_v4l2_s_fmt(cam, sf); break; } /*! * V4l2 VIDIOC_REQBUFS ioctl */ case VIDIOC_REQBUFS:{ struct v4l2_requestbuffers *req = arg; if (req->count > FRAME_NUM) { printk(KERN_ERR "VIDIOC_REQBUFS: not enough buffer\n"); req->count = FRAME_NUM; } if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || (req->memory != V4L2_MEMORY_MMAP)) { printk(KERN_ERR "VIDIOC_REQBUFS: wrong buffer type\n"); retval = -EINVAL; break; } mxc_streamoff(cam); mxc_free_frame_buf(cam); retval = mxc_allocate_frame_buf(cam, req->count); break; } /*! * V4l2 VIDIOC_QUERYBUF ioctl */ case VIDIOC_QUERYBUF:{ struct v4l2_buffer *buf = arg; int index = buf->index; if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { printk(KERN_ERR "VIDIOC_QUERYBUFS: wrong buffer type\n"); retval = -EINVAL; break; } memset(buf, 0, sizeof(buf)); buf->index = index; down(&cam->param_lock); retval = mxc_v4l2_buffer_status(cam, buf); up(&cam->param_lock); break; } /*! * V4l2 VIDIOC_QBUF ioctl */ case VIDIOC_QBUF:{ struct v4l2_buffer *buf = arg; int index = buf->index; spin_lock_irqsave(&cam->int_lock, lock_flags); cam->frame[index].buffer.m.offset = buf->m.offset; if ((cam->frame[index].buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) { cam->frame[index].buffer.flags |= V4L2_BUF_FLAG_QUEUED; if (cam->skip_frame > 0) { list_add_tail(&cam->frame[index].queue, &cam->working_q); retval = cam->enc_update_eba(cam-> frame[index]. buffer.m.offset, &cam-> ping_pong_csi); cam->skip_frame = 0; } else { list_add_tail(&cam->frame[index].queue, &cam->ready_q); } } else if (cam->frame[index].buffer. flags & V4L2_BUF_FLAG_QUEUED) { printk(KERN_ERR "VIDIOC_QBUF: buffer already queued\n"); } else if (cam->frame[index].buffer. flags & V4L2_BUF_FLAG_DONE) { printk(KERN_ERR "VIDIOC_QBUF: overwrite done buffer.\n"); cam->frame[index].buffer.flags &= ~V4L2_BUF_FLAG_DONE; cam->frame[index].buffer.flags |= V4L2_BUF_FLAG_QUEUED; } buf->flags = cam->frame[index].buffer.flags; spin_unlock_irqrestore(&cam->int_lock, lock_flags); break; } /*! * V4l2 VIDIOC_DQBUF ioctl */ case VIDIOC_DQBUF:{ struct v4l2_buffer *buf = arg; retval = mxc_v4l_dqueue(cam, buf); break; } /*! * V4l2 VIDIOC_STREAMON ioctl */ case VIDIOC_STREAMON:{ retval = mxc_streamon(cam); break; } /*! * V4l2 VIDIOC_STREAMOFF ioctl */ case VIDIOC_STREAMOFF:{ retval = mxc_streamoff(cam); break; } /*! * V4l2 VIDIOC_G_CTRL ioctl */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -