⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mx27_v4l2_capture.c

📁 freescale mx27 的TVP5150的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		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;	do_gettimeofday(&buf->timestamp);		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;	g_user_buf = buf;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -