linux下的cmos摄像头驱动设计2-应用程序的调用与驱动程序的关系
2014-12-01 00:44
756 查看
上一篇写了,摄像头驱动的注册过程,这次写写应用程序的调用与驱动程序的关系,遵循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)这个函数
4.接下来的操作一般是
和第二句应用程序的分析一样,最终会跳到
static long __video_do_ioctl(struct file *file,unsigned int cmd, void *arg)这个函数
在这里fimc_configure_subdev(ctrl)的作用主要就是就是注册一个i2c设备,当然它也干其他的了,还注册了一个V4L2子设备(sub-dev),并且把他们关联了起来,这样,以后可以通过I2C设备访问V4L2_SUB设备,也可以通过V4L2_SUB设备控制i2c设备,具体的代码我就不分析了,自己看源码吧。
5.接下来一般就是设置视频采集的格式了
明天再写吧,睡觉了
其实也比较简单,有时候驱动写的不标准,应用程序按标准的操作操作就不行,出不来图像,这时需要跟踪驱动程序,看看哪个地方出错了,
首先,要打开设备
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驱动程序编写&&应用程序对她的调用
- 分层设计的驱动程序 及gpio驱动(Linux驱动5)
- linux 应用程序设计基础--系统调用访问文件
- Linux驱动程序开发(4) - 字符设备驱动(3)-LED设备驱动和应用程序
- Linux驱动程序开发 003- 设备与驱动的关系
- Linux-USB驱动(5)-USB驱动程序设计
- 嵌入式Linux驱动学习之路(九)Linux系统调用、驱动程序框架
- linux驱动的异步通知 驱动程序向应用程序发送信号
- linux驱动的异步通知(kill_fasync,fasync)---- 驱动程序向应用程序发送信号
- linux驱动调用(运行/执行)应用程序
- 驱动程序与应用程序中函数调用关系分析(write)
- linux下的cmos摄像头驱动设计1-video驱动的注册
- 基于mini6410的linux驱动学习总结(四 设计字符设备驱动程序)
- linux驱动的异步通知(kill_fasync,fasync)---- 驱动程序向应用程序发送信号
- Linux驱动程序编写&&应用程序对她的调用
- Linux USB设备驱动程序设计 和 USB下载线驱动设计
- Linux按键驱动程序设计(1)-混杂设备驱动模型
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux系统调用的实现机制分析
- Linux设备驱动程序设计实例
- linux resource, platform_device和驱动的关系