Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3105665
  • 博文数量: 396
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4209
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-04 13:04
文章分类

全部博文(396)

文章存档

2022年(1)

2021年(2)

2020年(8)

2019年(24)

2018年(135)

2017年(158)

2016年(68)

我的朋友

分类: 嵌入式

2017-02-22 14:36:03

    在/dev下被创建的真正的设备节点是使用video_device结构体(v4l2-dev.h)。这个结构体同时也可以动态分配或嵌入到一个更大的结构体。

动态分配:  

复制代码
struct video_device *vdev = video_device_alloc(); if (vdev == NULL) return -ENOMEM;

vdev->release = video_device_release;
复制代码

  如果你嵌入到一个更大的结构体,你必须设置release()函数回调到你自己的函数:

struct video_device *vdev = &my_vdev->vdev;

vdev->release = my_vdev_release;

  release回调必须设置并且当最后一个使用video device的用户退出时会被回调。默认的video_device_release()调用仅仅调用Kfree来释放分配的内存。

你还需要设置以下成员:
- v4l2_dev : 设置v4l2_device的父设备
- name: 名称
- fops: set to the v4l2_file_operations struct.
- ioctl_ops: 如果你使用 v4l2_ioctl_ops 来简化ioctl 的维护(建议使用并且以后可能会变为强制使用),然后设置v4l2_ioctl_ops结构
- lock:如果你想在驱动中完成所有的locking,那么就设置为NULL。否则设置为struct mutex_lock指针并且在任何v4l2_file_operations被调用之前使用这个lock,改lock将会被core持有并且之后release。
- prio:跟踪优先级(priorities)。用来实现VIDIOC_G/S_PRIORITY。如果为NULL,将会使用v4l2_device的v4l2_prio_state成员。如果你想将每个设备节点的priority state分离,你可以将它指向你自己的struct v4l2_prio_state。

- parent:you only set this if v4l2_device was registered with NULL as  the parent device struct. This only happens in cases where one hardware device has multiple PCI devices that all share the same v4l2_device core.

cx88驱动: 一个核心的v4l2_device结构,但是同时被一个raw video PCI设备(cx8800)和一个特别的PCI设备使用。由于v4l2_device不能和特别的PCI设备关联,所以这将会导致它的没有父设备。但是当你知道使用哪个PCI设备作为video_device的父设备那么就会设置父设备。
- flags:可选设置。如果你想要处理VIDIOC_G/S_PRIORITY ioctls就设置为V4L2_FL_USE_FH_PRIO。这要求你使用v4l2_fh结构体。一旦所有驱动使用core priority处理时,最终flag将会消失。但是现在必须显式设置。

如果使用v4l2_ioctl_ops,需要在v4l2_file_operations结构中设置 .unlocked_ioctl到video_ioctl2结构。


Do not use .ioctl! This is deprecated and will go away in the future.

v4l2_file_operations是file_operations的一个子集。主要区别在于节点参数被删除,因为永远不会使用。

如果需要集成media framework,必须初始化video_device结构中的media_entity成员,通过调用media_entity_init:

struct media_pad *pad = &my_vdev->pad; int err;

err = media_entity_init(&vdev->entity, 1, pad, 0);

  pads array必须提前初始化,不需要手动设置media_entity的type和name。

  当video device打开/关闭时,entity的引用将会自动的acquired/released。

v4l2_file_operations and locking
  你可以设置一个指针只想video_device中的mutex_lock成员。通常,这个mutex是一个top-level mutex或每个设备节点的mutex。如果你想要更细粒度的锁,那么你必须将它设置为空,并做你自己的锁。
  如果lock被指定,所有的file operations将会在该lock上串行。如果使用videobuf必须传递一个这个lock到videobuf queue的初始化函数中:如果videobuf在等一帧数据到来,它将会临时unlock并且稍后relock。如果驱动同时也在等待,当地一个进程在等待某些资源时,应该允许其他进程访问设备节点。

  热插拔的实现也应该在调用v4l2_device_disconnect之前持有该锁。

