?? mx27_v4l2_capture.c
字號:
csi_enable_mclk(CSI_MCLK_I2C, true, true); cam->cam_sensor->set_color(cam->bright, cam->saturation, cam->red, cam->green, cam->blue); csi_enable_mclk(CSI_MCLK_I2C, false, false); break; case V4L2_CID_BLACK_LEVEL: cam->ae_mode = c->value & 0x03; csi_enable_mclk(CSI_MCLK_I2C, true, true); if (cam->cam_sensor->set_ae_mode) cam->cam_sensor->set_ae_mode(cam->ae_mode); csi_enable_mclk(CSI_MCLK_I2C, false, false); break; case V4L2_CID_MXC_FLASH: break; case V4L2_CID_AUTOGAIN: cam->ae_enable = c->value; csi_enable_mclk(CSI_MCLK_I2C, true, true); if (cam->cam_sensor->set_ae) cam->cam_sensor->set_ae(cam->ae_enable); csi_enable_mclk(CSI_MCLK_I2C, false, false); break; case V4L2_CID_AUTO_WHITE_BALANCE: cam->awb_enable = c->value; csi_enable_mclk(CSI_MCLK_I2C, true, true); if (cam->cam_sensor->set_awb) cam->cam_sensor->set_awb(cam->awb_enable); csi_enable_mclk(CSI_MCLK_I2C, false, false); break; case V4L2_CID_MXC_FLICKER: cam->flicker_ctrl = c->value; csi_enable_mclk(CSI_MCLK_I2C, true, true); if (cam->cam_sensor->flicker_control) cam->cam_sensor->flicker_control(cam->flicker_ctrl); csi_enable_mclk(CSI_MCLK_I2C, false, false); 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; csi_signal_cfg_t csi_param; if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { pr_debug("mxc_v4l2_s_param invalid type\n"); return -EINVAL; } if (parm->parm.capture.timeperframe.denominator > cam->standard.frameperiod.denominator) { pr_debug("mxc_v4l2_s_param frame rate %d larger " "than standard supported %d\n", parm->parm.capture.timeperframe.denominator, cam->standard.frameperiod.denominator); return -EINVAL; } cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; csi_enable_mclk(CSI_MCLK_I2C, true, true); param = cam->cam_sensor->config (&parm->parm.capture.timeperframe.denominator, parm->parm.capture.capturemode); 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)) { pr_debug("mxc_v4l2_s_param frame un-supported capture mode\n"); return -EINVAL; } if (parm->parm.capture.capturemode == cam->streamparm.parm.capture.capturemode) { return 0; } /* 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; csi_init_interface(param->width, param->height, param->pixel_fmt, csi_param); 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; } return 0;}/*! * 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; cont: if (!wait_event_interruptible_timeout(cam->enc_queue, cam->enc_counter != 0, 10 * HZ)) { if ((dq_timeout_cnt & 0x1f) == 0) printk(KERN_ERR "mxc_v4l_dqueue timeout enc_counter %x\n", cam->enc_counter); dq_timeout_cnt++; if (cam->overflow == 1) { cam->enc_enable(cam); cam->overflow = 0; if (!list_empty(&cam->ready_q)) { frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); list_del(cam->ready_q.next); list_add_tail(&frame->queue, &cam->working_q); cam->enc_update_eba(frame->paddress, &cam->ping_pong_csi); } goto cont; } return -ETIME; } else if (signal_pending(current)) { if (dq_intr_cnt == 0) printk(KERN_ERR "mxc_v4l_dqueue() interrupt received %d\n", dq_intr_cnt); dq_intr_cnt++; if (cam->overflow == 1) { cam->enc_enable(cam); cam->overflow = 0; if (!list_empty(&cam->ready_q)) { frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); list_del(cam->ready_q.next); list_add_tail(&frame->queue, &cam->working_q); cam->enc_update_eba(frame->paddress, &cam->ping_pong_csi); } goto cont; } return -ERESTARTSYS; } if (cam->overflow == 1) { cam->enc_enable(cam); cam->overflow = 0; if (!list_empty(&cam->ready_q)) { frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); list_del(cam->ready_q.next); list_add_tail(&frame->queue, &cam->working_q); cam->enc_update_eba(frame->paddress, &cam->ping_pong_csi); } printk(KERN_INFO "mxc_v4l_dqueue - overflow\n"); } 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; return retval;}/*! * Get the current attached camera device * * @param inode struct i2c_client * * * @param int int * p_input_index * * @return 0 success, ENODEV for invalid device instance, * -1 for other errors. */static int mxc_get_video_input(cam_data * cam){ int retval = 0; csi_enable_mclk(CSI_MCLK_I2C, true, true); retval = cam->cam_sensor->get_status(); csi_enable_mclk(CSI_MCLK_I2C, false, false); 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; csi_signal_cfg_t csi_param; struct video_device *dev = video_devdata(file); cam_data *cam = dev->priv; int err = 0; dq_intr_cnt = 0; dq_timeout_cnt = 0; empty_wq_cnt = 0; if (!cam) { pr_info("Internal error, cam_data not found!\n"); return -ENODEV; } err = mxc_get_video_input(cam); if (0 != err) return -ENODEV; if (down_interruptible(&cam->busy_lock)) return -EINTR; if (signal_pending(current)) goto oops; if (cam->open_count++ == 0) { wait_event_interruptible(cam->power_queue, cam->low_power == false); err = prp_enc_select(cam); 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); 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; 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); cam->cam_sensor->get_ae_mode(&cam->ae_mode); cam->cam_sensor->get_control_params(&cam->ae_enable, &cam->awb_enable, &cam->flicker_ctrl); csi_enable_mclk(CSI_MCLK_I2C, false, false); prp_init(cam); } 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; /* for the case somebody hit the ctrl C */ if (cam->overlay_pid == current->pid) { err = stop_preview(cam); cam->overlay_on = false; } if (cam->capture_pid == current->pid) { err |= mxc_streamoff(cam); cam->capture_on = false; wake_up_interruptible(&cam->enc_queue); } if (--cam->open_count == 0) { wait_event_interruptible(cam->power_queue, cam->low_power == false); pr_debug("mxc_v4l_close: release resource\n"); err |= prp_enc_deselect(cam); mxc_free_frame_buf(cam); file->private_data = NULL; /* capture off */ wake_up_interruptible(&cam->enc_queue); mxc_free_frames(cam); cam->enc_counter++; prp_exit(cam); } return err;}#ifdef CONFIG_VIDEO_MXC_CSI_DMA#include <asm/arch/dma.h>#define CSI_DMA_STATUS_IDLE 0 /* DMA is not started */#define CSI_DMA_STATUS_WORKING 1 /* DMA is transfering the data */#define CSI_DMA_STATUS_DONE 2 /* One frame completes successfully */#define CSI_DMA_STATUS_ERROR 3 /* Error occurs during the DMA *//* * Sometimes the start of the DMA is not synchronized with the CSI * SOF (Start of Frame) interrupt which will lead to incorrect * captured image. In this case the driver will re-try capturing * another frame. The following macro defines the maximum re-try * times. */#define CSI_DMA_RETRY 8/* * Size of the physical contiguous memory area used to hold image data * transfered by DMA. It can be less than the size of the image data. */#define CSI_MEM_SIZE (1024 * 600)/* Number of bytes for one DMA transfer */#define CSI_DMA_LENGTH (1024 * 200)static int g_dma_channel = 0;static int g_dma_status = CSI_DMA_STATUS_DONE;static volatile int g_dma_completed; /* number of completed DMA transfers */static volatile int g_dma_copied; /* number of copied DMA transfers */static struct tasklet_struct g_dma_tasklet;static char *g_user_buf; /* represents the buf passed by read() */static int g_user_count; /* represents the count passed by read() *//*! * @brief setup the DMA to transfer data * There may be more than one DMA to transfer the whole image. Those * DMAs work like chain. This function is used to setup the DMA in * case there is enough space to hold the data. * @param data pointer to the cam structure */static void mxc_csi_dma_chaining(void *data){ cam_data *cam = (cam_data *) data; int count, chained = 0; int max_dma = CSI_MEM_SIZE / CSI_DMA_LENGTH; mxc_dma_requestbuf_t dma_request; while (chained * CSI_DMA_LENGTH < g_user_count) { /* * Calculate how many bytes the DMA should transfer. It may * be less than CSI_DMA_LENGTH if the DMA is the last one. */ if ((chained + 1) * CSI_DMA_LENGTH > g_user_count) count = g_user_count - chained * CSI_DMA_LENGTH; else count = CSI_DMA_LENGTH; pr_debug("%s() DMA chained count = %d\n", __FUNCTION__, count); /* Config DMA */ memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t)); dma_request.dst_addr = cam->still_buf + (chained % max_dma) * CSI_DMA_LENGTH; dma_request.src_addr = (dma_addr_t) CSI_CSIRXFIFO_PHYADDR; dma_request.num_of_bytes = count; mxc_dma_config(g_dma_channel, &dma_request, 1, MXC_DMA_MODE_READ); chained++; }}/*! * @brief Copy image data from physical contiguous memory to user space buffer * Once the data are copied, there will be more spare space in the * physical contiguous memory to receive data from DMA. * @param data pointer to the cam structure */static void mxc_csi_dma_task(unsigned long data){ cam_data *cam = (cam_data *) data; int count; int max_dma = CSI_MEM_SIZE / CSI_DMA_LENGTH; while (g_dma_copied < g_dma_completed) { /* * Calculate how many bytes the DMA has transfered. It may * be less than CSI_DMA_LENGTH if the DMA is the last one. */ if ((g_dma_copied + 1) * CSI_DMA_LENGTH > g_user_count) count = g_user_count - g_dma_copied * CSI_DMA_LENGTH; else count = CSI_DMA_LENGTH; if (copy_to_user(g_user_buf + g_dma_copied * CSI_DMA_LENGTH, cam->still_buf_vaddr + (g_dma_copied % max_dma) * CSI_DMA_LENGTH, count)) pr_debug("Warning: some bytes not copied\n"); g_dma_copied++; } /* If the whole image has been captured */ if (g_dma_copied * CSI_DMA_LENGTH >= g_user_count) { cam->still_counter++; wake_up_interruptible(&cam->still_queue); } pr_debug("%s() DMA completed = %d copied = %d\n", __FUNCTION__, g_dma_completed, g_dma_copied);}/*! * @brief DMA interrupt callback function * @param data pointer to the cam structure * @param error DMA error flag * @param count number of bytes transfered by the DMA */static void mxc_csi_dma_callback(void *data, int error, unsigned int count){ cam_data *cam = (cam_data *) data; int max_dma = CSI_MEM_SIZE / CSI_DMA_LENGTH; unsigned long lock_flags; spin_lock_irqsave(&cam->int_lock, lock_flags); g_dma_completed++; if (error != MXC_DMA_DONE) { g_dma_status = CSI_DMA_STATUS_ERROR; pr_debug("%s() DMA error\n", __FUNCTION__); } /* If the whole image has been captured */ if ((g_dma_status != CSI_DMA_STATUS_ERROR) && (g_dma_completed * CSI_DMA_LENGTH >= g_user_count)) g_dma_status = CSI_DMA_STATUS_DONE; if ((g_dma_status == CSI_DMA_STATUS_WORKING) && (g_dma_completed >= g_dma_copied + max_dma)) { g_dma_status = CSI_DMA_STATUS_ERROR; pr_debug("%s() Previous buffer over written\n", __FUNCTION__); } /* Schedule the tasklet */ tasklet_schedule(&g_dma_tasklet); spin_unlock_irqrestore(&cam->int_lock, lock_flags); pr_debug("%s() count = %d bytes\n", __FUNCTION__, count);}/*! * @brief CSI interrupt callback function * @param data pointer to the cam structure * @param status CSI interrupt status */static void mxc_csi_irq_callback(void *data, unsigned long status){ cam_data *cam = (cam_data *) data; unsigned long lock_flags; spin_lock_irqsave(&cam->int_lock, lock_flags); /* Wait for SOF (Start of Frame) interrupt to sync the image */ if (status & BIT_SOF_INT) { if (g_dma_status == CSI_DMA_STATUS_IDLE) { /* Start DMA transfer to capture image */ mxc_dma_enable(g_dma_channel); g_dma_status = CSI_DMA_STATUS_WORKING; pr_debug("%s() DMA started.\n", __FUNCTION__); } else if (g_dma_status == CSI_DMA_STATUS_WORKING) { /* * Another SOF occurs during DMA transfer. In this * case the image is not synchronized so need to * report error and probably try again. */ g_dma_status = CSI_DMA_STATUS_ERROR; pr_debug("%s() Image is not synchronized with DMA - " "SOF before DMA completes\n", __FUNCTION__); } } spin_unlock_irqrestore(&cam->int_lock, lock_flags); pr_debug("%s() g_dma_status = %d\n", __FUNCTION__, g_dma_status);}/*! * 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; struct video_device *dev = video_devdata(file); cam_data *cam = dev->priv; int retry = CSI_DMA_RETRY;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -