博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
camera驱动(六)
阅读量:3897 次
发布时间:2019-05-23

本文共 6575 字,大约阅读时间需要 21 分钟。

1. 用户空间进行 ioctl 操作

        V4L2支持两种方式来采集数据,具体哪两种请回看,ioctl 编是摄像头驱动中通过mmap方式采集数据的最关键的一个接口。

static const struct file_operations v4l2_fops = {	.unlocked_ioctl = v4l2_ioctl,     ······};static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){    vdev->fops->ioctl(filp, cmd, arg);  //调用master的ioctl()}static long mxc_v4l_ioctl(struct file *file, unsigned int cmd,unsigned long arg){	/*通过video_usercopy函数间接调用mxc_v4l_do_ioctl函数*/     return video_usercopy(file, cmd, arg, mxc_v4l_do_ioctl);}static long mxc_v4l_do_ioctl(struct file *file, unsigned int ioctlnr, void *arg){	/*我们根据一般摄像头应用程序的执行调用过程的顺序来分析*/	switch (ioctlnr) {	/*1.它的目的很简单,只是简单问问,你是谁?你能干什么?基本就是驱动来填充应用程序传入的v4l2_capability结构体cap,设置其中的一些参数*/	/*然后应用程序就可以使用这些参数了,包括设置名字、capabilities属性等等*/	case VIDIOC_QUERYCAP: {		struct v4l2_capability *cap = arg;		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';		break;	}	/*6.获取第5步中设置的一些信息,后面有用*/	case VIDIOC_G_FMT: {		struct v4l2_format *gf = arg;		pr_debug("   case VIDIOC_G_FMT\n");		retval = mxc_v4l2_g_fmt(cam, gf);		break;	}	/*5.调用mxc_v4l2_s_fmt()函数*/	case VIDIOC_S_FMT: {		struct v4l2_format *sf = arg;		retval = mxc_v4l2_s_fmt(cam, sf);		break;	} 	/*7.分配内存*/	case VIDIOC_REQBUFS: {		struct v4l2_requestbuffers *req = arg;		/*判断申请的buffer数目是否超过最大的数目*/		if (req->count > FRAME_NUM) {			pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: not enough buffers\n");			req->count = FRAME_NUM;		}            ······		mxc_streamoff(cam);	/*-->*/		if (req->memory & V4L2_MEMORY_MMAP) {			mxc_free_frame_buf(cam); /*释放掉内存,主要是dma_free_coherent函数*/			retval = mxc_allocate_frame_buf(cam, req->count); /*重新分配内存*/		}		break;	}	/*9.调用mxc_v4l2_buffer_status*/	case VIDIOC_QUERYBUF: {		struct v4l2_buffer *buf = arg;		int index = buf->index;		if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {			pr_err("ERROR: v4l2 capture: VIDIOC_QUERYBUFS: wrong buffer type\n");			retval = -EINVAL;			break;		}		if (buf->memory & V4L2_MEMORY_MMAP) {			memset(buf, 0, sizeof(buf));			buf->index = index;		}		if (buf->memory & V4L2_MEMORY_MMAP)			retval = mxc_v4l2_buffer_status(cam, buf); /*-->*/		break;	}	/*10.根据cam->frame[index].buffer.flags的不同选择不同的操作,理论上走到这一步,flags应该是V4L2_BUF_FLAG_MAPPED*/	case VIDIOC_QBUF: {		struct v4l2_buffer *buf = arg;		int index = buf->index;		pr_debug("   case VIDIOC_QBUF\n");		frameerr=ipu_get_csi_frame_error(cam->ipu);		camerastatus = vidioc_int_g_lock_status(cam->sensor);		spin_lock_irqsave(&cam->queue_int_lock, lock_flags);		if ((cam->frame[index].buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) {			cam->frame[index].buffer.flags |= V4L2_BUF_FLAG_QUEUED;		/*给这个flags添加一个V4L2_BUF_FLAG_QUEUED属性*/			list_add_tail(&cam->frame[index].queue, &cam->ready_q);		/*然后将这个buffer添加到cam->ready_q*/		} else if                   ······		} else if (cam->frame[index].buffer.flags & V4L2_BUF_FLAG_DONE) {			pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: overwrite done buffer.\n");			cam->frame[index].buffer.flags &= ~V4L2_BUF_FLAG_DONE;	/*清零*/			cam->frame[index].buffer.flags |= V4L2_BUF_FLAG_QUEUED;	/*重新设置*/			retval = -EINVAL;		}		break;	}	/*12.当开始数据传输以后,当有数据填满一个buffer,就可以将这个buffer出队了,应用程序会调用到VIDIOC_DQBUF 	这个ioctl函数*/	case VIDIOC_DQBUF: {		struct v4l2_buffer *buf = arg;		pr_debug("   case VIDIOC_DQBUF\n");		if ((cam->enc_counter == 0) && (file->f_flags & O_NONBLOCK)) {			retval = -EAGAIN;			break;		}		retval = mxc_v4l_dqueue(cam, buf);  /*-->*/		break;	}	/*11.从第10步QBUF以后就可以开始传输数据了*/	case VIDIOC_STREAMON: {		pr_debug("   case VIDIOC_STREAMON\n");		retval = mxc_streamon(cam);	/-->/		break;	}	/*13.先等待idmac结束,然后先关掉csi,然关闭idmac,再关掉CSI--MEM channel*/	case VIDIOC_STREAMOFF: {		pr_debug("   case VIDIOC_STREAMOFF\n");		retval = mxc_streamoff(cam);		break;	}	/*3.判断传入的v4l2_cropcap *cap中type是否为V4L2_BUF_TYPE_VIDEO_CAPTURE或者V4L2_BUF_TYPE_VIDEO_OVERLAY*/	/*应用程序中设置成了V4L2_BUF_TYPE_VIDEO_CAPTURE??我不记得*/	case VIDIOC_CROPCAP: {		struct v4l2_cropcap *cap = arg;		pr_debug("   case VIDIOC_CROPCAP\n");		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {			retval = -EINVAL;			break;		}		/*cam->crop_bounds和cam->crop_defrect两个变量是在mxc_v4l_open函数中进行设置的*/		cap->bounds = cam->crop_bounds;		cap->defrect = cam->crop_defrect;		break;	}	/*4.跳转到mxc_v4l2_s_param中去执行*/	case VIDIOC_S_PARM:  {		struct v4l2_streamparm *parm = arg;		pr_debug("   case VIDIOC_S_PARM\n");		if (cam->sensor)			retval = mxc_v4l2_s_param(cam, parm);		break;	}	/*2.根据应用程序中传过来的args参数来判断,MXC_V4L2_CAPTURE_NUM_INPUTS==2*/	case VIDIOC_S_INPUT: {		int *index = arg;		pr_debug("   case VIDIOC_S_INPUT\n");		/*在init_camera_struct函数中将cam->current_input初始化为0了,如果要设置的input和当前input相同的话,就直接退出*/		if (*index == cam->current_input)			break;		/*因为mxc_capture_inputs[0].status==0,所以后面的函数不会执行*/		if ((mxc_capture_inputs[cam->current_input].status & V4L2_IN_ST_NO_POWER) == 0) {			retval = mxc_streamoff(cam);			if (retval)				break;			mxc_capture_inputs[cam->current_input].status |=							V4L2_IN_ST_NO_POWER;		}		/*根据mxc_capture_inputs[*index].name来选择执行哪个函数,在open函数中有执行过相同步骤,不理解??*/		if (strcmp(mxc_capture_inputs[*index].name, "CSI MEM") == 0) {#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)			retval = csi_enc_select(cam);			if (retval)				break;#endif		} else if (strcmp(mxc_capture_inputs[*index].name,				  "CSI IC MEM") == 0) {#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)			retval = prp_enc_select(cam);			if (retval)				break;#endif		}		/*将mxc_capture_inputs[*index].status标志位清零,然后将cam->current_input指向当前的mxc_capture_inputs[*index]*/		mxc_capture_inputs[*index].status &= ~V4L2_IN_ST_NO_POWER;		cam->current_input = *index;		break;	}  case VIDIOC_ENUM_FMT: {	//获取从设备的pixelformat				struct v4l2_fmtdesc *f = arg;		if (cam->sensor)			retval = vidioc_int_enum_fmt_cap(cam->sensor, f);		else {			pr_err("ERROR: v4l2 capture: slave not found!\n");			retval = -ENODEV;		}		break;	}		case VIDIOC_DBG_G_CHIP_IDENT: {	//获取解码芯片的身份,即名字和类型		struct v4l2_dbg_chip_ident *p = arg;		p->ident = V4L2_IDENT_NONE;		p->revision = 0;		if (cam->sensor)			retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p);		else {			pr_err("ERROR: v4l2 capture: slave not found!\n");			retval = -ENODEV;		}		break;	}	case VIDIOC_TRY_FMT:	case VIDIOC_G_TUNER:	case VIDIOC_S_TUNER:	case VIDIOC_G_FREQUENCY:	case VIDIOC_S_FREQUENCY:   ······	default:		pr_debug("   case default or not supported\n");		retval = -EINVAL;		break;	}	if (ioctlnr != VIDIOC_DQBUF)		up(&cam->busy_lock);	return retval;}

转载地址:http://keuen.baihongyu.com/

你可能感兴趣的文章
一年成为Emacs高手(像神一样使用编辑器) .--http://blog.csdn.net/redguardtoo/article/details/7222501
查看>>
GNU make 指南
查看>>
配置 vim
查看>>
CentOS6.3 minimal SSH中文显示
查看>>
centos 安装emacs24
查看>>
【转】结构体中Char a[0]用法——柔性数组
查看>>
结构体最后定义一个char p[0];这样的成员有何意义(转)
查看>>
一步一学Linux与Windows 共享文件Samba (v0.2b)
查看>>
Linux 下忘记root密码怎么办
查看>>
Linux软件下载源码编程文章资料周立发--之调试
查看>>
GIT分支管理是一门艺术
查看>>
Cscope在emacs中的配置与使用
查看>>
emacs 2.4安装问题 ecb
查看>>
ecb里使用自定义快捷键切换窗口
查看>>
vim(gvim)支持对齐线
查看>>
CentOS编译安装Lighttpd1.4.28
查看>>
实践HTTP206状态:部分内容和范围请求
查看>>
【C++基础】拷贝构造函数的参数必须是引用类型
查看>>
【C++基础】virtual析构函数
查看>>
【Java基础】面向对象
查看>>