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

📄 mxc_v4l2_capture.c

📁 LINUX下的ov2640驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
 * * @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 + -