分类: v4l2
2013-03-31 08:42
997人阅读
评论(0)
收藏
举报
一、 注册一个video_device设备
它代表系统/dev/videox设备节点的实际的物理设备。
下边一内核版本2.6.32种成熟的omap2432处理器摄像头控制器模块驱动为例分析:
下边的代码在driver/media/video/omap24xxcam.c中
1、Video device的操作函数集
- static struct v4l2_file_operations omap24xxcam_fops = {
- .ioctl = video_ioctl2,
- .poll = omap24xxcam_poll,
- .mmap = omap24xxcam_mmap,
- .open = omap24xxcam_open,
- .release = omap24xxcam_release,
- };
2、Video device控制操作函数集
- static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_parm = vidioc_g_parm,
- .vidioc_s_parm = vidioc_s_parm,
- };
3、注册函数:omap24xxcam_device_register
- static int omap24xxcam_device_register(struct v4l2_int_device *s)
- {
- struct omap24xxcam_device *cam = s->u.slave->master->priv;
- struct video_device *vfd;//定义struct video_device结构体
- int rval;
- 。。。。。。
- /* initialize the video_device struct */
- vfd = cam->vfd = video_device_alloc();
- if (!vfd) {
- dev_err(cam->dev, "could not allocate video device struct\n");
- rval = -ENOMEM;
- goto err;
- }
- vfd->release = video_device_release;
- vfd->parent = cam->dev;
- strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
- //该video device设备V4L2操作函数集,在下边定义,这个通过最顶级字符设备的响应操作函数调用
- vfd->fops = &omap24xxcam_fops;
- vfd->minor = -1;
- //该video device设备控制操作,和vfd->fops中的ioctl可能重复,下边进一步分析。
- vfd->ioctl_ops = &omap24xxcam_ioctl_fops;
- omap24xxcam_hwinit(cam);
- rval = omap24xxcam_sensor_init(cam);
- if (rval)
- goto err;
- //注册video device,VFL_TYPE_GRABBER表示注册的是视频处理设备,video_nr=-1表示自动分配从设备号
- if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
- dev_err(cam->dev, "could not register V4L device\n");
- vfd->minor = -1;
- rval = -EBUSY;
- goto err;
- }
- 。。。。。。。
- err:
- omap24xxcam_device_unregister(s);
- return rval;
- }
二、 调用过程
应用程序的read、write、ioctl等操作函数传到内核层
以ioctl为例作说明:
1、最顶层的调用
在driver/media/video/v4l2-dev.c中:
- static int v4l2_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
- {
- //根据次设备号从video_device[VIDEO_NUM_DEVICES]数组中得到当前操作的video device
- struct video_device *vdev = video_devdata(filp);
- if (!vdev->fops->ioctl)
- return -ENOTTY;
- /* Allow ioctl to continue even if the device was unregistered.
- Things like dequeueing buffers might still be useful. */
- return vdev->fops->ioctl(filp, cmd, arg);
- }
2、自己实现的操作函数集
根据上边注册时填充的fops,vdev->fops->ioctl(filp, cmd, arg)调用下边函数:
(在driver/media/video/omap24xxcam.c)
- static struct v4l2_file_operations omap24xxcam_fops = {
- .ioctl = video_ioctl2,
- 。。。。。
- }
3、中间层处理调用
Video_ioctl2是定义在driver/media/video/v4l2-ioctl.c中的函数:
- long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg)
- {
- char sbuf[128];
- void *mbuf = NULL;
- void *parg = NULL;
- long err = -EINVAL;
- int is_ext_ctrl;
- size_t ctrls_size = 0;
- void __user *user_ptr = NULL;
- 控制命令处理。。。。。。。。。。
- /* Handles IOCTL */
- err = __video_do_ioctl(file, cmd, parg);
- if (err == -ENOIOCTLCMD)
- err = -EINVAL;
- if (is_ext_ctrl) {
- struct v4l2_ext_controls *p = parg;
- p->controls = (void *)user_ptr;
- if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
- err = -EFAULT;
- goto out_ext_ctrl;
- }
- if (err < 0)
- goto out;
- 错误处理。。。。。。。。。
- }
4、根据命令调用相应的处理函数
下边就是根据传入的控制参数,调用相应的已经注册的v4l2_ioctl_ops操作处理
- static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
- {
- //得到当前操作的video device
- struct video_device *vfd = video_devdata(file);
- //v4l2 控制操作函数集,在video device注册时赋值。
- const struct v4l2_ioctl_ops *ops = vfd->omap24xxcam_ioctl_fops;
- void *fh = file->private_data;
- long ret = -EINVAL;
- 参数错误处理。。。。。
- #ifdef CONFIG_VIDEO_V4L1_COMPAT
- /***********************************************************
- Handles calls to the obsoleted V4L1 API
- Due to the nature of VIDIOCGMBUF, each driver that supports
- V4L1 should implement its own handler for this ioctl.
- ***********************************************************/
- /* --- streaming capture ------------------------------------- */
- if (cmd == VIDIOCGMBUF) {
- struct video_mbuf *p = arg;
- if (!ops->vidiocgmbuf)
- return ret;
- ret = ops->vidiocgmbuf(file, fh, p);
- if (!ret)
- dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
- p->size, p->frames,
- (unsigned long)p->offsets);
- return ret;
- }
- /********************************************************
- All other V4L1 calls are handled by v4l1_compat module.
- Those calls will be translated into V4L2 calls, and
- __video_do_ioctl will be called again, with one or more
- V4L2 ioctls.
- ********************************************************/
- if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
- return v4l_compat_translate_ioctl(file, cmd, arg,
- __video_do_ioctl);
- #endif
- switch (cmd) {
- /* --- 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;
- }
- }