linux下的cmos摄像头驱动设计2-应用程序的调用与驱动程序的关系

本文主要是介绍linux下的cmos摄像头驱动设计2-应用程序的调用与驱动程序的关系,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇写了,摄像头驱动的注册过程,这次写写应用程序的调用与驱动程序的关系,遵循V4L2架构的应用程序主要由几个ioctl组成,

其实也比较简单,有时候驱动写的不标准,应用程序按标准的操作操作就不行,出不来图像,这时需要跟踪驱动程序,看看哪个地方出错了,

首先,要打开设备  

1.fd = open(dev_name, O_RDWR /* required */| O_NONBLOCK, 0);

dev_name为video0 或者video1或者video几,首先要打开设备,打开这个设备后,就可以获得一个文件操作符fd,这时就可以通过它来执行视频设备的操作函数,

从而达到控制设备的目的。

2.ioctl(fd, VIDIOC_QUERYCAP, &cap)

查询设备节点具有的功能,执行视频节点的ioctl函数,最终会调用到内核中的

static long __video_do_ioctl(struct file *file,unsigned int cmd, void *arg)这个函数

	/* --- capabilities ------------------------------------------ */case VIDIOC_QUERYCAP:{struct v4l2_capability *cap = (struct v4l2_capability *)arg;if (!ops->vidioc_querycap)break;ret = ops->vidioc_querycap(file, fh, cap);if (!ret)dbgarg(cmd, "driver=%s, card=%s, bus=%s, ""version=0x%08x, ""capabilities=0x%08x\n",cap->driver, cap->card, cap->bus_info,cap->version,cap->capabilities);break;}
其中可以看到,核心的调用函数为
ret = ops->vidioc_querycap(file, fh, cap);
这个函数指针调用最终会通过

static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {.vidioc_querycap		= fimc_vidioc_querycap_capture,.vidioc_enum_fmt_vid_cap_mplane	= fimc_vidioc_enum_fmt_mplane,.vidioc_try_fmt_vid_cap_mplane	= fimc_vidioc_try_fmt_mplane,.vidioc_s_fmt_vid_cap_mplane	= fimc_cap_s_fmt_mplane,.vidioc_g_fmt_vid_cap_mplane	= fimc_vidioc_g_fmt_mplane,.vidioc_s_fmt_type_private	= fimc_s_fmt_vid_private,.vidioc_reqbufs			= fimc_cap_reqbufs,.vidioc_querybuf		= fimc_cap_querybuf,.vidioc_qbuf			= fimc_cap_qbuf,.vidioc_dqbuf			= fimc_cap_dqbuf,.vidioc_streamon		= fimc_cap_streamon,.vidioc_streamoff		= fimc_cap_streamoff,.vidioc_queryctrl		= fimc_vidioc_queryctrl,.vidioc_g_ctrl			= fimc_vidioc_g_ctrl,.vidioc_s_ctrl			= fimc_cap_s_ctrl,.vidioc_g_crop			= fimc_cap_g_crop,.vidioc_s_crop			= fimc_cap_s_crop,.vidioc_cropcap			= fimc_cap_cropcap,.vidioc_enum_input		= fimc_cap_enum_input,.vidioc_s_input			= fimc_cap_s_input,.vidioc_g_input			= fimc_cap_g_input,
};
调用到
static int fimc_vidioc_querycap_capture(struct file *file, void *priv,struct v4l2_capability *cap)
{struct fimc_ctx *ctx = file->private_data;struct fimc_dev *fimc = ctx->fimc_dev;strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);cap->bus_info[0] = 0;cap->version = KERNEL_VERSION(1, 0, 0);cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |V4L2_CAP_VIDEO_CAPTURE_MPLANE;return 0;
}
3,接下来的操作一般都是

 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {printf("************** %s, line = %d\n", __FUNCTION__, __LINE__);fprintf(stderr, "%s is no video capture device\n", dev_name);return false;}
  if (!(cap.capabilities & V4L2_CAP_STREAMING)) {printf("************** %s, line = %d\n", __FUNCTION__, __LINE__);fprintf(stderr, "%s does not support streaming i/o\n", dev_name);return false;}
根据上面驱动程序中的代码,说明,只有驱动程序注册正确,执行这些操作就不会报no video capture device 和does not support streaming 的错误。

4.接下来的操作一般是

  v4l2_input input;memset(&input, 0, sizeof(struct v4l2_input));input.index = 0;int rtn = ioctl(fd, VIDIOC_S_INPUT, &input);
设置输入,这个操作有时候是很重要的,没它不行,为什么重要,请看源码。

和第二句应用程序的分析一样,最终会跳到

static long __video_do_ioctl(struct file *file,unsigned int cmd, void *arg)这个函数


	case VIDIOC_S_INPUT:{unsigned int *i = arg;if (!ops->vidioc_s_input)break;dbgarg(cmd, "value=%d\n", *i);ret = ops->vidioc_s_input(file, fh, *i);break;}