video_device registration
  注册video device,将会创建字符设备。

err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); if (err) {
    video_device_release(vdev); /* or kfree(my_vdev); */ return err;
}

  如果v4l2_device的父设备非NULL,video device的entity将会被自动地使用media device注册。

哪个设备被注册依赖于type参数:
VFL_TYPE_GRABBER:videoX for video input/output devices
VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext)
VFL_TYPE_RADIO: radioX for radio tuners

最后一个参数指定了使用哪个设备节点数字(0 == /dev/video0, 1 == /dev/video1... -1 == first free)。但是有时用户想要选择一个特定的节点号。如果用户制定的节点号已经在使用,那么下一个空闲的设备节点号将被选中并且发送一个warning到kernel log。


另外一个使用案例是创建多个设备。此时,将video device放在不同的分离的范围是非常有用的。例如,video capture device起始于0,video output devices起始于16。因此可以使用最后参数制定最小的设备节点号,并且v4l2架构将会尽量在传递的数字中选择第一个free number或者更高的。如果失败,将会只选择第一个free number。

由于这种情况下,你不需要关心不能选择特定的设备节点号的warning,你可以调用video_register_device_no_warn()来替代。
无论何时创建一个设备节点的创建有一些attributes也会被创建。如果你查询/sys/class/video4linux可以看到这些设备。
‘index’属性是设备节点的index:每次调用video_register_device(),index仅仅被加1,第一个video设备节点通常起始的index为0。

用户可以设置udev规则,利用指标属性做出花哨的设备名称 (e.g. 'mpegX' for MPEG video capture device nodes)。

device注册成功后,可以使用如下成员:
- vfl_type: the device type passed to video_register_device.
- minor:the assigned device minor number.
- num: the device node number (i.e. the X in videoX).
- index: the device index number.

device注册失败后,需要调用video_device_release()来释放video_device结构体占用的内存。或者释放用户自己分配的结构。如果注册失败vdev->release()回调永不被调用,你也不用试图注销设备。


video_device cleanup

  当video device node被删除后,无论是在卸载该驱动程序或由于USB设备断开,那么你应该注销他们:

video_unregister_device(vdev);

  这个操作将会将设备节点从sysfs(由udev来从/dev上删除)上删除。

  在video_unregister_device()返回且没有新的操作时,注销成功。然而,有时USB设备在某些应用中可能仍然打开其中的一个设备节点。因此,在unregister后,所有的file operations(除release)将会返回一个错误。
  当video device node的最后一个用户退出时,vdev->release()被调用,你可以在这里做最后的清理工作。
  不要忘记清理media entity。

media_entity_cleanup(&vdev->entity);


 video_device helper functions
1. file/video_device private data

void *video_get_drvdata(struct video_device *vdev); void video_set_drvdata(struct video_device *vdev, void *data);

  注意:在调用video_register_device()之前可以安全的调用video_set_drvdata()。

struct video_device *video_devdata(struct file *file); // 返回video_device
void *video_drvdata(struct file *file); // 结合了video_get_drvdata和video_devdata的功能

从video_device结构获取v4l2_device结构的方法:

struct v4l2_device *v4l2_dev = vdev->v4l2_dev;

- Device node name

const char *video_device_node_name(struct video_device *vdev);

  name用于在用户空间的提示。在访问video_device::num和video_device::minor时,可能被使用。

video buffer helper functions
v4l2 core API为解决video buffer问题提供了一组标准方法("videobuf")。这些方法允许驱动一致实现read(), mmap(), overlay()函数。目前这些方法支持DMA分散/收集方法(videobuf-dma-sg),DMA以线性方式访问内存(videobuf_dma_contig),并且vmalloced buffers,大多数时候在USB驱动中使用(videobuf-vmalloc)。

阅读(2014) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~