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

📄 zc0301_v4l2.c

📁 在LINUX下编译的摄像头驱动源码,有MAKE文件
💻 C
字号:
/*	This file contains operations about V4L2 spec * *	The most effective way to understand V4L2 spec is read manual carefully more and more * *	It's created by WE.XCC at 2008.05.06 *
 *	Author's E-mail:84318391@163.com
 * */#include <linux/fs.h>#include <linux/version.h>#include <linux/errno.h>#include <linux/module.h>#include <asm/uaccess.h>#include "zc0301_struct.h"#include "zc0301_debug.h"int zc0301_request_buffers(struct zc0301_device *cam, u32 count){	void *buff = NULL;	const unsigned int imagesize = 640 * 480 * 8 / 8;	u32 i = 0;	if (cam == NULL)	{		debug_error("zc0301_request_buffers:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (count > ZC0301_MAX_FRAMES)		count = ZC0301_MAX_FRAMES;	cam->nbuffers = count;	buff = vmalloc_32_user(cam->nbuffers * PAGE_ALIGN(imagesize));	for (i = 0; i < cam->nbuffers; i++)	{		cam->frame[i].bufmem        = buff + i * PAGE_ALIGN(imagesize);		cam->frame[i].buf.index     = i;		cam->frame[i].buf.type      = V4L2_BUF_TYPE_VIDEO_CAPTURE;		cam->frame[i].buf.bytesused = 0;		cam->frame[i].buf.field     = V4L2_FIELD_NONE;		cam->frame[i].buf.sequence  = 0;		cam->frame[i].buf.memory    = V4L2_MEMORY_MMAP;		cam->frame[i].buf.m.offset  = i * PAGE_ALIGN(imagesize);		cam->frame[i].buf.length    = imagesize;		cam->frame[i].buf.flags     = 0;	}	return cam->nbuffers;}/*************************************************************/int zc0301_vidioc_querycap(struct zc0301_device *cam, void __user *arg){	u8 i = 0;	struct v4l2_capability cap;		if (cam == NULL)	{		debug_error("zc0301_vidioc_querycap:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	strlcpy(cap.driver, "webcam", sizeof(cap.driver));	strlcpy(cap.card, "zc0301[P] PC webcam", sizeof(cap.card));	cap.bus_info[0] = 0;	cap.version = KERNEL_VERSION(0, 9, 0);	cap.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;	for (i = 0; i < ARRAY_SIZE(cap.reserved); i++)		cap.reserved[i] = 0;	if (copy_to_user(arg, &cap, sizeof(struct v4l2_capability)))		return -EFAULT;	return 0;}int zc0301_vidioc_enuminput(struct zc0301_device *cam, void __user *arg){	struct v4l2_input i;	if (cam == NULL)	{		debug_error("zc0301_vidioc_enuminput:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&i, arg, sizeof(struct v4l2_input)))		return -EFAULT;	if (i.index)	{		debug_error("zc0301_vidioc_enuminput:index must begin from zero\n");		return -EINVAL;	}	memset(&i, 0, sizeof(struct v4l2_input));	strlcpy(i.name, "zc0301_camera", sizeof(i.name));	i.type = V4L2_INPUT_TYPE_CAMERA;	if (copy_to_user(arg, &i, sizeof(struct v4l2_input)))		return -EFAULT;	return 0;}int zc0301_vidioc_g_input(struct zc0301_device *cam, void __user *arg){	int index = 0;	if (cam == NULL)	{		debug_error("zc0301_vidioc_g_input:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&index, arg, sizeof(int)))		return -EFAULT;	if (index)	{		debug_error("zc0301_vidioc_g_input:index should be zero\n");		return -EINVAL;	}	if (copy_to_user(arg, &index, sizeof(int)))		return -EFAULT;	return 0;}int zc0301_vidioc_s_input(struct zc0301_device *cam, void __user *arg){	int index = 0;	if (cam == NULL)	{		debug_error("zc0301_vidioc_s_input:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&index, arg, sizeof(int)))		return -EFAULT;	if (index)	{		debug_error("zc0301_vidioc_s_input:index should be zero\n");		return -EFAULT;	}	if (copy_to_user(arg, &index, sizeof(int)))		return -EFAULT;	return 0;}int zc0301_vidioc_query_ctrl(struct zc0301_device *cam, void __user *arg){	//debug_param("%s\n", __FUNCTION__);	return -EINVAL;}int zc0301_vidioc_g_fmt(struct zc0301_device *cam, void __user *arg){	struct v4l2_format format;	if (cam == NULL)	{		debug_error("zc0301_vidioc_g_fmt:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&format, arg, sizeof(struct v4l2_format)))		return -EFAULT;	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	format.fmt.pix.width = 640;	format.fmt.pix.height = 480;	format.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;	format.fmt.pix.field = V4L2_FIELD_NONE;	format.fmt.pix.bytesperline = 0;	format.fmt.pix.sizeimage = 640 * 480 * 8 / 8;	format.fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;	format.fmt.pix.priv = 8;	if (copy_to_user(arg, &format, sizeof(struct v4l2_format)))		return -EFAULT;	return 0;}int zc0301_vidioc_s_fmt(struct zc0301_device *cam, void __user *arg){	struct v4l2_format format;	if (cam == NULL)	{		debug_error("zc0301_vidioc_s_fmt:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&format, arg, sizeof(struct v4l2_format)))		return -EFAULT;	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	format.fmt.pix.width = 640;	format.fmt.pix.height = 480;	format.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;	format.fmt.pix.field = V4L2_FIELD_NONE;	format.fmt.pix.bytesperline = 0;	format.fmt.pix.sizeimage = 640 * 480 * 8 / 8;	format.fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;	format.fmt.pix.priv = 8;	if (copy_to_user(arg, &format, sizeof(struct v4l2_format)))		return -EFAULT;	return 0;}int zc0301_vidioc_reqbufs(struct zc0301_device *cam, void __user *arg){	struct v4l2_requestbuffers rb;	u8 i = 0;	if (cam == NULL)	{		debug_error("zc0301_vidioc_reqbufs:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&rb, arg, sizeof(struct v4l2_requestbuffers)))		return -EFAULT;	if ((rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || (rb.memory != V4L2_MEMORY_MMAP))	{		debug_error("zc0301_vidioc_reqbufs:type or memory is wrong\n");		return -EINVAL;	}	//before alloc buffers, should check whether there is a vma still mmaped.	//if some one still mmaped, operation will fail.	//But here, I didn't add check function.	if (rb.count == 0)	{		debug_error("zc0301_vidioc_reqbufs:count must > 0\n");		return -EINVAL;	}	rb.count = zc0301_request_buffers(cam, rb.count);	for (i = 0; i < ARRAY_SIZE(rb.reserved); i++)		rb.reserved[i] = 0;	if (copy_to_user(arg, &rb, sizeof(struct v4l2_requestbuffers)))		return -EFAULT;	return 0;}int zc0301_vidioc_querybuf(struct zc0301_device *cam, void __user *arg){	struct v4l2_buffer b;	struct zc0301_frame *f = NULL;		if (cam == NULL)	{		debug_error("zc0301_vidioc_querybuf:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&b, arg, sizeof(struct v4l2_buffer)))		return -EFAULT;	if ((b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || (b.index >= cam->nbuffers))	{		if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)			debug_error("zc0301_vidioc_querybuf:type is wrong\n");		else			debug_error("zc0301_vidioc_querybuf:index is wrong\n");		return -EINVAL;	}	f = &cam->frame[b.index];	memcpy(&b, &cam->frame[b.index].buf, sizeof(struct v4l2_buffer));	if (f->f_state == F_DONE)		b.flags |= V4L2_BUF_FLAG_DONE;	if (f->f_state == F_QUEUED)		b.flags |= V4L2_BUF_FLAG_QUEUED;	b.flags |= V4L2_BUF_FLAG_MAPPED;	if (copy_to_user(arg, &b, sizeof(struct v4l2_buffer)))		return -EFAULT;	return 0;}int zc0301_vidioc_qbuf(struct zc0301_device *cam, void __user *arg){	struct v4l2_buffer b;	unsigned long lock_flags = 0;	if (cam == NULL)	{		debug_error("zc0301_vidioc_qbuf:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&b, arg, sizeof(struct v4l2_buffer)))		return -EFAULT;	if ((b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || (b.index >= cam->nbuffers)	    || (b.memory != V4L2_MEMORY_MMAP))	{		debug_error("zc0301_vidioc_qbuf:type or index or memory is wrong\n");		return -EINVAL;	}	if (cam->frame[b.index].f_state != F_UNUSED)	{		debug_error("zc0301_vidioc_qbuf:buffer queued into inqueue must be UNUSED!\n");		return -EINVAL;	}	cam->frame[b.index].f_state = F_QUEUED;	spin_lock_irqsave(&cam->queue_lock, lock_flags);	list_add_tail(&cam->frame[b.index].queue, &cam->inqueue);	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);	b.flags |= V4L2_BUF_FLAG_QUEUED;	b.flags &= ~V4L2_BUF_FLAG_DONE;	if (copy_to_user(arg, &b, sizeof(struct v4l2_buffer)))		return -EFAULT;	return 0;}int zc0301_vidioc_dqbuf(struct zc0301_device *cam, struct file *filp, void __user *arg){	struct v4l2_buffer b;	struct zc0301_frame *f = NULL;	unsigned long lock_flags = 0;	long timeout = 0;	if ((cam == NULL) || (filp == NULL))	{		debug_error("zc0301_vidioc_dqbuf:cam or filp is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&b, arg, sizeof(struct v4l2_buffer)))		return -EFAULT;	if ((b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || (b.memory != V4L2_MEMORY_MMAP))	{		debug_error("zc0301_vidioc_dqbuf:type or memory is wrong\n");		return -EINVAL;	}	if (list_empty(&cam->outqueue))	{		//if (cam->s_state == STREAM_OFF)		//{		//	debug_info("stream's state is STREAM_OFF in dqbuf\n");		//	return -EINVAL;		//}		if (filp->f_flags & O_NONBLOCK)		{			debug_info("zc0301_vidioc_dqbuf:this operation will non block\n");			return -EAGAIN;		}		timeout = wait_event_interruptible_timeout(cam->wait_frame,			!list_empty(&cam->outqueue) || cam->d_state & DISCONNECTED, 2000);	}	spin_lock_irqsave(&cam->queue_lock, lock_flags);	f = list_entry(cam->outqueue.next, struct zc0301_frame, queue);	list_del(cam->outqueue.next);	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);	f->f_state = F_UNUSED;	memcpy(&b, &f->buf, sizeof(struct v4l2_buffer));	b.flags |= V4L2_BUF_FLAG_MAPPED;	b.flags &= ~V4L2_BUF_FLAG_DONE;	b.flags &= ~V4L2_BUF_FLAG_QUEUED;	if (copy_to_user(arg, &b, sizeof(struct v4l2_buffer)))		return -EFAULT;	return 0;}int zc0301_vidioc_streamon(struct zc0301_device *cam, void __user *arg){	int type = 0;	if (cam == NULL)	{		debug_error("zc0301_vidioc_streamon:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&type, arg, sizeof(int)))		return -EFAULT;	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)	{		debug_error("zc0301_vidioc_streamon:type is wrong\n");		return -EINVAL;	}	if (list_empty(&cam->inqueue))	{		debug_error("zc0301_vidioc_streamon:inqueue cann't be empty\n");		return -EINVAL;	}	cam->s_state = STREAM_ON;	if (copy_to_user(arg, &type, sizeof(int)))		return -EFAULT;	return 0;}int zc0301_vidioc_streamoff(struct zc0301_device *cam, void __user *arg){	int type = 0;	if (cam == NULL)	{		debug_error("zc0301_vidioc_streamoff:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&type, arg, sizeof(int)))		return -EFAULT;	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)	{		debug_error("zc0301_vidioc_streamoff:type is wrong\n");		return -EINVAL;	}	cam->s_state = STREAM_OFF;	INIT_LIST_HEAD(&cam->inqueue);	INIT_LIST_HEAD(&cam->outqueue);	if (copy_to_user(arg, &type, sizeof(int)))		return -EFAULT;	return 0;}int zc0301_vidioc_g_parm(struct zc0301_device *cam, void __user *arg){	struct v4l2_streamparm sp;	if (cam == NULL)	{		debug_error("zc0301_vidioc_g_parm:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&sp, arg, sizeof(struct v4l2_streamparm)))		return -EFAULT;	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)	{		debug_error("zc0301_vidioc_g_parm:type is wrong\n");		return -EINVAL;	}	sp.parm.capture.extendedmode = 0;	if (copy_to_user(arg, &sp, sizeof(struct v4l2_streamparm)))		return -EFAULT;	return 0;}int zc0301_vidioc_s_parm(struct zc0301_device *cam, void __user *arg){	struct v4l2_streamparm sp;	if (cam == NULL)	{		debug_error("zc0301_vidioc_s_parm:cam is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	if (copy_from_user(&sp, arg, sizeof(struct v4l2_streamparm)))		return -EFAULT;	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)	{		debug_error("zc0301_vidioc_s_parm:type is wrong\n");		return -EINVAL;	}	sp.parm.capture.extendedmode = 0;	if (copy_to_user(arg, &sp, sizeof(struct v4l2_streamparm)))		return -EFAULT;	return 0;}int zc0301_ioctl_v4l2(struct inode *inode, struct file *filp, unsigned int cmd, void __user *arg){	struct zc0301_device *cam = NULL;	if (filp == NULL)	{		debug_error("zc0301_ioctl_v4l2:filp is null\n");		return -EIO;	}	//debug_param("%s\n", __FUNCTION__);	cam = filp->private_data;	switch (cmd)	{		case VIDIOC_QUERYCAP:				return zc0301_vidioc_querycap(cam, arg);			case VIDIOC_ENUMINPUT:				return zc0301_vidioc_enuminput(cam, arg);		case VIDIOC_G_INPUT:				return zc0301_vidioc_g_input(cam, arg);		case VIDIOC_S_INPUT:				return zc0301_vidioc_s_input(cam, arg);		case VIDIOC_QUERYCTRL:				return zc0301_vidioc_query_ctrl(cam, arg);		case VIDIOC_G_FMT:				return zc0301_vidioc_g_fmt(cam, arg);		case VIDIOC_S_FMT:				return zc0301_vidioc_s_fmt(cam, arg);		case VIDIOC_REQBUFS:				return zc0301_vidioc_reqbufs(cam, arg);		case VIDIOC_QUERYBUF:				return zc0301_vidioc_querybuf(cam, arg);		case VIDIOC_QBUF:				return zc0301_vidioc_qbuf(cam, arg);		case VIDIOC_DQBUF:				return zc0301_vidioc_dqbuf(cam, filp, arg);		case VIDIOC_STREAMON:				return zc0301_vidioc_streamon(cam, arg);		case VIDIOC_STREAMOFF:				return zc0301_vidioc_streamoff(cam, arg);		case VIDIOC_G_PARM:				return zc0301_vidioc_g_parm(cam, arg);		case VIDIOC_S_PARM:				return zc0301_vidioc_s_parm(cam, arg);		default:				//debug_info("zc0301_ioctl_v4l2:other ioctl for v4l2\n");				return -EINVAL;	}}EXPORT_SYMBOL(zc0301_vidioc_querycap);EXPORT_SYMBOL(zc0301_vidioc_enuminput);EXPORT_SYMBOL(zc0301_vidioc_g_input);EXPORT_SYMBOL(zc0301_vidioc_s_input);EXPORT_SYMBOL(zc0301_vidioc_query_ctrl);EXPORT_SYMBOL(zc0301_vidioc_g_fmt);EXPORT_SYMBOL(zc0301_vidioc_s_fmt);EXPORT_SYMBOL(zc0301_vidioc_reqbufs);EXPORT_SYMBOL(zc0301_vidioc_querybuf);EXPORT_SYMBOL(zc0301_vidioc_qbuf);EXPORT_SYMBOL(zc0301_vidioc_dqbuf);EXPORT_SYMBOL(zc0301_vidioc_streamon);EXPORT_SYMBOL(zc0301_vidioc_streamoff);EXPORT_SYMBOL(zc0301_vidioc_g_parm);EXPORT_SYMBOL(zc0301_vidioc_s_parm);EXPORT_SYMBOL(zc0301_ioctl_v4l2);

⌨️ 快捷键说明

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