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

相关文章

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

C#如何调用C++库

《C#如何调用C++库》:本文主要介绍C#如何调用C++库方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录方法一:使用P/Invoke1. 导出C++函数2. 定义P/Invoke签名3. 调用C++函数方法二:使用C++/CLI作为桥接1. 创建C++/CL

Linux之systemV共享内存方式

《Linux之systemV共享内存方式》:本文主要介绍Linux之systemV共享内存方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、工作原理二、系统调用接口1、申请共享内存(一)key的获取(二)共享内存的申请2、将共享内存段连接到进程地址空间3、将

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

usb接口驱动异常问题常用解决方案

《usb接口驱动异常问题常用解决方案》当遇到USB接口驱动异常时,可以通过多种方法来解决,其中主要就包括重装USB控制器、禁用USB选择性暂停设置、更新或安装新的主板驱动等... usb接口驱动异常怎么办,USB接口驱动异常是常见问题,通常由驱动损坏、系统更新冲突、硬件故障或电源管理设置导致。以下是常用解决

Linux命令之firewalld的用法

《Linux命令之firewalld的用法》:本文主要介绍Linux命令之firewalld的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux命令之firewalld1、程序包2、启动firewalld3、配置文件4、firewalld规则定义的九大

Linux之计划任务和调度命令at/cron详解

《Linux之计划任务和调度命令at/cron详解》:本文主要介绍Linux之计划任务和调度命令at/cron的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux计划任务和调度命令at/cron一、计划任务二、命令{at}介绍三、命令语法及功能 :at

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Linux内核参数配置与验证详细指南

《Linux内核参数配置与验证详细指南》在Linux系统运维和性能优化中,内核参数(sysctl)的配置至关重要,本文主要来聊聊如何配置与验证这些Linux内核参数,希望对大家有一定的帮助... 目录1. 引言2. 内核参数的作用3. 如何设置内核参数3.1 临时设置(重启失效)3.2 永久设置(重启仍生效

kali linux 无法登录root的问题及解决方法

《kalilinux无法登录root的问题及解决方法》:本文主要介绍kalilinux无法登录root的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录kali linux 无法登录root1、问题描述1.1、本地登录root1.2、ssh远程登录root2、