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

📄 mxc_v4l2_capture.c

📁 LINUX下的ov2640驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. *//* * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html *//*! * @file drivers/media/video/mxc/capture/mxc_v4l2_capture.c * * @brief Mxc Video For Linux 2 driver * * @ingroup MXC_V4L2_CAPTURE */#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/ctype.h>#include <asm/io.h>#include <asm/semaphore.h>#include <linux/pagemap.h>#include <linux/vmalloc.h>#include <linux/types.h>#include <linux/fb.h>#include <linux/dma-mapping.h>#include <asm/arch/mxcfb.h>#include "mxc_v4l2_capture.h"#include "ipu_prp_sw.h"static int csi_mclk_flag_backup;static int video_nr = -1;static cam_data *g_cam;#define MXC_V4L2_CAPTURE_NUM_OUTPUTS        2static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = {	{	 .index = 0,	 .name = "DISP3",	 .type = V4L2_OUTPUT_TYPE_ANALOG,	 .audioset = 0,	 .modulator = 0,	 .std = V4L2_STD_UNKNOWN,	 },	{	 .index = 1,	 .name = "DISP0",	 .type = V4L2_OUTPUT_TYPE_ANALOG,	 .audioset = 0,	 .modulator = 0,	 .std = V4L2_STD_UNKNOWN,	 }};/*! * Free frame buffers * * @param cam      Structure cam_data * * * @return status  0 success. */static int mxc_free_frame_buf(cam_data * cam){	int i;	for (i = 0; i < FRAME_NUM; i++) {		if (cam->frame[i].vaddress != 0) {			dma_free_coherent(0, cam->frame[i].buffer.length,					  cam->frame[i].vaddress,					  cam->frame[i].paddress);			cam->frame[i].vaddress = 0;		}	}	return 0;}/*! * Allocate frame buffers * * @param cam      Structure cam_data * * * @param count    int number of buffer need to allocated * * @return status  -0 Successfully allocated a buffer, -ENOBUFS	failed. */static int mxc_allocate_frame_buf(cam_data * cam, int count){	int i;	for (i = 0; i < count; i++) {		cam->frame[i].vaddress =		    dma_alloc_coherent(0,				       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),				       &cam->frame[i].paddress,				       GFP_DMA | GFP_KERNEL);		if (cam->frame[i].vaddress == 0) {			printk(KERN_ERR "mxc_allocate_frame_buf failed.\n");			mxc_free_frame_buf(cam);			return -ENOBUFS;		}		cam->frame[i].buffer.index = i;		cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;		cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		cam->frame[i].buffer.length =		    PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);		cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP;		cam->frame[i].buffer.m.offset = cam->frame[i].paddress;		cam->frame[i].index = i;	}	return 0;}/*! * Free frame buffers status * * @param cam    Structure cam_data * * * @return none */static void mxc_free_frames(cam_data * cam){	int i;	for (i = 0; i < FRAME_NUM; i++) {		cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;	}	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);}/*! * Return the buffer status * * @param cam 	   Structure cam_data * * @param buf      Structure v4l2_buffer * * * @return status  0 success, EINVAL failed. */static int mxc_v4l2_buffer_status(cam_data * cam, struct v4l2_buffer *buf){	if (buf->index < 0 || buf->index >= FRAME_NUM) {		printk(KERN_ERR		       "mxc_v4l2_buffer_status buffers not allocated\n");		return -EINVAL;	}	memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf));	return 0;}/*! * start the encoder job * * @param cam      structure cam_data * * * @return status  0 Success */static int mxc_streamon(cam_data * cam){	struct mxc_v4l_frame *frame;	int err = 0;	if (list_empty(&cam->ready_q)) {		printk(KERN_ERR "mxc_streamon buffer not been queued yet\n");		return -EINVAL;	}	cam->capture_pid = current->pid;	if (cam->enc_enable) {		err = cam->enc_enable(cam);		if (err != 0) {			return err;		}	}	cam->ping_pong_csi = 0;	if (cam->enc_update_eba) {		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);		err =		    cam->enc_update_eba(frame->buffer.m.offset,					&cam->ping_pong_csi);		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);		err |=		    cam->enc_update_eba(frame->buffer.m.offset,					&cam->ping_pong_csi);	} else {		return -EINVAL;	}	cam->capture_on = true;	return err;}/*! * Shut down the encoder job * * @param cam      structure cam_data * * * @return status  0 Success */static int mxc_streamoff(cam_data * cam){	int err = 0;	if (cam->capture_on == false)		return 0;	if (cam->enc_disable) {		err = cam->enc_disable(cam);	}	mxc_free_frames(cam);	cam->capture_on = false;	return err;}/*! * Valid whether the palette is supported * * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32 * * @return 0 if failed */static inline int valid_mode(u32 palette){	return ((palette == V4L2_PIX_FMT_RGB565) ||		(palette == V4L2_PIX_FMT_BGR24) ||		(palette == V4L2_PIX_FMT_RGB24) ||		(palette == V4L2_PIX_FMT_BGR32) ||		(palette == V4L2_PIX_FMT_RGB32) ||		(palette == V4L2_PIX_FMT_YUV422P) ||		(palette == V4L2_PIX_FMT_UYVY) ||		(palette == V4L2_PIX_FMT_YUV420));}/*! * Valid and adjust the overlay window size, position * * @param cam      structure cam_data * * @param win      struct v4l2_window  * * * @return 0 */static int verify_preview(cam_data * cam, struct v4l2_window *win){	int i = 0;	int *width, *height;	do {		cam->overlay_fb = (struct fb_info *)registered_fb[i];		if (cam->overlay_fb == NULL) {			printk(KERN_ERR "verify_preview No matched.\n");			return -1;		}		if (strncmp(cam->overlay_fb->fix.id,			    mxc_capture_outputs[cam->output].name, 5) == 0) {			break;		}	} while (++i < FB_MAX);	/* 4 bytes alignment for both FG and BG */	if (cam->overlay_fb->var.bits_per_pixel == 24) {		win->w.left -= win->w.left % 4;	} else if (cam->overlay_fb->var.bits_per_pixel == 16) {		win->w.left -= win->w.left % 2;	}	if (win->w.width + win->w.left > cam->overlay_fb->var.xres)		win->w.width = cam->overlay_fb->var.xres - win->w.left;	if (win->w.height + win->w.top > cam->overlay_fb->var.yres)		win->w.height = cam->overlay_fb->var.yres - win->w.top;	/* stride line limitation */	win->w.height -= win->w.height % 8;	win->w.width -= win->w.width % 8;	if (cam->rotation >= IPU_ROTATE_90_RIGHT) {		height = &win->w.width;		width = &win->w.height;	} else {		width = &win->w.width;		height = &win->w.height;	}	if ((cam->crop_bounds.width / *width > 8) ||	    ((cam->crop_bounds.width / *width == 8) &&	     (cam->crop_bounds.width % *width))) {		*width = cam->crop_bounds.width / 8;		if (*width % 8)			*width += 8 - *width % 8;		if (*width + win->w.left > cam->overlay_fb->var.xres) {			printk(KERN_ERR "width exceed resize limit.\n");			return -1;		}		printk(KERN_ERR "width exceed limit resize to %d.\n", *width);	}	if ((cam->crop_bounds.height / *height > 8) ||	    ((cam->crop_bounds.height / *height == 8) &&	     (cam->crop_bounds.height % *height))) {		*height = cam->crop_bounds.height / 8;		if (*height % 8)			*height += 8 - *height % 8;		if (*height + win->w.top > cam->overlay_fb->var.yres) {			printk(KERN_ERR "height exceed resize limit.\n");			return -1;		}		printk(KERN_ERR "height exceed limit resize to %d.\n", *height);	}	return 0;}/*! * start the viewfinder job * * @param cam      structure cam_data * * * @return status  0 Success */static int start_preview(cam_data * cam){	int err = 0;#if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE)	if (cam->output == 0) {		if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)#if defined(CONFIG_FB_MXC_OVERLAY)			return -1;#else			err = prp_vf_sdc_select(cam);#endif		else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)			err = prp_vf_sdc_select_bg(cam);		if (err != 0)			return err;		err = cam->vf_start_sdc(cam);	}#endif#if defined(CONFIG_MXC_IPU_PRP_VF_ADC) || defined(CONFIG_MXC_IPU_PRP_VF_ADC_MODULE)	if (cam->output == 1) {		err = prp_vf_adc_select(cam);		if (err != 0)			return err;		err = cam->vf_start_adc(cam);	}#endif	return err;}/*! * shut down the viewfinder job * * @param cam      structure cam_data * * * @return status  0 Success */static int stop_preview(cam_data * cam){	int err = 0;#if defined(CONFIG_MXC_IPU_PRP_VF_ADC) || defined(CONFIG_MXC_IPU_PRP_VF_ADC_MODULE)	if (cam->output == 1) {		err = prp_vf_adc_deselect(cam);	}#endif#if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE)	if (cam->output == 0) {		if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)#if defined(CONFIG_FB_MXC_OVERLAY)			return -1;#else			err = prp_vf_sdc_deselect(cam);#endif		else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)			err = prp_vf_sdc_deselect_bg(cam);	}#endif	return err;}/*! * V4L2 - mxc_v4l2_g_fmt function * * @param cam         structure cam_data * * * @param f           structure v4l2_format * * * @return  status    0 success, EINVAL failed */static int mxc_v4l2_g_fmt(cam_data * cam, struct v4l2_format *f){	int retval = 0;	switch (f->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		f->fmt.pix = cam->v2f.fmt.pix;		retval = 0;		break;	case V4L2_BUF_TYPE_VIDEO_OVERLAY:		f->fmt.win = cam->win;		break;	default:		retval = -EINVAL;	}	return retval;}/*! * V4L2 - mxc_v4l2_s_fmt function * * @param cam         structure cam_data * * * @param f           structure v4l2_format * * * @return  status    0 success, EINVAL failed */static int mxc_v4l2_s_fmt(cam_data * cam, struct v4l2_format *f){	int retval = 0;	int size = 0;	int bytesperline = 0;	int *width, *height;	switch (f->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		if (!valid_mode(f->fmt.pix.pixelformat)) {			printk(KERN_ERR			       "mxc_v4l2_s_fmt: format not supported\n");			return -EINVAL;		}		if (cam->rotation >= IPU_ROTATE_90_RIGHT) {			height = &f->fmt.pix.width;			width = &f->fmt.pix.height;		} else {			width = &f->fmt.pix.width;			height = &f->fmt.pix.height;		}		/* stride line limitation */		*width -= *width % 8;		*height -= *height % 8;		if ((cam->crop_bounds.width / *width > 8) ||		    ((cam->crop_bounds.width / *width == 8) &&		     (cam->crop_bounds.width % *width))) {			*width = cam->crop_bounds.width / 8;			if (*width % 8)				*width += 8 - *width % 8;			printk(KERN_ERR "width exceed limit resize to %d.\n",			       *width);		}		if ((cam->crop_bounds.height / *height > 8) ||		    ((cam->crop_bounds.height / *height == 8) &&		     (cam->crop_bounds.height % *height))) {			*height = cam->crop_bounds.height / 8;			if (*height % 8)				*height += 8 - *height % 8;			printk(KERN_ERR "height exceed limit resize to %d.\n",			       *height);		}		switch (f->fmt.pix.pixelformat) {		case V4L2_PIX_FMT_RGB565:			size = f->fmt.pix.width * f->fmt.pix.height * 2;			bytesperline = f->fmt.pix.width * 2;			break;		case V4L2_PIX_FMT_BGR24:			size = f->fmt.pix.width * f->fmt.pix.height * 3;			bytesperline = f->fmt.pix.width * 3;			break;		case V4L2_PIX_FMT_RGB24:			size = f->fmt.pix.width * f->fmt.pix.height * 3;			bytesperline = f->fmt.pix.width * 3;			break;		case V4L2_PIX_FMT_BGR32:			size = f->fmt.pix.width * f->fmt.pix.height * 4;			bytesperline = f->fmt.pix.width * 4;			break;		case V4L2_PIX_FMT_RGB32:			size = f->fmt.pix.width * f->fmt.pix.height * 4;			bytesperline = f->fmt.pix.width * 4;			break;		case V4L2_PIX_FMT_YUV422P:			size = f->fmt.pix.width * f->fmt.pix.height * 2;			bytesperline = f->fmt.pix.width;			break;		case V4L2_PIX_FMT_UYVY:			size = f->fmt.pix.width * f->fmt.pix.height * 2;			bytesperline = f->fmt.pix.width * 2;			break;		case V4L2_PIX_FMT_YUV420:			size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;			bytesperline = f->fmt.pix.width;			break;		default:			break;		}		if (f->fmt.pix.bytesperline < bytesperline) {			f->fmt.pix.bytesperline = bytesperline;		} else {			bytesperline = f->fmt.pix.bytesperline;		}		if (f->fmt.pix.sizeimage < size) {			f->fmt.pix.sizeimage = size;		} else {			size = f->fmt.pix.sizeimage;		}		cam->v2f.fmt.pix = f->fmt.pix;		copy_from_user(&cam->offset, (void *)cam->v2f.fmt.pix.priv,			       sizeof(cam->offset));		retval = 0;		break;	case V4L2_BUF_TYPE_VIDEO_OVERLAY:		retval = verify_preview(cam, &f->fmt.win);		cam->win = f->fmt.win;		break;	default:		retval = -EINVAL;	}	return retval;}/*! * get control param * * @param cam         structure cam_data * * * @param c           structure v4l2_control * * * @return  status    0 success, EINVAL failed */static int mxc_get_v42l_control(cam_data * cam, struct v4l2_control *c){	int status = 0;	switch (c->id) {	case V4L2_CID_HFLIP:		if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)			c->value = 1;		break;	case V4L2_CID_VFLIP:		if (cam->rotation == IPU_ROTATE_VERT_FLIP)			c->value = 1;		break;	case V4L2_CID_MXC_ROT:		c->value = cam->rotation;		break;	case V4L2_CID_BRIGHTNESS:		c->value = cam->bright;		break;	case V4L2_CID_HUE:		c->value = cam->hue;		break;	case V4L2_CID_CONTRAST:		c->value = cam->contrast;		break;	case V4L2_CID_SATURATION:		c->value = cam->saturation;		break;	case V4L2_CID_RED_BALANCE:		c->value = cam->red;		break;	case V4L2_CID_BLUE_BALANCE:		c->value = cam->blue;		break;	case V4L2_CID_BLACK_LEVEL:		c->value = cam->ae_mode;		break;	default:		status = -EINVAL;	}	return status;}/*! * V4L2 - set_control function *          V4L2_CID_PRIVATE_BASE is the extention for IPU preprocessing. *          0 for normal operation *          1 for vertical flip *          2 for horizontal flip *          3 for horizontal and vertical flip *          4 for 90 degree rotation * @param cam         structure cam_data * * * @param c           structure v4l2_control *

⌨️ 快捷键说明

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