然后根据操作函数集,会最终执行

int fimc_s_input(struct file *file, void *fh, unsigned int i)
{
<span style="white-space:pre">	</span>struct fimc_global *fimc = get_fimc_dev();
<span style="white-space:pre">	</span>struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
<span style="white-space:pre">	</span>struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
<span style="white-space:pre">	</span>int ret = 0;<span style="white-space:pre">	</span>fimc_dbg("%s: index %d\n", __func__, i);<span style="white-space:pre">	</span>if (i < 0 || i >= FIMC_MAXCAMS) {
<span style="white-space:pre">		</span>fimc_err("%s: invalid input index\n", __func__);
<span style="white-space:pre">		</span>return -EINVAL;
<span style="white-space:pre">	</span>}<span style="white-space:pre">	</span>if (!fimc->camera_isvalid[i])
<span style="white-space:pre">		</span>return -EINVAL;<span style="white-space:pre">	</span>if (fimc->camera[i]->sd && fimc_cam_use) {
<span style="white-space:pre">		</span>fimc_err("%s: Camera already in use.\n", __func__);
<span style="white-space:pre">		</span>return -EBUSY;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>mutex_lock(&ctrl->v4l2_lock);<span style="white-space:pre">	</span>/* If ctrl->cam is not NULL, there is one subdev already registered.
<span style="white-space:pre">	</span> * We need to unregister that subdev first. */
<span style="white-space:pre">	</span>if (i != fimc->active_camera) {
<span style="white-space:pre">		</span>fimc_info1("\n\nfimc_s_input activating subdev\n");
<span style="white-space:pre">		</span>if (ctrl->cam && (ctrl->cam->sd || ctrl->flite_sd))
<span style="white-space:pre">			</span>fimc_release_subdev(ctrl);
<span style="white-space:pre">		</span>else if (ctrl->is.sd)
<span style="white-space:pre">			</span>fimc_is_release_subdev(ctrl);
<span style="white-space:pre">		</span>ctrl->cam = fimc->camera[i];<span style="white-space:pre">		</span>if ((ctrl->cam->id != CAMERA_WB) && (ctrl->cam->id !=
<span style="white-space:pre">			</span>CAMERA_WB_B) && (!ctrl->cam->use_isp) && fimc_cam_use) {
<span style="white-space:pre">			</span>ret = fimc_configure_subdev(ctrl);
<span style="white-space:pre">			</span>if (ret < 0) {
<span style="white-space:pre">				</span>mutex_unlock(&ctrl->v4l2_lock);
<span style="white-space:pre">				</span>fimc_err("%s: Could not register camera" \
<span style="white-space:pre">					</span>" sensor with V4L2.\n", __func__);
<span style="white-space:pre">				</span>return -ENODEV;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>fimc->active_camera = i;
<span style="white-space:pre">		</span>fimc_info2("fimc_s_input activated subdev = %d\n", i);
<span style="white-space:pre">	</span>}<span style="white-space:pre">	</span>if (!fimc_cam_use) {
<span style="white-space:pre">		</span>if (i == fimc->active_camera) {
<span style="white-space:pre">			</span>ctrl->cam = fimc->camera[i];
<span style="white-space:pre">			</span>fimc_info2("fimc_s_input activating subdev FIMC%d\n",
<span style="white-space:pre">							</span>ctrl->id);
<span style="white-space:pre">		</span>} else {
<span style="white-space:pre">			</span>mutex_unlock(&ctrl->v4l2_lock);
<span style="white-space:pre">			</span>return -EINVAL;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}<span style="white-space:pre">	</span>if (ctrl->cam->use_isp) {
<span style="white-space:pre">	</span>    /* fimc-lite attatch */
<span style="white-space:pre">	</span>    ret = fimc_subdev_attatch(ctrl);
<span style="white-space:pre">	</span>    if (ret) {
<span style="white-space:pre">		</span>    fimc_err("subdev_attatch failed\n");
<span style="white-space:pre">		</span>    mutex_unlock(&ctrl->v4l2_lock);
<span style="white-space:pre">		</span>    return -ENODEV;
<span style="white-space:pre">	</span>    }
<span style="white-space:pre">	</span>    /* fimc-is attatch */
<span style="white-space:pre">	</span>    ctrl->is.sd = fimc_is_get_subdev(i);
<span style="white-space:pre">	</span>    if (IS_ERR_OR_NULL(ctrl->is.sd)) {
<span style="white-space:pre">		</span>fimc_err("fimc-is subdev_attatch failed\n");
<span style="white-space:pre">		</span>mutex_unlock(&ctrl->v4l2_lock);
<span style="white-space:pre">		</span>return -ENODEV;
<span style="white-space:pre">	</span>    }<span style="white-space:pre">	</span>    ctrl->is.fmt.width = ctrl->cam->width;
<span style="white-space:pre">	</span>    ctrl->is.fmt.height = ctrl->cam->height;
<span style="white-space:pre">	</span>    ctrl->is.frame_count = 0;
<span style="white-space:pre">	</span>    if (fimc_cam_use) {
<span style="white-space:pre">		</span>ret = fimc_is_init_cam(ctrl);
<span style="white-space:pre">		</span>if (ret < 0) {
<span style="white-space:pre">			</span>fimc_dbg("FIMC-IS init clock failed");
<span style="white-space:pre">			</span>mutex_unlock(&ctrl->v4l2_lock);
<span style="white-space:pre">			</span>return -ENODEV;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>ret = v4l2_subdev_call(ctrl->is.sd, core, s_power, 1);
<span style="white-space:pre">		</span>if (ret < 0) {
<span style="white-space:pre">			</span>fimc_dbg("FIMC-IS init failed");
<span style="white-space:pre">			</span>mutex_unlock(&ctrl->v4l2_lock);
<span style="white-space:pre">			</span>return -ENODEV;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>ret = v4l2_subdev_call(ctrl->is.sd, core, load_fw);
<span style="white-space:pre">		</span>if (ret < 0) {
<span style="white-space:pre">			</span>fimc_dbg("FIMC-IS init failed");
<span style="white-space:pre">			</span>mutex_unlock(&ctrl->v4l2_lock);
<span style="white-space:pre">			</span>return -ENODEV;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>ret = v4l2_subdev_call(ctrl->is.sd, core, init, ctrl->cam->sensor_index);
<span style="white-space:pre">		</span>if (ret < 0) {
<span style="white-space:pre">			</span>fimc_dbg("FIMC-IS init failed");
<span style="white-space:pre">			</span>mutex_unlock(&ctrl->v4l2_lock);
<span style="white-space:pre">			</span>return -ENODEV;
}}
}mutex_unlock(&ctrl->v4l2_lock);return 0;
}
这个函数中,最关键的是 ret = fimc_configure_subdev(ctrl);这句代码,我们知道cmos摄像头驱动也属于一个I2C驱动,因为在对摄像头芯片初始化时,设置参数时,要通过I2C 总线来操作,linux内核驱动为I2C总线驱动设计了一种框架,做到了设备与驱动的分离,这个类似于platform平台驱动原理,不懂的可以先去学一下那部分,前面我们驱动分析时,一直没有提到对于摄像头驱动I2C设备的注册,摄像头senor部分的初始化的触发,就在于这个对于的I2C设备的注册,只有系统中注册了摄像头senor对应的i2c设备,I2C设备与senor部分对应的driver就会进行匹配,然后执行对于的probe函数,probe函数中会进行摄像头senor部分的初始化。

在这里fimc_configure_subdev(ctrl)的作用主要就是就是注册一个i2c设备,当然它也干其他的了,还注册了一个V4L2子设备(sub-dev),并且把他们关联了起来,这样,以后可以通过I2C设备访问V4L2_SUB设备,也可以通过V4L2_SUB设备控制i2c设备,具体的代码我就不分析了,自己看源码吧。

5.接下来一般就是设置视频采集的格式了

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.width = width;fmt.fmt.pix.height = height;fmt.fmt.pix.sizeimage = (fmt.fmt.pix.width*fmt.fmt.pix.height*12)/8;fmt.fmt.pix.field = V4L2_FIELD_NONE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
ioctl(fd, VIDIOC_S_FMT, &fmt)
设置视频采集处理的格式、宽、高,通过IOCTL转到驱动程序,从而控制硬件,达到设置视频输出的目标

明天再写吧,睡觉了






这篇关于linux下的cmos摄像头驱动设计2-应用程序的调用与驱动程序的关系的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1086325

相关文章

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

Linux搭建ftp服务器的步骤

《Linux搭建ftp服务器的步骤》本文给大家分享Linux搭建ftp服务器的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录ftp搭建1:下载vsftpd工具2:下载客户端工具3:进入配置文件目录vsftpd.conf配置文件4:

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

Java调用Python脚本实现HelloWorld的示例详解

《Java调用Python脚本实现HelloWorld的示例详解》作为程序员,我们经常会遇到需要在Java项目中调用Python脚本的场景,下面我们来看看如何从基础到进阶,一步步实现Java与Pyth... 目录一、环境准备二、基础调用:使用 Runtime.exec()2.1 实现步骤2.2 代码解析三、

Springboot项目构建时各种依赖详细介绍与依赖关系说明详解

《Springboot项目构建时各种依赖详细介绍与依赖关系说明详解》SpringBoot通过spring-boot-dependencies统一依赖版本管理,spring-boot-starter-w... 目录一、spring-boot-dependencies1.简介2. 内容概览3.核心内容结构4.