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

📄 mx27_v4l2_capture.c

📁 freescale mx27 的TVP5150的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (down_interruptible(&cam->busy_lock))		return -EINTR;	/* Video capture and still image capture are exclusive */	if (cam->capture_on == true) {		err = -EBUSY;		goto exit0;	}	/* The CSI-DMA can not do CSC */	if (cam->v2f.fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) {		pr_info("mxc_v4l_read support YUYV pixel format only\n");		err = -EINVAL;		goto exit0;	}	/* The CSI-DMA can not do resize or crop */	if ((cam->v2f.fmt.pix.width != cam->crop_bounds.width)	    || (cam->v2f.fmt.pix.height != cam->crop_bounds.height)) {		pr_info("mxc_v4l_read resize is not supported\n");		pr_info("supported image size width = %d height = %d\n",			cam->crop_bounds.width, cam->crop_bounds.height);		err = -EINVAL;		goto exit0;	}	if ((cam->crop_current.left != cam->crop_bounds.left)	    || (cam->crop_current.width != cam->crop_bounds.width)	    || (cam->crop_current.top != cam->crop_bounds.top)	    || (cam->crop_current.height != cam->crop_bounds.height)) {		pr_info("mxc_v4l_read cropping is not supported\n");		err = -EINVAL;		goto exit0;	}	cam->still_buf_vaddr = dma_alloc_coherent(0,						  PAGE_ALIGN(CSI_MEM_SIZE),						  &cam->still_buf,						  GFP_DMA | GFP_KERNEL);	if (!cam->still_buf_vaddr) {		pr_info("mxc_v4l_read failed at allocate still_buf\n");		err = -ENOBUFS;		goto exit0;	}	/* Initialize DMA */	g_dma_channel = mxc_dma_request(MXC_DMA_CSI_RX, "CSI RX DMA");	if (g_dma_channel < 0) {		pr_debug("mxc_v4l_read failed to request DMA channel\n");		err = -EIO;		goto exit1;	}	err = mxc_dma_callback_set(g_dma_channel,				   (mxc_dma_callback_t) mxc_csi_dma_callback,				   (void *)cam);	if (err != 0) {		pr_debug("mxc_v4l_read failed to set DMA callback\n");		err = -EIO;		goto exit2;	}	g_user_buf = buf;	if (cam->v2f.fmt.pix.sizeimage < count)		g_user_count = cam->v2f.fmt.pix.sizeimage;	else		g_user_count = count & ~0x3;	tasklet_init(&g_dma_tasklet, mxc_csi_dma_task, (unsigned long)cam);	g_dma_status = CSI_DMA_STATUS_DONE;	csi_set_callback(mxc_csi_irq_callback, cam);	csi_enable_prpif(0);	/* clear current SOF first */	csi_clear_status(BIT_SOF_INT);	csi_enable_mclk(CSI_MCLK_RAW, true, true);	do {		g_dma_completed = g_dma_copied = 0;		mxc_csi_dma_chaining(cam);		cam->still_counter = 0;		g_dma_status = CSI_DMA_STATUS_IDLE;		if (!wait_event_interruptible_timeout(cam->still_queue,						      cam->still_counter != 0,						      10 * HZ)) {			pr_info("mxc_v4l_read timeout counter %x\n",				cam->still_counter);			err = -ETIME;			goto exit3;		}		if (g_dma_status == CSI_DMA_STATUS_DONE)			break;		if (retry-- == 0)			break;		pr_debug("Now retry image capture\n");	} while (1);	if (g_dma_status != CSI_DMA_STATUS_DONE)		err = -EIO;      exit3:	csi_enable_prpif(1);	g_dma_status = CSI_DMA_STATUS_DONE;	csi_set_callback(0, 0);	csi_enable_mclk(CSI_MCLK_RAW, false, false);	tasklet_kill(&g_dma_tasklet);      exit2:	mxc_dma_free(g_dma_channel);      exit1:	dma_free_coherent(0, PAGE_ALIGN(CSI_MEM_SIZE),			  cam->still_buf_vaddr, cam->still_buf);	cam->still_buf = 0;      exit0:	up(&cam->busy_lock);	if (err < 0)		return err;	else		return g_user_count;}#else/*! * 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;	/* Video capture and still image capture are exclusive */	if (cam->capture_on == true) {		err = -EBUSY;		goto exit0;	}	v_address = dma_alloc_coherent(0,				       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),				       &cam->still_buf, GFP_DMA | GFP_KERNEL);	if (!v_address) {		pr_info("mxc_v4l_read failed at allocate still_buf\n");		err = -ENOBUFS;		goto exit0;	}	if (prp_still_select(cam)) {		err = -EIO;		goto exit1;	}	cam->still_counter = 0;	if (cam->csi_start(cam)) {		err = -EIO;		goto exit2;	}	if (!wait_event_interruptible_timeout(cam->still_queue,					      cam->still_counter != 0,					      10 * HZ)) {		pr_info("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:	up(&cam->busy_lock);	if (err < 0)		return err;	else		return (cam->v2f.fmt.pix.sizeimage - err);}#endif				/* CONFIG_VIDEO_MXC_CSI_DMA *//*! * 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;	unsigned long lock_flags;	if (!cam)		return -EBADF;	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) {				pr_info("VIDIOC_REQBUFS: not enough buffer\n");				req->count = FRAME_NUM;			}			if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||			    (req->memory != V4L2_MEMORY_MMAP)) {				pr_debug("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) {				pr_debug				    ("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;			int overflow = 0;			pr_debug("VIDIOC_QBUF: %d\n", buf->index);			if (cam->overflow == 1) {				cam->enc_enable(cam);				cam->overflow = 0;				overflow = 1;				printk(KERN_INFO "VIDIOC_QBUF - overflow\n");			}			spin_lock_irqsave(&cam->int_lock, lock_flags);			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) || (overflow == 1)) {					list_add_tail(&cam->frame[index].queue,						      &cam->working_q);					retval =					    cam->enc_update_eba(cam->								frame[index].								paddress,								&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) {				pr_debug				    ("VIDIOC_QBUF: buffer already queued\n");			} else if (cam->frame[index].buffer.				   flags & V4L2_BUF_FLAG_DONE) {				pr_debug				    ("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:{			cam->capture_on = true;			retval = mxc_streamon(cam);			break;		}		/*!		 * V4l2 VIDIOC_STREAMOFF ioctl		 */	case VIDIOC_STREAMOFF:{			retval = mxc_streamoff(cam);			cam->capture_on = false;			break;		}		/*!		 * V4l2 VIDIOC_G_CTRL ioctl		 */	case VIDIOC_G_CTRL:{			retval = mxc_get_v42l_control(cam, arg);			break;		}		/*!		 * V4l2 VIDIOC_S_CTRL ioctl		 */	case VIDIOC_S_CTRL:{			retval = mxc_set_v42l_control(cam, arg);			break;		}		/*!		 * V4l2 VIDIOC_CROPCAP ioctl		 */	case VIDIOC_CROPCAP:{			struct v4l2_cropcap *cap = arg;			if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&			    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {				retval = -EINVAL;				break;			}			cap->bounds = cam->crop_bounds;			cap->defrect = cam->crop_defrect;			break;		}		/*!		 * V4l2 VIDIOC_G_CROP ioctl		 */	case VIDIOC_G_CROP:{			struct v4l2_crop *crop = arg;			if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&			    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {				retval = -EINVAL;				break;			}			crop->c = cam->crop_current;			break;		}		/*!		 * V4l2 VIDIOC_S_CROP ioctl		 */	case VIDIOC_S_CROP:{			struct v4l2_crop *crop = arg;			struct v4l2_rect *b = &cam->crop_bounds;			int i;			if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&			    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {				retval = -EINVAL;				break;			}			crop->c.top = (crop->c.top < b->top) ? b->top			    : crop->c.top;			if (crop->c.top > b->top + b->height)				crop->c.top = b->top + b->height - 1;			if (crop->c.height > b->top + b->height - crop->c.top)				crop->c.height =				    b->top + b->height - crop->c.top;			crop->c.left = (crop->c.left < b->left) ? b->left			    : crop->c.left;			if (crop->c.left > b->left + b->width)				crop->c.left = b->left + b->width - 1;			if (crop->c.width > b->left - crop->c.left + b->width)				crop->c.width =				    b->left - crop->c.left + b->width;			crop->c.width &= ~0x1;			/*			 * MX27 PrP limitation:			 * The right spare space (CSI_FRAME_X_SIZE			 *  - SOURCE_LINE_STRIDE - PICTURE_X_SIZE)) must be			 * multiple of 32.			 * So we tune the crop->c.left value to the closest			 * desired cropping value and meet the PrP requirement.			 */			i = ((b->left + b->width)			     - (crop->c.left + crop->c.width)) % 32;			if (i <= 16) {				if (crop->c.left + crop->c.width + i				    <= b->left + b->width)					crop->c.left += i;				else if (crop->c.left - (32 - i) >= b->left)					crop->c.left -= 32 - i;				else {					retval = -EINVAL;					break;				}			} else {				if (crop->c.left - (32 - i) >= b->left)					crop->c.left -= 32 - i;				else if (crop->c.left + crop->c.width + i					 <= b->left + b->width)					crop->c.left += i;				else {					retval = -EINVAL;					break;				}			}			cam->crop_current = crop->c;			break;		}		/*!		 * V4l2 VIDIOC_OVERLAY ioctl		 */	case VIDIOC_OVERLAY:{			int *on = arg;			if (*on) {				cam->overlay_on = true;				retval = start_preview(cam);			}			if (!*on) {				retval = stop_preview(cam);				cam->overlay_on = false;			}			break;		}		/*!		 * V4l2 VIDIOC_G_FBUF ioctl		 */	case VIDIOC_G_FBUF:{			struct v4l2_framebuffer *fb = arg;			struct fb_var_screeninfo *var;			if (cam->output >= num_registered_fb) {				retval = -EINVAL;				break;			}			var = &registered_fb[cam->output]->var;			cam->v4l2_fb.fmt.width = var->xres;			cam->v4l2_fb.fmt.height = var->yres;			cam->v4l2_fb.fmt.bytesperline =			    var->xres_virtual * var->bits_per_pixel;			cam->v4l2_fb.fmt.colorspace = V4L2_COLORSPACE_SRGB;			*fb = cam->v4l2_fb;			break;		}		/*!		 * V4l2 VIDIOC_S_FBUF ioctl		 */

⌨️ 快捷键说明

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